if ($issite) {
// Being displayed at site level. This will cause the filter to fall back to auto-detecting
// the list of courses it will be grabbing events from.
- $filtercourse = calendar_get_default_courses();
+ $course = get_site();
+ $courses = calendar_get_default_courses();
} else {
// Forcibly filter events to include only those from the particular course we are in.
- $filtercourse = array($courseid => $this->page->course);
+ $course = $this->page->course;
+ $courses = [$course->id => $course];
}
- list($courses, $group, $user) = calendar_set_filters($filtercourse);
- if ($issite) {
- // For the front page.
- $this->content->text .= calendar_get_mini($courses, $group, $user, false, false,
- 'frontpage', $courseid, $time);
- // No filters for now.
- } else {
- // For any other course.
- $this->content->text .= calendar_get_mini($courses, $group, $user, false, false,
- 'course', $courseid, $time);
- $this->content->text .= '<h3 class="eventskey">'.get_string('eventskey', 'calendar').'</h3>';
- $this->content->text .= '<div class="filters calendar_filters">' .
- calendar_filter_controls($this->page->url) . '</div>';
+ $renderer = $this->page->get_renderer('core_calendar');
+
+ $calendar = new calendar_information(0, 0, 0, $time);
+ $calendar->prepare_for_view($course, $courses);
+
+ list($data, $template) = calendar_get_view($calendar, 'mini');
+ $this->content->text .= $renderer->render_from_template($template, $data);
+
+ if (!$issite) {
+ $this->content->text .= $renderer->event_filter();
}
return $this->content;
}
}
-
-
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
When I add the "Calendar" block
- Then I should see "Events key" in the "Calendar" "block"
+ Then "Calendar" "block" should exist
@javascript
Scenario: View a global event in the calendar block
And I press "Save and display"
And I turn editing mode on
And I add the "Calendar" block
- And I create a calendar event with form data:
+ And I click on "This month" "link"
+ And I click on "New event" "button"
+ And I set the following fields to these values:
| id_eventtype | Group |
| id_name | Group Event |
+ And I set the following fields to these values:
+ | Group | Group 1 |
+ And I press "Save"
And I log out
Then I log in as "student1"
And I am on "Course 1" course homepage
And I hover over today in the calendar
And I should not see "Group Event"
- @javascript
+ @javascript @arn
Scenario: Filter group events in the calendar block
Given the following "groups" exist:
| name | course | idnumber |
| id_eventtype | Course |
| id_name | Course Event 1 |
And I am on "Course 1" course homepage
- And I create a calendar event with form data:
+ And I click on "This month" "link"
+ And I click on "New event" "button"
+ And I set the following fields to these values:
| id_eventtype | Group |
| id_name | Group Event 1 |
+ And I set the following fields to these values:
+ | Group | Group 1 |
+ And I press "Save"
And I log out
Then I log in as "student1"
And I am on "Course 1" course homepage
--- /dev/null
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module is responsible for the calendar filter.
+ *
+ * @module core_calendar/calendar_filter
+ * @package core_calendar
+ * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define([
+ 'jquery',
+ 'core_calendar/selectors',
+ 'core_calendar/events',
+ 'core/str',
+ 'core/templates',
+],
+function(
+ $,
+ CalendarSelectors,
+ CalendarEvents,
+ Str,
+ Templates
+) {
+
+ var registerEventListeners = function(root) {
+ root.on('click', CalendarSelectors.eventFilterItem, function(e) {
+ var target = $(e.currentTarget);
+
+ toggleFilter(target);
+
+ e.preventDefault();
+ });
+
+ $('body').on(CalendarEvents.viewUpdated, function() {
+ var filters = root.find(CalendarSelectors.eventFilterItem);
+
+ filters.each(function(i, filter) {
+ filter = $(filter);
+ if (filter.data('eventtype-hidden')) {
+ var data = getFilterData(filter);
+ fireFilterChangedEvent(data);
+ }
+ });
+ });
+ };
+
+ var toggleFilter = function(target) {
+ var data = getFilterData(target);
+
+ // Toggle the hidden. We need to render the template before we change the value.
+ data.hidden = !data.hidden;
+
+ return Str.get_string('eventtype' + data.type, 'calendar')
+ .then(function(nameStr) {
+ data.name = nameStr;
+
+ return data;
+ })
+ .then(function(context) {
+ return Templates.render('core_calendar/event_filter_key', context);
+ })
+ .then(function(html, js) {
+ return Templates.replaceNode(target, html, js);
+ })
+ .then(function() {
+ fireFilterChangedEvent(data);
+ return;
+ });
+ };
+
+ /**
+ * Fire the filterChanged event for the specified data.
+ *
+ * @param {object} data The data to include
+ */
+ var fireFilterChangedEvent = function(data) {
+ M.util.js_pending("month-mini-filterChanged");
+ $('body').trigger(CalendarEvents.filterChanged, {
+ type: data.type,
+ hidden: data.hidden,
+ });
+ M.util.js_complete("month-mini-filterChanged");
+ };
+
+ /**
+ * Get the filter data for the specified target.
+ *
+ * @param {jQuery} target The target node
+ * @return {Object}
+ */
+ var getFilterData = function(target) {
+ return {
+ type: target.data('eventtype'),
+ hidden: target.data('eventtype-hidden'),
+ };
+ };
+
+ return {
+ init: function(root) {
+ root = $(root);
+
+ registerEventListeners(root);
+ }
+ };
+});
--- /dev/null
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module is the highest level module for the calendar. It is
+ * responsible for initialising all of the components required for
+ * the calendar to run. It also coordinates the interaction between
+ * components by listening for and responding to different events
+ * triggered within the calendar UI.
+ *
+ * @module core_calendar/calendar
+ * @package core_calendar
+ * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define([
+ 'jquery',
+ 'core_calendar/selectors',
+ 'core_calendar/events',
+ 'core_calendar/view_manager',
+],
+function(
+ $,
+ CalendarSelectors,
+ CalendarEvents,
+ CalendarViewManager
+) {
+
+ var registerEventListeners = function(root) {
+ $('body').on(CalendarEvents.filterChanged, function(e, data) {
+ var daysWithEvent = root.find(CalendarSelectors.eventType[data.type]);
+
+ daysWithEvent.toggleClass('calendar_event_' + data.type, !data.hidden);
+ });
+ };
+
+ return {
+ init: function(root) {
+ root = $(root);
+
+ CalendarViewManager.init(root);
+ registerEventListeners(root);
+ }
+ };
+});
editActionEvent: 'calendar-events:edit_action_event',
eventMoved: 'calendar-events:event_moved',
monthChanged: 'calendar-events:month_changed',
- moveEvent: 'calendar-events:move_event'
+ moveEvent: 'calendar-events:move_event',
+ filterChanged: 'calendar-events:filter_changed',
+ viewUpdated: 'calendar-events:view_updated',
};
});
--- /dev/null
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module is responsible for the calendar filter.
+ *
+ * @module core_calendar/calendar_selectors
+ * @package core_calendar
+ * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define([], function() {
+ return {
+ eventFilterItem: "[data-action='filter-event-type']",
+ eventType: {
+ site: "[data-eventtype-site]",
+ course: "[data-eventtype-course]",
+ group: "[data-eventtype-group]",
+ user: "[data-eventtype-user]",
+ },
+ popoverType: {
+ site: "[data-popover-eventtype-site]",
+ course: "[data-popover-eventtype-course]",
+ group: "[data-popover-eventtype-group]",
+ user: "[data-popover-eventtype-user]",
+ },
+ };
+});
.then(function(html, js) {
return Templates.replaceNode(root.find(SELECTORS.CALENDAR_MONTH_WRAPPER), html, js);
})
+ .then(function() {
+ $('body').trigger(CalendarEvents.viewUpdated);
+ return;
+ })
.always(function() {
return stopLoading(root);
})
$values = parent::define_other_properties();
$values['url'] = ['type' => PARAM_URL];
+ $values['islastday'] = [
+ 'type' => PARAM_BOOL,
+ 'default' => false,
+ ];
+ $values['calendareventtype'] = [
+ 'type' => PARAM_TEXT,
+ ];
+ $values['popupname'] = [
+ 'type' => PARAM_RAW,
+ ];
return $values;
}
* @return array Keys are the property names, values are their values.
*/
protected function get_other_values(renderer_base $output) {
+ global $CFG;
+
$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);
+ $values['islastday'] = false;
+ $today = $this->related['type']->timestamp_to_date_array($this->related['today']);
+
+ $values['popupname'] = $this->event->get_name();
+
+ $times = $this->event->get_times();
+ if ($duration = $times->get_duration()) {
+ $enddate = $this->related['type']->timestamp_to_date_array($times->get_end_time()->getTimestamp());
+ $values['islastday'] = true;
+ $values['islastday'] = $values['islastday'] && $enddate['year'] == $today['year'];
+ $values['islastday'] = $values['islastday'] && $enddate['mon'] == $today['mon'];
+ $values['islastday'] = $values['islastday'] && $enddate['mday'] == $today['mday'];
+ }
+
+ $subscription = $this->event->get_subscription();
+ if ($subscription && !empty($subscription->get('id')) && $CFG->calendar_showicalsource) {
+ $a = (object) [
+ 'name' => $values['popupname'],
+ 'source' => $subscription->get('name'),
+ ];
+ $values['popupname'] = get_string('namewithsource', 'calendar', $a);
+ } else {
+ if ($values['islastday']) {
+ $startdate = $this->related['type']->timestamp_to_date_array($times->get_start_time()->getTimestamp());
+ $samedate = true;
+ $samedate = $samedate && $startdate['mon'] == $enddate['mon'];
+ $samedate = $samedate && $startdate['year'] == $enddate['year'];
+ $samedate = $samedate && $startdate['mday'] == $enddate['mday'];
+
+ if (!$samedate) {
+ $values['popupname'] = get_string('eventendtimewrapped', 'calendar', $values['popupname']);
+ }
+ }
+ }
+
+ // Include course's shortname into the event name, if applicable.
+ $course = $this->event->get_course();
+ if ($course && $course->get('id') && $course->get('id') !== SITEID) {
+ $eventnameparams = (object) [
+ 'name' => $values['popupname'],
+ 'course' => format_string($course->get('shortname'), true, [
+ 'context' => $this->related['context'],
+ ])
+ ];
+ $values['popupname'] = get_string('eventnameandcourse', 'calendar', $eventnameparams);
+ }
+
+ $values['calendareventtype'] = $this->get_calendar_event_type();
+
return $values;
}
protected static function define_related() {
$related = parent::define_related();
$related['daylink'] = \moodle_url::class;
+ $related['type'] = '\core_calendar\type_base';
+ $related['today'] = 'int';
return $related;
}
+
+ /**
+ * Return the normalised event type.
+ * Activity events are normalised to be course events.
+ *
+ * @return string
+ */
+ public function get_calendar_event_type() {
+ $type = $this->event->get_type();
+ if ($type == 'open' || $type == 'close') {
+ $type = 'course';
+ }
+
+ return $type;
+ }
}
'yday' => [
'type' => PARAM_INT,
],
+ // These are additional params.
+ 'istoday' => [
+ 'type' => PARAM_BOOL,
+ 'default' => false,
+ ],
+ 'isweekend' => [
+ 'type' => PARAM_BOOL,
+ 'default' => false,
+ ],
];
}
'events' => [
'type' => calendar_event_exporter::read_properties_definition(),
'multiple' => true,
- ]
+ ],
+ 'calendareventtypes' => [
+ 'type' => PARAM_RAW,
+ 'multiple' => true,
+ ],
+ 'popovertitle' => [
+ 'type' => PARAM_RAW,
+ 'default' => '',
+ ],
+ 'haslastdayofevent' => [
+ 'type' => PARAM_BOOL,
+ 'default' => false,
+ ],
];
}
$url = new moodle_url('/calendar/view.php', [
'view' => 'day',
'time' => $timestamp,
+ 'course' => $this->calendar->course->id,
]);
$return['viewdaylink'] = $url->out(false);
$cache = $this->related['cache'];
- $return['events'] = array_map(function($event) use ($cache, $output, $url) {
+ $eventexporters = 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,
+ 'type' => $this->related['type'],
+ 'today' => $this->data[0],
]);
- return $exporter->export($output);
+ return $exporter;
}, $this->related['events']);
+ $return['events'] = array_map(function($exporter) use ($output) {
+ return $exporter->export($output);
+ }, $eventexporters);
+
+ if ($popovertitle = $this->get_popover_title()) {
+ $return['popovertitle'] = $popovertitle;
+ }
+
+ $return['calendareventtypes'] = array_map(function($exporter) {
+ return $exporter->get_calendar_event_type();
+ }, $eventexporters);
+ $return['calendareventtypes'] = array_values(array_unique($return['calendareventtypes']));
+
+ $return['haslastdayofevent'] = false;
+ foreach ($return['events'] as $event) {
+ if ($event->islastday) {
+ $return['haslastdayofevent'] = true;
+ break;
+ }
+ }
+
return $return;
}
'type' => '\core_calendar\type_base',
];
}
+
+ /**
+ * Get the title for this popover.
+ *
+ * @return string
+ */
+ protected function get_popover_title() {
+ $title = null;
+
+ $userdate = userdate($this->data[0], get_string('strftimedayshort'));
+ if (count($this->related['events'])) {
+ $title = get_string('eventsfor', 'calendar', $userdate);
+ } else if ($this->data['istoday']) {
+ $title = $userdate;
+ }
+
+ if ($this->data['istoday']) {
+ $title = get_string('todayplustitle', 'calendar', $userdate);
+ }
+
+ return $title;
+ }
}
$related['type'] = $type;
- parent::__construct([], $related);
+ $data = [
+ 'url' => $this->url->out(false),
+ ];
+
+ parent::__construct($data, $related);
+ }
+
+ protected static function define_properties() {
+ return [
+ 'url' => [
+ 'type' => PARAM_URL,
+ ],
+ ];
}
/**
'view' => [
'type' => PARAM_ALPHA,
],
+ 'time' => [
+ 'type' => PARAM_INT,
+ ],
+ 'periodname' => [
+ // Note: We must use RAW here because the calendar type returns the formatted month name based on a
+ // calendar format.
+ 'type' => PARAM_RAW,
+ ],
'previousperiod' => [
'type' => PARAM_INT,
],
+ 'previousperiodname' => [
+ // Note: We must use RAW here because the calendar type returns the formatted month name based on a
+ // calendar format.
+ 'type' => PARAM_RAW,
+ ],
'nextperiod' => [
'type' => PARAM_INT,
],
- 'time' => [
- 'type' => PARAM_INT,
- ]
+ 'nextperiodname' => [
+ // Note: We must use RAW here because the calendar type returns the formatted month name based on a
+ // calendar format.
+ 'type' => PARAM_RAW,
+ ],
+ 'larrow' => [
+ // The left arrow defined by the theme.
+ 'type' => PARAM_RAW,
+ ],
+ 'rarrow' => [
+ // The right arrow defined by the theme.
+ 'type' => PARAM_RAW,
+ ],
];
}
* @return array Keys are the property names, values are their values.
*/
protected function get_other_values(renderer_base $output) {
+ $previousperiod = $this->get_previous_month_timestamp();
+ $nextperiod = $this->get_next_month_timestamp();
+
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),
- 'time' => $this->calendar->time
+ 'view' => 'month',
+ 'time' => $this->calendar->time,
+ 'periodname' => userdate($this->calendar->time, get_string('strftimemonthyear')),
+ 'previousperiod' => $previousperiod,
+ 'previousperiodname' => userdate($previousperiod, get_string('strftimemonthyear')),
+ 'nextperiod' => $nextperiod,
+ 'nextperiodname' => userdate($nextperiod, get_string('strftimemonthyear')),
+ 'larrow' => $output->larrow(),
+ 'rarrow' => $output->rarrow(),
];
}
*/
protected $postpadding = 0;
-
/**
* @var \calendar_information $calendar The calendar being displayed.
*/
* @return array Keys are the property names, values are their values.
*/
protected function get_other_values(renderer_base $output) {
+ global $CFG;
$return = [
'prepadding' => [],
'postpadding' => [],
}
$return['days'] = [];
+ $today = $this->related['type']->timestamp_to_date_array(time());
+
+ $weekend = CALENDAR_DEFAULT_WEEKEND;
+ if (isset($CFG->calendar_weekend)) {
+ $weekend = intval($CFG->calendar_weekend);
+ }
+ $numberofdaysinweek = $this->related['type']->get_num_weekdays();
+
foreach ($this->days as $daydata) {
$events = [];
foreach ($this->related['events'] as $event) {
$events[] = $event;
}
- $day = new week_day_exporter($daydata, [
+ $istoday = true;
+ $istoday = $istoday && $today['year'] == $daydata['year'];
+ $istoday = $istoday && $today['yday'] == $daydata['yday'];
+ $daydata['istoday'] = $istoday;
+
+ $daydata['isweekend'] = !!($weekend & (1 << ($daydata['wday'] % $numberofdaysinweek)));
+
+ $day = new week_day_exporter($this->calendar, $daydata, [
'events' => $events,
'cache' => $this->related['cache'],
'type' => $this->related['type'],
// Class and cell content.
if (isset($typesbyday[$day]['startglobal'])) {
- $class .= ' calendar_event_global';
+ $class .= ' calendar_event_site';
} else if (isset($typesbyday[$day]['startcourse'])) {
$class .= ' calendar_event_course';
} else if (isset($typesbyday[$day]['startgroup'])) {
$monthdays = $type->get_num_days_in_month($date['year'], $date['mon']);
$tend = $tstart + ($monthdays * DAYSECS) - 1;
$selectortitle = get_string('detailedmonthviewfor', 'calendar');
+ if ($view === 'mini') {
+ $template = 'core_calendar/calendar_mini';
+ } else {
+ $template = 'core_calendar/calendar_month';
+ }
}
list($userparam, $groupparam, $courseparam) = array_map(function($param) {
$month = new \core_calendar\external\month_exporter($calendar, $type, $related);
$data = $month->export($renderer);
- $template = 'core_calendar/calendar_month';
return [$data, $template];
}
return [$data, $template];
}
+
+/**
+ * Get the list of potential calendar filter types as a type => name
+ * combination.
+ *
+ * @return array
+ */
+function calendar_get_filter_types() {
+ $types = [
+ 'site',
+ 'course',
+ 'group',
+ 'user',
+ ];
+
+ return array_map(function($type) {
+ return [
+ 'type' => $type,
+ 'name' => get_string("eventtype{$type}", "calendar"),
+ ];
+ }, $types);
+}
$html .= html_writer::end_tag('form');
return $html;
}
+
+ /**
+ * Render the event filter region.
+ *
+ * @return string
+ */
+ public function event_filter() {
+ $data = [
+ 'eventtypes' => calendar_get_filter_types(),
+ ];
+ return $this->render_from_template('core_calendar/event_filter', $data);
+ }
}
--- /dev/null
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template calendar/calendar_mini
+
+ Calendar month view for blocks.
+
+ The purpose of this template is to render the month view for blocks.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Example context (json):
+ {
+ }
+}}
+<div{{!
+ }} id="calendar-month-{{uniqid}}-{{time}}" {{!
+ }} data-template="core_calendar/month_mini" {{!
+ }} data-includenavigation="{{#includenavigation}}true{{/includenavigation}}{{^includenavigation}}false{{/includenavigation}}"{{!
+ }}>
+ {{> core_calendar/month_mini}}
+</div>
+{{#js}}
+require(['jquery', 'core_calendar/calendar_mini'], function($, CalendarMini) {
+ CalendarMini.init($("#calendar-month-{{uniqid}}-{{time}}"));
+});
+{{/js}}
--- /dev/null
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template calendar/event_filter
+
+ Filter to select which event types displayed on this page.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Example context (json):
+ {
+ }
+}}
+<div id="event-filter-{{uniqid}}" class="calendar_filters m-t-2">
+ <ul>
+ {{#eventtypes}}
+ <li>
+ {{> core_calendar/event_filter_key }}
+ </li>
+ {{/eventtypes}}
+ </ul>
+</div>
+{{#js}}
+require(['jquery', 'core_calendar/calendar_filter'], function($, CalendarFilter) {
+ CalendarFilter.init($("#event-filter-{{uniqid}}"));
+});
+{{/js}}
--- /dev/null
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template calendar/event_filter_key
+
+ Key item for the event filter.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Example context (json):
+ {
+ }
+}}
+<a href="#" data-action="filter-event-type" data-eventtype="{{type}}" data-eventtype-hidden="{{hidden}}">
+ {{^hidden}}
+ <span class="calendar_event_{{type}}">
+ {{#pix}}i/hide, core, {{#str}}hideeventtype, calendar, {{name}}{{/str}}{{/pix}}
+ </span>
+ <span class="eventname">{{#str}}hideeventtype, calendar, {{name}}{{/str}}</span>
+ {{/hidden}}
+ {{#hidden}}
+ <span class="calendar_event_{{type}}">
+ {{#pix}}i/show, core, {{#str}}showeventtype, calendar, {{name}}{{/str}}{{/pix}}
+ </span>
+ <span class="eventname">{{#str}}showeventtype, calendar, {{name}}{{/str}}</span>
+ {{/hidden}}
+</a>
}}
{{< core/hover_tooltip }}
{{$anchor}}
- <a href="{{url}}">{{day}}</a>
+ <a href="{{url}}">{{$day}}{{day}}{{/day}}</a>
{{/anchor}}
{{$tooltip}}
- <b>{{title}}</b>
- {{{content}}}
+ <b>{{$title}}{{title}}{{/title}}</b>
+ {{$content}}{{{content}}}{{/content}}
{{/tooltip}}
{{/ core/hover_tooltip }}
--- /dev/null
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template calendar/month_mini
+
+ Calendar month view for blocks.
+
+ The purpose of this template is to render the month view for blocks.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Example context (json):
+ {
+ }
+}}
+<div id="month-mini-{{uniqid}}-{{time}}" class="calendarwrapper" data-courseid="{{courseid}}" data-current-time="{{time}}">
+ {{> core/overlay_loading}}
+ <table class="minicalendar calendartable">
+ <caption class="calendar-controls">
+ <a href="#" class="arrow_link previous" title="{{#str}}monthprev, calendar{{/str}}" data-time="{{previousperiod}}"><span class="arrow">{{{larrow}}}</span></a>
+ <span class="hide"> | </span>
+ <span class="current">
+ <a href="{{{url}}}" title="{{#str}}monththis, calendar{{/str}}" data-time="">{{periodname}}</a>
+ </span>
+ <span class="hide"> | </span>
+ <a href="#" class="arrow_link next" title="{{#str}}monthnext, calendar{{/str}}" data-time="{{nextperiod}}"><span class="arrow">{{{rarrow}}}</span></a>
+ </caption>
+ <thead>
+ <tr>
+ {{# daynames }}
+ <th class="header text-xs-center" scope="col">
+ <abbr title="{{fullname}}">{{shortname}}</abbr>
+ </th>
+ {{/ daynames }}
+ </tr>
+ </thead>
+ <tbody>
+{{#weeks}}
+ <tr data-region="month-view-week">
+ {{#prepadding}}
+ <td class="dayblank"> </td>
+ {{/prepadding}}
+ {{#days}}
+ <td class="day text-center{{!
+ This is the list of additional classes to display.
+
+ This cell is for today.
+ }}{{#istoday}} today{{/istoday}}{{!
+
+ This day falls on a weekend.
+ }}{{#isweekend}} weekend{{/isweekend}}{{!
+
+ There is at least one event.
+ }}{{#events.0}} hasevent{{/events.0}}{{!
+
+ There are events on this day which span multiple days.
+ }}{{#durationevents.0}} duration{{/durationevents.0}}{{!
+ }}{{#durationevents}} duration_{{.}}{{/durationevents}}{{!
+ }}{{#islastday}} duraction_finish{{/islastday}}{{!
+
+ These event types fall on this day.
+ }}{{#calendareventtypes}}{{!
+ }} calendar_event_{{.}}{{!
+ }}{{/calendareventtypes}}{{!
+
+ This day contains the last day of an event.
+ }}{{#haslastdayofevent}}{{!
+ }} duration_finish{{!
+ }}{{/haslastdayofevent}}{{!
+ }}"{{!
+
+ Add data-eventtype-[eventtype] data attributes.
+ These are used to show and hide events using the filter.
+ }}{{#calendareventtypes}}{{!
+ }} data-eventtype-{{.}}="1"{{!
+ }}{{/calendareventtypes}}{{!
+
+ This is the timestamp for this month.
+ }} data-day-timestamp="{{timestamp}}"{{!
+ }}>{{!
+ }}{{#popovertitle}}
+ {{< core_calendar/minicalendar_day_link }}
+ {{$day}}{{mday}}{{/day}}
+ {{$url}}{{viewdaylink}}{{/url}}
+ {{$title}}{{popovertitle}}{{/title}}
+ {{$nocontent}}{{#str}}eventnone, calendar{{/str}}{{/nocontent}}
+ {{$content}}
+ {{#events}}
+ <div data-popover-eventtype-{{calendareventtype}}="1">
+ {{#modulename}}
+ {{#pix}} icon, {{modulename}} {{/pix}}
+ {{/modulename}}
+ {{^modulename}}
+ {{#pix}} i/{{eventtype}}event, core {{/pix}}
+ {{/modulename}}
+ {{{popupname}}}
+ </div>
+ {{/events}}
+ {{/content}}
+ {{/ core_calendar/minicalendar_day_link }}
+ {{/popovertitle}}{{!
+ }}{{^popovertitle}}
+ {{mday}}
+ {{/popovertitle}}{{!
+ }}</td>
+ {{/days}}
+ {{#postpadding}}
+ <td class="dayblank"> </td>
+ {{/postpadding}}
+ </tr>
+{{/weeks}}
+ </tbody>
+ </table>
+</div>
+{{#js}}
+require([
+ 'jquery',
+ 'core_calendar/selectors',
+ 'core_calendar/events',
+], function(
+ $,
+ CalendarSelectors,
+ CalendarEvents
+) {
+
+ $('body').on(CalendarEvents.filterChanged, function(e, data) {
+ M.util.js_pending("month-mini-{{uniqid}}-filterChanged");
+ // A filter value has been changed.
+ // Find all matching cells in the popover data, and hide them.
+ $("#month-mini-{{uniqid}}-{{time}}")
+ .find(CalendarSelectors.popoverType[data.type])
+ .toggleClass('hidden', !!data.hidden);
+ M.util.js_complete("month-mini-{{uniqid}}-filterChanged");
+ });
+});
+{{/js}}
* @param int $day The day of the current month
*/
public function i_hover_over_day_of_this_month_in_calendar($day) {
- $summarytitle = get_string('calendarheading', 'calendar', userdate(time(), get_string('strftimemonthyear')));
+ $summarytitle = userdate(time(), get_string('strftimemonthyear'));
// The current month table.
- $currentmonth = "table[contains(concat(' ', normalize-space(@summary), ' '), ' {$summarytitle} ')]";
+ $currentmonth = "table[descendant::*[self::caption[contains(concat(' ', normalize-space(.), ' '), ' {$summarytitle} ')]]]";
// Strings for the class cell match.
$cellclasses = "contains(concat(' ', normalize-space(@class), ' '), ' day ')";
$dayofmonth = "a[{$daycontains}]";
$xpath = '//' . $currentmonth . '/descendant::' . $daycell . '/' . $dayofmonth;
+ $this->execute("behat_general::wait_until_the_page_is_ready");
$this->execute("behat_general::i_hover", array($xpath, "xpath_element"));
}
$string['activityprev'] = 'Previous activity';
$string['breadcrumb'] = 'Breadcrumb trail';
$string['hideblocka'] = 'Hide {$a} block';
-$string['monthnext'] = 'Next month';
-$string['monthprev'] = 'Previous month';
$string['showblocka'] = 'Show {$a} block';
$string['sitemap'] = 'Site map';
$string['skipa'] = 'Skip {$a}';
$string['tocontent'] = 'Skip to main content';
$string['tonavigation'] = 'Go to navigation';
$string['youarehere'] = 'You are here';
+
+// Deprecated since Moodle 3.4.
+$string['monthnext'] = 'Next month';
+$string['monthprev'] = 'Previous month';
$string['eventdescription'] = 'Description';
$string['eventduration'] = 'Duration';
$string['eventendtime'] = 'End time';
+$string['eventendtimewrapped'] = '{$a} (End time)';
$string['eventinstanttime'] = 'Time';
$string['eventkind'] = 'Type of event';
$string['eventname'] = 'Event title';
$string['hidecourseevents'] = 'Hide course events';
$string['hideglobalevents'] = 'Hide global events';
$string['hidegroupsevents'] = 'Hide group events';
+$string['hidemoduleevents'] = 'Hide module events';
$string['hideuserevents'] = 'Hide user events';
+$string['eventtypeglobal'] = 'global';
+$string['eventtypesite'] = 'global';
+$string['eventtypecourse'] = 'course';
+$string['eventtypemodule'] = 'module';
+$string['eventtypegroup'] = 'group';
+$string['eventtypeuser'] = 'user';
+$string['hideeventtype'] = 'Hide {$a} events';
+$string['showeventtype'] = 'Show {$a} events';
$string['hourly'] = 'Hourly';
$string['ical'] = 'iCal';
$string['importcalendar'] = 'Import calendar';
$string['monthly'] = 'Monthly';
$string['monthlyview'] = 'Monthly view';
$string['monthnext'] = 'Next month';
+$string['monthprev'] = 'Previous month';
$string['monththis'] = 'This month';
$string['more'] = 'More';
-$string['namewithsource'] = '{$a->name}({$a->source})';
+$string['namewithsource'] = '{$a->name} ({$a->source})';
$string['never'] = 'Never';
$string['newevent'] = 'New event';
$string['notitle'] = 'no title';
$string['timeformat_24'] = '24-hour';
$string['timeperiod'] = 'Time period';
$string['today'] = 'Today';
+$string['todayplustitle'] = 'Today {$a}';
$string['tomorrow'] = 'Tomorrow';
$string['tt_deleteevent'] = 'Delete event';
$string['tt_editevent'] = 'Edit event';
signinwithyouremail,core_badges
sectionusedefaultname,core
registermoochtips,core_hub
+monthnext,core_access
+monthprev,core_access
}
}
}
+
+.calendarwrapper {
+ position: relative;
+}
+
+.day-popover-content {
+ &:empty + .day-popover-alternate {
+ display: block;
+ }
+}
"content": "<img class='icon smallicon' src='../../../pix/i/siteevent.svg'>Test site event"
}
}}
-<a href="{{url}}"
- data-container="body"
- data-toggle="popover"
- data-html="true"
- data-trigger="hover"
- data-placement="top"
- data-title="{{title}}"
- data-content="{{content}}"
->{{day}}</a>
+<a {{!
+ }} id="calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}"{{!
+ }} href="{{$url}}{{url}}{{/url}}"{{!
+ }} data-container="body"{{!
+ }} data-toggle="popover"{{!
+ }} data-html="true"{{!
+ }} data-trigger="hover"{{!
+ }} data-placement="top"{{!
+ }} data-title="{{$title}}{{title}}{{/title}}"{{!
+ }} data-alternate="{{$nocontent}}{{/nocontent}}"{{!
+}}>{{$day}}{{day}}{{/day}}</a>
+<div class="hidden">
+ {{$content}}{{/content}}
+</div>
+{{#js}}
+require(['jquery'], function($) {
+ require(['theme_boost/popover'], function() {
+ var target = $("#calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}");
+ target.popover({
+ content: function() {
+ var source = target.next().find("> *:not('.hidden')");
+ var content = $('<div>');
+
+ if (source.length) {
+ content.html(source.clone(false));
+ } else {
+ content.html(target.data('alternate'));
+ }
+
+ return content.html();
+ }
+ });
+ });
+});
+{{/js}}
}
}
}
+
+
+.calendarwrapper {
+ position: relative;
+}
min-width: 1024px;
}
}
+.calendarwrapper {
+ position: relative;
+}
/* course.less */
/* COURSE CONTENT */
/* stylelint-disable unit-blacklist */
"content": "<img class='icon smallicon' src='../../../pix/i/siteevent.svg'>Test site event"
}
}}
-<a id="{{uniqid}}" href="{{url}}"
- data-container="body"
- data-toggle="popover"
- data-html="true"
- data-trigger="hover"
- data-placement="top"
- data-title="{{title}}"
- data-content="{{content}}">{{day}}</a>
+<a {{!
+ }} href="{{url}}"{{!
+ }} id="calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}"{{!
+ }} data-container="body"{{!
+ }} data-toggle="popover"{{!
+ }} data-html="true"{{!
+ }} data-trigger="hover"{{!
+ }} data-placement="top"{{!
+ }} data-title="{{$title}}{{title}}{{/title}}"{{!
+ }} data-alternate="{{$nocontent}}{{/nocontent}}"{{!
+}}>{{$day}}{{day}}{{/day}}</a>
+<div class="hidden">
+ {{$content}}{{/content}}
+</div>
{{#js}}
-require(['jquery'], function($) {
+require(['jquery', 'theme_bootstrapbase/bootstrap'], function($) {
require(['theme_bootstrapbase/bootstrap'], function() {
- $('#{{uniqid}}').popover();
+ var target = $("#calendar-day-popover-link-{{courseid}}-{{year}}-{{yday}}-{{uniqid}}");
+ target.popover({
+ content: function() {
+ var source = target.next().find("> *:not('.hidden')");
+ var content = $('<div>');
+
+ if (source.length) {
+ content.html(source.clone(false));
+ } else {
+ content.html(target.data('alternate'));
+ }
+
+ return content.html();
+ }
+ });
});
});
{{/js}}