From 64ff737a2f7bc3d1f7fad50fccb7c1af68ba70da Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 19 Jul 2017 09:34:34 +0800 Subject: [PATCH] MDL-59388 calendar: Switch monthly view to use templates --- .../external/calendar_event_exporter.php | 90 +++++++ calendar/classes/external/day_exporter.php | 111 +++++++++ .../classes/external/day_name_exporter.php | 47 ++++ calendar/classes/external/month_exporter.php | 226 +++++++++++++++++ calendar/classes/external/week_exporter.php | 108 ++++++++ calendar/lib.php | 105 ++++++++ calendar/renderer.php | 232 +----------------- calendar/templates/month_detailed.mustache | 66 +++++ calendar/templates/month_header.mustache | 5 + calendar/templates/month_navigation.mustache | 5 + calendar/view.php | 81 +++--- theme/boost/scss/moodle/calendar.scss | 6 +- theme/bootstrapbase/less/moodle/calendar.less | 6 +- theme/bootstrapbase/style/moodle.css | 6 +- 14 files changed, 816 insertions(+), 278 deletions(-) create mode 100644 calendar/classes/external/calendar_event_exporter.php create mode 100644 calendar/classes/external/day_exporter.php create mode 100644 calendar/classes/external/day_name_exporter.php create mode 100644 calendar/classes/external/month_exporter.php create mode 100644 calendar/classes/external/week_exporter.php create mode 100644 calendar/templates/month_detailed.mustache create mode 100644 calendar/templates/month_header.mustache create mode 100644 calendar/templates/month_navigation.mustache diff --git a/calendar/classes/external/calendar_event_exporter.php b/calendar/classes/external/calendar_event_exporter.php new file mode 100644 index 00000000000..e3b53a9afb1 --- /dev/null +++ b/calendar/classes/external/calendar_event_exporter.php @@ -0,0 +1,90 @@ +. + +/** + * Contains event class for displaying a calendar event. + * + * @package core_calendar + * @copyright 2017 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_calendar\external; + +defined('MOODLE_INTERNAL') || die(); + +use \core\external\exporter; +use \core_calendar\local\event\entities\event_interface; +use \core_calendar\local\event\entities\action_event_interface; +use \core_course\external\course_summary_exporter; +use \renderer_base; + +/** + * Class for displaying a calendar event. + * + * @package core_calendar + * @copyright 2017 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class calendar_event_exporter extends event_exporter_base { + + /** + * Return the list of additional properties. + * + * @return array + */ + protected static function define_other_properties() { + return [ + 'url' => ['type' => PARAM_URL], + 'icon' => [ + 'type' => event_icon_exporter::read_properties_definition(), + ], + 'course' => [ + 'type' => course_summary_exporter::read_properties_definition(), + 'optional' => true, + ] + ]; + } + + /** + * Get the additional values to inject while exporting. + * + * @param renderer_base $output The renderer. + * @return array Keys are the property names, values are their values. + */ + protected function get_other_values(renderer_base $output) { + $values = parent::get_other_values($output); + + $eventid = $this->event->get_id(); + + $url = new \moodle_url($this->related['daylink'], [], "event_{$eventid}"); + $values['url'] = $url->out(false); + + return $values; + } + + /** + * Returns a list of objects that are related. + * + * @return array + */ + protected static function define_related() { + $related = parent::define_related(); + $related['daylink'] = \moodle_url::class; + + return $related; + } +} diff --git a/calendar/classes/external/day_exporter.php b/calendar/classes/external/day_exporter.php new file mode 100644 index 00000000000..827b3025d3c --- /dev/null +++ b/calendar/classes/external/day_exporter.php @@ -0,0 +1,111 @@ + [ + 'type' => PARAM_INT, + ], + 'minutes' => [ + 'type' => PARAM_INT, + ], + 'hours' => [ + 'type' => PARAM_INT, + ], + 'mday' => [ + 'type' => PARAM_INT, + ], + 'wday' => [ + 'type' => PARAM_INT, + ], + 'year' => [ + 'type' => PARAM_INT, + ], + 'yday' => [ + 'type' => PARAM_INT, + ], + ]; + } + + protected static function define_other_properties() { + return [ + 'timestamp' => [ + 'type' => PARAM_INT, + ], + 'istoday' => [ + 'type' => PARAM_BOOL, + 'default' => false, + ], + 'isweekend' => [ + 'type' => PARAM_BOOL, + 'default' => false, + ], + 'viewdaylink' => [ + 'type' => PARAM_URL, + 'optional' => true, + ], + 'events' => [ + 'type' => event_exporter::read_properties_definition(), + 'multiple' => true, + ], + 'viewdaylink' => [ + 'type' => PARAM_URL, + ], + + //'viewdaylink' => $this->viewdaylink->out(false), + //'createeventlink' => $this->createeventlink, + //'viewdaylinktitle' => $this->get_title($renderer), + //'events' => $this->get_events($renderer), + //'hasevents' => !empty($this->events), + //'eventtypes' => array_unique($this->eventtypes), + //'eventcount' => count($this->events), + //'durationevents' => array_unique($this->durationevents), + ]; + } + + protected function get_other_values(renderer_base $output) { + //$events = new events_exporter($this->related['events'], $this->related); + $return = [ + 'timestamp' => $this->data[0], + ]; + + $url = new moodle_url('/calendar/view.php', [ + 'view' => 'day', + 'time' => $this->data[0], + ]); + $return['viewdaylink'] = $url->out(false); + + + $cache = $this->related['cache']; + $return['events'] = array_map(function($event) use ($cache, $output, $url) { + $context = $cache->get_context($event); + $course = $cache->get_course($event); + $exporter = new calendar_event_exporter($event, [ + 'context' => $context, + 'course' => $course, + 'daylink' => $url, + ]); + + return $exporter->export($output); + }, $this->related['events']); + + return $return; + } + + protected static function define_related() { + return [ + 'events' => '\core_calendar\local\event\entities\event_interface[]', + 'cache' => '\core_calendar\external\events_related_objects_cache', + 'type' => '\core_calendar\type_base', + ]; + } +} diff --git a/calendar/classes/external/day_name_exporter.php b/calendar/classes/external/day_name_exporter.php new file mode 100644 index 00000000000..afa17c78f43 --- /dev/null +++ b/calendar/classes/external/day_name_exporter.php @@ -0,0 +1,47 @@ + $dayno]; + + parent::__construct($data, []); + } + + protected static function define_properties() { + return [ + 'dayno' => [ + 'type' => PARAM_INT, + ], + 'shortname' => [ + // Note: The calendar type class has already formatted the names. + 'type' => PARAM_RAW, + ], + 'fullname' => [ + // Note: The calendar type class has already formatted the names. + 'type' => PARAM_RAW, + ], + ]; + } +} diff --git a/calendar/classes/external/month_exporter.php b/calendar/classes/external/month_exporter.php new file mode 100644 index 00000000000..701a2fd1e16 --- /dev/null +++ b/calendar/classes/external/month_exporter.php @@ -0,0 +1,226 @@ +calendar = $calendar; + $this->firstdayofweek = $type->get_starting_weekday(); + + $this->url = new moodle_url('/calendar/view.php', [ + 'view' => 'month', + 'time' => $calendar->time, + ]); + + if ($this->calendar->courseid) { + $this->url->param('course', $this->calendar->courseid); + } + + $related['type'] = $type; + + parent::__construct([], $related); + } + + protected static function define_other_properties() { + return [ + 'courseid' => [ + 'type' => PARAM_INT, + ], + 'filter_selector' => [ + 'type' => PARAM_RAW, + ], + 'navigation' => [ + 'type' => PARAM_RAW, + ], + 'weeks' => [ + 'type' => week_exporter::read_properties_definition(), + 'multiple' => true, + ], + 'daynames' => [ + 'type' => day_name_exporter::read_properties_definition(), + 'multiple' => true, + ], + 'view' => [ + 'type' => PARAM_ALPHA, + ], + 'previousperiod' => [ + 'type' => PARAM_INT, + ], + 'nextperiod' => [ + 'type' => PARAM_INT, + ], + ]; + } + + protected function get_other_values(renderer_base $output) { + return [ + 'courseid' => $this->calendar->courseid, + 'view' => 'month', + 'previousperiod' => $this->get_previous_month_timestamp(), + 'nextperiod' => $this->get_next_month_timestamp(), + 'filter_selector' => $this->get_course_filter_selector($output), + 'navigation' => $this->get_navigation($output), + 'weeks' => $this->get_weeks($output), + 'daynames' => $this->get_day_names($output), + ]; + } + + /** + * Get the course filter selector. + * TODO Convert to new exporter? + * + * @param renderer_base $output + * return string + */ + protected function get_course_filter_selector(renderer_base $output) { + $content = ''; + $content .= $output->course_filter_selector($this->url, get_string('detailedmonthviewfor', 'calendar')); + if (calendar_user_can_add_event($this->calendar->course)) { + $content .= $output->add_event_button($this->calendar->courseid, 0, 0, 0, $this->calendar->time); + } + + return $content; + } + + /** + * Get the course filter selector. + * TODO Convert to new exporter? + * + * @param renderer_base $output + * return string + */ + protected function get_navigation(renderer_base $output) { + return calendar_top_controls('month', [ + 'id' => $this->calendar->courseid, + 'time' => $this->calendar->time, + ]); + } + + /** + * Get the list of day names for display, re-ordered from the first day + * of the week. + * + * @param renderer_base $output + * @return day_name_exporter[] + */ + protected function get_day_names(renderer_base $output) { + $weekdays = $this->related['type']->get_weekdays(); + $daysinweek = count($weekdays); + + $daynames = []; + for ($i = 0; $i < $daysinweek; $i++) { + // Bump the currentdayno and ensure it loops. + $dayno = ($i + $this->firstdayofweek + $daysinweek) % $daysinweek; + $dayname = new day_name_exporter($dayno, $weekdays[$dayno]); + $daynames[] = $dayname->export($output); + } + + return $daynames; + } + + /** + * Get the list of week days, ordered into weeks and padded according + * to the value of the first day of the week. + * + * @param renderer_base $output + * @return array + */ + protected function get_weeks(renderer_base $output) { + $weeks = []; + $alldays = $this->get_days(); + + $daysinweek = count($this->related['type']->get_weekdays()); + + // Calculate which day number is the first, and last day of the week. + $firstdayofweek = $this->firstdayofweek; + $lastdayofweek = ($firstdayofweek + $daysinweek - 1) % $daysinweek; + + // The first week is special as it may have padding at the beginning. + $day = reset($alldays); + $firstdayno = $day['wday']; + + $prepadding = ($firstdayno + $daysinweek - 1) % $daysinweek; + $daysinfirstweek = $daysinweek - $prepadding; + $days = array_slice($alldays, 0, $daysinfirstweek); + $week = new week_exporter($days, $prepadding, ($daysinweek - count($days) - $prepadding), $this->related); + $weeks[] = $week->export($output); + + // Now chunk up the remaining day. and turn them into weeks. + $daychunks = array_chunk(array_slice($alldays, $daysinfirstweek), $daysinweek); + foreach ($daychunks as $days) { + $week = new week_exporter($days, 0, ($daysinweek - count($days)), $this->related); + $weeks[] = $week->export($output); + } + + return $weeks; + } + + /** + * Get the list of days with the matching date array. + * + * @return array + */ + protected function get_days() { + $date = $this->related['type']->timestamp_to_date_array($this->calendar->time); + $monthdays = $this->related['type']->get_num_days_in_month($date['year'], $date['mon']); + + $days = []; + for ($dayno = 1; $dayno <= $monthdays; $dayno++) { + // Get the gregorian representation of the day. + $timestamp = $this->related['type']->convert_to_timestamp($date['year'], $date['mon'], $dayno); + + $days[] = $this->related['type']->timestamp_to_date_array($timestamp); + } + + return $days; + } + + protected static function define_related() { + return [ + 'events' => '\core_calendar\local\event\entities\event_interface[]', + 'cache' => '\core_calendar\external\events_related_objects_cache', + 'type' => '\core_calendar\type_base', + ]; + } + + protected function get_previous_month_timestamp() { + $date = $this->related['type']->timestamp_to_date_array($this->calendar->time); + $month = calendar_sub_month($date['mon'], $date['year']); + $monthtime = $this->related['type']->convert_to_gregorian($month[1], $month[0], 1); + return make_timestamp($monthtime['year'], $monthtime['month'], $monthtime['day'], $monthtime['hour'], $monthtime['minute']); + } + + protected function get_next_month_timestamp() { + $date = $this->related['type']->timestamp_to_date_array($this->calendar->time); + $month = calendar_sub_month($date['mon'], $date['year']); + $monthtime = $this->related['type']->convert_to_gregorian($month[1], $month[0], 1); + return make_timestamp($monthtime['year'], $monthtime['month'], $monthtime['day'], $monthtime['hour'], $monthtime['minute']); + } +} diff --git a/calendar/classes/external/week_exporter.php b/calendar/classes/external/week_exporter.php new file mode 100644 index 00000000000..c8427cece56 --- /dev/null +++ b/calendar/classes/external/week_exporter.php @@ -0,0 +1,108 @@ +days = $days; + $this->prepadding = $prepadding; + $this->postpadding = $postpadding; + + parent::__construct([], $related); + } + + protected static function define_other_properties() { + return [ + 'prepadding' => [ + 'type' => PARAM_INT, + 'multiple' => true, + ], + 'postpadding' => [ + 'type' => PARAM_INT, + 'multiple' => true, + ], + 'days' => [ + 'type' => day_exporter::read_properties_definition(), + 'multiple' => true, + ], + ]; + } + + protected function get_other_values(renderer_base $output) { + $return = [ + 'prepadding' => [], + 'postpadding' => [], + 'days' => [], + ]; + + for ($i = 0; $i < $this->prepadding; $i++) { + $return['prepadding'][] = $i; + } + for ($i = 0; $i < $this->postpadding; $i++) { + $return['postpadding'][] = $i; + } + + $return['days'] = []; + foreach ($this->days as $daydata) { + $events = []; + foreach ($this->related['events'] as $event) { + $times = $event->get_times(); + $starttime = $times->get_start_time()->getTimestamp(); + $startdate = $this->related['type']->timestamp_to_date_array($starttime); + $endtime = $times->get_end_time()->getTimestamp(); + $enddate = $this->related['type']->timestamp_to_date_array($endtime); + + if ((($startdate['year'] * 366) + $startdate['yday']) > ($daydata['year'] * 366) + $daydata['yday']) { + // Starts after today. + continue; + } + if ((($enddate['year'] * 366) + $enddate['yday']) < ($daydata['year'] * 366) + $daydata['yday']) { + // Ends before today. + continue; + } + + $events[] = $event; + } + + + $day = new day_exporter($daydata, [ + 'events' => $events, + 'cache' => $this->related['cache'], + 'type' => $this->related['type'], + ]); + $return['days'][] = $day->export($output); + } + + return $return; + } + + protected static function define_related() { + return [ + 'events' => '\core_calendar\local\event\entities\event_interface[]', + 'cache' => '\core_calendar\external\events_related_objects_cache', + 'type' => '\core_calendar\type_base', + ]; + } +} diff --git a/calendar/lib.php b/calendar/lib.php index 55a12be7192..7cb8c821df6 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -3422,6 +3422,111 @@ function calendar_get_legacy_events($tstart, $tend, $users, $groups, $courses, $ }, []); } + +/** + * Get theh calendar view output. + * + * @param \calendar_information $calendar The calendar being represented + * @param string $view The type of calendar to have displayed + * @return array[array, string] + */ +function calendar_get_view(\calendar_information $calendar, $view) { + global $PAGE, $DB, $OUTPUT; + + $renderer = $PAGE->get_renderer('core_calendar'); + $type = \core_calendar\type_factory::get_calendar_instance(); + + // Calculate the bounds of the month. + $date = $type->timestamp_to_date_array($calendar->time); + $tstart = $type->convert_to_timestamp($date['year'], $date['mon'], 1); + + if ($view === 'day') { + $tend = $tstart + DAYSECS - 1; + $selectortitle = get_string('dayviewfor', 'calendar'); + } else if ($view === 'upcoming') { + $defaultlookahead = isset($CFG->calendar_lookahead) ? intval($CFG->calendar_lookahead) : CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD; + $tend = $tstart + get_user_preferences('calendar_lookahead', $defaultlookahead); + $selectortitle = get_string('upcomingeventsfor', 'calendar'); + } else { + $monthdays = $type->get_num_days_in_month($date['year'], $date['mon']); + $tend = $tstart + ($monthdays * DAYSECS) - 1; + $selectortitle = get_string('detailedmonthviewfor', 'calendar'); + } + + list($userparam, $groupparam, $courseparam) = array_map(function($param) { + // If parameter is true, return null. + if ($param === true) { + return null; + } + + // If parameter is false, return an empty array. + if ($param === false) { + return []; + } + + // If the parameter is a scalar value, enclose it in an array. + if (!is_array($param)) { + return [$param]; + } + + // No normalisation required. + return $param; + }, [$calendar->users, $calendar->groups, $calendar->courses]); + + $events = \core_calendar\local\api::get_events( + $tstart, + $tend, + null, + null, + null, + null, + 40, + null, + $userparam, + $groupparam, + $courseparam, + true, + true, + function ($event) { + if ($proxy = $event->get_course_module()) { + $cminfo = $proxy->get_proxied_instance(); + return $cminfo->uservisible; + + } + + return true; + } + ); + + $related = [ + 'events' => $events, + 'cache' => new \core_calendar\external\events_related_objects_cache($events), + ]; + + if ($view === 'day') { + // TODO: Export the days events in a new exporter. + } else if ($view === 'upcoming') { + $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD; + if (isset($CFG->calendar_lookahead)) { + $defaultlookahead = intval($CFG->calendar_lookahead); + } + $lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead); + + $defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS; + if (isset($CFG->calendar_maxevents)) { + $defaultmaxevents = intval($CFG->calendar_maxevents); + } + $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); + // TODO: Export the upcoming events in a new exporter. + } else { + $month = new \core_calendar\external\month_exporter($calendar, $type, $related); + $data = $month->export($renderer); + $template = 'core_calendar/month_detailed'; + } + + return [$data, $template]; +} + /** * Request and render event form fragment. * diff --git a/calendar/renderer.php b/calendar/renderer.php index f1bebaab0c1..6e7cab8ef0a 100644 --- a/calendar/renderer.php +++ b/calendar/renderer.php @@ -128,7 +128,7 @@ class core_calendar_renderer extends plugin_renderer_base { * $month and $year are kept for backwards compatibility. * @return string */ - protected function add_event_button($courseid, $day = null, $month = null, $year = null, $time = null) { + public function add_event_button($courseid, $day = null, $month = null, $year = null, $time = null) { // If a day, month and year were passed then convert it to a timestamp. If these were passed // then we can assume the day, month and year are passed as Gregorian, as no where in core // should we be passing these values rather than the time. This is done for BC. @@ -312,234 +312,6 @@ class core_calendar_renderer extends plugin_renderer_base { return html_writer::tag('div', $eventhtml, array('class' => 'event', 'id' => 'event_' . $event->id)); } - /** - * Displays a month in detail - * - * @param calendar_information $calendar - * @param moodle_url $returnurl the url to return to - * @return string - */ - public function show_month_detailed(calendar_information $calendar, moodle_url $returnurl = null) { - global $CFG; - - if (empty($returnurl)) { - $returnurl = $this->page->url; - } - - // Get the calendar type we are using. - $calendartype = \core_calendar\type_factory::get_calendar_instance(); - - // Store the display settings. - $display = new stdClass; - $display->thismonth = false; - - // Get the specified date in the calendar type being used. - $date = $calendartype->timestamp_to_date_array($calendar->time); - $thisdate = $calendartype->timestamp_to_date_array(time()); - if ($date['mon'] == $thisdate['mon'] && $date['year'] == $thisdate['year']) { - $display->thismonth = true; - $date = $thisdate; - $calendar->time = time(); - } - - // Get Gregorian date for the start of the month. - $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1); - // Store the gregorian date values to be used later. - list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], - $gregoriandate['hour'], $gregoriandate['minute']); - - // Get the starting week day for this month. - $startwday = dayofweek(1, $date['mon'], $date['year']); - // Get the days in a week. - $daynames = calendar_get_days(); - // Store the number of days in a week. - $numberofdaysinweek = $calendartype->get_num_weekdays(); - - $display->minwday = calendar_get_starting_weekday(); - $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); - $display->maxdays = calendar_days_in_month($date['mon'], $date['year']); - - // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. - $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); - $display->tend = $display->tstart + ($display->maxdays * DAYSECS) - 1; - - // Align the starting weekday to fall in our display range - // This is simple, not foolproof. - if ($startwday < $display->minwday) { - $startwday += $numberofdaysinweek; - } - - // Get events from database - $events = calendar_get_legacy_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, - $calendar->courses); - if (!empty($events)) { - foreach($events as $eventid => $event) { - $event = new calendar_event($event); - if (!empty($event->modulename)) { - $instances = get_fast_modinfo($event->courseid)->get_instances_of($event->modulename); - if (empty($instances[$event->instance]->uservisible)) { - unset($events[$eventid]); - } - } - } - } - - // Extract information: events vs. time - calendar_events_by_day($events, $date['mon'], $date['year'], $eventsbyday, $durationbyday, - $typesbyday, $calendar->courses); - - $output = html_writer::start_tag('div', array('class'=>'header')); - $output .= $this->course_filter_selector($returnurl, get_string('detailedmonthviewfor', 'calendar')); - if (calendar_user_can_add_event($calendar->course)) { - $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time); - } - $output .= html_writer::end_tag('div', array('class'=>'header')); - // Controls - $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, - 'time' => $calendar->time)), array('class' => 'controls')); - - $table = new html_table(); - $table->attributes = array('class'=>'calendarmonth calendartable'); - $table->summary = get_string('calendarheading', 'calendar', userdate($calendar->time, get_string('strftimemonthyear'))); - $table->data = array(); - - // Get the day names as the header. - $header = array(); - for($i = $display->minwday; $i <= $display->maxwday; ++$i) { - $header[] = $daynames[$i % $numberofdaysinweek]['shortname']; - } - $table->head = $header; - - // For the table display. $week is the row; $dayweek is the column. - $week = 1; - $dayweek = $startwday; - - $row = new html_table_row(array()); - - // Paddding (the first week may have blank days in the beginning) - for($i = $display->minwday; $i < $startwday; ++$i) { - $cell = new html_table_cell(' '); - $cell->attributes = array('class'=>'nottoday dayblank'); - $row->cells[] = $cell; - } - - // Now display all the calendar - $weekend = CALENDAR_DEFAULT_WEEKEND; - if (isset($CFG->calendar_weekend)) { - $weekend = intval($CFG->calendar_weekend); - } - - $daytime = strtotime('-1 day', $display->tstart); - for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { - $daytime = strtotime('+1 day', $daytime); - if($dayweek > $display->maxwday) { - // We need to change week (table row) - $table->data[] = $row; - $row = new html_table_row(array()); - $dayweek = $display->minwday; - ++$week; - } - - // Reset vars - $cell = new html_table_cell(); - $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', - array('view' => 'day', 'course' => $calendar->courseid)), 0, 0, 0, $daytime); - - $cellclasses = array(); - - if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) { - // Weekend. This is true no matter what the exact range is. - $cellclasses[] = 'weekend'; - } - - // Special visual fx if an event is defined - if (isset($eventsbyday[$day])) { - if(count($eventsbyday[$day]) == 1) { - $title = get_string('oneevent', 'calendar'); - } else { - $title = get_string('manyevents', 'calendar', count($eventsbyday[$day])); - } - $cell->text = html_writer::tag('div', html_writer::link($dayhref, $day, array('title'=>$title)), array('class'=>'day')); - } else { - $cell->text = html_writer::tag('div', $day, array('class'=>'day')); - } - - // Special visual fx if an event spans many days - $durationclass = false; - if (isset($typesbyday[$day]['durationglobal'])) { - $durationclass = 'duration_global'; - } else if (isset($typesbyday[$day]['durationcourse'])) { - $durationclass = 'duration_course'; - } else if (isset($typesbyday[$day]['durationgroup'])) { - $durationclass = 'duration_group'; - } else if (isset($typesbyday[$day]['durationuser'])) { - $durationclass = 'duration_user'; - } - if ($durationclass) { - $cellclasses[] = 'duration'; - $cellclasses[] = $durationclass; - } - - // Special visual fx for today - if ($display->thismonth && $day == $date['mday']) { - $cellclasses[] = 'day today'; - } else { - $cellclasses[] = 'day nottoday'; - } - $cell->attributes = array('class'=>join(' ',$cellclasses)); - - if (isset($eventsbyday[$day])) { - $cell->text .= html_writer::start_tag('ul', array('class'=>'events-new')); - foreach($eventsbyday[$day] as $eventindex) { - // If event has a class set then add it to the event
  • tag - $attributes = array(); - if (!empty($events[$eventindex]->class)) { - $attributes['class'] = $events[$eventindex]->class; - } - $dayhref->set_anchor('event_'.$events[$eventindex]->id); - - $eventcontext = $events[$eventindex]->context; - $eventformatopts = array('context' => $eventcontext); - // Get event name. - $eventname = format_string($events[$eventindex]->name, true, $eventformatopts); - // Include course's shortname into the event name, if applicable. - $courseid = $events[$eventindex]->courseid; - if (!empty($courseid) && $courseid !== SITEID) { - $course = get_course($courseid); - $eventnameparams = (object)[ - 'name' => $eventname, - 'course' => format_string($course->shortname, true, $eventformatopts) - ]; - $eventname = get_string('eventnameandcourse', 'calendar', $eventnameparams); - } - $link = html_writer::link($dayhref, $eventname, ['data-action' => 'view-event', - 'data-event-id' => $events[$eventindex]->id]); - $cell->text .= html_writer::tag('li', $link, $attributes); - } - $cell->text .= html_writer::end_tag('ul'); - } - if (isset($durationbyday[$day])) { - $cell->text .= html_writer::start_tag('ul', array('class'=>'events-underway')); - foreach($durationbyday[$day] as $eventindex) { - $cell->text .= html_writer::tag('li', '['.format_string($events[$eventindex]->name,true).']', array('class'=>'events-underway')); - } - $cell->text .= html_writer::end_tag('ul'); - } - $row->cells[] = $cell; - } - - // Paddding (the last week may have blank days at the end) - for($i = $dayweek; $i <= $display->maxwday; ++$i) { - $cell = new html_table_cell(' '); - $cell->attributes = array('class'=>'nottoday dayblank'); - $row->cells[] = $cell; - } - $table->data[] = $row; - $output .= html_writer::table($table); - - return $output; - } - /** * Displays upcoming events * @@ -587,7 +359,7 @@ class core_calendar_renderer extends plugin_renderer_base { * @param string $label The label to use for the course select. * @return string */ - protected function course_filter_selector(moodle_url $returnurl, $label=null) { + public function course_filter_selector(moodle_url $returnurl, $label=null) { global $USER, $SESSION, $CFG; if (!isloggedin() or isguestuser()) { diff --git a/calendar/templates/month_detailed.mustache b/calendar/templates/month_detailed.mustache new file mode 100644 index 00000000000..de10bc2827e --- /dev/null +++ b/calendar/templates/month_detailed.mustache @@ -0,0 +1,66 @@ + + {{> core_calendar/month_header }} + {{> core_calendar/month_navigation }} + + + + {{# daynames }} + + {{/ daynames }} + + + + {{#weeks}} + + {{#prepadding}} + + {{/prepadding}} + {{#days}} + + {{/days}} + {{#postpadding}} + + {{/postpadding}} + + {{/weeks}} + +
    + {{shortname}} +
      +
    + {{#events.0}} + {{mday}} + {{/events.0}} + {{^events.0}} + {{mday}} + {{/events.0}} + {{#events.0}} +
      + {{#events}} + {{#underway}} +
    • [{{name}}]
    • + {{/underway}} + {{^underway}} +
    • + {{name}} +
    • + {{/underway}} + {{/events}} +
    + {{/events.0}} +
    +
    + {{#events.0}} + {{mday}} + {{/events.0}} + {{^events.0}} + {{mday}} + {{/events.0}} +
    +
     
    +
    diff --git a/calendar/templates/month_header.mustache b/calendar/templates/month_header.mustache new file mode 100644 index 00000000000..d5ce533a85f --- /dev/null +++ b/calendar/templates/month_header.mustache @@ -0,0 +1,5 @@ +{{#filter_selector}} +
    + {{{filter_selector}}} +
    +{{/filter_selector}} diff --git a/calendar/templates/month_navigation.mustache b/calendar/templates/month_navigation.mustache new file mode 100644 index 00000000000..481021eeee3 --- /dev/null +++ b/calendar/templates/month_navigation.mustache @@ -0,0 +1,5 @@ +{{#navigation}} +
    + {{{navigation}}} +
    +{{/navigation}} diff --git a/calendar/view.php b/calendar/view.php index f974ba5bb84..fdf3cb05ff8 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -132,48 +132,51 @@ echo $renderer->start_layout(); echo html_writer::start_tag('div', array('class'=>'heightcontainer')); echo $OUTPUT->heading(get_string('calendar', 'calendar')); -switch($view) { - case 'day': - echo $renderer->show_day($calendar); - break; - case 'month': - echo $renderer->show_month_detailed($calendar, $url); - break; - case 'upcoming': - $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD; - if (isset($CFG->calendar_lookahead)) { - $defaultlookahead = intval($CFG->calendar_lookahead); - } - $lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead); +if ($view == 'day' || $view == 'upcoming') { + switch($view) { + case 'day': + echo $renderer->show_day($calendar); + break; + case 'upcoming': + $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD; + if (isset($CFG->calendar_lookahead)) { + $defaultlookahead = intval($CFG->calendar_lookahead); + } + $lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead); - $defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS; - if (isset($CFG->calendar_maxevents)) { - $defaultmaxevents = intval($CFG->calendar_maxevents); - } - $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); - echo $renderer->show_upcoming_events($calendar, $lookahead, $maxevents); - break; -} - -//Link to calendar export page. -echo $OUTPUT->container_start('bottom'); -if (!empty($CFG->enablecalendarexport)) { - echo $OUTPUT->single_button(new moodle_url('export.php', array('course'=>$courseid)), get_string('exportcalendar', 'calendar')); - if (calendar_user_can_add_event($course)) { - echo $OUTPUT->single_button(new moodle_url('/calendar/managesubscriptions.php', array('course'=>$courseid)), get_string('managesubscriptions', 'calendar')); + $defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS; + if (isset($CFG->calendar_maxevents)) { + $defaultmaxevents = intval($CFG->calendar_maxevents); + } + $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); + echo $renderer->show_upcoming_events($calendar, $lookahead, $maxevents); + break; } - if (isloggedin()) { - $authtoken = sha1($USER->id . $DB->get_field('user', 'password', array('id' => $USER->id)) . $CFG->calendar_exportsalt); - $link = new moodle_url( - '/calendar/export_execute.php', - array('preset_what'=>'all', 'preset_time' => 'recentupcoming', 'userid' => $USER->id, 'authtoken'=>$authtoken) - ); - echo html_writer::tag('a', 'iCal', - array('href' => $link, 'title' => get_string('quickdownloadcalendar', 'calendar'), 'class' => 'ical-link m-l-1')); - } -} -echo $OUTPUT->container_end(); + //Link to calendar export page. + echo $OUTPUT->container_start('bottom'); + if (!empty($CFG->enablecalendarexport)) { + echo $OUTPUT->single_button(new moodle_url('export.php', array('course'=>$courseid)), get_string('exportcalendar', 'calendar')); + if (calendar_user_can_add_event($course)) { + $manageurl = new moodle_url('/calendar/managesubscriptions.php', ['course' => $courseid]); + echo $OUTPUT->single_button($manageurl, get_string('managesubscriptions', 'calendar')); + } + if (isloggedin()) { + $authtoken = sha1($USER->id . $DB->get_field('user', 'password', array('id' => $USER->id)) . $CFG->calendar_exportsalt); + $link = new moodle_url( + '/calendar/export_execute.php', + array('preset_what'=>'all', 'preset_time' => 'recentupcoming', 'userid' => $USER->id, 'authtoken'=>$authtoken) + ); + echo html_writer::tag('a', 'iCal', + array('href' => $link, 'title' => get_string('quickdownloadcalendar', 'calendar'), 'class' => 'ical-link m-l-1')); + } + } + + echo $OUTPUT->container_end(); +} else if ($view == 'month') { + list($data, $template) = calendar_get_view($calendar, $view); + echo $renderer->render_from_template($template, $data); +} echo html_writer::end_tag('div'); echo $renderer->complete_layout(); $PAGE->requires->js_call_amd('core_calendar/calendar', 'init'); diff --git a/theme/boost/scss/moodle/calendar.scss b/theme/boost/scss/moodle/calendar.scss index 3a3de0798a0..47632cd7803 100644 --- a/theme/boost/scss/moodle/calendar.scss +++ b/theme/boost/scss/moodle/calendar.scss @@ -11,7 +11,7 @@ $calendarEventUserColor: #dce7ec !default; // Pale blue. background-color: $calendarEventCourseColor; } -.calendar_event_global { +.calendar_event_site { background-color: $calendarEventGlobalColor; } @@ -119,7 +119,7 @@ $calendarEventUserColor: #dce7ec !default; // Pale blue. } .calendar_event_course, - .calendar_event_global, + .calendar_event_site, .calendar_event_group, .calendar_event_user { border-width: 1px 1px 1px 12px; @@ -130,7 +130,7 @@ $calendarEventUserColor: #dce7ec !default; // Pale blue. border-color: $calendarEventCourseColor; } - .calendar_event_global { + .calendar_event_site { border-color: $calendarEventGlobalColor; } diff --git a/theme/bootstrapbase/less/moodle/calendar.less b/theme/bootstrapbase/less/moodle/calendar.less index cbb29dc26fe..447fef65d3c 100644 --- a/theme/bootstrapbase/less/moodle/calendar.less +++ b/theme/bootstrapbase/less/moodle/calendar.less @@ -10,7 +10,7 @@ .calendar_event_course { background-color: @calendarEventCourseColor; } -.calendar_event_global { +.calendar_event_site { background-color: @calendarEventGlobalColor; } .calendar_event_group { @@ -109,7 +109,7 @@ margin: 10px auto; } .calendar_event_course, - .calendar_event_global, + .calendar_event_site, .calendar_event_group, .calendar_event_user { border-width: 1px 1px 1px 12px; @@ -118,7 +118,7 @@ .calendar_event_course { border-color: @calendarEventCourseColor; } - .calendar_event_global { + .calendar_event_site { border-color: @calendarEventGlobalColor; } .calendar_event_group { diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index 066dc473b30..6407793764d 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -5542,7 +5542,7 @@ img.iconsmall { .calendar_event_course { background-color: #ffd3bd; } -.calendar_event_global { +.calendar_event_site { background-color: #d6f8cd; } .calendar_event_group { @@ -5630,7 +5630,7 @@ img.iconsmall { margin: 10px auto; } .path-calendar .maincalendar .calendar_event_course, -.path-calendar .maincalendar .calendar_event_global, +.path-calendar .maincalendar .calendar_event_site, .path-calendar .maincalendar .calendar_event_group, .path-calendar .maincalendar .calendar_event_user { border-width: 1px 1px 1px 12px; @@ -5639,7 +5639,7 @@ img.iconsmall { .path-calendar .maincalendar .calendar_event_course { border-color: #ffd3bd; } -.path-calendar .maincalendar .calendar_event_global { +.path-calendar .maincalendar .calendar_event_site { border-color: #d6f8cd; } .path-calendar .maincalendar .calendar_event_group {