Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
page_calendar.inc
1 <?php
17 require_once SQ_FUDGE_PATH.'/general/text.inc';
18 require_once SQ_FUDGE_PATH.'/general/datetime.inc';
19 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
20 require_once SQ_CORE_PACKAGE_PATH.'/page/page.inc';
21 require_once SQ_PACKAGES_PATH.'/calendar/calendar_event/calendar_event.inc';
22 require_once SQ_PACKAGES_PATH.'/calendar/calendar_events/calendar_event_recurring/calendar_event_recurring.inc';
23 require_once SQ_PACKAGES_PATH.'/calendar/lib/calendar_common.inc';
24 
37 class Page_Calendar extends Page
38 {
39 
40 
45  var $day_names = Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
46 
47 
52  var $month_names_full = Array(1=>'January', 2=>'February', 3=>'March', 4=>'April', 5=>'May', 6=>'June', 7=>'July', 8=>'August', 9=>'September', 10=>'October', 11=>'November', 12=>'December');
53 
54 
59  var $month_names_short = Array(1=>'Jan', 2=>'Feb', 3=>'Mar', 4=>'Apr', 5=>'May', 6=>'June', 7=>'July', 8=>'Aug', 9=>'Sept', 10=>'Oct', 11=>'Nov', 12=>'Dec');
60 
61 
70  function __construct($assetid=0)
71  {
72  $this->_ser_attrs = TRUE;
73  parent::__construct($assetid);
74 
75  }//end constructor
76 
86  function create(&$link)
87  {
88  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
89  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
90  $linkid = Page::create($link);
91  if (!$linkid) {
92  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
93  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
94  $this->id = 0;
95  return FALSE;
96  }
97  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
98  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
99  return $linkid;
100 
101  }//end create()
102 
103 
112  function isDeletableLink($linkid)
113  {
114  // the only reason why we would object to this link being
115  // deleted is if it is the bodycopy linked to us
116  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'major', 'page_contents', '1', '1');
117  $bodycopy_no_results_link = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'major', 'page_contents_no_results', '1', '1');
118 
119  // if this is not a purge trash
120  if (!$GLOBALS['SQ_PURGING_TRASH']) {
121 
122  // if the user is trying to delete the bodycopy or the no results body copy return an error message
123  if ((!empty($bodycopy_link)) && ($bodycopy_link[0]['linkid'] == $linkid)) {
124  return translate('cal_page_error_bodycopy_link_cannot_delete');
125  } else if ((!empty($bodycopy_no_results_link) && ($bodycopy_no_results_link[0]['linkid'] == $linkid))) {
126  return translate('cal_page_error_bodycopy_no_results_link_cannot_delete');
127  }
128  }
129 
130  return parent::isDeletableLink($linkid);
131 
132  }//end isDeletableLink()
133 
134 
154  function _createAdditional(&$link)
155  {
156  if (!Page::_createAdditional($link)) return FALSE;
157 
158  $GLOBALS['SQ_SYSTEM']->am->includeAsset('bodycopy');
159  $GLOBALS['SQ_SYSTEM']->am->includeAsset('folder');
160 
161  // create the page contents bodycopy
162  $page_contents_data = Array('content' => '<h2 style="text-align: center">%calendar_title%</h2><p style="text-align: center">%prev_link%&nbsp;&nbsp;&nbsp;&nbsp;%up_link%&nbsp;&nbsp;&nbsp;&nbsp;%next_link%</p>%calendar_contents%');
163  $asset = new Bodycopy();
164  $copy_link = Array('asset' => &$this, 'value' => 'page_contents' ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
165  $asset->setAttrValue('name', 'Page Contents');
166  if (!$asset->create($copy_link, $page_contents_data)) {
167  $this->id = 0;
168  return FALSE;
169  }
170  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
171  unset($asset);
172 
173  // create the event formats folder
174  $copy_link = Array('asset' => &$this, 'value' => 'type_formats' ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
175  $type_formats = new Folder();
176  $type_formats->setAttrValue('name', 'Type Formats');
177  if (!$type_formats->create($copy_link)) {
178  $this->id = 0;
179  return FALSE;
180  }
181 
182  // create the event format bodycopies
183  $copy_link = Array('asset' => &$type_formats, 'value' => '' ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
184  $event_bodycopy_data = Array('content' => '%asset_contents%');
185  $event_types = Array('single', 'recurring');
186  foreach ($event_types as $event_type) {
187  $copy_link['value'] = 'calendar_event_'.$event_type;
188  $asset = new Bodycopy();
189  $asset->setAttrValue('name', ucfirst($event_type).' Event Format');
190  if (!$asset->create($copy_link, $event_bodycopy_data)) {
191  $this->id = 0;
192  return FALSE;
193  }
194  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
195  unset($asset);
196  }
197 
198  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($type_formats);
199  unset($type_formats);
200 
201  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
202  unset($asset);
203 
204  return TRUE;
205 
206  }//end _createAdditional()
207 
208 
216  function _getAllowedLinks()
217  {
218  $page_links = parent::_getAllowedLinks();
219  $page_links[SQ_LINK_TYPE_2]['folder'] = Array('card' => 'M', 'exclusive' => FALSE);
220  $page_links[SQ_LINK_NOTICE]['asset'] = Array('card' => 'M', 'exclusive' => FALSE);
221  $page_links[SQ_LINK_TYPE_2]['bodycopy'] = Array('card' => 2, 'exclusive' => TRUE);
222  return $page_links;
223 
224  }//end _getAllowedLinks()
225 
226 
233  function printFrontend()
234  {
235 
236  return parent::printFrontend();
237 
238  }//end printFrontend()
239 
240 
247  function printHead()
248  {
249  if (!isset($this->_tmp['valid_request'])) {
250  $this->_tmp['valid_request'] = $this->_validateRequest();
251  }
252  if (!$this->_tmp['valid_request']) return;
253 
254  $view = $_REQUEST['SQ_CALENDAR_VIEW'];
255  $format = array_get_index($this->attr('enabled_views'), $view, '');
256  if (in_array($view, Array('day', 'week')) && ($format == 'calendar_format')) {
257  $partition_time = intval($this->attr('day_partition_time'));
258  $partition_height = $this->attr('day_partition_height');
259  $root_nodes = $this->attr('root_nodes');
260  $width = ($view == 'day') ? $this->attr('day_column_width') : $this->attr('table_column_width');
261  $click_to_add_ab = $this->attr('asset_builder_page');
262  ?>
263  <style type="text/css">
264  table#day tr td.sq-time-cell, table#week tr td.sq-time-cell {
265  width: <?php echo $width; ?>px;
266  height: <?php echo $partition_height; ?>px;
267  padding: 0px 1px;
268  border-width: 1px;
269  }
270  /* CSS Hack to cope with the unusual situation of strict-mode IE being better
271  than strict-mode Firefox. The following rule will be picked up only by firefox
272  and compensates for its td-height bug. */
273  html>body table#day tr td.sq-time-cell, html>body table#week tr td.sq-time-cell {
274  height: <?php echo $partition_height+1; ?>px;
275  }
276  <?php
277  if ($click_to_add_ab) {
278  ?>
279  table#day tr td.sq-time-cell, table#week tr td.sq-time-cell, td.sq-allday-cell {
280  cursor: pointer;
281  cursor: hand;
282  }
283  <?php
284  }
285  ?>
286  </style>
287  <?php
288  }//end if
289  ?>
290  <link rel="stylesheet" type="text/css" href="<?php echo sq_web_path('data'); ?>/asset_types/page_calendar/css/calendar_default.css" />
291  <?php
292 
293  }//end printHead()
294 
295 
302  function printBody()
303  {
304  // start performance mode timer
305  $GLOBALS['SQ_SYSTEM']->pm->startTimer($this);
306 
307  $root_node_ids = array_keys($this->attr('root_nodes'));
308  $res = '';
309  $action = array_get_index($_REQUEST,'SQ_CALENDAR_EVENT_ACTION',FALSE);
310  $event_id = array_get_index($_REQUEST,'SQ_CALENDAR_EVENT_ID',FALSE);
311 
312  if ($event_id) {
313  $event_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset((int)$_REQUEST['SQ_CALENDAR_EVENT_ID']);
314  if (!$event_asset->readAccess()) return;
315  }
316 
317  if ($action) {
318  if ($event_asset->readAccess()) {
319  $res = $event_asset->processEventAction($action);
320  echo $res;
321  } else {
322  $this->_tmp['valid_request'] = FALSE;
323  }
324  }
325 
326  if (!$res) {
327 
328  if (!isset($this->_tmp['valid_request'])) {
329  $this->_tmp['valid_request'] = $this->_validateRequest();
330  }
331  if (!$this->_tmp['valid_request']) return;
332 
333  // Try to get from cache
334  $cache_key = $this->_getCacheKey();
335  $cached_contents = FALSE;
336  if (!empty($cache_key)) {
337  $cm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('cache_manager');
338  $cached_contents = $cm->loadFromCache($this->id, $this->type(), $cache_key);
339  }
340  if ($cached_contents !== FALSE) {
341  echo $cached_contents;
342  } else {
343  // have to generate from scratch
344 
345  // Get replacements. Contents is first because it may change the view if,
346  // for example, we have just finished editing an event
347  $replacements = Array();
348 
349  // the following variable will store the event listing
350  // this array will be passed to getCalendarContents.
351  // getCalendarContents will make a call to
352  // getEventYear, or getEvent Month, or getWeekEvents or getDayEvents to list all the event.
353 
354  $events_array = Array();
355 
356  // Save the current calendar date - we need to edit it in contents to make it work
357  $calendar_date = $_REQUEST['SQ_CALENDAR_DATE'];
358  $cal_view = $_REQUEST['SQ_CALENDAR_VIEW'];
359  $replacements['calendar_contents'] = $this->getCalendarContents($events_array);
360  $_REQUEST['SQ_CALENDAR_DATE'] = $calendar_date;
361 
362  $replacements['calendar_title'] = $this->getCalendarTitle();
363  $replacements['current_user'] = $GLOBALS['SQ_SYSTEM']->user->name;
364 
365  $replacements += $this->_getNavLinkReplacements();
366 
367  // initialise the bodycopy link and contents bodycopy
368  $bodycopy_link = '';
369  $contents_bodycopy = '';
370  // get the number of events we will need to display
371 
372  $nb_events = count($events_array);
373  $event_view = FALSE;
374  if ($cal_view == 'event') $event_view = TRUE;
375  if ($cal_view == 'edit') $event_view = TRUE;
376 
377  // if there is no event and use_no_results_body_copy is true then we use the page_contents_no_results
378  $use_no_results_body_copy = $this->attr('use_no_results_body_copy');
379 
380  if ( (!empty($use_no_results_body_copy)) && (($nb_events == 0) && !($event_view))) {
381  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'page_contents_no_results');
382  if (empty($bodycopy_link)) return FALSE;
383  $contents_bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_link['minorid'], $bodycopy_link['minor_type_code']);
384  } else {
385  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'page_contents');
386  if (empty($bodycopy_link)) return FALSE;
387  $contents_bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_link['minorid'], $bodycopy_link['minor_type_code']);
388  }
389 
390  if (is_null($contents_bodycopy)) return FALSE;
391 
392 
393 
394  ob_start();
395  echo '<script type="text/javascript">if (typeof cal != "undefined") cal.setDate(\''.$_REQUEST['SQ_CALENDAR_DATE'].'\')</script>';
396  // print the contents of page - replacing the global keywords
397  $calendar_replacements = $replacements;
398  $keywords = $contents_bodycopy->getKeywords();
399  foreach ($keywords as $word) {
400  if (isset($calendar_replacements[$word]) && !empty($calendar_replacements[$word])) {
401  $replacements[$word] = $calendar_replacements[$word];
402  } else {
403  $replacements[$word] = $this->getKeywordReplacement($word);
404  }
405  }
406  $contents_bodycopy->setKeywordReplacements($replacements);
407  $contents_bodycopy->printBody();
408  if (!empty($cache_key)) {
409  $cm->saveToCache($this->id, $this->type(), $cache_key, ob_get_contents());
410  }
411  ob_end_flush();
412 
413  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($contents_bodycopy);
414 
415  }//end else no cache
416 
417  }//end if
418  // stop performance mode timer
419  $GLOBALS['SQ_SYSTEM']->pm->stopTimer($this);
420  }//end printBody()
421 
422 
437  function getKeywordReplacement($keyword)
438  {
439  $prefix = $this->getPrefix();
440 
441  // No keywords here, just go and get the global keywords
442  return parent::getKeywordReplacement($keyword);
443 
444  }//end getKeywordReplacement()
445 
446 
455  function _validateRequest()
456  {
457  // Validate View:
458  // If we get a valid and available view type in the request, use it;
459  // otherwise use the initial view attribute.
460  $enabled_views = $this->attr('enabled_views');
461  $enabled_views['edit'] = 1;
462  $cal_view = array_get_index($_REQUEST, 'SQ_CALENDAR_VIEW', FALSE);
463  if (!$cal_view || empty($enabled_views[$cal_view])) {
464  $cal_view = $this->attr('initial_view');
465  }
466 
467  // Validate date:
468  // If no date supplied, use today's
469  // If view is month or year, some incomplete dates can be accepted
470  $cal_date = array_get_index($_REQUEST,'SQ_CALENDAR_DATE', date('Y-m-d'));
471  if (!is_iso8601($cal_date)) {
472  if (($cal_view == 'month') && (strlen($cal_date) >= 7)) {
473  list($year, $month) = sscanf($cal_date, '%04d-%02d');
474  $cal_date = sprintf('%04d-%02d-%02d', $year, $month, 1);
475  } else if (($cal_view == 'year') && (strlen($cal_date) >= 4)) {
476  // still need list() here because sscanf returns array, no exceptions
477  list($year) = sscanf($cal_date, '%04d');
478  $cal_date = sprintf('%04d-%02d-%02d', $year, 1, 1);
479  } else {
480  // no good, use today's date
481  $cal_date = date('Y-m-d');
482  }
483  }
484  // if view is week, we want the first day in that week
485  if ($cal_view == 'week') {
486  $week_start_day = $this->day_names[$this->attr('week_starts_on')];
487  if (date('l',strtotime($cal_date)) != $week_start_day) {
488  $cal_date = date('Y-m-d', strtotime('last '.$week_start_day, strtotime($cal_date)));
489  }
490  }
491  // if we've somehow ended up with an invalid date, use today's
492  list($year, $month, $day) = explode('-', $cal_date);
493  if (!checkdate($month, $day, $year)) {
494  trigger_localised_error('CAL0022', E_USER_WARNING, $cal_date);
495  $cal_date = date('Y-m-d');
496  }
497 
498  // If the view is 'event' or 'edit' we need the eventid too
499  $event_id = FALSE;
500  if (($cal_view == 'event') || ($cal_view == 'edit')) {
501  if (!isset($_REQUEST['SQ_CALENDAR_EVENT_ID'])) {
502  trigger_localised_error('CAL0023', E_USER_WARNING, ucfirst($cal_view));
503  return FALSE;
504  }
505  if (!assert_valid_assetid($_REQUEST['SQ_CALENDAR_EVENT_ID'])) {
506  return FALSE;
507  }
508  }
509 
510  // Store validated values in globals for future reference
511  $_REQUEST['SQ_CALENDAR_VIEW'] = $cal_view;
512  $_REQUEST['SQ_CALENDAR_DATE'] = $cal_date;
513  return TRUE;
514 
515  }//end _validateRequest()
516 
517 
524  function _getCacheKey()
525  {
526  $cache_key = '';
527  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
528 
529  if (!isset($this->_tmp['valid_request'])) {
530  $this->_tmp['valid_request'] = $this->_validateRequest();
531  }
532 
533  if ($this->_tmp['valid_request']) {
534  // Cache key will be a letter representing the view type (Y, M, W, D)
535  // followed by as precise an iso-date as necessary (2004, 2004-02, 2004-04-01)
536  list($year, $month, $day) = explode('-', $_REQUEST['SQ_CALENDAR_DATE']);
537  switch ($_REQUEST['SQ_CALENDAR_VIEW']) {
538  case 'year':
539  $cache_key = 'Y'.$year;
540  case 'month':
541  $cache_key = sprintf('M%04d-%02d', $year, $month);
542  case 'week':
543  $cache_key = sprintf('W%04d-%02d-%02d', $year, $month, $day);
544  case 'day':
545  $cache_key = sprintf('D%04d-%02d-%02d', $year, $month, $day);
546  }
547  }
548 
549  // Append the context ID to the cache key, but only if we have a
550  // cache key to begin with - otherwise we shouldn't be caching at all
551  if ($cache_key !== '') {
552  $cache_key .= '-ctx'.$contextid;
553  }
554 
555  return $cache_key;
556 
557  }//end _getCacheKey()
558 
559 
567  function _getNavLinkReplacements()
568  {
569  $replacements = Array();
570  $cal_view = $_REQUEST['SQ_CALENDAR_VIEW'];
571  $cal_date = $_REQUEST['SQ_CALENDAR_DATE'];
572 
573  $event_id = array_get_index($_REQUEST, 'SQ_CALENDAR_EVENT_ID', FALSE);
574 
575  // the link to the prev/next/current month always points to
576  // the first date of the month.
577  if ($cal_view == 'month') {
578  $date_format = 'Y-m-01';
579  } else {
580  $date_format = 'Y-m-d';
581  }
582 
583  $prev_date = date($date_format, strtotime('-1 '.$cal_view, strtotime(date($date_format, strtotime($cal_date)))));
584  $next_date = date($date_format, strtotime('+1 '.$cal_view, strtotime(date($date_format, strtotime($cal_date)))));
585 
586  list ($forward_limit,$forward_date) = $this->formatDatesToCompare($cal_view,$next_date,'forward','+');
587  list ($backward_limit,$backward_date) = $this->formatDatesToCompare($cal_view,$prev_date,'backward','-');
588 
589  if ($forward_limit == '' || $forward_limit >= $forward_date) {
590  $replacements['next_link'] = ($cal_view == 'event') ? '' : '<a class="calendarNavLink" href="'.$this->getURL().'?SQ_CALENDAR_VIEW='.$cal_view.'&amp;SQ_CALENDAR_DATE='.$next_date.'" rel="nofollow">'.(str_replace('%v%', ucfirst($cal_view), htmlentities($this->attr('next_link_text')))).'</a>';
591  } else {
592  $replacements['next_link'] = '';
593  }
594  if ($backward_limit == '' || $backward_date >= $backward_limit) {
595  $replacements['prev_link'] = ($cal_view == 'event') ? '' : '<a class="calendarNavLink" href="'.$this->getURL().'?SQ_CALENDAR_VIEW='.$cal_view.'&amp;SQ_CALENDAR_DATE='.$prev_date.'" rel="nofollow">'.(str_replace('%v%', ucfirst($cal_view), htmlentities($this->attr('prev_link_text')))).'</a>';
596  } else {
597  $replacements['prev_link'] = '';
598  }
599  if ($backward_date > $forward_limit || $forward_date < $backward_limit) {
600  $replacements['prev_link'] = '';
601  $replacements['next_link'] = '';
602  }
603 
604  $enabled_views = $this->attr('enabled_views');
605  $replacements['today_link'] = ($cal_view == 'event') ? '' : '<a class="calendarNavLink calendarTodayLink" href="'.$this->getURL().'?SQ_CALENDAR_VIEW='.$cal_view.'" rel="nofollow">'.htmlentities($this->attr('today_link_text')).'</a>';
606 
607  if ($cal_view == 'week') {
608  $cal_date = date('Y-m-01', iso8601_ts($cal_date));
609  }
610 
611  $up_view = '';
612  foreach ($enabled_views as $view => $type) {
613  if ($view == $cal_view) break;
614  if ($type) $up_view = $view;
615  }
616 
617  // Check if the up view is an event, then we need to pass an event id
618  $eventview = '';
619  if ($up_view == 'event' && !empty($event_id)) {
620  $eventview = '&amp;SQ_CALENDAR_EVENT_ID='.$event_id;
621  }
622 
623  $replacements['up_link'] = $up_view ? '<a class="calendarNavLink" href="'.$this->getHref().'?SQ_CALENDAR_VIEW='.$up_view.$eventview.'&amp;SQ_CALENDAR_DATE='.$cal_date.'" rel="nofollow">'.str_replace('%v%', ucfirst($up_view), $this->attr('up_link_text')).'</a>' : '';
624 
625  return $replacements;
626 
627  }//end _getNavLinkReplacements()
628 
629 
640  function onRequestKeywords(&$broadcaster, $vars=Array())
641  {
642  if (!isset($vars['keywords'])) return;
643  if (empty($vars['keywords'])) {
644  parent::onRequestKeywords($broadcaster, $vars);
645  }
646  $bc_parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'bodycopy', FALSE);
647  if (empty($bc_parents)) return;
648 
649  $tf_folder_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'folder', TRUE, 'type_formats');
650  $tf_bc_link = $GLOBALS['SQ_SYSTEM']->am->getLinkByAsset($tf_folder_link['minorid'], key($bc_parents), SQ_SC_LINK_ALL);
651  if (empty($tf_bc_link)) {
652  // presume it was the contents BC
653  $vars['keywords'] = array_merge($vars['keywords'], $this->_getContentsKeywords());
654  } else {
655  // it's a type format BC
656  $GLOBALS['SQ_SYSTEM']->am->includeAsset($tf_bc_link['value']);
657  $dummy = new $tf_bc_link['value']();
658  $vars['keywords'] = array_merge($vars['keywords'], $dummy->getAvailableKeywords());
659  }
660 
661  }//end onRequestKeywords()
662 
663 
677  function _getContentsKeywords()
678  {
679  $keywords = Array(
680  'calendar_contents' => translate('cal_page_calendar_contents'),
681  'calendar_title' => translate('cal_page_calendar_title'),
682  'up_link' => translate('cal_page_up_link'),
683  'prev_link' => translate('cal_page_prev_link'),
684  'next_link' => translate('cal_page_next_link'),
685  'current_user' => translate('cal_page_current_user'),
686  'today_link' => translate('cal_page_today_link'),
687  );
688 
689  return $keywords;
690 
691  }//end _getContentsKeywords()
692 
693 
700  function getViewOptions()
701  {
702  return Array(
703  'year' => Array(
704  '' => translate('cal_no_display'),
705  'list_without_headings' => translate('cal_list_without_headings'),
706  'list_with_headings' => translate('cal_list_with_month_headings'),
707  'calendar_format' => translate('cal_calendar_format'),
708  ),
709  'month' => Array(
710  '' => translate('cal_no_display'),
711  'list_without_headings' => translate('cal_list_without_headings'),
712  'list_with_headings' => translate('cal_list_with_day_headings'),
713  'calendar_format' => translate('cal_calendar_format'),
714  ),
715  'week' => Array(
716  '' => translate('cal_no_display'),
717  'list_without_headings' => translate('cal_list_without_headings'),
718  'list_with_headings' => translate('cal_list_with_day_headings'),
719  'calendar_format' => translate('cal_calendar_format'),
720  ),
721  'day' => Array(
722  '' => translate('cal_no_display'),
723  'list_without_headings' => translate('cal_list_without_headings'),
724  'calendar_format' => translate('cal_calendar_format'),
725  ),
726  'event' => Array(
727  '' => translate('cal_no_display'),
728  'single_event_view' => translate('cal_show_single_event_view'),
729  'event_itself' => translate('cal_show_single_event_itself'),
730  ),
731  );
732 
733  }//end getViewOptions()
734 
735 
736 //-- FUNCTIONS TO GET CALENDAR CONTENTS --//
737 
738 
747  function getCalendarTitle()
748  {
749  $title_formats = $this->attr('view_title_formats');
750  $title_formats['edit'] = translate('cal_page_edit_event');
751  $view = $_REQUEST['SQ_CALENDAR_VIEW'];
752  if (($view == 'event') || ($view == 'edit')) {
753  // _validateRequest already made sure we have a valid event id
754  $info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($_REQUEST['SQ_CALENDAR_EVENT_ID']));
755  return $info[$_REQUEST['SQ_CALENDAR_EVENT_ID']]['name'];
756  } else {
757  return date($title_formats[$view], strtotime($_REQUEST['SQ_CALENDAR_DATE']));
758  }
759 
760  }//end getCalendarTitle()
761 
762 
772  function getCalendarContents(&$events_array)
773  {
774  $cal_view = $_REQUEST['SQ_CALENDAR_VIEW'];
775  $formats = $this->attr('enabled_views');
776  $format = array_get_index($formats, $cal_view, '');
777  $res = $this->_getGeneralScript();
778  if (strpos($format, 'list') === FALSE) {
779  $res .= '<div id="calendarTable">';
780  }
781  $func = 'get'.ucfirst($cal_view).'View';
782  $res .= (($cal_view == 'event') || ($cal_view == 'edit')) ? $this->$func($_REQUEST['SQ_CALENDAR_EVENT_ID']) : $this->$func($_REQUEST['SQ_CALENDAR_DATE'], $format, $events_array);
783  if (strpos($format, 'list') === FALSE) {
784  $res .= '</div>';
785  }
786  return $res;
787 
788  }//end getCalendarContents()
789 
790 
801  function getYearView($date, $format, &$events_array)
802  {
803  ob_start();
804  list($year, $month, $day) = explode('-', $date);
805  $enabled_views = $this->attr('enabled_views');
806 
807  if ($format == 'list_without_headings') {
808  $list_entry_types = $this->attr('list_entry_types');
809  $events = $this->getYearEvents($year);
810  $events_array = $events;
811  uasort($events, Array('Calendar_Common', 'compareStartDates'));
812  if ($list_entry_types['year'] == 'title') {
813  echo $this->_getTitleList($events);
814  } else {
815  $this->_printEventList($events);
816  }
817  } else if ($format == 'list_with_headings') {
818  $list_entry_types = $this->attr('list_entry_types');
819 
820  $events = $this->getYearEventsByMonth($year);
821 
822  // copy all the events to $events_array
823  foreach ($events as $month => $month_events) {
824  $events_array = array_merge($events_array, $month_events);
825  }
826 
827  foreach ($this->month_names_full as $month_num => $month_name) {
828  $_REQUEST['SQ_CALENDAR_DATE']= $year.'-'.sprintf('%02d', $month_num).'-01';
829  uasort($events[$month_num], Array('Calendar_Common', 'compareStartDates'));
830  echo '<h3>';
831  if ($enabled_views['month']) {
832  echo '<a href="'.$this->getHref().'?SQ_CALENDAR_VIEW=month&amp;SQ_CALENDAR_DATE='.$year.'-'.sprintf('%02d', $month_num).'-01">';
833  }
834  echo $month_name;
835  if ($enabled_views['month']) echo '</a>';
836  echo '</h3>';
837 
838  if ($list_entry_types['year'] == 'title') {
839  echo $this->_getTitleList($events[$month_num], $enabled_views['event']);
840  } else {
841  $this->_printEventList($events[$month_num]);
842  }
843  }
844  } else {
845  $events = $this->getYearEventsByMonthAndDay($year);
846 
847  // add all events to the $events_array
848  foreach ($events as $month => $month_array) {
849  foreach ($month_array as $day => $day_events) {
850  $events_array = array_merge($events_array, $day_events);
851  }
852  }
853 
854  $week_start_day = $this->attr('week_starts_on');
855  $today_iso = date('Y-m-d');
856  ?>
857  <table id="year">
858  <tr>
859  <th class="dayLabel" style="width: 6ex">&nbsp;</th>
860  <?php
861  for ($i = $week_start_day; $i < $week_start_day + 37; $i++) {
862  $day = strtolower(substr($this->day_names[$i % 7], 0, 3));
863  $label = $this->attr('label_'.$day);
864  ?>
865  <th class="dayLabel<?php echo (($i%7)==0 || ($i%7)==6) ? ' dayLabelWeekend' : ''; ?>" style="width: 3.5ex"><b><?php echo substr($label, 0, 1); ?></b></th>
866  <?php
867  }
868  ?>
869  </tr>
870  <?php
871  for ($current_month=1; $current_month<13; $current_month++) {
872  ?>
873  <tr>
874  <th class="monthLabel">
875  <?php
876  // print the month name, linked to month view if it's available
877  if ($enabled_views['month']) {
878  echo '<a href="'.$this->getHref().'?SQ_CALENDAR_VIEW=month&amp;SQ_CALENDAR_DATE='.$year.'-'.sprintf('%02d', $current_month).'-01">';
879  }
880  echo $this->month_names_short[$current_month];
881  if ($enabled_views['month']) echo '</a>';
882  ?>
883  </th>
884 
885  <?php
886  // print blank days of week before the day our month starts on
887  $i=0;
888  $blank_days = (date('w', strtotime("$year-".sprintf('%02d', $current_month).'-01')) + 7 - $week_start_day) % 7;
889  for ($i = 0; $i < $blank_days; $i++) {
890  ?>
891  <td class="<?php echo (((($week_start_day + $i) % 7)==0) || ((($week_start_day + $i) % 7)==6)) ? ' weekend' : ''; ?> ">&nbsp;</td>
892  <?php
893  }
894 
895  // print the days of the month
896  for ($current_day = 1; $current_day <= days_in_month($current_month, $year); $current_day++) {
897  $i++;
898  $tag_attrs = Array();
899  $classes = Array('date');
900  if (sprintf('%04d-%02d-%02d', $year, $current_month, $current_day) == $today_iso) {
901  $classes[] = 'today';
902  }
903  if (in_array(date('D', strtotime("$year-$current_month-$current_day")), Array('Sat', 'Sun'))) {
904  $classes[] = 'weekend';
905  }
906  if (!empty($events[$current_month][$current_day])) {
907  $classes[] = 'eventDate';
908  }
909  $tag_attrs[] = 'class="'.implode(' ', $classes).'"';
910  $day_href = $this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.sprintf('%04d-%02d-%02d', $year, $current_month, $current_day);
911  echo '<td '.implode(' ', $tag_attrs).'>';
912  echo '<a href="'.$day_href.'">'.$current_day.'</a>';
913  echo '</td>';
914 
915  }
916 
917  // print blank days after the end of our month
918  while ($i < 37) {
919  ?>
920  <td class="<?php echo (((($week_start_day + $i) % 7)==0) || ((($week_start_day + $i) % 7)==6)) ? ' weekend' : ''; ?>">&nbsp;</td>
921  <?php
922  $i++;
923  }
924  ?>
925  </tr>
926  <?php
927  }//end for
928  ?>
929  </table>
930  <?php
931  }//end else
932  $res = ob_get_contents();
933  ob_end_clean();
934  return $res;
935 
936  }//end getYearView()
937 
938 
949  function getMonthView($date, $format, &$events_array)
950  {
951  $popups_enabled = $this->attr('enable_description_popups');
952  if ($popups_enabled) $this->_printPopupsScript();
953  list($year, $month, $day) = explode('-', $date);
954  $enabled_views = $this->attr('enabled_views');
955  $drill_down_views = Array('week', 'day');
956  $drill_down_view = current($drill_down_views);
957  while (empty($enabled_views[$drill_down_view]) && ($drill_down_view !== FALSE)) {
958  $drill_down_view = next($drill_down_views);
959  }
960 
961  ob_start();
962  if ($format == 'list_without_headings') {
963  $list_entry_types = $this->attr('list_entry_types');
964  $raw_events = $this->getMonthEvents($year, $month);
965  $events_array = $raw_events;
966  $this->_initEventLabels('month', $raw_events);
967  $events = $this->groupMonthEventsByDay($raw_events, $year, $month);
968  $month_length = days_in_month($month, $year);
969  $done_events = Array();
970 
971  // loop through each day, but if it's been printed before then
972  // don't print it again
973  for ($current_day = 1; $current_day <= $month_length; $current_day++) {
974  uasort($events[$current_day], Array('Calendar_Common', 'compareStartDates'));
975  $current_date = sprintf('%04s-%02s-%02s', $year, $month, $current_day);
976  $_REQUEST['SQ_CALENDAR_DATE'] = $current_date;
977  foreach ($events[$current_day] as $event_id => $event_data) {
978  list($event_assetid, ) = explode(':', $event_id);
979  if (!isset($done_events[$event_assetid])) {
980  $done_events[$event_assetid] = 1;
981  } else {
982  unset($events[$current_day][$event_id]);
983  }
984  }
985  if ($list_entry_types['month'] == 'title') {
986  echo $this->_getTitleList($events[$current_day], $enabled_views['event']);
987  } else {
988  $this->_printEventList($events[$current_day]);
989  }
990  }
991  } else if ($format == 'list_with_headings') {
992  // Dates in month view with 'Listing with day Headings' option should always have url with day view
993  $drill_down_view = $enabled_views['day'] ? 'day' : '';
994 
995  $list_entry_types = $this->attr('list_entry_types');
996  $raw_events = $this->getMonthEvents($year, $month);
997  $events_array = $raw_events;
998  $this->_initEventLabels('month', $raw_events);
999  $events = $this->groupMonthEventsByDay($raw_events, $year, $month);
1000  $month_length = days_in_month($month, $year);
1001  $day_heading_format = 'l jS';
1002  $heading_formats = $this->attr('view_heading_formats');
1003  if (isset($heading_formats['month_day']) && !empty($heading_formats['month_day'])) {
1004  $day_heading_format = $heading_formats['month_day'];
1005  }
1006  for ($current_day = 1; $current_day <= $month_length; $current_day++) {
1007  uasort($events[$current_day], Array('Calendar_Common', 'compareStartDates'));
1008  echo '<h3>';
1009  if ($drill_down_view) {
1010  echo '<a href="'.$this->getHref().'?SQ_CALENDAR_VIEW='.$drill_down_view.'&amp;SQ_CALENDAR_DATE='.$year.'-'.$month.'-'.sprintf('%02d', $current_day).'">';
1011  }
1012  $current_date = sprintf('%04s-%02s-%02s', $year, $month, $current_day);
1013  $_REQUEST['SQ_CALENDAR_DATE'] = $current_date;
1014  echo date($day_heading_format, strtotime($current_date));
1015  if ($drill_down_view) echo '</a>';
1016  echo '</h3>';
1017  if ($list_entry_types['month'] == 'title') {
1018  echo $this->_getTitleList($events[$current_day], $enabled_views['event']);
1019  } else {
1020  $this->_printEventList($events[$current_day]);
1021  }
1022  }
1023  } else {
1024  $raw_events = $this->getMonthEvents($year, $month);
1025  $events_array = $raw_events;
1026  $this->_initEventLabels('month', $raw_events);
1027  $events = $this->groupMonthEventsByDay($raw_events, $year, $month);
1028  $column_width = $this->attr('month_column_width');
1029  $row_height = $this->attr('month_row_height');
1030  $week_start_day = $this->attr('week_starts_on');
1031  $week_length = 7;
1032  $month_length = days_in_month($month, $year);
1033  $current_day = 1;
1034  $current_date = $_REQUEST['SQ_CALENDAR_DATE'];
1035  $current_day_name = date('l',iso8601_ts($current_date));
1036  $today_iso = date('Y-m-d');
1037  ?>
1038  <table id="month" style="width: <?php echo (7.35 * $column_width); ?>px">
1039  <tr>
1040  <?php
1041  // print the day headings
1042  if ($this->attr('month_links_to_week')) {
1043  echo '<th class="dayLabel">&nbsp;</th>';
1044  }
1045  for ($i=0; $i < $week_length; $i++) {
1046  $day_name = $this->day_names[($week_start_day + $i) % 7];
1047  $day = substr(strtolower($day_name), 0, 3);
1048  $day_label = $this->attr('label_'.$day);
1049  ?>
1050  <th style="width: <?php echo $column_width; ?>px" class="dayLabel<?php echo (($day_name == 'Saturday') || ($day_name == 'Sunday')) ? 'Weekend' : ''; ?>">
1051  <?php echo $day_label; ?>
1052  </th>
1053  <?php
1054  }
1055  ?>
1056  </tr>
1057  <tr>
1058  <?php
1059  // First Week
1060  if ($this->attr('month_links_to_week')) {
1061  $offset = 0;
1062  $day_in_seconds = 24 * 60 * 60;
1063  $first_week_link_date = $current_date;
1064  $week_start_index = $this->attr('week_starts_on');
1065  $curr_day_index = array_search(date('l', iso8601_ts($current_date)), $this->day_names);
1066  if ($week_start_index != $curr_day_index) {
1067  if ($week_start_index < $curr_day_index) {
1068  $offset = $curr_day_index - $week_start_index;
1069  } else {
1070  $offset = $curr_day_index + (7 - $week_start_index);
1071  }
1072  }
1073  $first_week_link_date = iso8601_date_component(ts_iso8601(iso8601_ts($current_date) - ($offset * $day_in_seconds)));
1074  ?>
1075  <th class="weekLink" onclick="clickChild(this)"><a class="dateLink" href="<?php echo $this->getHref().'?SQ_CALENDAR_VIEW=week&amp;SQ_CALENDAR_DATE='.$first_week_link_date ?>">&raquo;</a></th>
1076  <?php
1077  }
1078 
1079  // print blank days if necessrary
1080  $i = 0;
1081  $blank_days = (date('w', strtotime("$year-".sprintf('%02d', $month).'-01')) + 7 - $week_start_day) % 7;
1082  for ($i = 0; $i < $blank_days; $i++) {
1083  ?>
1084  <td class="<?php echo (((($week_start_day + $i) % 7)==0) || ((($week_start_day + $i) % 7)==6)) ? 'weekend' : ''; ?>">&nbsp;</td>
1085  <?php
1086  }
1087 
1088  // print the rest of the first week
1089  for (; $i < $week_length; $i++) {
1090  $tag_attrs = Array();
1091  $current_date = sprintf('%04d-%02d-%02d', $year, $month, $current_day);
1092  $_REQUEST['SQ_CALENDAR_DATE'] = $current_date;
1093  $contents = $this->_getMonthCellContents($events[$current_day], $current_date, $column_width*0.99);
1094  $classes = Array('date');
1095  if ($current_date == $today_iso) $classes[] = 'today';
1096  if ($contents) $classes[] = 'eventDate';
1097  if (in_array(date('D', strtotime("$year-$month-$current_day")), Array('Sat', 'Sun'))) {
1098  $classes[] = 'weekend';
1099  }
1100  $tag_attrs[] = 'class="'.implode(' ', $classes).'"';
1101  $tag_attrs[] = 'style="height: '.$row_height.'px"';
1102  $date_url = $this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.$current_date;
1103  ?>
1104  <td <?php echo implode(' ', $tag_attrs); ?>>
1105  <a class="dateLink" href="<?php echo $date_url; ?>"><?php echo $current_day; ?></a>
1106  <br />
1107  <?php echo $contents; ?>
1108  </td>
1109  <?php
1110  $current_day++;
1111  }
1112  ?>
1113  </tr>
1114 
1115  <?php
1116  // print the full weeks
1117  $num_full_weeks = floor(($month_length - $current_day) / 7);
1118  for ($w = 0; $w < $num_full_weeks; $w++) {
1119  ?>
1120  <tr>
1121  <?php
1122  if ($this->attr('month_links_to_week')) {
1123  ?>
1124  <th class="weekLink" onclick="clickChild(this)"><a class="dateLink" href="<?php echo $this->getHref().'?SQ_CALENDAR_VIEW=week&amp;SQ_CALENDAR_DATE='.add_days_to_iso($current_date) ?>">&raquo;</a></th>
1125  <?php
1126  }
1127  for ($i=0; $i < $week_length; $i++) {
1128  $tag_attrs = Array();
1129  $current_date = sprintf('%04d-%02d-%02d', $year, $month, $current_day);
1130  $_REQUEST['SQ_CALENDAR_DATE'] = $current_date;
1131  $contents = $this->_getMonthCellContents($events[$current_day], $current_date, $column_width*0.99);
1132  $classes = Array('date');
1133  if ($current_date == date('Y-m-d')) {
1134  $classes[] = 'today';
1135  }
1136  if ($contents) $classes[] = 'eventDate';
1137  if (in_array(date('D', strtotime("$year-$month-$current_day")), Array('Sat', 'Sun'))) {
1138  $classes[] = 'weekend';
1139  }
1140  $tag_attrs[] = 'class="'.implode(' ', $classes).'"';
1141  $tag_attrs[] = 'style="height: '.$row_height.'px"';
1142  $date_url = $this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.$current_date;
1143  ?>
1144  <td <?php echo implode(' ', $tag_attrs); ?>>
1145  <a class="dateLink" href="<?php echo $date_url; ?>"><?php echo $current_day; ?></a>
1146  <br />
1147  <?php echo $contents; ?>
1148  </td>
1149  <?php
1150  $current_day++;
1151  }//end for
1152  ?>
1153  </tr>
1154  <?php
1155  }//end for
1156  $current_date = sprintf('%04d-%02d-%02d', $year, $month, $current_day);
1157 
1158  // print the final week, if necessary
1159  if ($current_day <= $month_length) {
1160  $i = 0;
1161  ?>
1162  <tr>
1163  <?php
1164  if ($this->attr('month_links_to_week')) {
1165  ?>
1166  <th class="weekLink" onclick="clickChild(this)"><a class="dateLink" href="<?php echo $this->getHref().'?SQ_CALENDAR_VIEW=week&amp;SQ_CALENDAR_DATE='.$current_date ?>">&raquo;</a></th>
1167  <?php
1168  }
1169  while ($current_day <= $month_length) {
1170  $tag_attrs = Array();
1171  $current_date = sprintf('%04d-%02d-%02d', $year, $month, $current_day);
1172  $_REQUEST['SQ_CALENDAR_DATE'] = $current_date;
1173  $contents = $this->_getMonthCellContents($events[$current_day], $current_date, $column_width*0.99);
1174  $classes = Array('date');
1175  if ($current_date == date('Y-m-d')) {
1176  $classes[] = 'today';
1177  }
1178  if ($contents) $classes[] = 'eventDate';
1179  if (in_array(date('D', strtotime("$year-$month-$current_day")), Array('Sat', 'Sun'))) {
1180  $classes[] = 'weekend';
1181  }
1182  $tag_attrs[] = 'class="'.implode(' ', $classes).'"';
1183  $tag_attrs[] = 'style="height: '.$row_height.'px"';
1184  $date_url = $this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.$current_date;
1185  ?>
1186  <td <?php echo implode(' ', $tag_attrs); ?>>
1187  <a class="dateLink" href="<?php echo $date_url; ?>"><?php echo $current_day; ?></a>
1188  <br />
1189  <?php echo $contents; ?>
1190  </td>
1191  <?php
1192  $current_day++;
1193  $i++;
1194  }
1195 
1196  // print blank days, if necessary
1197  while ($i < $week_length) {
1198  ?>
1199  <td class="<?php echo (((($week_start_day + $i) % 7)==0) || ((($week_start_day + $i) % 7)==6)) ? ' weekend' : ''; ?>">&nbsp;</td>
1200  <?php
1201  $i++;
1202  }
1203  ?>
1204  </tr>
1205  <?php
1206  }//end if
1207  ?>
1208  </table>
1209  <?php
1210 
1211  }//end else
1212 
1213  $res = ob_get_contents();
1214  ob_end_clean();
1215  return $res;
1216 
1217  }//end getMonthView()
1218 
1219 
1230  function getWeekView($date, $format, &$events_array)
1231  {
1232  ob_start();
1233  $root_nodes = $this->attr('root_nodes');
1234  $enabled_views = $this->attr('enabled_views');
1235  if ($format == 'list_without_headings') {
1236  $list_entry_types = $this->attr('list_entry_types');
1237  $raw_events = $this->getWeekEvents($date);
1238  $events_array = $raw_events;
1239  $this->_initEventLabels('week', $raw_events);
1240  $events = $this->groupWeekEventsByDay($raw_events, $date);
1241  $done_events = Array();
1242 
1243  // loop through each day but exclude events that have already
1244  // been printed
1245  foreach ($events as $day_date => $day_events) {
1246  $_REQUEST['SQ_CALENDAR_DATE'] = $day_date;
1247  uasort($events[$day_date], Array('Calendar_Common', 'compareStartDates'));
1248 
1249  foreach ($events[$day_date] as $event_id => $event_data) {
1250  list($event_assetid, ) = explode(':', $event_id);
1251  if (!isset($done_events[$event_assetid])) {
1252  $done_events[$event_assetid] = 1;
1253  } else {
1254  unset($events[$day_date][$event_id]);
1255  }
1256  }
1257 
1258  if ($list_entry_types['week'] == 'title') {
1259  echo $this->_getTitleList($events[$day_date], $enabled_views['event']);
1260  } else {
1261  $this->_printEventList($events[$day_date]);
1262  }
1263  }
1264 
1265  } else if ($format == 'list_with_headings') {
1266  $list_entry_types = $this->attr('list_entry_types');
1267  $raw_events = $this->getWeekEvents($date);
1268  $events_array = $raw_events;
1269  $this->_initEventLabels('week', $raw_events);
1270  $events = $this->groupWeekEventsByDay($raw_events, $date);
1271  $day_heading_format = 'l jS';
1272  $heading_formats = $this->attr('view_heading_formats');
1273  if (isset($heading_formats['week_day']) && !empty($heading_formats['week_day'])) {
1274  $day_heading_format = $heading_formats['week_day'];
1275  }
1276  foreach ($events as $day_date => $day_events) {
1277  $_REQUEST['SQ_CALENDAR_DATE'] = $day_date;
1278  uasort($events[$day_date], Array('Calendar_Common', 'compareStartDates'));
1279  echo '<h3>'.(($enabled_views['day']) ? '<a href="'.$this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.$day_date.'">' : '');
1280  echo date($day_heading_format, strtotime($day_date));
1281  echo (($enabled_views['day']) ? '</a>' : '').'</h3>';
1282  if ($list_entry_types['week'] == 'title') {
1283  echo $this->_getTitleList($events[$day_date], $enabled_views['event']);
1284  } else {
1285  $this->_printEventList($events[$day_date]);
1286  }
1287  }
1288  } else {
1289  $raw_events = $this->getWeekEvents($date);
1290  $events_array = $raw_events;
1291  $this->_initEventLabels('week', $raw_events);
1292  $events = $this->groupWeekEventsByDayAndTime($raw_events, $date);
1293  $column_names = Array();
1294  $column_links = Array();
1295  foreach ($events as $day_date => $day_events) {
1296  $_REQUEST['SQ_CALENDAR_DATE'] = $day_date;
1297  $date = date('l', strtotime($day_date));
1298  $day = strtolower(substr($date, 0, 3));
1299  $label = $this->attr('label_'.$day);
1300  $column_names[$day_date] = $label.' '.date('jS', strtotime($day_date));
1301  if ($enabled_views['week']) {
1302  $column_links[$day_date] = $this->getHref().'?SQ_CALENDAR_VIEW=day&amp;SQ_CALENDAR_DATE='.$day_date;
1303  }
1304  }
1305  $this->_printTimedTable('week', $column_names, $column_links, $events, $enabled_views['event']);
1306  }
1307  $res = ob_get_contents();
1308  ob_end_clean();
1309  return $res;
1310 
1311  }//end getWeekView()
1312 
1313 
1324  function getDayView($date, $format, &$events_array)
1325  {
1326  ob_start();
1327  if (strpos($format, 'list') === 0) {
1328  $list_entry_types = $this->attr('list_entry_types');
1329  $enabled_views = $this->attr('enabled_views');
1330  $events = $this->getDayEvents($date);
1331  $events_array = $events;
1332  $this->_initEventLabels('day', $events);
1333  if ($list_entry_types['day'] == 'title') {
1334  echo $this->_getTitleList($events, $enabled_views['event']);
1335  } else {
1336  $this->_printEventList($events);
1337  }
1338  } else {
1339  $column_names = Array();
1340  $column_links = Array();
1341  $column_ids = $this->attr('columnise_day_view_by_root_node');
1342  if (array_values($column_ids) != Array('*')) {
1343  $root_nodes = array_keys($this->attr('root_nodes'));
1344  $column_names_raw = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($column_ids, Array(), TRUE, 'name');
1345  foreach ($column_ids as $column_id) {
1346  if (in_array($column_id, $root_nodes)) {
1347  $column_names[$column_id] = $column_names_raw[$column_id];
1348  }
1349  }
1350 
1351  if (in_array('*', $column_ids)) {
1352  $column_names['*'] = ($this->attr('other_column_name') == '') ? translate('other') : $this->attr('other_column_name');
1353  }
1354  $raw_events = $this->getDayEvents($date);
1355  $events_array = $raw_events;
1356  $this->_initEventLabels('day', $raw_events);
1357  $events = $this->groupDayEventsByRootNodeAndTime($raw_events);
1358  } else {
1359  $column_names['*'] = ($this->attr('other_column_name') == '') ? translate('events') : $this->attr('other_column_name');
1360  $raw_events = $this->getDayEvents($date);
1361  $events_array = $raw_events;
1362  $this->_initEventLabels('day', $raw_events);
1363  $events = Array('*' => $this->groupDayEventsByTime($raw_events, $date));
1364  }
1365  $enabled_views = $this->attr('enabled_views');
1366  $this->_printTimedTable('day', $column_names, $column_links, $events, $enabled_views['event']);
1367  }
1368 
1369  $res = ob_get_contents();
1370  ob_end_clean();
1371  return $res;
1372 
1373  }//end getDayView()
1374 
1375 
1384  function getEventView($event_id)
1385  {
1386  $res = '';
1387  ob_start();
1388  $info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($event_id));
1389  if (!empty($info)) $this->_printEventList($info);
1390 
1391  $res = ob_get_contents();
1392  ob_end_clean();
1393  return $res;
1394 
1395  }//end getEventView()
1396 
1397 
1409  function getEditView($event_id)
1410  {
1411  $event = $GLOBALS['SQ_SYSTEM']->am->getAsset($event_id);
1412  require_once SQ_INCLUDE_PATH.'/limbo_outputter.inc';
1413  $o = new Limbo_Outputter();
1414  if (!$event->id) {
1415  trigger_localised_error('CAL0024', E_USER_WARNING, $event_id);
1416  return FALSE;
1417  }
1418 
1419  // Process the form if appropriate
1420  if (isset($_POST['asset_action'])) {
1421  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
1422  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
1423  $link = Array();
1424  if ($event->processBackend($o, $link)) {
1425  // The form has been committed and there are no probs, so go to event view
1426  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
1427  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
1428  $GLOBALS['SQ_SYSTEM']->am->releaseLock($event_id, 'attributes');
1429  $_REQUEST['SQ_CALENDAR_VIEW'] = 'event';
1430  $_REQUEST['SQ_CALENDAR_EVENT_ID'] = $event_id;
1431  return $this->getEventView($event_id);
1432  } else {
1433  // There was a problem, so roll back transaction and continue printing the form
1434  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
1435  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
1436  }
1437  }
1438 
1439  // Acquire the lock and print the interface
1440  if (!$GLOBALS['SQ_SYSTEM']->am->acquireLock($event_id, 'attributes')) {
1441  trigger_localised_error('CAL0025', E_USER_WARNING, $event->name, $event_id);
1442  return $this->getEventView($event_id);
1443  }
1444  $o->addHiddenField('SQ_CALENDAR_VIEW', 'edit');
1445  $o->addHiddenField('SQ_CALENDAR_EVENT_ID', $event_id);
1446  $o->addHiddenField('SQ_CALENDAR_DATE', array_get_index($_REQUEST, 'SQ_CALENDAR_DATE'));
1447  $o->addHiddenField('asset_action', 'limbo');
1448  $o->addJsInclude(sq_web_path('lib').'/html_form/html_form.js');
1449  $o->openRaw();
1450  $ei = $event->getEI();
1451  $ei->printEditInterface('screen_details', $event, $o);
1452  $o->closeRaw();
1453  $o->commitButton(translate('cal_page_update_event'));
1454  ob_start();
1455  $o->_paintHeader();
1456  $o->paint();
1457  $res = ob_get_contents();
1458  ob_end_clean();
1459  return $res;
1460 
1461  }//end getEditView()
1462 
1463 
1464 //-- HELPER FUNCTIONS FOR CONTENTS-GETTING FUNCTIONS --//
1465 
1466 
1475  function _getTitleList($events)
1476  {
1477  $res = '';
1478  if (!empty($events)) {
1479  $res = '<ul>';
1480  foreach ($events as $id => $data) {
1481  $real_id = strtok($id, ':');
1482  $res .= '<li>';
1483  $event_date = sprintf('%04d-%02d-%02d', $data['start_date_year'], $data['start_date_mon'], $data['start_date_mday']);
1484  $event_url = $this->_getEventLinkHref($real_id, $event_date);
1485  if ($event_url) $res .= '<a href="'.htmlentities($event_url).'">';
1486 
1487  $current_view = htmlentities($_REQUEST['SQ_CALENDAR_VIEW']);
1488  switch ($current_view) {
1489  case 'week':
1490  case 'month':
1491  case 'day':
1492  $res .= $this->_getEventLabel($current_view, $data);
1493  break;
1494  default:
1495  $res .= $data['name'];
1496  break;
1497  }
1498  if ($event_url) $res .= '</a>';
1499  $res .= '</li>';
1500  }
1501  $res .= '</ul>';
1502  }//end if
1503 
1504  return $res;
1505 
1506  }//end _getTitleList()
1507 
1508 
1521  function _printTimedTable($view, $column_names, $column_links, $events)
1522  {
1523  $partition_time = intval($this->attr('day_partition_time'));
1524  $partition_height = $this->attr('day_partition_height');
1525  $columns_are_assets = ($view == 'day') && (array_keys($column_names) != Array('*'));
1526 
1527  $root_nodes = $this->attr('root_nodes');
1528  $width = ($view == 'day') ? $this->attr('day_column_width') : $this->attr('table_column_width');
1529 
1530  $layout_maps = Array();
1531  foreach ($events as $date => $times_events) {
1532  $layout_maps[$date] = Array();
1533  foreach (array_keys($times_events) as $time) {
1534  $layout_maps[$date][$time] = Array();
1535  }
1536  }
1537 
1538  $dragging_enabled = $this->attr('enable_event_dragging');
1539  $popups_enabled = $this->attr('enable_description_popups');
1540  $click_to_add_ab = $this->attr('asset_builder_page');
1541  $today_iso = date('Y-m-d');
1542 
1543  $mousedown_code = $dragging_enabled ? 'onmousedown="'.($popups_enabled ? 'stopTrailingPopup(); ' : '').'startDragging(this)"' : '';
1544  $mouseup_code = $dragging_enabled ? 'onmouseup="stopDragging(); formSubmitted=true; setTimeout(\'formSubmitted=false\', 100)"' : '';
1545  ?>
1546 
1547  <table id="<?php echo $view; ?>" border="0" cellspacing="0" cellpadding="0" summary="<?php echo translate('cal_page_events_in_this_'.$view); ?>" style="width: <?php echo ($width * count($events)) + 65; ?>px">
1548  <?php
1549 
1550  // PRINT HEADER ROW
1551  ?>
1552  <tr>
1553  <th><?php echo translate('time'); ?></th>
1554  <?php
1555  foreach ($column_names as $id => $name) {
1556  $today_class = ($id == $today_iso) ? ' today' : '';
1557  ?>
1558  <th class="columnLabel<?php echo $today_class; ?>" style="width: <?php echo $width; ?>px;">
1559  <?php
1560  if (!empty($column_links)) {
1561  echo '<a href="'.$column_links[$id].'">';
1562  }
1563  echo str_replace(' ', '&nbsp;', $name);
1564  if (!empty($column_links)) echo '</a>';
1565  ?>
1566  </th>
1567  <?php
1568  }
1569  ?>
1570  </tr>
1571  <?php
1572  $div_width = $width * 0.99;
1573  list($current_hour, $current_mins) = explode(':', $this->attr('day_starts_at'));
1574  list($end_hour, $end_mins) = explode(':', $this->attr('day_ends_at'));
1575 
1576  // PRINT THE 'ALL DAY' ROW
1577  ?>
1578  <tr>
1579  <th class="timeLabel">*</th>
1580  <?php
1581  foreach ($column_names as $id => $name) {
1582  $today_class = ($id == $today_iso) ? ' today' : '';
1583  $col_events = $events[$id];
1584  $event_link_date = is_iso8601($id) ? $id : $_REQUEST['SQ_CALENDAR_DATE'];
1585  $click_to_add_code = '';
1586  if ($click_to_add_ab) {
1587  $root_node_code = ($columns_are_assets && ($id != '*')) ? ', '.$id : '';
1588  $click_to_add_code = ' onclick="addEvent(\''.$event_link_date.'\', \'*\''.$root_node_code.');"';
1589  }
1590  $cell_id = $event_link_date.'_allday_'.($columns_are_assets ? $id : '');
1591  ?>
1592  <td class="sq-allday-cell<?php echo $today_class; ?>" id="cell_<?php echo $cell_id; ?>"<?php echo $click_to_add_code; ?>>
1593  <?php
1594  if (empty($col_events['all_day'])) echo '&nbsp;';
1595  foreach ($col_events['all_day'] as $assetid => $event) {
1596  $assetid = strtok($assetid,':');
1597  $event_href = $this->_getEventLinkHref($assetid, $event_link_date);
1598  $event_classes = $this->_getClasses($event['treeid']);
1599  $event_classes[] = 'event';
1600  $onclick_code = $event_href ? ' onclick="sq_cal_redirect(this)"' : '';
1601  $cursor_code = $event_href ? ' cursor: pointer; cursor: hand' : '';
1602  $current_mouse_up_down_code = $mousedown_code.' '.$mouseup_code;
1603  if (!empty($mousedown_code) && (($event['type_code'] == 'calendar_event_recurring') || (isset($event['expanded'])))) {
1604  $current_mouse_up_down_code = 'onmousedown="statusBarMsg(\''.translate('cal_page_recurring_cannot_drag').'\')" onmouseup="statusBarMsg(\'\');"';
1605  }
1606  $current_mouse_over_out_code = '';
1607  if (!empty($event['description'])) {
1608  if (!isset($this->_tmp['popup_printed'][$assetid])) {
1609  $popup_div_id = $assetid.'_'.$id;
1610  echo '<div id="event_'.$popup_div_id.'_description" class="popup">'.$event['description'].'</div>';
1611  $this->_tmp['popup_printed'][$assetid] = 1;
1612  }
1613  $current_mouse_over_out_code = 'onmouseover="startTrailingPopup(\'event_'.$popup_div_id.'_description\')" onmouseout="stopTrailingPopup()"';
1614  }
1615  echo '<div id="event_'.$assetid.'" '.$current_mouse_up_down_code.' '.$current_mouse_over_out_code.' style="width: '.($width-2).'px;'.$cursor_code.'" class="'.implode(' ', $event_classes).'"'.$onclick_code.'>';
1616 
1617  // if drag-n-drop is enabled, click-through-to-event-view is supported
1618  // via javascript only, because otherwise the link elements cause trouble
1619  // with the dragging
1620  $label = $this->_getEventLabel($view, $event);
1621  if ($event_href && empty($mousedown_code)) {
1622  $label = '<a class="'.implode(' ', $event_classes).'" href="'.htmlentities($event_href).'">'.$label.'</a>';
1623  } else {
1624  // print a hidden link so we can store the HREF
1625  // in the right attr and have the browser
1626  // interpret the entities
1627  $label = '<span class="'.implode(' ', $event_classes).'">'.$label.'</span>';
1628  $label .= '<a style="display:none" href="'.htmlentities($event_href).'"></a>';
1629  }
1630  echo $label;
1631  echo '</div>';
1632 
1633  }//end foreach allday events
1634  ?>
1635  </td>
1636  <?php
1637 
1638  }//end foreach
1639  ?>
1640  </tr>
1641  <?php
1642 
1643  // PRINT THE ROWS WITH TIMES
1644  while (($current_hour*60 + $current_mins) < ($end_hour*60 + $end_mins)) {
1645  ?>
1646  <tr>
1647  <th class="timeLabel"><?php printf('%d:%02d', (($current_hour % 12 == 0) ? 12 : ($current_hour % 12)), $current_mins); ?></th>
1648  <?php
1649  foreach ($column_names as $id => $name) {
1650  $today_class = ($id == $today_iso) ? ' today' : '';
1651  $col_events = $events[$id];
1652  $event_link_date = is_iso8601($id) ? $id : $_REQUEST['SQ_CALENDAR_DATE'] ;
1653  $time_key = sprintf('%02d:%02d', $current_hour, $current_mins);
1654  if ($click_to_add_ab) {
1655  $root_node_code = ($columns_are_assets && ($id != '*')) ? ', '.$id : '';
1656  $click_to_add_code = ' onclick="addEvent(\''.$event_link_date.'\', \''.$time_key.'\''.$root_node_code.');"';
1657  }
1658  $cell_id = $event_link_date.'_'.$time_key.'_'.($columns_are_assets ? $id : '');
1659  ?>
1660  <td id="cell_<?php echo $cell_id; ?>" class="sq-time-cell<?php echo $today_class; ?>" <?php echo $click_to_add_code; ?>>
1661  <?php
1662  $denominator = max($col_events['_overlap_'], $this->attr('column_capacity'));
1663  echo $this->_getTimedTableCellContents($view, $col_events[$time_key], $event_link_date, $root_nodes, ($current_mins + ($current_hour * 60)), $partition_time, $partition_height, $div_width / $denominator, $layout_maps[$id], $mousedown_code, $mouseup_code);
1664  ?>
1665  <span style="font-size: 1px">&nbsp;</span>
1666  </td>
1667  <?php
1668  }
1669  ?>
1670  </tr>
1671  <?php
1672  $current_mins += $partition_time;
1673  $current_hour += floor($current_mins / 60);
1674  $current_mins = $current_mins % 60;
1675  }//end while
1676  ?>
1677  </table>
1678  <?php
1679 
1680  // print all the javascript last so it doesn't screw up spacing in mozilla
1681  if ($dragging_enabled) {
1682  $this->_printEventDraggingScript($view, ($view == 'day') ? $column_names : NULL);
1683  }
1684  if ($popups_enabled) $this->_printPopupsScript();
1685  if ($click_to_add_ab) {
1686  $this->_printAddEventScript($click_to_add_ab);
1687  }
1688 
1689 
1690  }//end _printTimedTable()
1691 
1692 
1711  function _getTimedTableCellContents($view, &$events, $event_link_date, &$root_nodes, $cell_ts, $partition_time, $cell_height, $event_width, &$layout_map, $mousedown_code, $mouseup_code)
1712  {
1713  if (empty($events)) return '';
1714 
1715  $time_label = sprintf('%02d:%02d', (int)($cell_ts / 60), $cell_ts % 60);
1716 
1717  // get events in order
1718  uasort($events, Array('Calendar_Common', 'compareStartDates'));
1719  $res = '';
1720  foreach ($events as $assetid => $details) {
1721 
1722  $real_assetid = current(explode(':', $assetid));
1723  $event_href = $this->_getEventLinkHref($real_assetid, $event_link_date);
1724 
1725  // get horizontal position of div and update the layout map
1726  $k = reset($layout_map);
1727  while ((key($layout_map) != $time_label) && (FALSE !== $k)) {
1728  next($layout_map);
1729  }
1730  $horizontal_index = 0;
1731  if (FALSE !== $k) {
1732  while (isset($layout_map[$time_label][$horizontal_index])) {
1733  $horizontal_index++;
1734  }
1735  for ($i=0; $i < ceil(($details['end_date_minutes'] + $details['end_date_hours']*60 - $details['start_date_minutes']-$details['start_date_hours']*60) / $partition_time); $i++) {
1736  $layout_map[key($layout_map)][$horizontal_index] = 1;
1737  next($layout_map);
1738  }
1739  }
1740  $event_left_margin = ($event_width * $horizontal_index);
1741 
1742  // get top position of div
1743  $event_ts = $details['start_date_minutes'] + (60 * $details['start_date_hours']);
1744  $end_ts = $details['end_date_minutes'] + (60 * $details['end_date_hours']);
1745  $event_top_margin = (($event_ts - $cell_ts) / $partition_time) * $cell_height;
1746 
1747  // get height of div
1748  $event_duration = is_null($details['end_date_ts']) ? 0 : ($end_ts - $event_ts);
1749  $event_height = ($event_duration / $partition_time) * $cell_height;
1750  if ($event_height < 0) continue;
1751  $event_height += floor($event_duration / $partition_time);
1752  $event_height -= 2;
1753 
1754  $event_classes = $this->_getClasses($details['treeid']);
1755  $event_classes[] = 'event';
1756 
1757  // mouse action handlers
1758  $onclick_code = $event_href ? 'onclick="sq_cal_redirect(this)"' : '';
1759  $current_mouse_up_down_code = $mousedown_code.' '.$mouseup_code;
1760  if (!empty($mousedown_code) && (($details['type_code'] == 'calendar_event_recurring') || (isset($details['expanded'])))) {
1761  $current_mouse_up_down_code = 'onmousedown="statusBarMsg(\''.translate('cal_page_recurring_cannot_drag').'\')" onmouseup="statusBarMsg(\'\');"';
1762  }
1763  $current_mouse_over_out_code = '';
1764 
1765  if (!empty($details['description'])) {
1766  if (!isset($this->_tmp['popup_printed'][$assetid])) {
1767  $res .= '<div id="event_'.$assetid.'_description" class="popup">'.$details['description'].'</div>';
1768  $this->_tmp['popup_printed'][$assetid] = 1;
1769  }
1770  $current_mouse_over_out_code = 'onmouseover="startTrailingPopup(\'event_'.$assetid.'_description\')" onmouseout="stopTrailingPopup()"';
1771  }
1772 
1773  // other special CSS for cursors and zero-length events
1774  $zero_length_code = $event_height ? '' : 'border-style: dashed; border-bottom: 0px; border-left: 0px; border-right: 0px; padding-top: 0px; background-color: transparent;';
1775  $cursor_code = $event_href ? 'cursor: pointer; cursor: hand;' : '';
1776 
1777  // showtime!
1778  $res .= '<div id="event_'.$assetid.'" '.$current_mouse_up_down_code.' '.$current_mouse_over_out_code.' class="'.implode(' ', $event_classes).' event" style="float: left; position: absolute; width: '.($event_width-3).'px; margin-left: '.$event_left_margin.'px; margin-top: '.$event_top_margin.'px; height: '.$event_height.'px; border-width: 1px; '.$cursor_code.' '.$zero_length_code.'" '.$onclick_code.'>';
1779  $res .= '<div class="eventText" style="z-index: 30; position: absolute; width: '.($event_width-4).'px; border: none; background-color: transparent">';
1780 
1781  // if drag-n-drop is enabled, click-through-to-event-view is supported
1782  // via javascript only, because otherwise the link elements cause trouble
1783  // with the dragging
1784  $label = $this->_getEventLabel($view, $details);
1785  if ($event_href && empty($mousedown_code)) {
1786  $label = '<a class="'.implode(' ', $event_classes).'" href="'.htmlentities($event_href).'">'.$label.'</a>';
1787  } else {
1788  $label = '<span class="'.implode(' ', $event_classes).'">'.$label.'</span>';
1789  // add a hidden link to store the HREF so that the browser
1790  // decodes the entities within it
1791  $label .= '<a style="display:none" href="'.htmlentities($event_href).'"></a>';
1792  }
1793  $res .= $label;
1794 
1795  $res .= '</div></div>';
1796 
1797  }//end foreach
1798  return $res;
1799 
1800  }//end _getTimedTableCellContents()
1801 
1802 
1813  function _getMonthCellContents(&$events, $event_link_date, $width)
1814  {
1815  $res = '';
1816  uasort($events, Array('Calendar_Common', 'compareStartDates'));
1817 
1818  foreach ($events as $assetid => $details) {
1819  $popup_div_id = str_replace(':', '_', $assetid);
1820  $assetid = strtok($assetid, ':');
1821  $event_url = htmlentities($this->_getEventLinkHref($assetid, $event_link_date));
1822  $event_classes = $this->_getClasses($details['treeid']);
1823  $event_classes[] = 'event';
1824  $onclick_code =$event_url ? ' onclick="clickChild(this); "' : '';
1825  $cursor_code = $event_url ? 'cursor: pointer; cursor: hand;' : '';
1826 
1827  $current_mouse_over_out_code = '';
1828 
1829  if (!empty($details['description'])) {
1830  if (!isset($this->_tmp['popup_printed'][$assetid])) {
1831  $res .= '<div id="event_'.$assetid.'_description" class="popup">'.$details['description'].'</div>';
1832  $this->_tmp['popup_printed'][$assetid] = 1;
1833  }
1834  $current_mouse_over_out_code = 'onmouseover="startTrailingPopup(\'event_'.$assetid.'_description\')" onmouseout="stopTrailingPopup()"';
1835  }
1836 
1837 
1838  $res .= '<div style="width: '.$width.'px; '.$cursor_code.'"'.$onclick_code.' '.$current_mouse_over_out_code.'><div style="width: auto; margin-bottom: 1px;" class="'.implode(' ', $event_classes).'">';
1839  if ($event_url) {
1840  $res .= '<a href="'.$event_url.'" class="'.implode(' ', $event_classes).'">';
1841  }
1842  $res .= $this->_getEventLabel('month', $details);
1843  if ($event_url) $res .= '</a>';
1844  $res .= '</div></div>';
1845  }
1846  return $res;
1847 
1848  }//end _getMonthCellContents()
1849 
1850 
1857  function _getGeneralScript()
1858  {
1859  $res = '<script type="text/javascript" src="'.sq_web_path('lib').'/js/general.js"></script>';
1860  foreach ($GLOBALS['SQ_SYSTEM']->lm->getJavascriptIncludes() as $js_include) {
1861  $res .= '<script type="text/javascript" src="'.$js_include.'"></script>';
1862  }
1863  $res .= '
1864 
1865  <!-- GENERAL CALENDAR PAGE JAVASCRIPT, ALWAYS PRESENT -->
1866  <script type="text/javascript">
1867  <!--
1868  var formSubmitted = false;
1869 
1870  function clickChild(elt) {
1871  if (formSubmitted) {
1872  return;
1873  }
1874  formSubmitted = true;
1875  linkChildren = elt.getElementsByTagName("A");
1876  if (linkChildren.length > 0) {
1877  linkChildren.item(0).click();
1878  }
1879  }
1880  function sq_cal_redirect(url) {
1881  if (url.getElementsByTagName) {
1882  url = url.getElementsByTagName("A")[0].href;
1883  }
1884  if ((typeof moved == "undefined") || !moved) {
1885  document.location.href = url;
1886  formSubmitted = true;
1887  }
1888  }
1889  function statusBarMsg(m) {
1890  window.status = m;
1891  setTimeout(\'window.status=""\', 2000);
1892  }
1893  //-->
1894  </script>
1895  <!-- /GENERAL CALENDAR PAGE JAVASCRIPT, ALWAYS PRESENT -->
1896 
1897  ';
1898  return $res;
1899 
1900  }//end _getGeneralScript()
1901 
1902 
1911  function _printAddEventScript($ab_id)
1912  {
1913  ?>
1914 
1915  <!-- SCRIPT FOR CLICK-TO-ADD-EVENT -->
1916  <script type="text/javascript">
1917  <!--
1918  function addEvent(date, time, node) {
1919  if (formSubmitted) return;
1920  loc = "<?php echo $GLOBALS['SQ_SYSTEM']->am->getAssetHref($ab_id); ?>?SQ_CALENDAR_DATE="+date;
1921  if (time != '*') loc += '&SQ_CALENDAR_TIME='+time+'&SQ_CALENDAR_DURATION=<?php echo (int)$this->attr('day_partition_time');?>_i';
1922  if (typeof node != 'undefined') loc += '&SQ_CALENDAR_LOCATION='+node;
1923  document.location = loc;
1924  }
1925  //-->
1926  </script>
1927  <!-- /SCRIPT FOR CLICK-TO-ADD-EVENT -->
1928 
1929  <?php
1930 
1931  }//end _printAddEventScript()
1932 
1933 
1943  function _printEventDraggingScript($table_id, $columns=NULL)
1944  {
1945  ?>
1946 
1947  <!-- DRAG AND DROP SUPPORT -->
1948  <script type="text/javascript" src="<?php echo sq_web_path('data'); ?>/asset_types/page_calendar/js/drag_n_drop.js"></script>
1949  <script type="text/javascript"><!--
1950  //<![CDATA[
1951  destinationTableId = '<?php echo $table_id; ?>';
1952  columnNames = new Array(<?php echo count($columns); ?>);
1953  <?php
1954  if (!is_null($columns)) {
1955  foreach ($columns as $id => $name) {
1956  ?>
1957  columnNames['<?php echo $id; ?>'] = '<?php echo $name; ?>';
1958  <?php
1959  }
1960  }
1961  ?>
1962  document.onselectstart=new Function ("return false")
1963  //]]> -->
1964  </script>
1965  <form method="get" id="dragForm" action="<?php echo $_SERVER['PHP_SELF']; ?>">
1966  <input type="hidden" name="SQ_CALENDAR_NEW_LOC" id="SQ_CALENDAR_NEW_LOC" />
1967  <input type="hidden" name="SQ_CALENDAR_OLD_LOC" id="SQ_CALENDAR_OLD_LOC" />
1968  <input type="hidden" name="SQ_CALENDAR_EVENT_ID" id="SQ_CALENDAR_EVENT_ID" />
1969  <input type="hidden" name="SQ_CALENDAR_DATE" value="<?php echo htmlspecialchars($_REQUEST['SQ_CALENDAR_DATE']); ?>" />
1970  <input type="hidden" name="SQ_CALENDAR_NEW_DATE" id="SQ_CALENDAR_NEW_DATE" />
1971  <input type="hidden" name="SQ_CALENDAR_NEW_TIME" id="SQ_CALENDAR_NEW_TIME" />
1972  <input type="hidden" name="SQ_CALENDAR_VIEW" value="<?php echo htmlspecialchars(array_get_index($_REQUEST, 'SQ_CALENDAR_VIEW', '')); ?>" />
1973  <input type="hidden" name="SQ_CALENDAR_EVENT_ACTION" id="SQ_CALENDAR_EVENT_ACTION" value="move" />
1974  </form>
1975  <!-- /DRAG AND DROP SUPPORT -->
1976 
1977  <?php
1978 
1979  }//end _printEventDraggingScript()
1980 
1981 
1988  function _printPopupsScript()
1989  {
1990  ?>
1991 
1992  <!-- DESCRIPTION POPUPS SUPPORT -->
1993  <script type="text/javascript" src="<?php echo sq_web_path('data'); ?>/asset_types/page_calendar/js/popup.js"></script>
1994  <!-- /DESCRIPTION POPUPS SUPPORT -->
1995 
1996  <?php
1997 
1998  }//end _printPopupsScript()
1999 
2000 
2017  function _countOverlappingEvents(&$events, $start, $end, $spacing, $root_node=NULL)
2018  {
2019  if (empty($events) || !is_array($events)) {
2020  return 1;
2021  }
2022 
2023  list($start_time_h, $start_time_m) = explode(':',$start);
2024  list($end_time_h, $end_time_m) = explode(':',$end);
2025 
2026  // turn these times into number of minutes since midnight
2027  $start_time = $start_time_h * 60 + $start_time_m;
2028  $end_time = $end_time_h * 60 + $end_time_m;
2029 
2030  $end_section = (ceil(($end_time - $start_time) / $spacing) - 1);
2031 
2032  $event_lists = Array();
2033 
2034  foreach (array_values($events) as $event) {
2035  if (empty($event['start_date_hours'])) continue; // no-time event
2036  $event_start_time = $event['start_date_hours'] * 60 + $event['start_date_minutes'];
2037  if (is_null($event['end_date_hours']) || is_null($event['end_date_minutes'])) {
2038  $event_end_time = $event_start_time;
2039  } else {
2040  $event_end_time = $event['end_date_hours'] * 60 + $event['end_date_minutes'];
2041  }
2042  $event_start_section = floor(($event_start_time - $start_time) / $spacing);
2043  $event_end_section = (ceil(($event_end_time - $start_time) / $spacing) - 1);
2044 
2045  for ($i = $event_start_section; $i <= min($end_section, $event_end_section); $i++) {
2046  if ((!is_null($root_node)) && ($event['root_node'] != $root_node)) {
2047  continue;
2048  }
2049  if (!isset($event_lists[$i])) $event_lists[$i] = 0;
2050  $event_lists[$i]++;
2051  }
2052 
2053  }
2054 
2055  array_multisort($event_lists, SORT_DESC, SORT_NUMERIC);
2056  return max(1,reset($event_lists));
2057 
2058  }//end _countOverlappingEvents()
2059 
2060 
2071  function _numPeriodsBetweenTimes($start, $end, $spacing)
2072  {
2073  list($start_time_h, $start_time_m) = explode(':',$start);
2074  list($end_time_h, $end_time_m) = explode(':',$end);
2075 
2076  // turn these times into number of minutes since midnight
2077  $start_time = $start_time_h * 60 + $start_time_m;
2078  $end_time = $end_time_h * 60 + $end_time_m;
2079 
2080  return ceil(($end_time - $start_time) / $spacing);
2081 
2082  }//end _numPeriodsBetweenTimes()
2083 
2084 
2095  function _addMinutes(&$current_hour, &$current_mins, $add_mins)
2096  {
2097  $current_mins += $add_mins;
2098  $current_hour += floor($current_mins / 60);
2099  $current_mins = $current_mins % 60;
2100 
2101  }//end _addMinutes()
2102 
2103 
2116  function _trimEvent(&$details, $day_start_dts, $day_end_dts)
2117  {
2118  $event_dts = $details['start_date_hours'] * 60 + $details['start_date_minutes'];
2119  $event_end_dts = $details['end_date_hours'] * 60 + $details['end_date_minutes'];
2120  if ((!empty($details['end_date_ts']) && ($event_end_dts < $day_start_dts)) || ($event_dts > $day_end_dts)) {
2121  $details = Array();
2122  }
2123 
2124  // start-of-table / end-of-table adjustments to make sure that those events
2125  // partly outside the bounds of the table are (a) kept inside the table and
2126  // (b) show on the table in the first place (in case of start time adjustment)
2127  if (($event_dts < $day_start_dts) && ($event_end_dts > $day_start_dts)) {
2128  $event_dts = $day_start_dts;
2129  $details['start_date_hours'] = floor($day_start_dts / 60);
2130  $details['start_date_minutes'] = $day_start_dts % 60;
2131  $details['trimmed'] = 1;
2132  }
2133  if (($event_dts < $day_end_dts) && ($event_end_dts > $day_end_dts)) {
2134  $event_end_dts = $day_end_dts;
2135  $details['end_date_hours'] = floor($day_end_dts / 60);
2136  $details['end_date_minutes'] = $day_end_dts % 60;
2137  $details['trimmed'] = 1;
2138  }
2139 
2140  }//end _trimEvent()
2141 
2142 
2154  function _printEventList(&$events)
2155  {
2156 
2157  if (empty($events)) return;
2158  uasort($events, Array('Calendar_Common', 'compareStartDates'));
2159 
2160  $assetids = array_keys($events);
2161  $am =& $GLOBALS['SQ_SYSTEM']->am;
2162 
2163 
2164  if (!isset($this->_tmp['type_format_bcs'])) {
2165  // Get our two type format BCs
2166  $type_format_bodycopies = Array();
2167  $folder_link = $am->getLink($this->id, SQ_LINK_TYPE_2, 'folder', TRUE, 'type_formats');
2168  $links = $am->getLinks($folder_link['minorid'], SQ_LINK_TYPE_2, 'bodycopy', TRUE);
2169  $this->_tmp['list_needs_asset_info'] = FALSE;
2170  foreach ($links as $bodycopy) {
2171  $bodycopy_type_code = $bodycopy['value'];
2172  $type_format_bodycopies[$bodycopy_type_code] = Array();
2173  $type_format_bodycopies[$bodycopy_type_code]['obj'] = $am->getAsset($bodycopy['minorid'], 'bodycopy');
2174  $type_format_bodycopies[$bodycopy_type_code]['keywords'] = $type_format_bodycopies[$bodycopy_type_code]['obj']->getKeywords();
2175  $data_reqs = $this->_getKeywordDataRequirements($type_format_bodycopies[$bodycopy_type_code]['keywords']);
2176  $type_format_bodycopies[$bodycopy_type_code]['needs_asset'] = ($data_reqs == 2);
2177  if ($data_reqs == 1) {
2178  $this->_tmp['list_needs_asset_info'] = TRUE;
2179  }
2180  }
2181  $this->_tmp['type_format_bcs'] =& $type_format_bodycopies;
2182  } else {
2183  $type_format_bodycopies =& $this->_tmp['type_format_bcs'];
2184  }
2185 
2186  foreach ($assetids as $i => $assetid) {
2187  $assetids[$i] = strtok($assetid, ':');
2188  }
2189  $assetids = array_unique($assetids);
2190 
2191  if ($this->_tmp['list_needs_asset_info']) {
2192  $this->_tmp['asset_infos'] = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($assetids);
2193  foreach ($this->_tmp['asset_infos'] as $id => $info) {
2194  $asset_info[$id]['assetid'] = $id;
2195  }
2196  }
2197 
2198  // loop each event
2199  foreach ($events as $assetid => $event) {
2200  $event['assetid'] = $assetid;
2201  $type_code = $event['type_code'];
2202  $assetid = strtok($assetid, ':');
2203 
2204  // Determine which bodycopy to use
2205  $found_bodycopy = FALSE;
2206  if (isset($type_format_bodycopies[$type_code])) {
2207  $bodycopy =& $type_format_bodycopies[$type_code];
2208  $found_bodycopy = TRUE;
2209  } else if ($type_code == 'calendar_event_modification' ) {
2210  // Modification Event
2211  $link = $am->getLink($assetid, SQ_LINK_TYPE_2, 'calendar_event_recurring', TRUE, NULL, 'minor');
2212  $bodycopy =& $type_format_bodycopies[$link['major_type_code']];
2213  $found_bodycopy = TRUE;
2214  } else if ($type_code == 'calendar_event_cancellation' ) {
2215  continue;
2216  } else {
2217  // check parent type
2218  $type_ancestors = $am->getTypeAncestors($type_code);
2219  foreach ($type_ancestors as $parent_type) {
2220  if (isset($type_format_bodycopies[$parent_type])) {
2221  $type_format_bodycopies[$type_code] =& $type_format_bodycopies[$parent_type];
2222  $bodycopy =& $type_format_bodycopies[$parent_type];
2223  $found_bodycopy = TRUE;
2224  break;
2225  } else if ($parent_type == 'calendar_event_cancellation' ) {
2226  continue(2);
2227  }
2228  }
2229  if (!$found_bodycopy) {
2230  trigger_localised_error('CAL0061', E_USER_WARNING, $assetid);
2231  continue;
2232  }
2233  }
2234 
2235  $replacements = Array();
2236  if ($bodycopy['needs_asset']) {
2237  $event = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid, $type_code);
2238  foreach ($bodycopy['keywords'] as $keyword) {
2239  if ($keyword == 'asset_contents') {
2240  ob_start();
2241  $event->printBody();
2242  $replacements['asset_contents'] = ob_get_clean();
2243  } else {
2244  $replacements[$keyword] = $event->getKeywordReplacement($keyword);
2245  }
2246  }
2247  unset($event);
2248  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($event);
2249  } else {
2250  foreach ($bodycopy['keywords'] as $keyword) {
2251  $replacements[$keyword] = $this->_getEventKeywordReplacement($keyword, $event);
2252  }
2253  }
2254  $bodycopy['obj']->setKeywordReplacements($replacements);
2255  $bodycopy['obj']->printBody();
2256 
2257  }//end foreach event
2258 
2259  }//end _printEventList()
2260 
2261 
2268  function _getRootNodeIds()
2269  {
2270  $root_asset_ids = array_keys($this->attr('root_nodes'));
2271  if (empty($root_asset_ids)) {
2272  $root_asset_ids = Array($this->id);
2273  }
2274  return $root_asset_ids;
2275 
2276  }//end _getRootNodeIds()
2277 
2278 
2287  function _getClasses($treeids)
2288  {
2289  usort($treeids, Array(&$this, '_strlenCmp'));
2290  $treeid_key = implode(',', $treeids);
2291  $root_nodes = $this->attr('root_nodes');
2292  if (!isset($this->_tmp['treeid_map'])) {
2293  $root_node_roots = $GLOBALS['SQ_SYSTEM']->am->getAssetTreeids(array_keys($root_nodes));
2294  $treeid_map = Array();
2295  foreach ($root_node_roots as $assetid => $root_treeids) {
2296  $root_treeid = $root_treeids[0];
2297  $treeid_map[reset($root_treeid)] = $assetid;
2298  }
2299  uksort($treeid_map, Array(&$this, '_strlenCmp'));
2300  $this->_tmp['treeid_map'] = $treeid_map;
2301  }
2302  $treeids = $treeids;
2303  $classes = Array();
2304  $res = Array();
2305  foreach ($treeids as $treeid) {
2306  foreach ($this->_tmp['treeid_map'] as $class_treeid => $assetid) {
2307  if (0 === strpos($treeid, $class_treeid) && !empty($root_nodes[$assetid]['class_name'])) {
2308  $res[] = $root_nodes[$assetid]['class_name'];
2309  }
2310  }
2311  }
2312  return array_unique($res);
2313 
2314  }//end _getClasses()
2315 
2316 
2326  function _strlenCmp($a, $b)
2327  {
2328  if (strlen($a) == strlen($b)) return $a > $b;
2329  return strlen($a) > strlen($b);
2330 
2331  }//end _strlenCmp()
2332 
2333 
2346  function _getEventLinkHref($eventid, $date=NULL)
2347  {
2348  if (!isset($this->_tmp['single_event_view'])) {
2349  $enabled_views = $this->attr('enabled_views');
2350  $this->_tmp['single_event_view'] = $enabled_views['event'];
2351  }
2352  $res = '';
2353  switch ($this->_tmp['single_event_view']) {
2354  case '':
2355  return '';
2356  break;
2357  case 'single_event_view':
2358  $res = $this->getURL().'?SQ_CALENDAR_VIEW=event&SQ_CALENDAR_EVENT_ID='.$eventid;
2359  if (!empty($res) && !is_null($date)) {
2360  $res .= '&SQ_CALENDAR_DATE='.$date;
2361  }
2362  break;
2363  case 'event_itself':
2364  $res = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($eventid);
2365  if (!empty($res) && !is_null($date)) {
2366  $res .= '?SQ_CALENDAR_DATE='.$date;
2367  }
2368  break;
2369  }
2370  return $res;
2371 
2372  }//end _getEventLinkHref()
2373 
2374 
2384  function _initEventLabels($view, &$events)
2385  {
2386  $this->_tmp['event_label_format'] = $this->attr($view.'_view_event_label_format');
2387  $this->_tmp['event_label_format_keywords'] = retrieve_keywords_replacements($this->_tmp['event_label_format']);
2388  $data_requirements = $this->_getKeywordDataRequirements($this->_tmp['event_label_format_keywords']);
2389  $this->_tmp['event_label_need_asset'] = ($data_requirements == 2);
2390  if ($data_requirements == 1) {
2391  $this->_tmp['asset_infos'] = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(array_keys($events));
2392  }
2393 
2394  }//end _initEventLabels()
2395 
2396 
2408  function _getKeywordDataRequirements($keywords)
2409  {
2410  $calendar_result_keywords = Array('asset_attribute_start_date', 'asset_attribute_end_date');
2411  $asset_info_fields = $GLOBALS['SQ_SYSTEM']->am->getAssetInfoFields();
2412  $date_formats = get_date_formats();
2413  $need_asset_info = FALSE;
2414  $need_asset = FALSE;
2415  foreach ($keywords as $keyword) {
2416  if ($keyword == 'asset_name') continue;
2417  foreach ($calendar_result_keywords as $calendar_keyword) {
2418  if ($keyword == $calendar_keyword) continue 2;
2419  if (0 === strpos($keyword, $calendar_keyword.'_')) {
2420  $suffix = substr($keyword, strlen($calendar_keyword)+1);
2421  if (isset($date_formats[$suffix])) continue 2;
2422  }
2423  }
2424  if (0 === strpos($keyword, 'asset_')) {
2425  $fieldname = substr($keyword, 6);
2426  if (isset($asset_info_fields[$fieldname])) {
2427  $need_asset_info = TRUE;
2428  continue;
2429  } else {
2430  $need_asset = TRUE;
2431  continue;
2432  }
2433  }
2434  return 2;
2435  }
2436 
2437  if ($need_asset) return 2;
2438  if ($need_asset_info) return 1;
2439 
2440  return 0;
2441 
2442 
2443  }//end _getKeywordDataRequirements()
2444 
2445 
2455  function _getEventLabel($view, &$event_data)
2456  {
2457  $replacements = Array();
2458  if ($this->_tmp['event_label_need_asset']) {
2459  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($event_data['assetid']);
2460  foreach ($this->_tmp['event_label_format_keywords'] as $keyword) {
2461  $replacements[$keyword] = $asset->getKeywordReplacement($keyword);
2462  }
2463  } else {
2464  foreach ($this->_tmp['event_label_format_keywords'] as $keyword) {
2465  $replacements[$keyword] = $this->_getEventKeywordReplacement($keyword, $event_data);
2466  }
2467  }
2468  $fmt = $this->_tmp['event_label_format'];
2469  replace_keywords($fmt, $replacements);
2470  return $fmt;
2471 
2472  }//end _getEventLabel()
2473 
2474 
2487  function _getEventKeywordReplacement($keyword, $event_data)
2488  {
2489  $date_formats = get_date_formats();
2490  if ($keyword == 'asset_name') {
2491  return $event_data['name'];
2492  }
2493  if ($keyword == 'asset_assetid') {
2494  return $event_data['assetid'];
2495  }
2496  $calendar_result_keywords = Array('start_date', 'end_date');
2497  foreach ($calendar_result_keywords as $calendar_field) {
2498  if ($keyword == 'asset_attribute_'.$calendar_field) {
2499  return ts_iso8601($event_data[$calendar_field.'_ts']);
2500  }
2501  if (0 === strpos($keyword, 'asset_attribute_'.$calendar_field.'_')) {
2502  $suffix = substr($keyword, strlen($calendar_field)+17);
2503  if (isset($date_formats[$suffix])) {
2504  return date($date_formats[$suffix], $event_data[$calendar_field.'_ts']);
2505  }
2506  }
2507  }
2508  if (0 === strpos($keyword, 'asset_')) {
2509  $field = substr($keyword, 6);
2510  if (isset($this->_tmp['asset_infos'][$event_data['assetid']][$field])) {
2511  return $this->_tmp['asset_infos'][$event_data['assetid']][$field];
2512  }
2513  }
2514 
2515  }//end _getEventKeywordReplacement()
2516 
2517 
2518 //-- FUNCTIONS TO EXTRACT EVENTS FROM DB --//
2519 
2520 
2530  function getYearEvents($year)
2531  {
2532  $res = Array();
2533  $db = MatrixDAL::getDb();
2534 
2535  $root_ids = $this->_getRootNodeIds();
2536  if (empty($root_ids)) {
2537  trigger_localised_error('CAL0026', E_USER_WARNING);
2538  return Array();
2539  }
2540 
2541  // formulate the date restriction clauses
2542  $start_ts = strtotime("$year-01-01 00:00:00");
2543  $next_year = $year + 1;
2544  $end_ts = strtotime("$next_year-01-01 00:00:00") - 1;
2545 
2546  // Get our single events
2547  $bind_vars = Array();
2548  $date_sql = '(cd.start_date_year = :start_date_year) OR (cd.end_date_year = :end_date_year) OR ((cd.start_date_ts < :start_date_ts) AND (cd.end_date_ts > :end_date_ts))';
2549  $sql = Calendar_Common::getSingleEventQueryBase($root_ids, 'calendar_event_single', TRUE, $bind_vars)."\n AND (".$date_sql.')';
2550  $sql .= $this->_getRootNodeRestrictionSQL();
2551 
2552  $single_events = Array();
2553  try {
2554  $query = MatrixDAL::preparePdoQuery($sql);
2555  foreach($bind_vars as $bind_value => $bind_var) {
2556  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2557  }
2558  MatrixDAL::bindValueToPdo($query, 'start_date_year', $year);
2559  MatrixDAL::bindValueToPdo($query, 'end_date_year', $year);
2560  MatrixDAL::bindValueToPdo($query, 'start_date_ts', $start_ts);
2561  MatrixDAL::bindValueToPdo($query, 'end_date_ts', $start_ts);
2562 
2563  $single_events = MatrixDAL::executePdoAll($query);
2564  } catch (Exception $e) {
2565  throw new Exception($e->getMessage());
2566  }//end
2567 
2568  $single_events = Calendar_Common::condenseResultTreeids($single_events);
2569 
2570  // Get our recurring events
2571  $bind_vars = Array();
2572  $date_sql = 'cd.start_date_ts < :start_date_ts';
2573  $sql = Calendar_Common::getRecurringEventQueryBase($root_ids, 'year', $year, NULL, 'calendar_event_recurring', $bind_vars)."\nAND (".$date_sql.')';
2574  $sql .= $this->_getRootNodeRestrictionSQL();
2575 
2576  $recurring_events = Array();
2577  try {
2578  $query = MatrixDAL::preparePdoQuery($sql);
2579  foreach($bind_vars as $bind_value => $bind_var) {
2580  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2581  }
2582  MatrixDAL::bindValueToPdo($query, 'start_date_ts', $end_ts);
2583  $recurring_events = MatrixDAL::executePdoAll($query);
2584  } catch (Exception $e) {
2585  throw new Exception($e->getMessage());
2586  }//end
2587 
2588  $recurring_events = Calendar_Common::condenseResultTreeids($recurring_events);
2589 
2590  $res = $single_events + $recurring_events;
2591  return $res;
2592 
2593  }//end getYearEvents()
2594 
2595 
2605  function getYearEventsByMonth($year)
2606  {
2607  $res = Array();
2608 
2609  foreach (range(1, 12) as $month_num) {
2610  $res[$month_num] = Array();
2611  }
2612 
2613  $cal_date = sprintf('%04d-%02d-%02d', $year, 1, 1);
2614  $last_day = sprintf('%04d-%02d-%02d', $year, 12, 31);
2615 
2616  $plain_events = $this->getYearEvents($year);
2617 
2618  $events =& Calendar_Common::expandEventList($plain_events, $cal_date, $last_day);
2619 
2620  foreach ($events as $id => $details) {
2621  if ($details['start_date_year'] == $year) {
2622  $res[$details['start_date_mon']][strtok($id, ':')] = $details; // use strtok because we only want to see one instance per month
2623  }
2624  }
2625 
2626  return $res;
2627 
2628  }//end getYearEventsByMonth()
2629 
2630 
2641  function getYearEventsByMonthAndDay($year)
2642  {
2643  $res = Array();
2644 
2645  foreach (range(1, 12) as $month_num) {
2646  $res[$month_num] = Array();
2647  foreach (range(1, days_in_month($month_num, $year)) as $dom) {
2648  $res[$month_num][$dom] = Array();
2649  }
2650  }
2651 
2652  $cal_date = sprintf('%04d-%02d-%02d', $year, 1, 1);
2653  $last_day = sprintf('%04d-%02d-%02d', $year, 12, 31);
2654 
2655  $plain_events = $this->getYearEvents($year);
2656  $events =& Calendar_Common::expandEventList($plain_events, $cal_date, $last_day);
2657 
2658  foreach ($events as $id => $details) {
2659  if ($details['start_date_year'] == $year) {
2660  $res[$details['start_date_mon']][$details['start_date_mday']][$id] = $details;
2661  }
2662  }
2663  foreach (array_keys($res) as $month) {
2664  foreach (array_keys($res[$month]) as $date) {
2665  Calendar_Common::processExceptions($res[$month][$date]);
2666  }
2667  }
2668  return $res;
2669 
2670  }//end getYearEventsByMonthAndDay()
2671 
2672 
2683  function getMonthEvents($year, $month)
2684  {
2685  $db = MatrixDAL::getDb();
2686 
2687  // get the where clauses ready for tree restrictions
2688  $root_ids = $this->_getRootNodeIds();
2689  if (empty($root_ids)) {
2690  trigger_localised_error('CAL0027', E_USER_WARNING);
2691  return Array();
2692  }
2693 
2694  // formulate the date restriction clauses
2695  $start_ts = strtotime("$year-$month-01 00:00:00 GMT");
2696  $next_month = ($month % 12) + 1;
2697  $next_year = ($next_month == 1) ? $year + 1 : $year;
2698  $end_ts = strtotime("$next_year-$next_month-01 00:00:00 GMT") - 1;
2699 
2700  // Get our single events
2701  $bind_vars = Array();
2702  $date_sql = '((cd.start_date_year = :start_date_year AND (cd.start_date_mon = :start_date_month OR cd.end_date_mon = :end_date_month)) OR (cd.start_date_ts < :start_date_ts AND cd.end_date_ts > :end_date_ts))';
2703  $sql = Calendar_Common::getSingleEventQueryBase($root_ids, 'calendar_event_single', TRUE, $bind_vars)."\n AND (".$date_sql.')';
2704  $sql .= $this->_getRootNodeRestrictionSQL();
2705 
2706  $single_result = Array();
2707  try {
2708  $query = MatrixDAL::preparePdoQuery($sql);
2709  foreach($bind_vars as $bind_value => $bind_var) {
2710  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2711  }
2712  MatrixDAL::bindValueToPdo($query, 'start_date_year', $year);
2713  MatrixDAL::bindValueToPdo($query, 'start_date_month', $month);
2714  MatrixDAL::bindValueToPdo($query, 'end_date_month', $month);
2715  MatrixDAL::bindValueToPdo($query, 'start_date_ts', $start_ts);
2716  MatrixDAL::bindValueToPdo($query, 'end_date_ts' , $start_ts);
2717  $single_result = MatrixDAL::executePdoAll($query);
2718  } catch (Exception $e) {
2719  throw new Exception($e->getMessage());
2720  }//end
2721 
2722  $single_result = Calendar_Common::condenseResultTreeids($single_result);
2723 
2724  $cal_date = sprintf('%04d-%02d-%02d', $year, $month, 1);
2725  $first_day = iso8601_ts($cal_date);
2726  $last_day = sprintf('%04d-%02d-%02d', $year, $month, days_in_month($month, $year));
2727 
2728  // Get our recurring events
2729  $sql = Calendar_Common::getRecurringEventQueryBase($root_ids, 'month', "$year-$month", NULL, 'calendar_event_recurring', $bind_vars);
2730  $sql .= $this->_getRootNodeRestrictionSQL();
2731 
2732  $recur_result = Array();
2733  try {
2734  $query = MatrixDAL::preparePdoQuery($sql);
2735  foreach($bind_vars as $bind_value => $bind_var) {
2736  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2737  }
2738  $recur_result = MatrixDAL::executePdoAll($query);
2739  } catch (Exception $e) {
2740  throw new Exception($e->getMessage());
2741  }//end
2742  $recur_result = Calendar_Common::condenseResultTreeids($recur_result);
2743 
2744  $res = $single_result + $recur_result;
2745  if ($this->attr('enable_description_popups')) {
2746  $descriptions = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('description', 'calendar_event', array_keys($res));
2747  foreach ($descriptions as $assetid => $description) {
2748  $res[$assetid]['description'] = $description;
2749  }
2750  }
2751  return $res;
2752 
2753  }//end getMonthEvents()
2754 
2755 
2766  function groupMonthEventsByDay($plain_events, $year, $month)
2767  {
2768  $month_length = days_in_month($month, $year);
2769 
2770  $res = Array();
2771  for ($i = 1; $i <= $month_length; $i++) {
2772  $res[$i] = Array();
2773  }
2774 
2775  $cal_date = sprintf('%04d-%02d-%02d', $year, $month, 1);
2776  $last_day = sprintf('%04d-%02d-%02d', $year, $month, $month_length);
2777 
2778  $events =& Calendar_Common::expandEventList($plain_events, $cal_date, $last_day);
2779 
2780  foreach ($events as $id => $details) {
2781  if (($details['start_date_mon'] == $month) && ($details['start_date_year'] == $year)) {
2782  $res[$details['start_date_mday']][$id] = $details;
2783  }
2784  }
2785 
2786  foreach ($res as $date => $events) {
2788  }
2789  return $res;
2790 
2791  }//end groupMonthEventsByDay()
2792 
2793 
2803  function getWeekEvents($date)
2804  {
2805  $db = MatrixDAL::getDb();
2806 
2807  list($year,$month,$day) = sscanf($date, '%04d-%02d-%02d');
2808 
2809  $root_ids = $this->_getRootNodeIds();
2810  if (empty($root_ids)) {
2811  trigger_localised_error('CAL0028', E_USER_WARNING);
2812  return Array();
2813  }
2814 
2815  // get the single events
2816  $bind_vars = Array();
2817  $start_date_stamp = Calendar_Common::_getDayStamp($date);
2818  $end_date_stamp = $start_date_stamp + 6;
2819  $date_sql = '(cd.start_date_ds BETWEEN :start_date_ds AND :end_date_ds) OR (cd.start_date_ds < :start_date_ds_1 AND cd.end_date_ds >= :start_date_ds_2)';
2820  $sql = Calendar_Common::getSingleEventQueryBase($root_ids, 'calendar_event_single', TRUE, $bind_vars).' AND ('.$date_sql.')';
2821  $sql .= $this->_getRootNodeRestrictionSQL();
2822 
2823  $single_result = Array();
2824  try {
2825  $query = MatrixDAL::preparePdoQuery($sql);
2826  foreach($bind_vars as $bind_value => $bind_var) {
2827  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2828  }
2829  MatrixDAL::bindValueToPdo($query, 'start_date_ds', $start_date_stamp, PDO::PARAM_INT);
2830  MatrixDAL::bindValueToPdo($query, 'start_date_ds_1', $start_date_stamp, PDO::PARAM_INT);
2831  MatrixDAL::bindValueToPdo($query, 'start_date_ds_2', $start_date_stamp, PDO::PARAM_INT);
2832  MatrixDAL::bindValueToPdo($query, 'end_date_ds', $end_date_stamp, PDO::PARAM_INT);
2833  $single_result = MatrixDAL::executePdoAll($query);
2834  } catch (Exception $e) {
2835  throw new Exception($e->getMessage());
2836  }//end
2837 
2838  $single_result = Calendar_Common::condenseResultTreeids($single_result);
2839 
2840  // get the recurring events
2841  $sql = Calendar_Common::getRecurringEventQueryBase($root_ids, 'week', $date, NULL, 'calendar_event_recurring', $bind_vars);
2842  $sql .= $this->_getRootNodeRestrictionSQL();
2843 
2844  $recur_result = Array();
2845  try {
2846  $query = MatrixDAL::preparePdoQuery($sql);
2847  foreach($bind_vars as $bind_value => $bind_var) {
2848  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
2849  }
2850  $recur_result = MatrixDAL::executePdoAll($query);
2851  } catch (Exception $e) {
2852  throw new Exception($e->getMessage());
2853  }//end
2854 
2855  $recur_result = Calendar_Common::condenseResultTreeids($recur_result);
2856 
2857  $plain_events = $single_result + $recur_result;
2858 
2859  $week_start_day = $this->attr('week_starts_on');
2860  $seconds_in_day = 86400;
2861  $first_day = iso8601_ts($date) - ((7+(date('w', iso8601_ts($date)) - $week_start_day))%7)*$seconds_in_day;
2862  $cal_date = date('Y-m-d', $first_day);
2863 
2864  $last_day = add_days_to_iso($cal_date, 6);
2865 
2866  $events =& Calendar_Common::expandEventList($plain_events, $cal_date, $last_day);
2867 
2868  $res = Array();
2869  foreach ($events as $id => $details) {
2870  $event_date = iso8601_ts(sprintf('%04d-%02d-%02d', $details['start_date_year'], $details['start_date_mon'], $details['start_date_mday']));
2871  list($assetid, ) = explode(':', $id);
2872  if ($event_date >= iso8601_ts($date) && $event_date < iso8601_ts($date)+7*86400) {
2873  $res[$assetid] = $plain_events[$assetid];
2874  }
2875  }
2876 
2877  if ($this->attr('enable_description_popups')) {
2878  $descriptions = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('description', 'calendar_event', array_keys($res));
2879  foreach ($descriptions as $assetid => $description) {
2880  $res[$assetid]['description'] = $description;
2881  }
2882  }
2883 
2884  return $res;
2885 
2886  }//end getWeekEvents()
2887 
2888 
2898  function groupWeekEventsByDay($plain_events, $date)
2899  {
2900  $res = Array();
2901  $day_in_second = 24 * 60 * 60; // 86400 seconds
2902  $days_to_show = $this->attr('week_view_show_days');
2903 
2904  $i = iso8601_ts($date);
2905  while ($i <= iso8601_ts(add_days_to_iso($date, 6))) {
2906  $iso_date = iso8601_date_component(ts_iso8601($i));
2907  if ($days_to_show[date('w', $i)]) {
2908  $res[$iso_date] = Array();
2909  }
2910  $i = iso8601_ts(add_days_to_iso($iso_date));
2911  }
2912 
2913  $week_start_day = $this->attr('week_starts_on');
2914  $first_day = iso8601_ts($date) - ((7+(date('w', iso8601_ts($date)) - $week_start_day))%7)*$day_in_second;
2915  $cal_date = date('Y-m-d', $first_day);
2916 
2917  $last_day = add_days_to_iso($cal_date, 6);
2918  $events =& Calendar_Common::expandEventList($plain_events, $cal_date, $last_day, $this->attr('day_starts_at'), $this->attr('day_ends_at'));
2919 
2920  foreach ($events as $id => $details) {
2921  $event_date = sprintf('%04d-%02d-%02d', $details['start_date_year'], $details['start_date_mon'], $details['start_date_mday']);
2922  if (isset($res[$event_date])) {
2923  $res[$event_date][$id] = $details;
2924  }
2925  }
2926 
2927  foreach ($res as $date => $events) {
2929  }
2930 
2931  return $res;
2932 
2933  }//end groupWeekEventsByDay()
2934 
2935 
2948  function groupWeekEventsByDayAndTime($plain_events, $date, $first_time='', $time_partition='', $last_time='')
2949  {
2950  if (!$first_time) {
2951  $first_time = $this->attr('day_starts_at');
2952  }
2953  if (!$time_partition) {
2954  $time_partition = $this->attr('day_partition_time');
2955  }
2956  $days_to_show = $this->attr('week_view_show_days');
2957 
2958  if (!$last_time) {
2959  $last_time = $this->attr('day_ends_at');
2960  }
2961  $partition_keys = Array();
2962  list($e_hour, $e_mins) = explode(':', $last_time);
2963  $end_ts = $e_mins + (60 * $e_hour);
2964  list($hour, $mins) = explode(':', $first_time);
2965  $ts = $mins + (60 * $hour);
2966  $start_ts = $ts;
2967  while ($ts < $end_ts) {
2968  $partition_keys[$ts] = sprintf('%02d', $ts/60).':'.sprintf('%02d', $ts%60);
2969  $ts += $time_partition;
2970  }
2971  $partitions = array_flip($partition_keys);
2972  foreach ($partitions as $key => $val) {
2973  $partitions[$key] = Array();
2974  }
2975  $partitions['all_day'] = Array();
2976 
2977  $res = Array();
2978 
2979  $week_start_day = $this->attr('week_starts_on');
2980  $first_day = iso8601_ts($date) - ((7+(date('w', iso8601_ts($date)) - $week_start_day))%7)*86400;
2981  $cal_date = date('Y-m-d', $first_day);
2982 
2983  $last_day = add_days_to_iso($cal_date, 6);
2984 
2985  $i = iso8601_ts($cal_date);
2986  while ($i <= iso8601_ts(add_days_to_iso($cal_date, 6))) {
2987  $iso_date = iso8601_date_component(ts_iso8601($i));
2988  if ($days_to_show[date('w', $i)]) {
2989  $res[$iso_date] = $partitions;
2990  }
2991  $i = iso8601_ts(add_days_to_iso($iso_date));
2992  }
2993 
2994  $plain_events = $this->groupWeekEventsByDay($plain_events, $date);
2995  foreach ($plain_events as $event_date => $events) {
2996  $res[$event_date]['_overlap_'] = $this->_countOverlappingEvents($events, $first_time, $last_time, $time_partition);
2997  foreach ($events as $id => $details) {
2998  if (isset($res[$event_date])) {
2999  if (is_null($details['start_date_hours']) || ($details['start_date_hours'] == '--')) {
3000  $res[$event_date]['all_day'][$id] = $details;
3001  } else {
3002  $this->_trimEvent($details, $start_ts, $end_ts);
3003  if (empty($details)) continue;
3004  $event_ts = $details['start_date_hours'] * 60 + $details['start_date_minutes'];
3005  foreach ($partition_keys as $partition_ts => $key) {
3006  if (($event_ts - $partition_ts) < $time_partition) {
3007  $res[$event_date][$key][$id] = $details;
3008  break;
3009  }
3010  }
3011  }
3012  }
3013  }
3014  }
3015 
3016  foreach ($res as $date => $events) {
3017  foreach ($partition_keys as $partition) {
3018  Calendar_Common::processExceptions($res[$date][$partition]);
3019  }
3020  }
3021  return $res;
3022 
3023  }//end groupWeekEventsByDayAndTime()
3024 
3025 
3036  function getDayEvents($date)
3037  {
3038  $db = MatrixDAL::getDb();
3039  list($year,$month,$day) = sscanf($date, '%04d-%02d-%02d');
3040 
3041  $root_ids = $this->_getRootNodeIds();
3042  if (empty($root_ids)) {
3043  trigger_localised_error('CAL0029', E_USER_WARNING);
3044  return Array();
3045  }
3046 
3047  // GET SINGLE EVENTS:
3048  $bind_vars = Array();
3049  $today_date_stamp = Calendar_Common::_getDayStamp($date);
3050  $date_sql = '(('.$today_date_stamp.' = cd.start_date_ds) OR ('.$today_date_stamp.' BETWEEN cd.start_date_ds AND cd.end_date_ds))';
3051  $sql = Calendar_Common::getSingleEventQueryBase($root_ids, 'calendar_event_single', TRUE, $bind_vars).' AND '.$date_sql;
3052  $sql .= $this->_getRootNodeRestrictionSQL();
3053 
3054  $single_result = Array();
3055  try {
3056  $query = MatrixDAL::preparePdoQuery($sql);
3057  foreach($bind_vars as $bind_value => $bind_var) {
3058  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
3059  }
3060  $single_result = MatrixDAL::executePdoAll($query);
3061  } catch (Exception $e) {
3062  throw new Exception($e->getMessage());
3063  }//end
3064  $single_result = Calendar_Common::condenseResultTreeids($single_result);
3065 
3066  // GET RECURRING EVENTS:
3067  $bind_vars = Array();
3068  $sql = Calendar_Common::getRecurringEventQueryBase($root_ids, 'day', $date, NULL, 'calendar_event_recurring', $bind_vars);
3069  $sql .= $this->_getRootNodeRestrictionSQL();
3070 
3071  $recur_result = Array();
3072  try {
3073  $query = MatrixDAL::preparePdoQuery($sql);
3074  foreach($bind_vars as $bind_value => $bind_var) {
3075  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
3076  }
3077  $recur_result = MatrixDAL::executePdoAll($query);
3078  } catch (Exception $e) {
3079  throw new Exception($e->getMessage());
3080  }//end
3081  $recur_result = Calendar_Common::condenseResultTreeids($recur_result);
3082 
3083  // PUT IT ALL TOGETHER:
3084  $res = $single_result + $recur_result;
3085  if ($this->attr('enable_description_popups')) {
3086  $descriptions = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('description', 'calendar_event', array_keys($res));
3087  foreach ($descriptions as $assetid => $description) {
3088  $res[$assetid]['description'] = $description;
3089  }
3090  }
3091 
3092  $res =& Calendar_Common::expandEventList($res, $date, $date, $this->attr('day_starts_at'), $this->attr('day_ends_at'));
3094 
3095  uasort($res, Array('Calendar_Common', 'compareStartDates'));
3096 
3097  return $res;
3098 
3099  }//end getDayEvents()
3100 
3101 
3114  function groupDayEventsByTime($events, $date, $first_time='', $time_partition='', $last_time='')
3115  {
3116  if (!$first_time) {
3117  $first_time = $this->attr('day_starts_at');
3118  }
3119  if (!$time_partition) {
3120  $time_partition = $this->attr('day_partition_time');
3121  }
3122  if (!$last_time) {
3123  $last_time = $this->attr('day_ends_at');
3124  }
3125 
3126  $partition_keys = Array();
3127  list($hour, $mins) = explode(':', $last_time);
3128  $end_ts = $mins + (60 * $hour);
3129  list($hour, $mins) = explode(':', $first_time);
3130  $ts = $mins + (60 * $hour);
3131  $start_ts = $ts;
3132  while ($ts < $end_ts) {
3133  $partition_keys[$ts] = sprintf('%02d', $ts/60).':'.sprintf('%02d', $ts%60);
3134  $ts += $time_partition;
3135  }
3136  $partitions = array_flip($partition_keys);
3137  foreach ($partitions as $key => $val) {
3138  $partitions[$key] = Array();
3139  }
3140  $partitions['all_day'] = Array();
3141 
3142  $res = $partitions;
3143 
3144  foreach ($events as $id => $details) {
3145  $event_date = sprintf('%04d-%02d-%02d', $details['start_date_year'], $details['start_date_mon'], $details['start_date_mday']);
3146  if (($event_date == $date)) {
3147  if (is_null($details['start_date_hours']) || $details['start_date_hours'] == '--') {
3148  $res['all_day'][$id] = $details;
3149  } else {
3150  $this->_trimEvent($details, $start_ts, $end_ts);
3151  if (empty($details)) continue;
3152  $event_ts = $details['start_date_hours'] * 60 + $details['start_date_minutes'];
3153  foreach ($partition_keys as $partition_ts => $key) {
3154  if (($event_ts - $partition_ts) < $time_partition) {
3155  $res[$key][$id] = $details;
3156  break;
3157  }
3158  }
3159  }
3160  }
3161  }
3162  $res['_overlap_'] = $this->_countOverlappingEvents($events, $first_time, $last_time, $time_partition);
3163  return $res;
3164 
3165  }//end groupDayEventsByTime()
3166 
3167 
3180  function groupDayEventsByRootNodeAndTime($events, $first_time='', $time_partition='', $last_time='', $root_nodes='')
3181  {
3182  if (!$first_time) {
3183  $first_time = $this->attr('day_starts_at');
3184  }
3185  if (!$time_partition) {
3186  $time_partition = $this->attr('day_partition_time');
3187  }
3188  if (!$last_time) {
3189  $last_time = $this->attr('day_ends_at');
3190  }
3191  if (!$root_nodes) {
3192  $root_nodes = array_keys($this->attr('root_nodes'));
3193  }
3194  $partition_keys = Array();
3195  list($e_hour, $e_mins) = explode(':', $last_time);
3196  $end_ts = $e_mins + (60 * $e_hour);
3197  list($hour, $mins) = explode(':', $first_time);
3198  $ts = $mins + (60 * $hour);
3199  $start_ts = $ts;
3200  while ($ts < $end_ts) {
3201  $partition_keys[$ts] = sprintf('%02d', $ts/60).':'.sprintf('%02d', $ts%60);
3202  $ts += $time_partition;
3203  }
3204  $partitions = array_flip($partition_keys);
3205  foreach ($partitions as $key => $val) {
3206  $partitions[$key] = Array();
3207  }
3208  $partitions['all_day'] = Array();
3209 
3211  $res = Array();
3212 
3213  $columnise_by_root = $this->attr('columnise_day_view_by_root_node');
3214  foreach ($columnise_by_root as $node_id) {
3215  if (($node_id == '*') || in_array($node_id, $root_nodes)) {
3216  $res[$node_id] = $partitions;
3217  }
3218  }
3219  $column_treeids = $GLOBALS['SQ_SYSTEM']->am->getAssetTreeids(array_diff($columnise_by_root, Array('*')));
3220 
3221  foreach ($events as $id => $details) {
3222  $event_date = sprintf('%04d-%02d-%02d', $details['start_date_year'], $details['start_date_mon'], $details['start_date_mday']);
3223 
3224  $cols = Array();
3225  foreach ($column_treeids as $column_id => $this_column_treeids) {
3226  foreach ($this_column_treeids[0] as $column_treeid) {
3227  foreach ($details['treeid'] as $event_treeid) {
3228  if (0 === strpos($event_treeid, $column_treeid)) {
3229  $cols[] = $column_id;
3230  }
3231  }
3232  }
3233  }
3234  if (empty($cols) && isset($res['*'])) {
3235  $cols[] = '*';
3236  }
3237  foreach ($cols as $col) {
3238  if (empty($details['start_date_hours'])) {
3239  $res[$col]['all_day'][$id] = $details;
3240  } else {
3241  $this->_trimEvent($details, $start_ts, $end_ts);
3242  if (empty($details)) continue;
3243  $event_ts = $details['start_date_hours'] * 60 + $details['start_date_minutes'];
3244  foreach ($partition_keys as $partition_ts => $key) {
3245  if (($event_ts - $partition_ts) < $time_partition) {
3246  $res[$col][$key][$id] = $details;
3247  break;
3248  }
3249  }
3250  }
3251  }
3252  }//end foreach event
3253 
3254  foreach ($res as $root_node => $null) {
3255  $max_events = 1;
3256  $rrn = Array();
3257  foreach ($res[$root_node] as $key => $null) {
3258  foreach ($res[$root_node][$key] as $id => $null) {
3259  $rrn[] = &$res[$root_node][$key][$id];
3260  }
3261  }
3262 
3263  $max_events = max($max_events, $this->_countOverlappingEvents($rrn, $first_time, $last_time, $time_partition));
3264 
3265  $res[$root_node]['_overlap_'] = $max_events;
3266  }
3267  return $res;
3268 
3269  }//end groupDayEventsByRootNodeAndTime()
3270 
3271 
3278  function _getRootNodeRestrictionSQL()
3279  {
3280  $restrictive_roots = $this->_getRestrictiveRootNodeIds();
3281  if (!empty($restrictive_roots)) {
3282  $db = MatrixDal::getDb();
3283  $root_treeids = $GLOBALS['SQ_SYSTEM']->am->getAssetTreeids($restrictive_roots);
3284  $treeid_options = Array();
3285  foreach ($root_treeids as $rootid => $this_root_treeids) {
3286  // bug fix : #3363 Event Personalisation on Calendar Page does not show events
3287  $treeid_options[] = 'salt.treeid LIKE '.MatrixDAL::quote(reset(reset($this_root_treeids)).'%');
3288  }
3289  $sql = '
3290  AND a.assetid IN (
3291  SELECT minorid
3292  FROM '.SQ_TABLE_RUNNING_PREFIX.'ast_lnk sal
3293  JOIN '.SQ_TABLE_RUNNING_PREFIX.'ast_lnk_tree salt ON (sal.linkid = salt.linkid)
3294  WHERE ('.implode(' OR ', $treeid_options).')
3295  )';
3296  return $sql;
3297  }
3298  return '';
3299 
3300  }//end _getRootNodeRestrictionSQL()
3301 
3302 
3309  function _getRestrictiveRootNodeIds()
3310  {
3311  // Personalisation is one option
3312  if ($this->attr('personalised')) {
3313  return Array($GLOBALS['SQ_SYSTEM']->user->id);
3314  }
3315 
3316  // Otherwise we might have a dynamic parameter
3317  $parameter_map = $this->getAttribute('parameter_map');
3318  $raw_dynamic_root_nodes = $parameter_map->getParameterValue('replacement_root_node');
3319  if (!empty($raw_dynamic_root_nodes)) {
3320  $dynamic_root_nodes = Array();
3321  // note that dynamic roots can be supplied as an array of asset ids or
3322  // as a comma delimited string of asset ids
3323  if (!is_array($raw_dynamic_root_nodes)) {
3324  $raw_dynamic_root_nodes = explode(',', $raw_dynamic_root_nodes);
3325  }
3326 
3327  $original_root_ids = array_keys($this->attr('root_nodes'));
3328  foreach ($raw_dynamic_root_nodes as $dynamic_root) {
3329  if (!strlen($dynamic_root)) continue;
3330  // Check to see if the dynamic parameter specified is a child of one of the root
3331  // nodes. If so, use the dynamic parameter as the root node; otherwise return an error.
3332  $dynamic_parents = $GLOBALS['SQ_SYSTEM']->am->getParents($dynamic_root);
3333  $matching_root_ids = array_intersect(array_keys($dynamic_parents), $original_root_ids);
3334  if (empty($matching_root_ids)) {
3335  trigger_localised_error('CAL0067', E_USER_WARNING, $dynamic_root, $this->id);
3336  } else {
3337  $dynamic_root_nodes[] = $dynamic_root;
3338  }
3339  }
3340 
3341  if (!empty($dynamic_root_nodes)) {
3342  return $dynamic_root_nodes;
3343  }
3344 
3345  }//end if
3346  return Array();
3347 
3348  }//end _getRestrictiveRootNodeIds()
3349 
3350 
3362  function formatDatesToCompare($view,$date,$direction, $operator)
3363  {
3364  if ($view == 'event' || $view == 'edit') {
3365  return Array('','');
3366  }
3367 
3368  $navi_limit = $this->attr($view.'_navi_limit');
3369  $curr_date = date('Y-m-d');
3370 
3371  // return true if no limit specified
3372  if ($navi_limit[$direction] == '') {
3373  return Array('','');
3374  }
3375 
3376  // depepnding on current view, we set limit date and date to compare
3377  switch ($view) {
3378  case 'year':
3379  $limit_date = date('Y',strtotime($operator.$navi_limit[$direction].' year',strtotime($curr_date)));
3380  $compared_date = date('Y',strtotime($date));
3381  break;
3382  case 'month':
3383  $limit_date = date('Y-m',strtotime($operator.$navi_limit[$direction].' month',strtotime($curr_date)));
3384  $compared_date = date('Y-m',strtotime($date));
3385  break;
3386  case 'week':
3387  $offset = 0;
3388  $day_in_seconds = 24 * 60 * 60;
3389  $week_start_index = $this->attr('week_starts_on');
3390  $curr_day_index = array_search(date('l', iso8601_ts($curr_date)), $this->day_names);
3391  if ($week_start_index != $curr_day_index) {
3392  if ($week_start_index < $curr_day_index) {
3393  $offset = $curr_day_index - $week_start_index;
3394  } else {
3395  $offset = $curr_day_index + (7 - $week_start_index);
3396  }
3397  }
3398  $limit_date = date('Y-m-d',strtotime($operator.$navi_limit[$direction].' week',strtotime($curr_date)));
3399  $limit_date = strtotime($limit_date) - ($offset * $day_in_seconds);
3400  $limit_date = date('Y-m-d',$limit_date);
3401 
3402  $offset = 0;
3403  $compared_day_index = array_search(date('l', iso8601_ts($date)), $this->day_names);
3404  if ($week_start_index != $compared_day_index) {
3405  if ($week_start_index < $compared_day_index) {
3406  $offset = $compared_day_index - $week_start_index;
3407  } else {
3408  $offset = $compared_day_index + (7 - $week_start_index);
3409  }
3410  }
3411  $compared_date = strtotime($date) - ($offset * $day_in_seconds);
3412  $compared_date = date('Y-m-d',$compared_date);
3413  break;
3414  case 'day':
3415  $limit_date = date('Y-m-d',strtotime($operator.$navi_limit[$direction].' day',strtotime($curr_date)));
3416  $compared_date = $date;
3417  break;
3418  }
3419 
3420  return Array($limit_date,$compared_date);
3421 
3422  }//end formatDatesToCompare()
3423 
3424 
3431  function createNoResultsBodycopy()
3432  {
3433  $bodycopy_name = "page_contents_no_results";
3434 
3435  // Check if "No result page" already exists
3436  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, $bodycopy_name);
3437  if (!empty($bodycopy_link)) {
3438  return TRUE;
3439  }
3440 
3441  // Being here means bodycopy doesn't exist, so create it
3442  $copy_link = Array(
3443  'asset' => &$this,
3444  'link_type' => SQ_LINK_TYPE_2,
3445  'is_dependant' => 1,
3446  'is_exclusive' => 1,
3447  'value' => $bodycopy_name,
3448  );
3449 
3450  $page_contents_data = Array(
3451  'content' => '<h2 style="text-align: center">%calendar_title%</h2><p style="text-align: center">%prev_link%&nbsp;&nbsp;&nbsp;&nbsp;%up_link%&nbsp;&nbsp;&nbsp;&nbsp;%next_link%</p><p>No events</p>',
3452  );
3453 
3454  $GLOBALS['SQ_SYSTEM']->am->includeAsset('bodycopy');
3455  $bodycopy = new Bodycopy();
3456  $bodycopy->setAttrValue('name', "Page Contents (No Results)");
3457 
3458  if (!$bodycopy->create($copy_link, $page_contents_data)) {
3459  trigger_localised_error('CAL0062', E_USER_WARNING);
3460  return FALSE;
3461  }
3462 
3463  return TRUE;
3464 
3465  }//end createNoResultsBodycopy()
3466 
3467 }//end class
3468 ?>