Skip to content

Commit

Permalink
MDL-60826 calendar: lazy load groups on event form
Browse files Browse the repository at this point in the history
  • Loading branch information
lameze committed Jul 23, 2018
1 parent 633c5ff commit dfc609e
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 125 deletions.
2 changes: 1 addition & 1 deletion calendar/amd/build/event_form.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion calendar/amd/build/repository.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 21 additions & 63 deletions calendar/amd/src/event_form.js
Expand Up @@ -21,42 +21,12 @@
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery'], function($) {
define(['jquery', 'core_calendar/repository'], function($, CalendarRepository) {

var SELECTORS = {
EVENT_GROUP_COURSE_ID: '[name="groupcourseid"]',
EVENT_GROUP_ID: '[name="groupid"]',
SELECT_OPTION: 'option',
};

/**
* Parse the group id select element in the event form and pull out
* the course id from the value to allow us to toggle other select
* elements based on the course id for the group a user selects.
*
* This is a little hacky but I couldn't find a better way to pass
* the course id for each group id with the limitations of mforms.
*
* The group id options are rendered with a value like:
* "<courseid>-<groupid>"
* E.g.
* For a group with id 10 in a course with id 3 the value of the
* option will be 3-10.
*
* @method parseGroupSelect
* @param {object} formElement The root form element
*/
var parseGroupSelect = function(formElement) {
formElement.find(SELECTORS.EVENT_GROUP_ID)
.find(SELECTORS.SELECT_OPTION)
.each(function(index, element) {
element = $(element);
var value = element.attr('value');
var splits = value.split('-');
var courseId = splits[0];

element.attr('data-course-id', courseId);
});
SELECT_OPTION: 'option'
};

/**
Expand All @@ -69,39 +39,29 @@ define(['jquery'], function($) {
*/
var addCourseGroupSelectListeners = function(formElement) {
var courseGroupSelect = formElement.find(SELECTORS.EVENT_GROUP_COURSE_ID);
var groupSelect = formElement.find(SELECTORS.EVENT_GROUP_ID);
var groupSelectOptions = groupSelect.find(SELECTORS.SELECT_OPTION);
var filterGroupSelectOptions = function() {
var selectedCourseId = courseGroupSelect.val();
var selectedIndex = null;
var hasGroups = false;
groupSelectOptions.each(function(index, element) {
element = $(element);

if (element.attr('data-course-id') == selectedCourseId) {
element.removeClass('hidden');
element.prop('disabled', false);
hasGroups = true;
if (selectedIndex === null || element.attr('selected')) {
selectedIndex = index;
}
} else {
element.addClass('hidden');
element.prop('disabled', true);
}
});
var loadGroupSelectOptions = function(groups) {
var groupSelect = formElement.find(SELECTORS.EVENT_GROUP_ID),
groupSelectOptions = groupSelect.find(SELECTORS.SELECT_OPTION),
courseGroups = $(groups);

if (hasGroups) {
groupSelect.prop('disabled', false);
} else {
groupSelect.prop('disabled', true);
}

groupSelect.prop('selectedIndex', selectedIndex);
// Let's clear all options first.
groupSelectOptions.remove();
groupSelect.prop("disabled", false);
courseGroups.each(function(id, group) {
$(groupSelect).append($("<option></option>").attr("value", group.id).text(group.name));
});
};

courseGroupSelect.on('change', filterGroupSelectOptions);
filterGroupSelectOptions();
// If the user choose a course in the selector do a WS request to get groups.
courseGroupSelect.on('change', function() {
var courseId = formElement.find(SELECTORS.EVENT_GROUP_COURSE_ID).val();
CalendarRepository.getCourseGroupsData(courseId)
.then(function(groups) {
return loadGroupSelectOptions(groups);
})
.catch(Notification.exception);
});
};

/**
Expand All @@ -112,8 +72,6 @@ define(['jquery'], function($) {
*/
var init = function(formId) {
var formElement = $('#' + formId);

parseGroupSelect(formElement);
addCourseGroupSelectListeners(formElement);
};

Expand Down
20 changes: 19 additions & 1 deletion calendar/amd/src/repository.js
Expand Up @@ -181,13 +181,31 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
return Ajax.call([request])[0];
};

/**
* Get the groups by course id.
*
* @param {Number} courseid The course id to fetch the groups from.
* @return {promise} Resolved with the course groups.
*/
var getCourseGroupsData = function(courseid) {
var request = {
methodname: 'core_group_get_course_groups',
args: {
courseid: courseid
}
};

return Ajax.call([request])[0];
};

return {
getEventById: getEventById,
deleteEvent: deleteEvent,
updateEventStartDay: updateEventStartDay,
submitCreateUpdateForm: submitCreateUpdateForm,
getCalendarMonthData: getCalendarMonthData,
getCalendarDayData: getCalendarDayData,
getCalendarUpcomingData: getCalendarUpcomingData
getCalendarUpcomingData: getCalendarUpcomingData,
getCourseGroupsData: getCourseGroupsData
};
});
26 changes: 17 additions & 9 deletions calendar/classes/local/event/forms/create.php
Expand Up @@ -66,9 +66,11 @@ public function definition() {
$mform = $this->_form;
$starttime = isset($this->_customdata['starttime']) ? $this->_customdata['starttime'] : 0;
$editoroptions = !(empty($this->_customdata['editoroptions'])) ? $this->_customdata['editoroptions'] : null;
$eventtypes = calendar_get_all_allowed_types();
$courseid = !(empty($this->_customdata['courseid'])) ? $this->_customdata['courseid'] : null;

if (empty($eventtypes)) {
$eventtypes = calendar_get_allowed_event_types($courseid);

if (in_array(true, $eventtypes, true) === false) {
print_error('nopermissiontoupdatecalendar');
}

Expand Down Expand Up @@ -120,18 +122,20 @@ public function definition() {
* @return array
*/
public function validation($data, $files) {
global $DB, $CFG;
global $DB;

$errors = parent::validation($data, $files);
$eventtypes = calendar_get_all_allowed_types();
$eventtype = isset($data['eventtype']) ? $data['eventtype'] : null;
$coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid';
if (empty($eventtype) || !isset($eventtypes[$eventtype])) {
$courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null;
$eventtypes = calendar_get_allowed_event_types($courseid);

if (empty($eventtype) || !isset($eventtypes[$eventtype]) || $eventtypes[$eventtype] == false) {
$errors['eventtype'] = get_string('invalideventtype', 'calendar');
}

if (isset($data[$coursekey]) && $data[$coursekey] > 0) {
if ($course = $DB->get_record('course', ['id' => $data[$coursekey]])) {
if ($courseid && $courseid > 0) {
if ($course = $DB->get_record('course', ['id' => $courseid])) {
if ($data['timestart'] < $course->startdate) {
$errors['timestart'] = get_string('errorbeforecoursestart', 'calendar');
}
Expand All @@ -140,11 +144,15 @@ public function validation($data, $files) {
}
}

if ($eventtype == 'course' && empty($data['courseid'])) {
if ($eventtype == 'course' && empty($courseid)) {
$errors['courseid'] = get_string('selectacourse');
}

if ($eventtype == 'group' && empty($data['groupcourseid'])) {
if ($eventtype == 'group' && (!empty($courseid) && empty($data['groupid']))) {
$errors['groupcourseid'] = get_string('nogroups', 'core_group');
}

if ($eventtype == 'group' && empty($courseid)) {
$errors['groupcourseid'] = get_string('selectacourse');
}

Expand Down
51 changes: 23 additions & 28 deletions calendar/classes/local/event/forms/eventtype.php
Expand Up @@ -53,28 +53,29 @@ trait eventtype {
* @param array $eventtypes The available event types for the user
*/
protected function add_event_type_elements($mform, $eventtypes) {
global $DB;
$options = [];

if (isset($eventtypes['user'])) {
if (!empty($eventtypes['user'])) {
$options['user'] = get_string('user');
}
if (isset($eventtypes['group'])) {
if (!empty($eventtypes['group'])) {
$options['group'] = get_string('group');
}
if (isset($eventtypes['course'])) {
if (!empty($eventtypes['course'])) {
$options['course'] = get_string('course');
}
if (isset($eventtypes['category'])) {
if (!empty($eventtypes['category'])) {
$options['category'] = get_string('category');
}
if (isset($eventtypes['site'])) {
if (!empty($eventtypes['site'])) {
$options['site'] = get_string('site');
}

// If we only have one event type and it's 'user' event then don't bother
// rendering the select boxes because there is no choice for the user to
// make.
if (count(array_keys($eventtypes)) == 1 && isset($eventtypes['user'])) {
if (!empty($eventtypes['user']) && count($options) == 1) {
$mform->addElement('hidden', 'eventtype');
$mform->setType('eventtype', PARAM_TEXT);
$mform->setDefault('eventtype', 'user');
Expand All @@ -87,43 +88,37 @@ protected function add_event_type_elements($mform, $eventtypes) {
$mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $options);
}

if (isset($eventtypes['category'])) {
if (!empty($eventtypes['category'])) {
$categoryoptions = [];
foreach ($eventtypes['category'] as $id => $category) {
foreach (\coursecat::make_categories_list('moodle/category:manage') as $id => $category) {
$categoryoptions[$id] = $category;
}

$mform->addElement('select', 'categoryid', get_string('category'), $categoryoptions);
$mform->hideIf('categoryid', 'eventtype', 'noteq', 'category');
}

if (isset($eventtypes['course'])) {
if (!empty($eventtypes['course'])) {
$limit = !has_capability('moodle/calendar:manageentries', \context_system::instance());
$mform->addElement('course', 'courseid', get_string('course'), ['limittoenrolled' => $limit]);
$mform->hideIf('courseid', 'eventtype', 'noteq', 'course');
}

if (isset($eventtypes['group'])) {
$options = ['limittoenrolled' => true];
// Exclude courses without group.
if (isset($eventtypes['course']) && isset($eventtypes['groupcourses'])) {
$options['exclude'] = array_diff(array_keys($eventtypes['course']),
array_keys($eventtypes['groupcourses']));
}

$mform->addElement('course', 'groupcourseid', get_string('course'), $options);
if (!empty($eventtypes['group'])) {
$groups = !(empty($this->_customdata['groups'])) ? $this->_customdata['groups'] : null;
$limit = !has_capability('moodle/calendar:manageentries', \context_system::instance());
// Get the list of courses without groups to filter on the course selector.
$sql = "SELECT c.id
FROM {course} c
LEFT JOIN {groups} g ON g.courseid = c.id
GROUP BY c.id
HAVING COUNT(g.id) = 0";
$coursesnogroup = $DB->get_records_sql($sql);
$mform->addElement('course', 'groupcourseid', get_string('course'), ['limittoenrolled' => $limit,
'exclude' => array_keys($coursesnogroup)]);
$mform->hideIf('groupcourseid', 'eventtype', 'noteq', 'group');

$groupoptions = [];
foreach ($eventtypes['group'] as $group) {
// We are formatting it this way in order to provide the javascript both
// the course and group ids so that it can enhance the form for the user.
$index = "{$group->courseid}-{$group->id}";
$groupoptions[$index] = format_string($group->name, true,
['context' => \context_course::instance($group->courseid)]);
}

$mform->addElement('select', 'groupid', get_string('group'), $groupoptions);
$mform->addElement('select', 'groupid', get_string('group'), $groups);
$mform->hideIf('groupid', 'eventtype', 'noteq', 'group');
// We handle the group select hide/show actions on the event_form module.
}
Expand Down
Expand Up @@ -58,7 +58,7 @@ public function from_legacy_event_to_data(\calendar_event $legacyevent) {

if ($legacyevent->eventtype == 'group') {
// Set up the correct value for the to display on the form.
$data->groupid = "{$legacyevent->courseid}-{$legacyevent->groupid}";
$data->groupid = $legacyevent->groupid;
$data->groupcourseid = $legacyevent->courseid;
}
if ($legacyevent->eventtype == 'course') {
Expand Down Expand Up @@ -93,12 +93,8 @@ public function from_data_to_event_properties(\stdClass $data) {
$properties->courseid = $data->groupcourseid;
unset($properties->groupcourseid);
}

// Pull the group id back out of the value. The form saves the value
// as "<courseid>-<groupid>" to allow the javascript to work correctly.
if (isset($data->groupid)) {
list($courseid, $groupid) = explode('-', $data->groupid);
$properties->groupid = $groupid;
$properties->groupid = $data->groupid;
}
} else {
// Default course id if none is set.
Expand Down
20 changes: 18 additions & 2 deletions calendar/externallib.php
Expand Up @@ -865,15 +865,31 @@ public static function submit_create_update_form($formdata) {
self::validate_context($context);
parse_str($params['formdata'], $data);

$eventtype = isset($data['eventtype']) ? $data['eventtype'] : null;
$coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid';
$courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null;
$editoroptions = \core_calendar\local\event\forms\create::build_editor_options($context);
$formoptions = ['editoroptions' => $editoroptions, 'courseid' => $courseid];
if ($courseid) {
require_once($CFG->libdir . '/grouplib.php');
$groupcoursedata = groups_get_course_data($courseid);
if (!empty($groupcoursedata->groups)) {
$formoptions['groups'] = [];
foreach ($groupcoursedata->groups as $groupid => $groupdata) {
$formoptions['groups'][$groupid] = $groupdata->name;
}
}
}

if (!empty($data['id'])) {
$eventid = clean_param($data['id'], PARAM_INT);
$legacyevent = calendar_event::load($eventid);
$legacyevent->count_repeats();
$formoptions = ['event' => $legacyevent];
$formoptions['event'] = $legacyevent;
$mform = new update_event_form(null, $formoptions, 'post', '', null, true, $data);
} else {
$legacyevent = null;
$mform = new create_event_form(null, null, 'post', '', null, true, $data);
$mform = new create_event_form(null, $formoptions, 'post', '', null, true, $data);
}

if ($validateddata = $mform->get_data()) {
Expand Down

0 comments on commit dfc609e

Please sign in to comment.