fd9b99eeb55220e8b0db01e1b383e9fb09901175
[moodle.git] / calendar / renderer.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This file contains the renderers for the calendar within Moodle
20  *
21  * @copyright 2010 Sam Hemelryk
22  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  * @package calendar
24  */
26 if (!defined('MOODLE_INTERNAL')) {
27     die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
28 }
30 /**
31  * The primary renderer for the calendar.
32  */
33 class core_calendar_renderer extends plugin_renderer_base {
35     /**
36      * Creates a basic export form
37      *
38      * @param bool $allowthisweek
39      * @param bool $allownextweek
40      * @param bool $allownextmonth
41      * @param int $userid
42      * @param string $authtoken
43      * @return string
44      */
45     public function basic_export_form($allowthisweek, $allownextweek, $allownextmonth, $userid, $authtoken) {
46         global $CFG;
48         $output  = html_writer::tag('div', get_string('export', 'calendar'), array('class'=>'header'));
49         $output .= html_writer::start_tag('fieldset');
50         $output .= html_writer::tag('legend', get_string('commontasks', 'calendar'));
51         $output .= html_writer::start_tag('form', array('action'=>new moodle_url('/calendar/export_execute.php'), 'method'=>'get'));
53         $output .= html_writer::tag('div', get_string('iwanttoexport', 'calendar'));
55         $output .= html_writer::start_tag('div', array('class'=>'indent'));
56         $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_what', 'id'=>'pw_all', 'value'=>'all', 'checked'=>'checked'));
57         $output .= html_writer::tag('label', get_string('eventsall', 'calendar'), array('for'=>'pw_all'));
58         $output .= html_writer::empty_tag('br');
59         $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_what', 'id'=>'pw_course', 'value'=>'courses'));
60         $output .= html_writer::tag('label', get_string('eventsrelatedtocourses', 'calendar'), array('for'=>'pw_course'));
61         $output .= html_writer::empty_tag('br');
62         $output .= html_writer::end_tag('div');
64         $output .= html_writer::tag('div', get_string('for', 'calendar').':');
66         $output .= html_writer::start_tag('div', array('class'=>'indent'));
67         if ($allowthisweek) {
68             $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_time', 'id'=>'pt_wknow', 'value'=>'weeknow', 'checked'=>'checked'));
69             $output .= html_writer::tag('label', get_string('weekthis', 'calendar'), array('for'=>'pt_wknow'));
70             $output .= html_writer::empty_tag('br');
71         }
72         if ($allownextweek) {
73             $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_time', 'id'=>'pt_wknext', 'value'=>'weeknext'));
74             $output .= html_writer::tag('label', get_string('weeknext', 'calendar'), array('for'=>'pt_wknext'));
75             $output .= html_writer::empty_tag('br');
76         }
77         $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_time', 'id'=>'pt_monnow', 'value'=>'monthnow'));
78         $output .= html_writer::tag('label', get_string('monththis', 'calendar'), array('for'=>'pt_monnow'));
79         $output .= html_writer::empty_tag('br');
80         if ($allownextmonth) {
81             $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_time', 'id'=>'pt_monnext', 'value'=>'monthnext'));
82             $output .= html_writer::tag('label', get_string('monthnext', 'calendar'), array('for'=>'pt_monnext'));
83             $output .= html_writer::empty_tag('br');
84         }
85         $output .= html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'preset_time', 'id'=>'pt_recupc', 'value'=>'recentupcoming'));
86         $output .= html_writer::tag('label', get_string('recentupcoming', 'calendar'), array('for'=>'pt_recupc'));
87         $output .= html_writer::empty_tag('br');
89         if ($CFG->calendar_customexport) {
90             $a = new stdClass();
91             $now = time();
92             $time = $now - $CFG->calendar_exportlookback * DAYSECS;
93             $a->timestart = userdate($time, get_string('strftimedatefullshort', 'langconfig'));
94             $time = $now + $CFG->calendar_exportlookahead * DAYSECS;
95             $a->timeend = userdate($time, get_string('strftimedatefullshort', 'langconfig'));
96             $output .= html_writer::empty_tag('input', array('type' => 'radio', 'name' => 'preset_time', 'id' => 'pt_custom', 'value' => 'custom'));
97             $output .= html_writer::tag('label', get_string('customexport', 'calendar', $a), array('for' => 'pt_custom'));
98             $output .= html_writer::empty_tag('br');
99         }
101         $output .= html_writer::end_tag('div');
102         $output .= html_writer::start_tag('div', array('class'=>'rightalign'));
103         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_d', 'value'=>''));
104         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_m', 'value'=>''));
105         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_y', 'value'=>''));
106         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'userid', 'value'=>$userid));
107         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'authtoken', 'value'=>$authtoken));
109         $output .= html_writer::empty_tag('input', array('type'=>'submit', 'name' => 'generateurl', 'id'=>'generateurl', 'value'=>get_string('generateurlbutton', 'calendar')));
110         $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('exportbutton', 'calendar')));
112         $output .= html_writer::end_tag('div');
114         $output .= html_writer::end_tag('form');
115         $output .= html_writer::end_tag('fieldset');
117         $output .= html_writer::start_tag('div', array('id'=>'urlbox', 'style'=>'display:none;'));
118         $output .= html_writer::tag('p', get_string('urlforical', 'calendar'));
119         $output .= html_writer::tag('div', '', array('id'=>'url', 'style'=>'overflow:scroll;width:650px;'));
120         $output .= html_writer::end_tag('div');
122         return $output;
123     }
125     /**
126      * Starts the standard layout for the page
127      *
128      * @return string
129      */
130     public function start_layout() {
131         return html_writer::start_tag('div', array('class'=>'maincalendar'));
132     }
134     /**
135      * Creates the remainder of the layout
136      *
137      * @return string
138      */
139     public function complete_layout() {
140         return html_writer::end_tag('div');
141     }
143     /**
144      * Produces the content for the filters block (pretend block)
145      *
146      * @param int $courseid
147      * @param int $day
148      * @param int $month
149      * @param int $year
150      * @param int $view
151      * @param int $courses
152      * @return string
153      */
154     public function fake_block_filters($courseid, $day, $month, $year, $view, $courses) {
155         $returnurl = $this->page->url;
156         $returnurl->param('course', $courseid);
157         return html_writer::tag('div', calendar_filter_controls($returnurl), array('class'=>'calendar_filters filters'));
158     }
160     /**
161      * Produces the content for the three months block (pretend block)
162      *
163      * This includes the previous month, the current month, and the next month
164      *
165      * @param calendar_information $calendar
166      * @return string
167      */
168     public function fake_block_threemonths(calendar_information $calendar) {
169         // Get the calendar type we are using.
170         $calendartype = \core_calendar\type_factory::get_calendar_instance();
172         $date = $calendartype->timestamp_to_date_array($calendar->time);
174         $prevmonth = calendar_sub_month($date['mon'], $date['year']);
175         $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], 1);
176         $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day'],
177             $prevmonthtime['hour'], $prevmonthtime['minute']);
179         $nextmonth = calendar_add_month($date['mon'], $date['year']);
180         $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], 1);
181         $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day'],
182             $nextmonthtime['hour'], $nextmonthtime['minute']);
184         $content  = html_writer::start_tag('div', array('class' => 'minicalendarblock'));
185         $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $prevmonthtime);
186         $content .= html_writer::end_tag('div');
187         $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock'));
188         $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $calendar->time);
189         $content .= html_writer::end_tag('div');
190         $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock'));
191         $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $nextmonthtime);
192         $content .= html_writer::end_tag('div');
193         return $content;
194     }
196     /**
197      * Adds a pretent calendar block
198      *
199      * @param block_contents $bc
200      * @param mixed $pos BLOCK_POS_RIGHT | BLOCK_POS_LEFT
201      */
202     public function add_pretend_calendar_block(block_contents $bc, $pos=BLOCK_POS_RIGHT) {
203         $this->page->blocks->add_fake_block($bc, $pos);
204     }
206     /**
207      * Creates a button to add a new event
208      *
209      * @param int $courseid
210      * @param int $day
211      * @param int $month
212      * @param int $year
213      * @param int $time the unixtime, used for multiple calendar support. The values $day,
214      *     $month and $year are kept for backwards compatibility.
215      * @return string
216      */
217     protected function add_event_button($courseid, $day = null, $month = null, $year = null, $time = null) {
218         // If a day, month and year were passed then convert it to a timestamp. If these were passed
219         // then we can assume the day, month and year are passed as Gregorian, as no where in core
220         // should we be passing these values rather than the time. This is done for BC.
221         if (!empty($day) && !empty($month) && !empty($year)) {
222             if (checkdate($month, $day, $year)) {
223                 $time = make_timestamp($year, $month, $day);
224             } else {
225                 $time = time();
226             }
227         } else if (empty($time)) {
228             $time = time();
229         }
231         $output = html_writer::start_tag('div', array('class'=>'buttons'));
232         $output .= html_writer::start_tag('form', array('action' => CALENDAR_URL . 'event.php', 'method' => 'get'));
233         $output .= html_writer::start_tag('div');
234         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'action', 'value' => 'new'));
235         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'course', 'value' => $courseid));
236         $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'time', 'value' => $time));
237         $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value' => get_string('newevent', 'calendar')));
238         $output .= html_writer::end_tag('div');
239         $output .= html_writer::end_tag('form');
240         $output .= html_writer::end_tag('div');
241         return $output;
242     }
244     /**
245      * Displays the calendar for a single day
246      *
247      * @param calendar_information $calendar
248      * @return string
249      */
250     public function show_day(calendar_information $calendar, moodle_url $returnurl = null) {
252         if ($returnurl === null) {
253             $returnurl = $this->page->url;
254         }
256         $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, 1, 100, $calendar->timestamp_today());
258         $output  = html_writer::start_tag('div', array('class'=>'header'));
259         if (calendar_user_can_add_event($calendar->course)) {
260             $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time);
261         }
262         //$output .= html_writer::tag('label', get_string('dayview', 'calendar'), array('for'=>'cal_course_flt_jump'));
263         $output .= $this->course_filter_selector($returnurl, get_string('dayview', 'calendar'));
264         $output .= html_writer::end_tag('div');
265         // Controls
266         $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class'=>'controls'));
268         if (empty($events)) {
269             // There is nothing to display today.
270             $output .= $this->output->heading(get_string('daywithnoevents', 'calendar'), 3);
271         } else {
272             $output .= html_writer::start_tag('div', array('class'=>'eventlist'));
273             $underway = array();
274             // First, print details about events that start today
275             foreach ($events as $event) {
276                 $event = new calendar_event($event);
277                 $event->calendarcourseid = $calendar->courseid;
278                 if ($event->timestart >= $calendar->timestamp_today() && $event->timestart <= $calendar->timestamp_tomorrow()-1) {  // Print it now
279                     $event->time = calendar_format_event_time($event, time(), null, false, $calendar->timestamp_today());
280                     $output .= $this->event($event);
281                 } else {                                                                 // Save this for later
282                     $underway[] = $event;
283                 }
284             }
286             // Then, show a list of all events that just span this day
287             if (!empty($underway)) {
288                 $output .= $this->output->heading(get_string('spanningevents', 'calendar'), 3);
289                 foreach ($underway as $event) {
290                     $event->time = calendar_format_event_time($event, time(), null, false, $calendar->timestamp_today());
291                     $output .= $this->event($event);
292                 }
293             }
295             $output .= html_writer::end_tag('div');
296         }
298         return $output;
299     }
301     /**
302      * Displays an event
303      *
304      * @param calendar_event $event
305      * @param bool $showactions
306      * @return string
307      */
308     public function event(calendar_event $event, $showactions=true) {
309         global $CFG;
311         $event = calendar_add_event_metadata($event);
313         $anchor  = html_writer::tag('a', '', array('name'=>'event_'.$event->id));
315         $table = new html_table();
316         $table->attributes = array('class'=>'event', 'cellspacing'=>'0');
317         $table->data = array(
318             0 => new html_table_row(),
319             1 => new html_table_row(),
320         );
322         if (!empty($event->icon)) {
323             $table->data[0]->cells[0] = new html_table_cell($anchor.$event->icon);
324         } else {
325             $table->data[0]->cells[0] = new html_table_cell($anchor.$this->output->spacer(array('height'=>16, 'width'=>16, 'br'=>true)));
326         }
327         $table->data[0]->cells[0]->attributes['class'] .= ' picture';
329         $table->data[0]->cells[1] = new html_table_cell();
330         $table->data[0]->cells[1]->attributes['class'] .= ' topic';
331         if (!empty($event->referer)) {
332             $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->referer, array('class'=>'referer'));
333         } else {
334             $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->name, array('class'=>'name'));
335         }
336         if (!empty($event->courselink)) {
337             $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->courselink, array('class'=>'course'));
338         }
339         // Show subscription source if needed.
340         if (!empty($event->subscription) && $CFG->calendar_showicalsource) {
341             if (!empty($event->subscription->url)) {
342                 $source = html_writer::link($event->subscription->url, get_string('subsource', 'calendar', $event->subscription));
343             } else {
344                 // File based ical.
345                 $source = get_string('subsource', 'calendar', $event->subscription);
346             }
347             $table->data[0]->cells[1]->text .= html_writer::tag('div', $source, array('class' => 'subscription'));
348         }
349         if (!empty($event->time)) {
350             $table->data[0]->cells[1]->text .= html_writer::tag('span', $event->time, array('class'=>'date'));
351         } else {
352             $table->data[0]->cells[1]->text .= html_writer::tag('span', calendar_time_representation($event->timestart), array('class'=>'date'));
353         }
355         $table->data[1]->cells[0] = new html_table_cell('&nbsp;');
356         $table->data[1]->cells[0]->attributes['class'] .= 'side';
358         $table->data[1]->cells[1] = new html_table_cell($event->description);
359         $table->data[1]->cells[1]->attributes['class'] .= ' description';
360         if (isset($event->cssclass)) {
361             $table->data[1]->cells[1]->attributes['class'] .= ' '.$event->cssclass;
362         }
364         if (calendar_edit_event_allowed($event) && $showactions) {
365             if (empty($event->cmid)) {
366                 $editlink = new moodle_url(CALENDAR_URL.'event.php', array('action'=>'edit', 'id'=>$event->id));
367                 $deletelink = new moodle_url(CALENDAR_URL.'delete.php', array('id'=>$event->id));
368                 if (!empty($event->calendarcourseid)) {
369                     $editlink->param('course', $event->calendarcourseid);
370                     $deletelink->param('course', $event->calendarcourseid);
371                 }
372             } else {
373                 $editlink = new moodle_url('/course/mod.php', array('update'=>$event->cmid, 'return'=>true, 'sesskey'=>sesskey()));
374                 $deletelink = null;
375             }
377             $commands  = html_writer::start_tag('div', array('class'=>'commands'));
378             $commands .= html_writer::start_tag('a', array('href'=>$editlink));
379             $commands .= html_writer::empty_tag('img', array('src'=>$this->output->pix_url('t/edit'), 'alt'=>get_string('tt_editevent', 'calendar'), 'title'=>get_string('tt_editevent', 'calendar')));
380             $commands .= html_writer::end_tag('a');
381             if ($deletelink != null) {
382                 $commands .= html_writer::start_tag('a', array('href'=>$deletelink));
383                 $commands .= html_writer::empty_tag('img', array('src'=>$this->output->pix_url('t/delete'), 'alt'=>get_string('tt_deleteevent', 'calendar'), 'title'=>get_string('tt_deleteevent', 'calendar')));
384                 $commands .= html_writer::end_tag('a');
385             }
386             $commands .= html_writer::end_tag('div');
387             $table->data[1]->cells[1]->text .= $commands;
388         }
389         return html_writer::table($table);
390     }
392     /**
393      * Displays a month in detail
394      *
395      * @param calendar_information $calendar
396      * @param moodle_url $returnurl the url to return to
397      * @return string
398      */
399     public function show_month_detailed(calendar_information $calendar, moodle_url $returnurl  = null) {
400         global $CFG;
402         if (empty($returnurl)) {
403             $returnurl = $this->page->url;
404         }
406         // Get the calendar type we are using.
407         $calendartype = \core_calendar\type_factory::get_calendar_instance();
409         // Store the display settings.
410         $display = new stdClass;
411         $display->thismonth = false;
413         // Get the specified date in the calendar type being used.
414         $date = $calendartype->timestamp_to_date_array($calendar->time);
415         $thisdate = $calendartype->timestamp_to_date_array(time());
416         if ($date['mon'] == $thisdate['mon'] && $date['year'] == $thisdate['year']) {
417             $display->thismonth = true;
418             $date = $thisdate;
419             $calendar->time = time();
420         }
422         // Get Gregorian date for the start of the month.
423         $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1);
424         // Store the gregorian date values to be used later.
425         list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'],
426             $gregoriandate['hour'], $gregoriandate['minute']);
428         // Get the starting week day for this month.
429         $startwday = dayofweek(1, $date['mon'], $date['year']);
430         // Get the days in a week.
431         $daynames = calendar_get_days();
432         // Store the number of days in a week.
433         $numberofdaysinweek = $calendartype->get_num_weekdays();
435         $display->minwday = calendar_get_starting_weekday();
436         $display->maxwday = $display->minwday + ($numberofdaysinweek - 1);
437         $display->maxdays = calendar_days_in_month($date['mon'], $date['year']);
439         // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates.
440         $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0);
441         $display->tend = $display->tstart + ($display->maxdays * DAYSECS) - 1;
443         // Align the starting weekday to fall in our display range
444         // This is simple, not foolproof.
445         if ($startwday < $display->minwday) {
446             $startwday += $numberofdaysinweek;
447         }
449         // Get events from database
450         $events = calendar_get_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, $calendar->courses);
451         if (!empty($events)) {
452             foreach($events as $eventid => $event) {
453                 $event = new calendar_event($event);
454                 if (!empty($event->modulename)) {
455                     $cm = get_coursemodule_from_instance($event->modulename, $event->instance);
456                     if (!groups_course_module_visible($cm)) {
457                         unset($events[$eventid]);
458                     }
459                 }
460             }
461         }
463         // Extract information: events vs. time
464         calendar_events_by_day($events, $date['mon'], $date['year'], $eventsbyday, $durationbyday, $typesbyday, $calendar->courses);
466         $output  = html_writer::start_tag('div', array('class'=>'header'));
467         if (calendar_user_can_add_event($calendar->course)) {
468             $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time);
469         }
470         $output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector($returnurl);
471         $output .= html_writer::end_tag('div', array('class'=>'header'));
472         // Controls
473         $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class' => 'controls'));
475         $table = new html_table();
476         $table->attributes = array('class'=>'calendarmonth calendartable');
477         $table->summary = get_string('calendarheading', 'calendar', userdate($calendar->time, get_string('strftimemonthyear')));
478         $table->data = array();
480         // Get the day names as the header.
481         $header = array();
482         for($i = $display->minwday; $i <= $display->maxwday; ++$i) {
483             $header[] = $daynames[$i % $numberofdaysinweek]['shortname'];
484         }
485         $table->head = $header;
487         // For the table display. $week is the row; $dayweek is the column.
488         $week = 1;
489         $dayweek = $startwday;
491         $row = new html_table_row(array());
493         // Paddding (the first week may have blank days in the beginning)
494         for($i = $display->minwday; $i < $startwday; ++$i) {
495             $cell = new html_table_cell('&nbsp;');
496             $cell->attributes = array('class'=>'nottoday dayblank');
497             $row->cells[] = $cell;
498         }
500         // Now display all the calendar
501         $weekend = CALENDAR_DEFAULT_WEEKEND;
502         if (isset($CFG->calendar_weekend)) {
503             $weekend = intval($CFG->calendar_weekend);
504         }
506         $daytime = $display->tstart - DAYSECS;
507         for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
508             $daytime = $daytime + DAYSECS;
509             if($dayweek > $display->maxwday) {
510                 // We need to change week (table row)
511                 $table->data[] = $row;
512                 $row = new html_table_row(array());
513                 $dayweek = $display->minwday;
514                 ++$week;
515             }
517             // Reset vars
518             $cell = new html_table_cell();
519             $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'day', 'course' => $calendar->courseid)), 0, 0, 0, $daytime);
521             $cellclasses = array();
523             if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) {
524                 // Weekend. This is true no matter what the exact range is.
525                 $cellclasses[] = 'weekend';
526             }
528             // Special visual fx if an event is defined
529             if (isset($eventsbyday[$day])) {
530                 if(count($eventsbyday[$day]) == 1) {
531                     $title = get_string('oneevent', 'calendar');
532                 } else {
533                     $title = get_string('manyevents', 'calendar', count($eventsbyday[$day]));
534                 }
535                 $cell->text = html_writer::tag('div', html_writer::link($dayhref, $day, array('title'=>$title)), array('class'=>'day'));
536             } else {
537                 $cell->text = html_writer::tag('div', $day, array('class'=>'day'));
538             }
540             // Special visual fx if an event spans many days
541             $durationclass = false;
542             if (isset($typesbyday[$day]['durationglobal'])) {
543                 $durationclass = 'duration_global';
544             } else if (isset($typesbyday[$day]['durationcourse'])) {
545                 $durationclass = 'duration_course';
546             } else if (isset($typesbyday[$day]['durationgroup'])) {
547                 $durationclass = 'duration_group';
548             } else if (isset($typesbyday[$day]['durationuser'])) {
549                 $durationclass = 'duration_user';
550             }
551             if ($durationclass) {
552                 $cellclasses[] = 'duration';
553                 $cellclasses[] = $durationclass;
554             }
556             // Special visual fx for today
557             if ($display->thismonth && $day == $date['mday']) {
558                 $cellclasses[] = 'day today';
559             } else {
560                 $cellclasses[] = 'day nottoday';
561             }
562             $cell->attributes = array('class'=>join(' ',$cellclasses));
564             if (isset($eventsbyday[$day])) {
565                 $cell->text .= html_writer::start_tag('ul', array('class'=>'events-new'));
566                 foreach($eventsbyday[$day] as $eventindex) {
567                     // If event has a class set then add it to the event <li> tag
568                     $attributes = array();
569                     if (!empty($events[$eventindex]->class)) {
570                         $attributes['class'] = $events[$eventindex]->class;
571                     }
572                     $dayhref->set_anchor('event_'.$events[$eventindex]->id);
573                     $link = html_writer::link($dayhref, format_string($events[$eventindex]->name, true));
574                     $cell->text .= html_writer::tag('li', $link, $attributes);
575                 }
576                 $cell->text .= html_writer::end_tag('ul');
577             }
578             if (isset($durationbyday[$day])) {
579                 $cell->text .= html_writer::start_tag('ul', array('class'=>'events-underway'));
580                 foreach($durationbyday[$day] as $eventindex) {
581                     $cell->text .= html_writer::tag('li', '['.format_string($events[$eventindex]->name,true).']', array('class'=>'events-underway'));
582                 }
583                 $cell->text .= html_writer::end_tag('ul');
584             }
585             $row->cells[] = $cell;
586         }
588         // Paddding (the last week may have blank days at the end)
589         for($i = $dayweek; $i <= $display->maxwday; ++$i) {
590             $cell = new html_table_cell('&nbsp;');
591             $cell->attributes = array('class'=>'nottoday dayblank');
592             $row->cells[] = $cell;
593         }
594         $table->data[] = $row;
595         $output .= html_writer::table($table);
597         return $output;
598     }
600     /**
601      * Displays a filter selection table
602      *
603      * @param calendar_information $calendar
604      * @return string
605      * @deprecated since Moodle 2.4 MDL-32309
606      * @see calendar_filter_controls()
607      */
608     protected function filter_selection_table(calendar_information $calendar, moodle_url $returnurl = null) {
609         global $SESSION;
610         debugging('Method core_calendar_renderer::filter_selection_table() is deprecated, please use '.
611                 'calendar_filter_controls() instead', DEBUG_DEVELOPER);
613         if ($returnurl === null) {
614             $returnurl = $this->page->url;
615         }
617         $output  = html_writer::start_tag('div', array('class'=>'filters'));
618         $output .= html_writer::start_tag('table');
619         $output .= html_writer::start_tag('tr');
621         // Global events
622         $link = new moodle_url(CALENDAR_URL.'set.php', array('var' => 'showglobal', 'return' => base64_encode($returnurl->out(false)), 'sesskey'=>sesskey()));
623         $strglobalevents = get_string('globalevents', 'calendar');
624         if (calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
625             $output .= html_writer::tag('td', '', array('class'=>'calendar_event_global', 'style'=>'width:8px;'));
626             $output .= html_writer::tag('td', html_writer::tag('strong', $strglobalevents).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar').'<span class="accesshide">'.$strglobalevents.'</span>').')');
627         } else {
628             $output .= html_writer::tag('td', '', array('style'=>'width:8px;'));
629             $output .= html_writer::tag('td', html_writer::tag('strong', $strglobalevents).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar').'<span class="accesshide">'.$strglobalevents.'</span>').')');
630         }
632         // Course events
633         $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showcourses', 'return' => base64_encode($returnurl->out(false)), 'sesskey'=>sesskey()));
634         $strcourseevents = get_string('courseevents', 'calendar');
635         if (calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
636             $output .= html_writer::tag('td', '', array('class'=>'calendar_event_course', 'style'=>'width:8px;'));
637             $output .= html_writer::tag('td', html_writer::tag('strong', $strcourseevents).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar').'<span class="accesshide">'.$strcourseevents.'</span>').')');
638         } else {
639             $output .= html_writer::tag('td', '', array('style'=>'width:8px;'));
640             $output .= html_writer::tag('td', html_writer::tag('strong', $strcourseevents).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar').'<span class="accesshide">'.$strcourseevents.'</span>').')');
641         }
642         $output .= html_writer::end_tag('tr');
644         if(isloggedin() && !isguestuser()) {
645             $output .= html_writer::start_tag('tr');
646             // Group events
647             $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showgroups', 'return' => base64_encode($returnurl->out(false)), 'sesskey'=>sesskey()));
648             $strgroupevents = get_string('groupevents', 'calendar');
649             if (calendar_show_event_type(CALENDAR_EVENT_GROUP)) {
650                 $output .= html_writer::tag('td', '', array('class'=>'calendar_event_group', 'style'=>'width:8px;'));
651                 $output .= html_writer::tag('td', html_writer::tag('strong', $strgroupevents).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar').'<span class="accesshide">'.$strgroupevents.'</span>').')');
652             } else {
653                 $output .= html_writer::tag('td', '', array('style'=>'width:8px;'));
654                 $output .= html_writer::tag('td', html_writer::tag('strong', $strgroupevents).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar').'<span class="accesshide">'.$strgroupevents.'</span>').')');
655             }
656             // User events
657             $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showuser', 'return' => base64_encode($returnurl->out(false)), 'sesskey'=>sesskey()));
658             $struserevents = get_string('userevents', 'calendar');
659             if (calendar_show_event_type(CALENDAR_EVENT_USER)) {
660                 $output .= html_writer::tag('td', '', array('class'=>'calendar_event_user', 'style'=>'width:8px;'));
661                 $output .= html_writer::tag('td', html_writer::tag('strong', $struserevents).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar').'<span class="accesshide">'.$struserevents.'</span>').')');
662             } else {
663                 $output .= html_writer::tag('td', '', array('style'=>'width:8px;'));
664                 $output .= html_writer::tag('td', html_writer::tag('strong', $struserevents).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar').'<span class="accesshide">'.$struserevents.'</span>').')');
665             }
666             $output .= html_writer::end_tag('tr');
667         }
668         $output .= html_writer::end_tag('table');
669         $output .= html_writer::end_tag('div');
670         return $output;
671     }
673     /**
674      * Displays upcoming events
675      *
676      * @param calendar_information $calendar
677      * @param int $futuredays
678      * @param int $maxevents
679      * @return string
680      */
681     public function show_upcoming_events(calendar_information $calendar, $futuredays, $maxevents, moodle_url $returnurl = null) {
683         if ($returnurl === null) {
684             $returnurl = $this->page->url;
685         }
687         $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, $futuredays, $maxevents);
689         $output  = html_writer::start_tag('div', array('class'=>'header'));
690         if (calendar_user_can_add_event($calendar->course)) {
691             $output .= $this->add_event_button($calendar->course->id);
692         }
693         $output .= html_writer::tag('label', get_string('upcomingevents', 'calendar'), array('for'=>'cal_course_flt_jump'));
694         $output .= $this->course_filter_selector($returnurl);
695         $output .= html_writer::end_tag('div');
697         if ($events) {
698             $output .= html_writer::start_tag('div', array('class'=>'eventlist'));
699             foreach ($events as $event) {
700                 // Convert to calendar_event object so that we transform description
701                 // accordingly
702                 $event = new calendar_event($event);
703                 $event->calendarcourseid = $calendar->courseid;
704                 $output .= $this->event($event);
705             }
706             $output .= html_writer::end_tag('div');
707         } else {
708             $output .= $this->output->heading(get_string('noupcomingevents', 'calendar'));
709         }
711         return $output;
712     }
714     /**
715      * Displays a course filter selector
716      *
717      * @param array $getvars
718      * @return string
719      */
720     protected function course_filter_selector(moodle_url $returnurl, $label=null) {
721         global $USER, $SESSION, $CFG;
723         if (!isloggedin() or isguestuser()) {
724             return '';
725         }
727         if (has_capability('moodle/calendar:manageentries', context_system::instance()) && !empty($CFG->calendar_adminseesall)) {
728             $courses = get_courses('all', 'c.shortname','c.id,c.shortname');
729         } else {
730             $courses = enrol_get_my_courses();
731         }
733         unset($courses[SITEID]);
735         $courseoptions = array();
736         $courseoptions[SITEID] = get_string('fulllistofcourses');
737         foreach ($courses as $course) {
738             $coursecontext = context_course::instance($course->id);
739             $courseoptions[$course->id] = format_string($course->shortname, true, array('context' => $coursecontext));
740         }
742         if ($this->page->course->id !== SITEID) {
743             $selected = $this->page->course->id;
744         } else {
745             $selected = '';
746         }
747         $select = new single_select(new moodle_url(CALENDAR_URL.'set.php', array('return' => base64_encode($returnurl->out(false)), 'var' => 'setcourse', 'sesskey'=>sesskey())), 'id', $courseoptions, $selected, null);
748         $select->class = 'cal_courses_flt';
749         if ($label !== null) {
750             $select->set_label($label);
751         } else {
752             $select->set_label(get_string('listofcourses'), array('class' => 'accesshide'));
753         }
754         return $this->output->render($select);
755     }
757     /**
758      * Renders a table containing information about calendar subscriptions.
759      *
760      * @param int $courseid
761      * @param array $subscriptions
762      * @param string $importresults
763      * @return string
764      */
765     public function subscription_details($courseid, $subscriptions, $importresults = '') {
766         $table = new html_table();
767         $table->head  = array(
768             get_string('colcalendar', 'calendar'),
769             get_string('collastupdated', 'calendar'),
770             get_string('eventkind', 'calendar'),
771             get_string('colpoll', 'calendar'),
772             get_string('colactions', 'calendar')
773         );
774         $table->align = array('left', 'left', 'left', 'center');
775         $table->width = '100%';
776         $table->data  = array();
778         if (empty($subscriptions)) {
779             $cell = new html_table_cell(get_string('nocalendarsubscriptions', 'calendar'));
780             $cell->colspan = 4;
781             $table->data[] = new html_table_row(array($cell));
782         }
783         $strnever = new lang_string('never', 'calendar');
784         foreach ($subscriptions as $sub) {
785             $label = $sub->name;
786             if (!empty($sub->url)) {
787                 $label = html_writer::link($sub->url, $label);
788             }
789             if (empty($sub->lastupdated)) {
790                 $lastupdated = $strnever->out();
791             } else {
792                 $lastupdated = userdate($sub->lastupdated, get_string('strftimedatetimeshort', 'langconfig'));
793             }
795             $cell = new html_table_cell($this->subscription_action_form($sub, $courseid));
796             $cell->colspan = 2;
797             $type = $sub->eventtype . 'events';
799             $table->data[] = new html_table_row(array(
800                 new html_table_cell($label),
801                 new html_table_cell($lastupdated),
802                 new html_table_cell(get_string($type, 'calendar')),
803                 $cell
804             ));
805         }
807         $out  = $this->output->box_start('generalbox calendarsubs');
809         $out .= $importresults;
810         $out .= html_writer::table($table);
811         $out .= $this->output->box_end();
812         return $out;
813     }
815     /**
816      * Creates a form to perform actions on a given subscription.
817      *
818      * @param stdClass $subscription
819      * @param int $courseid
820      * @return string
821      */
822     protected function subscription_action_form($subscription, $courseid) {
823         // Assemble form for the subscription row.
824         $html = html_writer::start_tag('form', array('action' => new moodle_url('/calendar/managesubscriptions.php'), 'method' => 'post'));
825         if (empty($subscription->url)) {
826             // Don't update an iCal file, which has no URL.
827             $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'pollinterval', 'value' => '0'));
828         } else {
829             // Assemble pollinterval control.
830             $html .= html_writer::start_tag('div', array('style' => 'float:left;'));
831             $html .= html_writer::start_tag('select', array('name' => 'pollinterval'));
832             foreach (calendar_get_pollinterval_choices() as $k => $v) {
833                 $attributes = array();
834                 if ($k == $subscription->pollinterval) {
835                     $attributes['selected'] = 'selected';
836                 }
837                 $attributes['value'] = $k;
838                 $html .= html_writer::tag('option', $v, $attributes);
839             }
840             $html .= html_writer::end_tag('select');
841             $html .= html_writer::end_tag('div');
842         }
843         $html .= html_writer::start_tag('div', array('style' => 'float:right;'));
844         $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
845         $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'course', 'value' => $courseid));
846         $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'id', 'value' => $subscription->id));
847         if (!empty($subscription->url)) {
848             $html .= html_writer::tag('button', get_string('update'), array('type'  => 'submit', 'name' => 'action',
849                                                                             'value' => CALENDAR_SUBSCRIPTION_UPDATE));
850         }
851         $html .= html_writer::tag('button', get_string('remove'), array('type'  => 'submit', 'name' => 'action',
852                                                                         'value' => CALENDAR_SUBSCRIPTION_REMOVE));
853         $html .= html_writer::end_tag('div');
854         $html .= html_writer::end_tag('form');
855         return $html;
856     }