File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/modules/calendar/module.calendar.php
<?php
/**
* This file contains most of the core PHP code associated with the IWP Calendar module
*
* @package IWP_Modules
* @subpackage Calendar
*/
// the timezone mapper can use an implementation of InterspireStash to cache it's lookups, which we also use in the core events system
InterspireICalendarTimezoneMapper::$_stash = iwp_eventstash::getInstance();
/**
* Model for calendar exceptions.
* @author Gwilym
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_exception extends iwp_base {
/**
*
* @var iwp_module_calendar_exception
*/
public static $Instance;
/**
*
* @var array
*/
protected $tableFields = array(
'event',
'exdate',
);
/**
*
* @return iwp_module_calendar_exception
*/
public static function getInstance () {
if(!isset(self::$Instance)){
self::$Instance = new self();
}
return self::$Instance;
}
}
/**
* Data model for calendar occurrences produced by repetition rules
* @author Gwilym
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_occurrence {
/**
*
* @var iwp_module_calendar_event
*/
public static $Instance;
/**
*
* @var int
*/
public $id;
/**
*
* @var iwp_module_calendar_event
*/
public $event;
public $begin;
public $end;
/**
*
* @return iwp_module_calendar_event
*/
public static function getInstance () {
if(!isset(self::$Instance)){
self::$Instance = new self();
}
return self::$Instance;
}
}
/**
* CalendarRepeat Field Class
* This class is used by the api form class to generate a field for editing a calendar event's repeat options.
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_field_calendarrepeat extends iwp_field {
/**
* This is the form field type of the field
*
* @var string
*/
public $type = 'calendarrepeat';
/**
* For holding whether the label should be shown for this field or not
*
* @var Boolean
**/
protected $showLabel = false;
/**
* __construct
* The constructor which calls the parent constructor that sets up the field name if it is passed in during the initialization
*
* @var string
*/
public function __construct($name=null){
parent::__construct($name);
}
/**
* GetFieldOutput
* Returns the HTML for this field. It generates the relevant parts, assigns them to template variables and returns a parse template file.
*
* @return string Returns the field HTML
*/
public function GetFieldOutput($setOnly=false){
$inputField = $this->Prepend . '
<div id="PermissionItemTemplate" style="display:none;">
<div class="PermissionItemRow PermissionItemRow_Flag_%%flag%%" id="PermissionItemRow_%%permid%%">
<input type="checkbox" class="PermissionItemCheckbox" id="PermissionItemCheckbox_%%permid%%" value="%%permid%%" />
<label for="PermissionItemCheckbox_%%permid%%">%%permission%%%%granularity%% <a href="#" onclick="editPermissionItem(\'%%permid%%\');return false;"><img src="images/configure.png" alt="' . iwp_htmlentities($this->lang->Get('Edit')) . '" /></a></label>
</div>
</div>
<div id="PermissionItemList" ' . $this->GetAttributes() . '>
<div id="PermissionItemListEmpty" style="display:none;">' . iwp_htmlentities($this->lang->Get('EmptyPermissionList')) . '</div>
</div>
<input type="button" class="FormButton" onclick="return addNewPermissionClick()" value="' . iwp_htmlentities($this->lang->Get('AddNewGroupPermission')) . '" />
<input type="button" class="FormButton" onclick="return deleteSelectedPermissionClick()" value="' . iwp_htmlentities($this->lang->Get('DeleteSelected')) . '" /><br />
' . $this->Append;
parent::GetFieldOutput();
$this->template->Assign('inputField', $inputField);
$this->template->Assign('FieldName', $this->FieldName);
if(!$setOnly){
return $this->template->ParseTemplate('form.field', true);
}
return '';
}
/**
* Validate
* This is the function that data for this field is passed to to ensure it was submitted properly.
*
* @return string|boolean If the data is not valid, it will return false, if it is valid it will return a value
*/
public function Validate($arrData){
return $arrData[$this->FieldName];
}
}
/**
* Interface to be implemented by various actions in this module's mini framework
*
* @package IWP_Modules
* @subpackage Calendar
*/
interface iwp_module_calendar_action_interface {
/**
* Function to be routed to by the action-handling framework
*
*/
public function handleAction ();
}
/**
* Base action class used by this module's mini framework, extended on by more specific action handlers
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_action extends iwp_base {
/**
*
* @var iwp_module_calendar
*/
protected $module;
public function __construct (iwp_module_calendar $module) {
$this->module = $module;
}
}
/**
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminaction extends iwp_module_calendar_action {
public function handleAction ($dialog = false) {
if (!$dialog) {
$this->module->addAdminResources();
$this->module->displaySessionTemplateMessages();
$this->template->Assign('BreadCrumbSection', $this->module->lang->Get('BreadCrumbSection'));
$this->template->Assign('BreadCrumbAction', '');
}
$data = array();
$data['lang'] = $this->module->lang->GetLangVars();
$this->template->Assign($this->module->moduleName, $data, false);
// admin language js
$this->template->AddLanguageForJS(array(
'Starts',
'Ends',
'Location',
'more',
'Editthisevent',
'Deletethisevent',
'ConfirmDelete',
'Today',
'ViewName_Day',
'ViewName_Week',
'ViewName_Month',
'ViewName_Tinymonth',
'NoPermissionEventEdit',
'NoPermissionEventDelete',
'NoPermissionEventCreate',
'SubmittingPleaseWait',
'EventColor',
'CreateEvent',
'or',
'AddMoreDetails',
'Calendar_Summary',
'Alldayeventfor',
'ClosePopup',
'Closeandapplycolor',
'Bookmarkthiscolor',
), $this->module->lang, 'module_calendar_');
}
}
/**
* Base class used by all 'remote' actions (actions usually triggered by form submits or ajax requests)
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_remoteaction extends iwp_module_calendar_action {
/**
*
* @var array
*/
protected $parameters;
/**
*
* @var string
*/
protected $extension;
/**
* put your comment there...
*
* @param iwp_module_calendar $module
* @param array $parameters
* @param string $extension
* @return iwp_module_calendar_remoteaction
*/
public function __construct (iwp_module_calendar $module, $parameters, $extension) {
$this->parameters = $parameters;
$this->extension = $extension;
parent::__construct($module);
}
/**
*
* @param DateTime $date
* @return string DateTime formatted as YYYYMMDD[HHMM] - The time is dropped off if it is 00:00
*/
public static function formatDateJSON (DateTime $date) {
$string = $date->format(iwp_module_calendar::JSON_DATETIME_FORMAT); // the client js is programmed to recognise a compressed date format
return preg_replace('/0{4}$/', '', $string); // drop any '0000' time from the data packet, the client js will assume midnight if it's not present
}
public static function outputJavascript (&$data) {
$charset = iwp_config::Get('charset');
if (!$charset) {
$charset = 'utf-8';
}
header('Content-type: application/x-javascript; charset=' . $charset);
echo '{}&& '; // json prefix - http://trac.dojotoolkit.org/ticket/6380
echo $data;
}
public static function outputJSON (&$data) {
$javascript = json_encode($data);
self::outputJavascript($javascript);
}
}
/**
* Base class used by all 'remote' actions in the admin (actions usually triggered by form submits or ajax requests)
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminremoteaction extends iwp_module_calendar_remoteaction { }
/**
* This class handles the CalendarDisplayOptions admin remote action, displaying the Display Options form for when a gallery is inserted as a block or as part of tinymce content
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminremotecalendardisplayoptionsaction extends iwp_module_calendar_adminremoteaction {
public function handleAction () {
if (isset($this->parameters['blockId'])) {
$blockId = (int)$this->parameters['blockId'];
$data = $this->parameters['data'];
$blockdata = unserialize($data['content']);
} else {
$blockdata = array(
'views' => array('day', 'week', 'month'),
'first' => 'month',
'title' => '',
);
}
$this->template->Assign('blockdata', $blockdata);
$vars = array();
$vars['lang'] = $this->module->lang->GetLangVars();
$this->module->template->Assign($this->module->moduleName, $vars, false);
$this->template->ParseTemplate('block.displayoptions', false, $this->module->moduleName);
}
}
/**
* This class handles the EventDelete admin remote action, deleting an event if the admin permissions are correct
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminremoteeventdeleteaction extends iwp_module_calendar_adminremoteaction implements iwp_module_calendar_action_interface {
public function handleAction () {
$eventid = (int)@$_POST['id'];
if (!$this->module->hasPerm('eventdelete', $eventid)) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('message', $this->module->lang->Get('NoPermissionEventDelete'));
$this->xml->outputXML();
die();
}
$event = new iwp_module_calendar_event();
if (!$event->Load($eventid)) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('message', $this->module->lang->Get('InvalidEventID'));
$this->xml->outputXML();
die();
}
$summary = $event->Get('summary');
if (!$event->Delete()) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('message', $this->module->lang->Get('ContentDeleteError'));
$this->xml->outputXML();
die();
}
iwp_activity::AddEntry('module', 'calendar', 'eventdelete', $eventid, $summary);
iwp_module_calendar::flushOccurrenceCache();
$this->xml->writeElement('status', 1);
$this->xml->writeElement('message', $this->module->lang->Get('ContentDeleteSuccess'));
$this->xml->outputXML();
}
}
/**
* Implements the saving of new and edited calendar events
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminremoteeventeditsaveaction extends iwp_module_calendar_adminremoteaction implements iwp_module_calendar_action_interface {
public function handleAction () {
$event = new iwp_module_calendar_event();
$eventid = intval(@$_POST['eventid']);
$editing = false;
// editing or creating?
if ($eventid) {
// editing
$editing = true;
$event->Load($eventid);
$formAction = new iwp_module_calendar_admineventeditaction($this->module);
if (!$this->module->hasPerm('eventedit', $eventid)) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('error', $this->module->lang->Get('NoPermissionEventEdit'));
$this->xml->outputXML();
die();
}
} else {
// creating
$formAction = new iwp_module_calendar_admineventcreateaction($this->module);
if (!$this->module->hasPerm('eventcreate')) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('error', $this->module->lang->Get('NoPermissionEventCreate'));
$this->xml->outputXML();
die();
}
}
// although the client side form has been replaced, still use server side form class for validation
$form = $formAction->getForm();
$data = $_POST;
// @todo this is a hack, I don't like modifying post data, don't know how else to do it in iwp field framework - merge the datetime post fields back into one field for the $form->Validate call
$data['startdatetime'] = trim($data['startdatetime_date'] . ' ' . @$data['startdatetime_time']);
$data['enddatetime'] = trim($data['enddatetime_date'] . ' ' . @$data['enddatetime_time']);
// form class validation
$valid = $form->Validate($data, $errorMessages, $errorFields);
if ($errorMessages === null) {
$errorMessages = array();
}
if ($errorFields === null) {
$errorFields = array();
}
// validation specific to calendar module
// validate that the time has been provided if all-day is not checked
if (!isset($data['allday'])) {
$data['allday'] = false;
// event is not all day, so a starting time is required
if (!@$data['startdatetime_time']) {
$valid = false;
$errorFields[] = 'startdatetime';
$errorMessages[] = sprintf($this->lang->Get('ValidError_IsNotBlank'), $this->module->lang->Get('field_startdatetime_Name'));
} else if (!@$data['enddatetime_time']) {
// starting time provided but no ending time provided; the field is not required, so use the starting time as ending time
$data['enddatetime_time'] = $data['startdatetime_time'];
}
} else {
$data['allday'] = true;
// wipe out any provided time values if the event is all day
$data['startdatetime_time'] = '';
$data['enddatetime_time'] = '';
}
// validate start date/time and translate into database storable value
$data['startdatetime'] = '';
if (!in_array('startdatetime', $errorFields)) {
if (!$this->valid->ParseDateString($data['startdatetime_date'], $parts)) {
$valid = false;
$errorFields[] = 'startdatetime';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_IsNotValidDate'), $this->module->lang->Get('field_startdatetime_Name'));
} else {
$data['startdatetime'] .= $parts['year'] . str_pad($parts['month'], 2, '0', STR_PAD_LEFT) . str_pad($parts['day'], 2, '0', STR_PAD_LEFT);
}
if (!$data['allday']) {
// validate the provided time
if (!$this->valid->ParseTimeString($data['startdatetime_time'], $parts)) {
$valid = false;
$errorFields[] = 'startdatetime';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_IsNotValidTime'), $this->module->lang->Get('field_startdatetime_Name'));
} else {
$data['startdatetime'] .= str_pad($parts['hour'], 2, '0', STR_PAD_LEFT) . str_pad($parts['minute'], 2, '0', STR_PAD_LEFT);
}
}
}
// validate end date/time and translate into database storable value
$data['enddatetime'] = '';
if (!in_array('enddatetime', $errorFields)) {
if (!$this->valid->ParseDateString($data['enddatetime_date'], $parts)) {
$valid = false;
$errorFields[] = 'enddatetime';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_IsNotValidDate'), $this->module->lang->Get('field_enddatetime_Name'));
} else {
$data['enddatetime'] = $parts['year'] . str_pad($parts['month'], 2, '0', STR_PAD_LEFT) . str_pad($parts['day'], 2, '0', STR_PAD_LEFT);
}
if (!$data['allday']) {
// validate the provided time
if (!$this->valid->ParseTimeString($data['enddatetime_time'], $parts)) {
$valid = false;
$errorFields[] = 'enddatetime';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_IsNotValidTime'), $this->module->lang->Get('field_enddatetime_Name'));
} else {
$data['enddatetime'] .= str_pad($parts['hour'], 2, '0', STR_PAD_LEFT) . str_pad($parts['minute'], 2, '0', STR_PAD_LEFT);
}
}
}
// validate that the end and start dates make sense (they've already been validated as valid dates by ParseDateString calls above)
if (!in_array('startdatetime', $errorFields) && !in_array('enddatetime', $errorFields)) {
// recurrence rule backend expects events to have a duration, so all end dates must be > the start date
// except for all-day events where the date provided in the form is allowed tobe 20090101 - 20090101 for example, because we'll actually save it as 20090101 - 20090102
$data['startdatetime_object'] = new DateTime($data['startdatetime']);
$data['enddatetime_object'] = new DateTime($data['enddatetime']);
if ($data['allday'] && $data['enddatetime_object'] < $data['startdatetime_object'] || !$data['allday'] && $data['enddatetime_object'] <= $data['startdatetime_object']) {
$valid = false;
$errorFields[] = 'enddatetime';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_EndTimeStartTime'));
}
}
// if custom repeat type was selected, need to validate the values inside the hidden form
/*
if (@$data['repeat_type'] == 'custom') {
// interval is used by all custom repeat types; validate it always
$data['repeat_custom_interval'] = intval($data['repeat_custom_interval']);
if ($data['repeat_custom_interval'] < 1) {
$valid = false;
$errorFields[] = 'repeat_custom_interval';
$errorMessages[] = $this->module->lang->Get('ValidError_InvalidInterval');
}
// range is used by all custom repeat types; validate it always
if ($data['repeat_custom_range'] == 'none') {
// nothing to validate
} else if ($data['repeat_custom_range'] == 'until') {
// validate the provided 'until' date
if (!$this->valid->ParseDateString($data['repeat_custom_range_until'], $parts)) {
$valid = false;
$errorFields[] = 'repeat_custom_range_until';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_IsNotValidDate'), $this->module->lang->Get('field_repeat_custom_range_until_Name'));
} else {
$data['repeat_custom_range_until'] = $parts['year'] . str_pad($parts['month'], 2, '0', STR_PAD_LEFT) . str_pad($parts['day'], 2, '0', STR_PAD_LEFT);
}
} else {
$valid = false;
$errorFields[] = 'repeat_custom_range';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_RepeatCustomRange'), $data['repeat_custom_range']);
}
if ($data['repeat_custom_type'] == 'daily') {
// nothing to validate
} else if ($data['repeat_custom_type'] == 'weekly') {
// validate the first day of the week
if (!is_numeric($data['repeat_custom_week_fdotw']) || (int)$data['repeat_custom_week_fdotw'] < 0 || (int)$data['repeat_custom_week_fdotw'] > 6) {
$valid = false;
$errorFields[] = 'repeat_custom_week_fdotw';
$errorMessages[] = $this->module->lang->Get('ValidError_RepeatCustomWeekFDOTW');
} else {
$data['repeat_custom_week_fdotw'] = (int)$data['repeat_custom_week_fdotw'];
}
// validate the byweekday selection
if (!isset($data['repeat_custom_week'])) {
// blank arrays are fine as this indicates that the weekday should be taken from the event start date
$data['repeat_custom_week'] = array();
} else if (!is_array($data['repeat_custom_week'])) {
// should always be an array
$valid = false;
$errorFields[] = 'repeat_custom_week';
$errorMessages[] = $this->module->lang->Get('ValidError_RepeatCustomWeek');
} else {
$data['repeat_custom_week'] = array_unique($data['repeat_custom_week']);
// array_diff will return elements from array 1 that do not exist in expected array 2
$invalidElements = array_diff($data['repeat_custom_week'], array('MO','TU','WE','TH','FR','SA','SU'));
if (count($invalidElements)) {
$valid = false;
$errorFields[] = 'repeat_custom_week';
$errorMessages[] = $this->module->lang->Get('ValidError_RepeatCustomWeek');
}
}
} else if ($data['repeat_custom_type'] == 'monthly') {
if ($data['repeat_custom_monthly_type'] == 'bysetpos') {
$invalidElements = @array_diff(array(@$data['repeat_custom_monthly_bysetpos_position']), array('1','2','3','4','5','-1'));
} else if ($data['repeat_custom_monthly_type'] == 'bymonthday') {
// validate the bymonthday selection
if (!isset($data['repeat_custom_monthly_bymonthday'])) {
// blank arrays are fine as this indicates that the monthday should be taken from the event start date
$data['repeat_custom_monthly_bymonthday'] = array();
} else if (!is_array($data['repeat_custom_monthly_bymonthday'])) {
// should always be an array
$valid = false;
$errorFields[] = 'repeat_custom_monthly_bymonthday';
$errorMessages[] = $this->module->lang->Get('ValidError_RepeatCustomMonthlyBymonthday');
} else {
$data['repeat_custom_monthly_bymonthday'] = array_unique($data['repeat_custom_monthly_bymonthday']);
// array_diff will return elements from array 1 that do not exist in expected array 2
$invalidElements = array_diff($data['repeat_custom_monthly_bymonthday'], array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'));
if (count($invalidElements)) {
$valid = false;
$errorFields[] = 'repeat_custom_monthly_bymonthday';
$errorMessages[] = $this->module->lang->Get('ValidError_RepeatCustomMonthlyBymonthday');
}
}
} else {
$valid = false;
$errorFields[] = 'repeat_custom_monthly_type';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_RepeatCustomMonthlyType'), $data['repeat_custom_monthly_type']);
}
} else if ($data['repeat_custom_type'] == 'yearly') {
} else {
$valid = false;
$errorFields[] = 'repeat_custom_type';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_RepeatCustomType'), $data['repeat_custom_type']);
}
} else
*/
if (@$data['repeat_type'] == 'daily') {
// translate into daily repeat rule
$data['rrule'] = iwp_module_calendar::RRULE_STANDARD_DAILY;
} else if (@$data['repeat_type'] == 'weekly') {
// translate into weekly repeat rule
$data['rrule'] = iwp_module_calendar::RRULE_STANDARD_WEEKLY;
} else if (@$data['repeat_type'] == 'monthly') {
// translate into monthly repeat rule
$data['rrule'] = iwp_module_calendar::RRULE_STANDARD_MONTHLY;
} else if (@$data['repeat_type'] == 'yearly') {
// translate into yearly repeat rule
$data['rrule'] = iwp_module_calendar::RRULE_STANDARD_YEARLY;
} else if (@$data['repeat_type'] == 'none') {
$data['rrule'] = '';
} else {
// no valid repeat type selected
$valid = false;
$errorFields[] = 'repeat_type';
$errorMessages[] = sprintf($this->module->lang->Get('ValidError_RepeatType'), @$data['repeat_type']);
}
// send error message if validation failed
if (!$valid) {
$this->xml->writeElement('status', 0);
$this->xml->startElement('error');
$this->xml->writeAttribute('html', 'true');
$this->xml->writeCdata(sprintf(iwp_language::getInstance()->Get('ContentSaveErrors') . '<ul><li>' . implode('</li><li>', $errorMessages) . '</li></ul>', $this->module->lang->Get('event')));
$this->xml->endElement();
foreach ($errorFields as $errorField) {
$this->xml->startElement('field');
$this->xml->writeAttribute('name', $errorField);
$this->xml->writeAttribute('highlight', 'true');
$this->xml->endElement();
}
$this->xml->outputXML();
die();
}
if ($editing) {
// fields that are set only when editing
$event->Set('sequence', (int)$event->Get('sequence') + 1); // increment the sequence counter, which is an internal 'edits' counter used in ical
} else {
// fields that are set only when creating
$event->Set('uid', iwp_module_calendar_event::generateUid());
$event->Set('sequence', 0);
$event->Set('created', gmdate('YmdHis'));
}
if (preg_match('#^[A-Fa-f0-9]{6}$#', @$data['color']) > 0) {
$event->Set('color', $data['color']);
} else if (!$editing) {
// if creating, generate a random colour for one not provided
$event->Set('color', iwp_module_calendar_event::getRandomColor());
}
// basic editable fields
$event->Set('summary', $data['summary']);
$event->Set('description', @$data['description']);
$event->Set('location', @$data['location']);
$event->Set('rrule', $data['rrule']);
// date/time fields that should have been formatted properly by the above validation (into either YYYYMMDD or YYYYMMDDHHMM values)
$event->Set('dtstart', $data['startdatetime']);
if ($data['allday']) {
// all-day events must be stored as form day + 1 because date calculations are performed on a range-start >= now > range-end basis, so this creates an end date that is equivalent to 20090101 23:59 for example
$date = $data['enddatetime_object'];
$date->modify('1 day');
$event->Set('dtend', $date->format('Ymd'));
} else {
$event->Set('dtend', $data['enddatetime']);
}
$eventId = $event->Save();
iwp_module_calendar::flushOccurrenceCache();
if ($eventId === false) {
$this->xml->writeElement('status', 0);
$this->xml->writeElement('error', sprintf(iwp_language::getInstance()->Get('ContentSaveErrors') . '<ul><li>' . $this->module->lang->Get('ContentSaveError') . '</li><li>' . $event->GetError() . '</li></ul>', $this->module->lang->Get('event')));
$this->xml->outputXML();
die();
}
if ($editing) {
iwp_activity::AddEntry('module', 'calendar', 'eventedit', $eventId, $event->Get('summary'));
} else {
iwp_activity::AddEntry('module', 'calendar', 'eventcreate', $eventId, $event->Get('summary'));
}
$this->xml->writeElement('status', 1);
$this->xml->writeElement('eventid', $eventId);
$this->xml->writeElement('message', $this->module->lang->Get('EventSavedSuccessfully'));
$this->xml->writeElement('updatedata', 1);
if (@$_POST['savemethod'] == 'andexit') {
$this->xml->writeElement('closemodal', 1);
}
$this->xml->outputXML();
}
}
/**
* Implements the display of the admin calendar event creation form
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_admineventcreateaction extends iwp_module_calendar_adminaction implements iwp_module_calendar_action_interface {
/**
*
* @return iwp_form
*/
public function getForm () {
$form = new iwp_form();
//$form->AddGroup($this->module->lang->Get('EditFormGroupEventDetails'));
$form->AddField('hidden', 'eventid', null, $this->module->lang);
$form->AddField('hidden', 'color', null, $this->module->lang);
$form->AddField('textbox', 'summary', null, $this->module->lang)
->DisableLabel()
->DisableHelpTip()
->AddValidation('IsNotBlank')
->SetAttribute('class', 'Field250')
->Required = true;
$form->AddField('checkbox', 'allday', null, $this->module->lang)
->DisableHelpTip();
$form->AddField('datetime', 'startdatetime', null, $this->module->lang)
->DisableHelpTip()
->AddValidation('IsNotBlank')
->Required = true;
$form->AddField('datetime', 'enddatetime', null, $this->module->lang)
->DisableHelpTip()
->AddValidation('IsNotBlank')
->Required = true;
$form->AddField(array('module_custom:repeat', 'calendar'), 'repeat', null, $this->module->lang);
$form->AddField('textbox', 'location', null, $this->module->lang)
->DisableLabel()
->SetAttribute('class', 'Field250')
->DisableHelpTip();
$field = $form->AddField('wysiwyg', 'description', null, $this->module->lang)
->DisableLabel()
->DisableHelpTip()
->AddValidation('GetWYSIWYGContent');
$field->editor->buttons1 = 'undo,redo,|,bold,italic,underline,|,cut,copy,paste,pastetext,|,link,unlink,iwpinsertlink,|,forecolor,backcolor,|,code';
$field->editor->buttons2 = '';
$field->editor->buttons3 = '';
$field->editor->buttons4 = '';
$field->editor->horizontalResizing = false;
$field->editor->width = 430;
return $form;
}
public function handleAction () {
// @todo create permission check
parent::handleAction(true);
$templateData = array();
//
// populate the form with creation defaults based on the request
// adopt start date from query string or use now
$allDay = true;
if (preg_match('#^\d{8}$#', @$_GET['eventdtstart'])) {
$dtstart = new InterspireICalendarDateTime($_GET['eventdtstart'] . date('H', time()) . '00');
} else if (preg_match('#^\d{12}$#', @$_GET['eventdtstart'])) {
$allDay = false;
$dtstart = new InterspireICalendarDateTime($_GET['eventdtstart']);
} else {
$dtstart = new InterspireICalendarDateTime();
}
// adopt end date from query string or use start + 30 mins
if (preg_match('#^\d{8}$#', @$_GET['eventdtend'])) {
$dtend = new InterspireICalendarDateTime($_GET['eventdtend'] . date('H', time() + 3600) . '00');
} else if (preg_match('#^\d{12}$#', @$_GET['eventdtend'])) {
$allDay = false;
$dtend = new InterspireICalendarDateTime($_GET['eventdtend']);
} else {
$dtend = clone($dtstart);
$dtend->modify('30 minutes');
}
$templateData['allday'] = $allDay;
// apply date and time
$dateFormat = iwp_settings::IsAmericanDateFormat(iwp_getShortDateFormat()) ? 'm/d/Y' : 'd/m/Y'; // date format which is usable by the date picker
$templateData['startdatetime_date'] = $dtstart->format($dateFormat);
$templateData['startdatetime_time'] = $dtstart->format('g:i A');
$templateData['enddatetime_date'] = $dtend->format($dateFormat);
$templateData['enddatetime_time'] = $dtend->format('g:i A');
// other defaults
$templateData['summary'] = @$_GET['eventsummary'];
$templateData['color'] = @$_GET['eventcolor'];
// render form html, js, etc.
$templateData['lang'] = $this->module->lang->GetLangVars();
$this->template->Assign('calendar', $templateData);
// display page
$this->template->ParseTemplate('calendar.event.edit', false, 'calendar');
}
}
/**
* Implements the display of the admin calendar event edit form by extending on the create action
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_admineventeditaction extends iwp_module_calendar_admineventcreateaction implements iwp_module_calendar_action_interface {
public function handleAction () {
//
// populate the form with event values from database
$eventId = (int)@$_GET['eventid'];
$event = new iwp_module_calendar_event();
if (!$event->Load($eventId)) {
throw new Exception('Invalid Event ID');
}
$templateData = array();
$templateData['eventid'] = $eventId;
$templateData['summary'] = $event->Get('summary');
$templateData['location'] = $event->Get('location');
$templateData['description'] = $event->Get('description');
$templateData['repeat'] = $event->Get('rrule');
$templateData['color'] = $event->Get('color');
// adopt start date from event data or use now
$allDay = true;
if (preg_match('#^\d{8}$#', $event->Get('dtstart'))) {
$dtstart = new InterspireICalendarDateTime($event->Get('dtstart') . date('H', time()) . '00');
} else if (preg_match('#^\d{12}$#', $event->Get('dtstart'))) {
$allDay = false;
$dtstart = new InterspireICalendarDateTime($event->Get('dtstart'));
} else {
$dtstart = new InterspireICalendarDateTime();
}
// adopt end date from event data or use start + 30 mins
if (preg_match('#^\d{8}$#', $event->Get('dtend'))) {
$dtend = new InterspireICalendarDateTime($event->Get('dtend') . date('H', time() + 3600) . '00');
} else if (preg_match('#^\d{12}$#', $event->Get('dtend'))) {
$allDay = false;
$dtend = new InterspireICalendarDateTime($event->Get('dtend'));
} else {
$dtend = clone($dtstart);
$dtend->modify('30 minutes');
}
$templateData['allday'] = $allDay;
if ($allDay) {
// all-day end dates are stored in the database as day + 1 for calculation purposes
$dtend->modify('-1 day');
}
$dateFormat = iwp_settings::IsAmericanDateFormat(iwp_getShortDateFormat()) ? 'm/d/Y' : 'd/m/Y'; // date format which is usable by the date picker
$templateData['startdatetime_date'] = $dtstart->format($dateFormat);
$templateData['startdatetime_time'] = $dtstart->format('g:i A');
$templateData['enddatetime_date'] = $dtend->format($dateFormat);
$templateData['enddatetime_time'] = $dtend->format('g:i A');
// render form html, js, etc.
$templateData['lang'] = $this->module->lang->GetLangVars();
$this->template->Assign('calendar', $templateData);
// display page
$this->template->ParseTemplate('calendar.event.edit', false, 'calendar');
}
}
/**
* Implements the admin calendar view
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminviewaction extends iwp_module_calendar_adminaction implements iwp_module_calendar_action_interface {
protected function getViewList () {
$serverDate = new DateTime();
$events = iwp_module_calendar_event::getInstance()->LoadInstances();
iwp_module_calendar_event::sortEvents($events);
$results = array();
foreach ($events as $event) {
$result = array();
$result['id'] = $event->GetId();
$result['summary'] = $event->Get('summary');
$dtstart = $event->dtstart();
$result['startdate'] = $dtstart->format(iwp_config::Get('ShortDateFormat') . ' ' . iwp_module_calendar::TIME_FORMAT);
$result['startdate_tz'] = $event->Get('dtstart_tz');
if (!$result['startdate_tz']) {
$result['startdate_utc_ts'] = $dtstart->format('Y-m-d\TH:i:s');
}
$dtstart->setTimezone($serverDate->getTimezone());
$result['startdate_server'] = $dtstart->format(iwp_config::Get('ShortDateFormat') . ' ' . iwp_module_calendar::TIME_FORMAT);
$dtstart->setTimezone(new DateTimeZone('UTC'));
$result['startdate_utc'] = $dtstart->format(iwp_config::Get('ShortDateFormat') . ' ' . iwp_module_calendar::TIME_FORMAT);
if ($result['startdate_tz']) {
$result['startdate_utc_ts'] = $dtstart->format('Y-m-d\TH:i:s') . 'Z';
}
$result['rrule'] = $event->Get('rrule');
$result['can_anyaction'] = true;
$results[] = $result;
}
return $results;
}
public function handleAction () {
// @todo view permission check
parent::handleAction();
//$this->template->Assign('ViewList', $this->getViewList($this->module));
$editor = new tiny_mce();
$editor->mode = 'none';
$editor->buttons1 = 'undo,redo,|,bold,italic,underline,|,cut,copy,paste,pastetext,|,link,unlink,iwpinsertlink,|,forecolor,backcolor,|,code';
$editor->buttons2 = '';
$editor->buttons3 = '';
$editor->buttons4 = '';
$editor->horizontalResizing = false;
$editor->width = 430;
$this->template->Assign('editorCode', $editor->GetEditorHTML('blockhtml'));
$this->template->Assign(array('calendar', 'american'), iwp_settings::IsAmericanDateFormat(iwp_getShortDateFormat()), false);
$this->template->Assign('PageTitle', $this->module->lang->Get('PageTitle'));
$this->template->Assign('PageIntro', $this->module->lang->Get('PageIntro'));
$this->template->ParseTemplate('header');
$this->template->ParseTemplate('calendar.view', false, 'calendar');
$this->template->ParseTemplate('footer');
}
}
/**
* Handle a request for occurrence information from admin users
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_adminremoteoccurrencesaction extends iwp_module_calendar_adminremoteaction implements iwp_module_calendar_action_interface {
public function handleAction () {
// load the front end occurrences handler and pass-through to it, telling it to return data instead of output
$frontEndAction = new iwp_module_calendar_remoteoccurrencesaction($this->module, array(@$_GET['range']), 'json');
$data = $frontEndAction->handleAction(true);
// process the data and add control panel permission information to the output
foreach ($data['e'] as &$event) {
// control panel edit
$event['ce'] = $this->module->hasPerm('eventedit', $event['i']);
// control panel delete
$event['cd'] = $this->module->hasPerm('eventdelete', $event['i']);
}
$this->outputJSON($data);
die();
}
}
/**
* Handle a request for occurrence information from front end users
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_remoteoccurrencesaction extends iwp_module_calendar_remoteaction implements iwp_module_calendar_action_interface {
public function handleAction ($return = false) {
// --- VALIDATE AND PARSE INPUT
if (!preg_match('/^(?P<year>[\d]{4})(?P<month>[\d]{2})?$/', $this->parameters[0], $range)) {
throw new Exception('Invalid URL');
}
$range['year'] = intval($range['year']);
if ($range['year'] < 1900 || $range['year'] >= 2100) {
// safety check, 1900-2099 is the selectable date range in windows so may as well limit queries to this range
// (high year numbers can generate long-running calculations since repeating events are calculated from their start date)
throw new Exception('Invalid URL');
}
if (isset($range['month'])) {
$range['month'] = intval($range['month']);
if ($range['month'] < 1 || $range['month'] > 12) {
// month is too low or too high
throw new Exception('Invalid URL');
}
$rangeBegin = $range['year'] . '-' . $range['month'] . '-01';
$rangeScale = '1 month';
} else {
// no month specified, assume a year range
$rangeBegin = $range['year'] . '-01-01';
$rangeScale = '1 year';
}
// --- FETCH AND SORT DATA
$now = new iwp_module_calendar_datetime();
$timezone = $now->getTimezone();
$timezoneIdentifier = $timezone->getName();
$cacheBlock = $this->parameters[0]; // parameters[0] has been validated above
$cacheRow = $this->db->FetchQuery("SELECT data FROM " . GetConfig('tablePrefix') . "module_calendar_occurrencecache WHERE cacheblock = '" . $cacheBlock . "' AND tz = '" . $this->db->Quote($timezoneIdentifier) . "'");
if ($cacheRow) {
$data = unserialize($cacheRow['data']);
if ($return) {
return $data;
}
self::outputJSON($data);
die();
}
// create a date range based on the session, cookie or config specified time
$rangeBegin = new iwp_module_calendar_datetime($rangeBegin);
$rangeEnd = clone($rangeBegin);
$rangeEnd->modify($rangeScale);
$event = iwp_module_calendar_event::getInstance();
// json data uses abbreviations for smaller data packets
$data = array(
'k' => $cacheBlock, // the range that this is in response to
'e' => array(), // event list
);
// @todo needs to be optimised to only load repeating instances that end after the given timeframe, and non-repeating instances within the given timeframe, instead of all repeating instances
$events = $event->LoadInstances();
foreach ($events as $event) {
$occurrences = $event->occurrences($rangeBegin, $rangeEnd);
if (empty($occurrences)) {
// event does not have occurrences in this time range, exclude it from output
continue;
}
$dtstart = $event->dtstart();
$dtstart->setTimezone($timezone);
$dtend = $event->dtend();
$dtend->setTimezone($timezone);
// format this event and it's occurrences into a small json packet
$json_occurrences = array();
foreach ($occurrences as $occurrence) {
// adjust the occurence timezone to match the range
$occurrence->setTimezone($timezone);
$json_occurrences[] = self::formatDateJSON($occurrence);
}
$eventPacket = array(
'i' => $event->GetId(), // id
's' => $event->Get('summary'), // summary
'l' => $event->Get('location'), // location
'd' => $event->Get('description'), // description
'c' => $event->Get('color'), // color
'ds' => self::formatDateJSON($dtstart), // event start
'de' => self::formatDateJSON($dtend), // event end
'o' => $json_occurrences, // occurrence list in queried range
);
// add it to the json packet output
$data['e'][] = $eventPacket;
}
$this->db->InsertQuery(GetConfig('tablePrefix') . 'module_calendar_occurrencecache', array(
'cacheblock' => $cacheBlock,
'tz' => $timezoneIdentifier,
'data' => serialize($data),
));
if ($return) {
return $data;
}
$json = json_encode($data);
self::outputJSON($data);
}
}
/**
* Handles a request for parsing and returning a template from this module's template folder - was going to be used for streaming view templates to the calendar front end but may no longer be used
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar_remotetemplateaction extends iwp_module_calendar_remoteaction implements iwp_module_calendar_action_interface {
public function getRequestedTemplateName () {
return $this->parameters[0];
}
public function handleAction () {
if ($this->extension != 'html') {
$this->controller->ShowPage('NotFound');
die();
}
$template = $this->getRequestedTemplateName();
try {
$charset = iwp_config::Get('charset');
if (!$charset) {
$charset = 'utf-8';
}
header('Content-type: text/html; charset=' . $charset);
$this->template->ParseTemplate($template, false, $this->module->moduleName);
die();
} catch (InterspireTemplateNothingToParseException $exception) {
$this->controller->ShowPage('NotFound');
die();
}
}
}
/**
* This class contains the core of the calendar module; defining properties and functions so the module fits into the IWP framework and dispatching requests for more specific stuff off to handler classes
*
* @package IWP_Modules
* @subpackage Calendar
*/
class iwp_module_calendar extends iwp_module {
const TIME_FORMAT = 'h:i a';
const JSON_DATETIME_FORMAT = 'YmdHi';
const RRULE_STANDARD_DAILY = 'FREQ=DAILY';
const RRULE_STANDARD_WEEKLY = 'FREQ=WEEKLY';
const RRULE_STANDARD_MONTHLY = 'FREQ=MONTHLY';
const RRULE_STANDARD_YEARLY = 'FREQ=YEARLY';
/**
* Defines that this module has draggable blocks
*
* @var bool
*/
public $hasBlocks = true;
/**
* A list of event listeners used for registering and unregistering events during the module's activation and deactivation.
*
* @var array
*/
protected $eventListeners = array(
'iwp_event_admin_navigation_dropdownmenucreated' => array(
'iwp_module_calendar', 'onDropdownMenuCreated'
),
'iwp_event_content_afterdbload' => array(
'iwp_module_calendar', 'onContentAfterDbLoad'
),
'iwp_event_admin_content_tinymceplugin' => array(
'iwp_module_calendar', 'onContentTinyMCEPlugin'
),
'iwp_event_lists_dynamicoutput' => array(
'iwp_module_calendar', 'onListsDynamicOutput'
),
'iwp_event_categories_beforeshowtemplate' => array(
'iwp_module_calendar', 'onCategoriesBeforeShowTemplate'
),
'iwp_event_template_outputblockbeforeparsesection' => array(
'iwp_module_calendar', 'onTemplateOutputBlockBeforeParseSection'
),
'iwp_event_users_beforeprofiledisplay' => array(
'iwp_module_calendar', 'onUserProfileDisplay'
),
);
/**
*
* @var iwp_module_calendar
*/
public static $Instance;
/**
*
* @var string
*/
public $moduleName = 'calendar';
/**
*
* @var string
*/
protected $contentIdColumn = 'id';
/**
*
* @var array
*/
protected $_columns = array(
'id' => '',
'contentdisplayposiiton' => '',
);
/**
*
* @return iwp_module_calendar
*/
public static function getInstance () {
if(!isset(self::$Instance)){
self::$Instance = new self();
}
return self::$Instance;
}
/**
* Returns a list of database tables for this module.
*
* @param boolean $withoutPrefix A boolean for whether or not to include the prefix for the table.
*
* @return string
*/
public function getTables($withoutPrefix=false) {
$tables = array(
'calendar',
// 'calendar_exception', See the CreateModuleTable() function
'calendar_event',
'calendar_occurrencecache',
);
if($withoutPrefix) {
return $tables;
}
foreach($tables as $k=>$table ){
$tables[$k] = IWP_MODULE_DB_PREFIX . $table;
}
return $tables;
}
/**
* Listener for the iwp_event_admin_content_tinymceplugin event. This adds a tinymce plugin for the calendar module.
*
* @param iwp_event_admin_content_tinymceplugin $data
*/
public static function onContentTinyMCEPlugin (iwp_event_admin_content_tinymceplugin $data) {
$module = iwp_module_calendar::getInstance();
//
// to reuse the code for the block modal dialog we need to present it with 'blockdata' variables
$blockdata = array(
'views' => array('day', 'week', 'month'),
'first' => 'month',
'title' => '',
);
$module->template->Assign('blockdata', $blockdata, false);
//
// create language vars that this module should be using
$vars = array();
$vars['lang'] = $module->lang->GetLangVars();
$module->template->Assign($module->moduleName, $vars, false);
$vars['modalHTML'] = $module->template->ParseTemplate('block.displayoptions', true, $module->moduleName);
$module->template->Assign($module->moduleName, $vars, false); // need to assign this twice because the modalHTML template needed the language vars above to work properly
$module->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $module->moduleName . '/templates/admin.calendar.css');
$module->template->AddRequiredJS(IWP_MODULES_URI . '/' . $module->moduleName . '/javascript/jquery.htmlEncode.js');
$module->template->AddRequiredJS(IWP_BASE_URI . '/javascript/jquery/plugins/json.js');
//
// append the resulting js code to the tinymce loader code
$data->code .= $module->template->ParseTemplate('calendar.tinymce.plugin', true, $module->moduleName);
}
/**
* Processes calendar placeholders in the given string, replacing them with calendar module html
*
* @param string $string String to process (usually HTML)
* @return string
*/
public function processContentPlaceholders ($string) {
// look for <p> tags immediately around the comment since this is a common occurrence with how tinymce works, but putting a div inside a p tag is bad xhtml
$result = preg_match_all('#(?:<p>)?\s*<!--\s+iwp_module_calendar:(.*?)\s+-->\s*(?:</p>)?#ism', $string, $matches, PREG_SET_ORDER);
if ($result === false || $result === 0) {
// preg error or no results
return $string;
}
foreach ($matches as $match) {
$json = json_decode(html_entity_decode_utf8($match[1]));
$replace = $this->generateFrontendOutput('middle', @$json->views, @$json->first, @$json->title);
$string = str_replace($match[0], $replace, $string);
}
return $string;
}
/**
* Listener for the iwp_event_lists_dynamicoutput event which scans list output for calendar placeholders and replaces them with calendar output
*
* @param iwp_event_lists_dynamicoutput $data
*/
public static function onListsDynamicOutput (iwp_event_lists_dynamicoutput $data) {
if (!isset($data->listRowArray['Summary']) || !$data->listRowArray['Summary']) {
return;
}
$data->listRowArray['Summary'] = self::getInstance()->processContentPlaceholders($data->listRowArray['Summary']);
}
/**
* Listener for the iwp_event_categories_beforeshowtemplate event which adjusts template output to make calendars appear on front end category descriptions
*
* @param iwp_event_categories_beforeshowtemplate $data
*/
public static function onCategoriesBeforeShowTemplate (iwp_event_categories_beforeshowtemplate $data) {
$data->template->Assign('categoryDescription', self::getInstance()->processContentPlaceholders($data->template->Get('categoryDescription')), false);
}
/**
* Listener for the iwp_event_template_outputblockbeforeparsesection event which adjusts custom block output to make calendars appear on front end custom blocks
*
* @param iwp_event_categories_beforeshowtemplate $data
*/
public static function onTemplateOutputBlockBeforeParseSection (iwp_event_template_outputblockbeforeparsesection $data) {
switch (strtolower($data->type)) {
case 'customcontent':
$data->template->Assign('blockContent', self::getInstance()->processContentPlaceholders($data->template->Get('blockContent')), false);
break;
}
}
/**
* Listener for the iwp_event_users_beforeprofiledisplay event which adjusts user biography output to make calendars appear on front end custom blocks
*
* @param iwp_event_users_beforeprofiledisplay $data
*/
public static function onUserProfileDisplay (iwp_event_users_beforeprofiledisplay $data) {
$data->user->Set('biography', self::getInstance()->processContentPlaceholders($data->user->Get('biography')));
}
/**
* Listener for the iwp_event_content_afterdbload event which scans loaded content for calendar placeholders and replaces them with calendar output
*
* @param iwp_event_content_afterdbload $data
*/
public static function onContentAfterDbLoad (iwp_event_content_afterdbload $data) {
$module = self::getInstance();
$replaceFields = array('content', 'summary');
foreach ($replaceFields as $replaceFieldName) {
$html = $data->content->Get($replaceFieldName);
if (!$html) {
// blank field
continue;
}
$html = self::getInstance()->processContentPlaceholders($html);
$data->content->Set($replaceFieldName, $html);
}
}
/**
* Listener for the iwp_event_admin_navigation_dropdownmenucreated event
*
* @param iwp_event_admin_navigation_dropdownmenucreated $data
*/
public static function onDropdownMenuCreated (iwp_event_admin_navigation_dropdownmenucreated $data) {
$module = self::getInstance();
$auth = iwp_admin_auth::getInstance();
/*
// disabled the permission check here because calendars are publicly viewable anyway
// will need to re-enable this if it ever becomes possible to set events as not visible, because the admin view will then differ from the front end view
if (!$auth->HasPerm('sitemodules', 'calendar', '*')) {
return;
}
*/
$mnuContent = array();
foreach($data->menuItems['mnuContent'] as $key => $menuItem) {
$mnuContent[] = $menuItem;
if(isset($menuItem['link']) && $menuItem['link'] == 'index.php?section=categories&action=view') {
$mnuContent[] = array(
'text' => $module->lang->Get('menuManageCalendar'),
'link' => 'index.php?section=module&action=custom&module=calendar',
'show' => true,
'help' => $module->lang->Get('menuManageCalendarHelp'),
'icon' => '../../modules/calendar/images/calendar.png',
);
}
}
$data->menuItems['mnuContent'] = $mnuContent;
if (@$_GET['section'] == 'module' && @$_GET['action'] == 'custom' && @$_GET['module'] == 'calendar') {
$data->currentMenu = 'mnuCalendar';
}
}
/**
* ArrayInsert
* Inserts one array into another at a given position.
*
* @param array $array The recipient array to be inserted into, passed by reference and will have it's pointer reset
* @param mixed $position The index (numeric) position at which to insert
* @param mixed $insert_array The array to be inserted
*/
private static function ArrayInsert (&$array, $position, $insert_array) {
$first_array = array_splice ($array, 0, $position);
$array = array_merge ($first_array, $insert_array, $array);
}
/**
* (non-PHPdoc)
* @see api/iwp_module#IsContentModule()
*/
public function IsContentModule () { return false; }
/**
* (non-PHPdoc)
* @see api/iwp_module#IsWebsiteModule()
*/
public function IsWebsiteModule () { return true; }
/**
* (non-PHPdoc)
* @see api/iwp_module#HasConfigurationScreen()
*/
public function HasConfigurationScreen () {
return false;
}
/**
* (non-PHPdoc)
* @see api/iwp_module#CreateModuleTable()
*/
public function CreateModuleTable () {
$this->table = array();
$this->tableSchema = array();
// settings table
$table = new iwp_tablecreator($this->getTable('calendar'));
$table->AddField('id')->SetAsPrimaryKey();
$table->AddField('contentdisplayposition')->SetAsVarChar('255');
$this->table[] = $table;
$this->tableSchema[$table->name] = $table->GetCreateTable();
// events table
$table = new iwp_tablecreator($this->getTable('calendar_event'));
$table->AddField('id')->SetAsPrimaryKey();
$table->AddField('description')->SetAsText()->SetIsNull(true)->SetDefault(null);
$table->AddField('dtstart')->SetAsChar(12)->SetIsNull(true)->SetDefault(null);
$table->AddField('dtstart_tz')->SetAsVarChar(255)->SetIsNull(true)->SetDefault(null);
$table->AddField('dtend')->SetAsChar(12)->SetIsNull(true)->SetDefault(null);
$table->AddField('dtend_tz')->SetAsVarChar(255)->SetIsNull(true)->SetDefault(null);
$table->AddField('location')->SetAsText()->SetIsNull(true)->SetDefault(null);
$table->AddField('sequence')->SetAsInt()->SetIsNull(true)->SetDefault(0);
$table->AddField('uid')->SetAsVarChar(255)->SetIsNull(true)->SetDefault(null);
$table->AddField('created')->SetAsDateTime()->SetIsNull(true)->SetDefault(null);
$table->AddField('summary')->SetAsText()->SetIsNull(true)->SetDefault(null);
$table->AddField('class')->SetAsVarChar(255)->SetIsNull(true)->SetDefault(null);
$table->AddField('rrule')->SetAsText()->SetIsNull(true)->SetDefault(null);
$table->AddField('color')->SetAsVarChar(6)->SetIsNull(true)->SetDefault(null);
$this->table[] = $table;
$this->tableSchema[$table->name] = $table->GetCreateTable();
// occurrence cache table
$table = new iwp_tablecreator($this->getTable('calendar_occurrencecache'));
$table->AddField('cacheblock')->SetAsChar(6)->SetAsPrimaryKey(false);
$table->AddField('tz')->SetAsVarChar(50)->SetAsPrimaryKey(false);
$table->AddField('data')->SetAsText();
$this->table[] = $table;
$this->tableSchema[$table->name] = $table->GetCreateTable();
/*
// exceptions table
// if this is ever uncommented, you must uncomment the line in the getTables() function that hides this table
$table = new iwp_tablecreator($this->getTable('calendar_exception'));
$table->AddField('event')->SetAsPrimaryKey(false)->SetAsInt();
$table->AddField('exdate')->SetAsPrimaryKey(false)->Set('type', 'timestamp')->SetDefault('0000-00-00 00:00:00');
$this->table[] = $table;
$this->tableSchema[$table->name] = $table->GetCreateTable();
*/
}
/**
* Custom activation routine for the calendar module
*
* @return boolean
*/
public function ActivateModule () {
if (version_compare(PHP_VERSION, '5.2.0') === -1) {
$this->messages[] = $this->lang->Get('RequiresPHP52');
return false;
}
return parent::ActivateModule();
}
/**
* Passes remote actions through to handler classes
*
* @return unknown_type
*/
public function RemoteAction () {
$moduleAction = preg_replace('#[^a-zA-Z0-9]#', '', iwp_strtolower(@$_GET['moduleaction']));
if (!$moduleAction) {
$moduleAction = 'view';
}
$className = 'iwp_module_calendar_adminremote' . $moduleAction . 'action';
if (!class_exists($className)) {
throw new Exception('RemoteAction class name not found for: ' . $moduleAction);
}
$actionHandler = new $className($this, false, false);
$actionHandler->handleAction();
die();
}
/**
* (non-PHPdoc)
* @see api/iwp_module#AdminCustom()
*/
public function AdminCustom () {
$moduleAction = preg_replace('#[^a-zA-Z0-9]#', '', iwp_strtolower(@$_GET['moduleaction']));
if (!$moduleAction) {
$moduleAction = 'view';
}
$className = 'iwp_module_calendar_admin' . $moduleAction . 'action';
if (!class_exists($className)) {
$className = 'iwp_module_calendar_adminviewaction';
}
$actionHandler = new $className($this);
$actionHandler->handleAction();
die();
}
/**
* (non-PHPdoc)
* @see api/iwp_module#ShowPageByIniUri()
*/
public function ShowPageByIniUri () {
$matchedUri = $this->urls->GetCurrentModulePage();
$uriBits = $this->urls->GetCurrentMatches();
if ($matchedUri == 'Remote') {
$data = explode('/', $uriBits['structure']);
$action = array_shift($data);
$extension = $uriBits['extension'];
$className = 'iwp_module_calendar_remote' . $action . 'action';
if (!class_exists($className)) {
$this->controller->ShowPage('NotFound');
die();
}
$handler = new $className($this, $data, $extension);
$handler->handleAction();
}
}
/**
* Storage for this module's site-wide permission options
*
* @var array
*/
public static $SitePermissionOptions;
/**
* Returns this module's site-wide permission options
*
* @return array
*/
public static function GetSitePermissionOptions () {
return iwp_module_calendar::$SitePermissionOptions;
}
public function addAdminResources () {
$this->addAdminJavascript();
$this->addAdminCSS();
}
/**
* Adds common js files used by the calendar admin pages to the template output
*
* @return void Returns nothing
*/
public function addAdminJavascript () {
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/javascript/jquery.form.js');
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/javascript/jquery.field.js');
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/js.php?f=admin.modules§ion=module&a=1');
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/js.php?f=admin.validator§ion=module&a=1');
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/javascript/jquery/plugins/jquery.interspireAjaxForm.js');
$this->template->AddRequiredJS(iwp_config::Get('siteURL') . '/javascript/date.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/colorpicker/js/colorpicker.js');
// if minify js is enabled, use this
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.js');
// during development, use this
/*
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.htmlEncode.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.revealer.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.calendarBubble.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.dateRange.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.common.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.week.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.day.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.month.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.tinymonth.js');
*/
// admin-specific js
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/admin.' . $this->moduleName . '.js');
}
/**
* Adds common css files used by the calendar admin pages to the template output
*
* @return void Returns nothing
*/
public function addAdminCSS () {
$this->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $this->moduleName . '/colorpicker/css/colorpicker.css');
$this->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $this->moduleName . '/colorpicker/css/colorpicker.local.css');
$this->template->AddRequiredCSS(iwp_config::Get('siteURL') . '/css.php?m=' . urlencode($this->moduleName) . '&f=styles');
$this->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $this->moduleName . '/templates/admin.' . $this->moduleName . '.css');
}
public function displaySessionTemplateMessages () {
if ($this->session->Exists('successMessage')) {
$this->template->Assign('MessageText', $this->session->Get('successMessage'));
$this->template->Assign('MessageType', MSG_SUCCESS);
}
}
/**
* Taken from undocumented function in twitter module
*
* @see api/iwp_module#GetLayoutBlocks()
*/
public function GetLayoutBlocks(){
$icon = IWP_MODULES_URI . '/' . $this->moduleName . '/images/calendar.png';
$blocks = array();
$blocks['CalendarDisplay'] = array(
'id' => 'CalendarDisplay',
'name' => $this->lang->Get('CalendarDisplayBlockName'),
'icon' => $icon,
'hasPopup' => true,
);
$blocks['CompactDisplay'] = array(
'id' => 'CompactDisplay',
'name' => $this->lang->Get('CompactDisplayBlockName'),
'icon' => $icon,
'hasPopup' => false,
);
$this->template->AddLanguageForJS(array(
'CalendarDisplayBlockName',
'SelectFirstError',
'SelectViewsError',
), $this->lang, 'module_calendar_');
return $blocks;
}
/**
* Returns HTML for displaying on the front end and adds the required css and js includes to the current template instance
*
* @param string $position
* @param array $views
* @param string $first
* @param string $title
*/
public function generateFrontendOutput ($position, $views = null, $first = null, $title = null) {
if ($views === null || count($views) < 1) {
$views = array(
'day',
'week',
'month',
);
}
if ($first === null || count($views) == 1) {
$first = $views[0];
}
if ($title === null) {
$title = '';
}
//$this->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $this->moduleName . '/templates/styles.css');
// when minified code is enabled, use this
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.js');
// during development, use this
/*
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.htmlEncode.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.revealer.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.calendarBubble.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/jquery.dateRange.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.common.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.week.js'); // the day view depends on having week view js available so always include it, and include it before
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.day.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.month.js');
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.views.tinymonth.js');
*/
// frontend specific js
$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/' . $this->moduleName . '.frontend.js');
// frontend language js
$this->template->AddLanguageForJS(array(
'Starts',
'Ends',
'Location',
'more',
'event',
'Thereareeventsscheduledtoday',
'Therearenoevents',
'Today',
'ViewName_Day',
'ViewName_Week',
'ViewName_Month',
'ViewName_Tinymonth',
'ClosePopup',
'alldayevent',
), $this->lang, 'module_calendar_');
$data = array();
$data['lang'] = $this->lang->GetLangVars();
$this->template->Assign($this->moduleName, $data, false);
$instanceId = iwp_module_calendar_event::generateUid();
$viewsHTML = '';
foreach ($views as $viewName) {
$firstViewClass = '';
if ($first == $viewName) {
$firstViewClass = 'calendar-firstview';
}
$viewsHTML .= '<div class="calendar-view calendar-view-' . $viewName . ' ' . $firstViewClass . '" style="display:none;">';
// if a template exists for this view, parse it, otherwise leave it as just the containing div
if (file_exists(IWP_MODULES_PATH . '/' . $this->moduleName . '/templates/calendar.views.' . $viewName . '.html')) {
$viewsHTML .= $this->template->ParseTemplate('calendar.views.' . strtolower($viewName), true, $this->moduleName);
}
$viewsHTML .= '</div>';
}
$calendarHTML = '<div class="calendar-container calendar-container-frontend">' . $viewsHTML . '</div>';
if ($title) {
$this->template->Assign('blockTitle', $title);
$this->template->Assign('blockContent', $calendarHTML, false);
$this->template->Assign(array('calendar', 'american'), iwp_settings::IsAmericanDateFormat(iwp_getShortDateFormat()), false);
return $this->template->ParseSection('customcontent_' . $position . '_standard');
}
return $calendarHTML;
}
/**
* Outputs a block for this module which is saved in the template_data table
*
* @param int $blockId The block id to output
* @param string $position
* @return string The resulting output HTML
*/
public function OutputSavedBlock ($blockId, $position) {
$blockId = (int)$blockId;
$result = $this->db->Query("SELECT `type`, `content` FROM `" . IWP_TABLE_TEMPLATE_DATA . "` WHERE `blockid` = " . $blockId);
$row = $this->db->Fetch($result);
if (!$row) {
return '';
}
$data = unserialize($row['content']);
return $this->generateFrontendOutput($position, @$data['views'], @$data['first'], @$data['title']);
}
/**
* Taken from undocumented function in twitter module
*
* @return string
*/
public function OutputBlock ($blockName, $position, $data = null) {
// verify that the requested block is provided by this module
$blocks = $this->GetLayoutBlocks();
if (!isset($blocks[$blockName])) {
return '';
}
return $this->generateFrontendOutput($position, array('tinymonth'), 'tinymonth', '');
}
/**
* Implements conversion of request data into data insertable to the template_data table for this module
*
* @param array $request
* @param array $insert
* @return boolean
*/
public function getSavedBlockInsert ($request, &$insert) {
$insert['name'] = $this->lang->Get('CalendarDisplayBlockName');
$data = array(
'views' => $request['views'],
'first' => $request['first'],
'title' => $request['title'],
);
$insert['content'] = serialize($data);
// This associates the saved block to the layoutBlocks array in this module,
// it then allows the right icon to be added to the block
$insert['title'] = 'CalendarDisplay';
return true;
}
/**
* Implements output of an edit saved block template for this module. See parent function for more info.
*
* @param int $blockId
* @param array $data
* @return mixed
*/
public function getEditSavedBlockTemplate ($blockId, $data) {
$parameters = array(
'blockId' => $blockId,
'data' => $data,
);
$action = new iwp_module_calendar_adminremotecalendardisplayoptionsaction($this, $parameters, false);
ob_start();
$action->handleAction();
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Flushes the occurrence cache
*
* @return bool
*/
public static function flushOccurrenceCache () {
return self::getInstance()->db->Query("TRUNCATE " . GetConfig('tablePrefix') . "module_calendar_occurrencecache");
}
/**
* Returns a granularity list for this class.
*
* @param Integer $total Total will be populated with number of rows found in query (by reference)
* @param String $filter Filter string, optional
* @param Integer $page Page number of records to return, optional
* @return Array List of value/text pairs
*/
public static function getGranularityList (&$total, &$page, $filter = '') {
$module = iwp_module_calendar::getInstance();
$event = iwp_module_calendar_event::getInstance();
$limitStart = ($page * IWP_PERMISSIONGRANULARITEMS_PER_PAGE) - IWP_PERMISSIONGRANULARITEMS_PER_PAGE;
$where = '';
if ($filter) {
$filter = '%'. self::getInstance()->db->Quote($filter) .'%';
$where = sprintf("WHERE (`summary` LIKE '%s')", $filter);
}
$result = self::getInstance()->db->Query(sprintf("SELECT SQL_CALC_FOUND_ROWS `id` AS `value`, `summary` AS `text` FROM %s %s ORDER BY `summary` LIMIT %d, %d", $module->getTable('calendar_event'), $where, $limitStart, IWP_PERMISSIONGRANULARITEMS_PER_PAGE));
$total = self::getInstance()->db->FetchOne('SELECT found_rows()');
$list = array();
if ($result) {
while ($row = self::getInstance()->db->Fetch($result)) {
$row['value'] = (int)$row['value'];
array_push($list, $row);
}
self::getInstance()->db->FreeResult($result);
}
return $list;
}
}
/**
* @see iwp_module::$SitePermissionOptions
*/
iwp_module_calendar::$SitePermissionOptions = array(
'full' => new iwp_permissionoption(true, false, false),
'eventcreate' => new iwp_permissionoption(false, false, false),
'eventedit' => new iwp_permissionoption(true, false, false),
'eventdelete' => new iwp_permissionoption(true, false, false),
);