ea3e4172d08d332f3d9e358c7550f0f1abf45078
[moodle.git] / calendar / amd / src / event_form.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * A javascript module to enhance the event form.
18  *
19  * @module     core_calendar/event_form
20  * @package    core_calendar
21  * @copyright  2017 Ryan Wyllie <ryan@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 define(['jquery', 'core/templates'], function($, Templates) {
26     var SELECTORS = {
27         EVENT_TYPE: '[name="eventtype"]',
28         EVENT_COURSE_ID: '[name="courseid"]',
29         EVENT_GROUP_COURSE_ID: '[name="groupcourseid"]',
30         EVENT_GROUP_ID: '[name="groupid"]',
31         FORM_GROUP: '.form-group',
32         SELECT_OPTION: 'option',
33         ADVANCED_ELEMENT: '.fitem.advanced',
34         FIELDSET_ADVANCED_ELEMENTS: 'fieldset.containsadvancedelements',
35         MORELESS_TOGGLE: '.moreless-actions'
36     };
38     var EVENTS = {
39         SHOW_ADVANCED: 'event_form-show-advanced',
40         HIDE_ADVANCED: 'event_form-hide-advanced',
41         ADVANCED_SHOWN: 'event_form-advanced-shown',
42         ADVANCED_HIDDEN: 'event_form-advanced-hidden',
43     };
45     /**
46      * Find the old show more / show less toggle added by the mform and destroy it.
47      * We are handling the visibility of the advanced fields with the more/less button
48      * in the footer of the modal that this form is rendered within.
49      *
50      * @method destroyOldMoreLessToggle
51      * @param {object} formElement The root form element
52      */
53     var destroyOldMoreLessToggle = function(formElement) {
54         formElement.find(SELECTORS.FIELDSET_ADVANCED_ELEMENTS).removeClass('containsadvancedelements');
55         var element = formElement.find(SELECTORS.MORELESS_TOGGLE);
56         Templates.replaceNode(element, '', '');
57     };
59     /**
60      * Find each of the advanced form elements and make them visible.
61      *
62      * This function triggers the ADVANCED_SHOWN event for any other
63      * component to handle (e.g. the event form modal).
64      *
65      * @method destroyOldMoreLessToggle
66      * @param {object} formElement The root form element
67      */
68     var showAdvancedElements = function(formElement) {
69         formElement.find(SELECTORS.ADVANCED_ELEMENT).removeClass('hidden');
70         formElement.trigger(EVENTS.ADVANCED_SHOWN);
71     };
73     /**
74      * Find each of the advanced form elements and hide them.
75      *
76      * This function triggers the ADVANCED_HIDDEN event for any other
77      * component to handle (e.g. the event form modal).
78      *
79      * @method hideAdvancedElements
80      * @param {object} formElement The root form element
81      */
82     var hideAdvancedElements = function(formElement) {
83         formElement.find(SELECTORS.ADVANCED_ELEMENT).addClass('hidden');
84         formElement.trigger(EVENTS.ADVANCED_HIDDEN);
85     };
87     /**
88      * Listen for any events telling this module to show or hide it's
89      * advanced elements.
90      *
91      * This function listens for SHOW_ADVANCED and HIDE_ADVANCED.
92      *
93      * @method listenForShowHideEvents
94      * @param {object} formElement The root form element
95      */
96     var listenForShowHideEvents = function(formElement) {
97         formElement.on(EVENTS.SHOW_ADVANCED, function() {
98             showAdvancedElements(formElement);
99         });
101         formElement.on(EVENTS.HIDE_ADVANCED, function() {
102             hideAdvancedElements(formElement);
103         });
104     };
106     /**
107      * Parse the group id select element in the event form and pull out
108      * the course id from the value to allow us to toggle other select
109      * elements based on the course id for the group a user selects.
110      *
111      * This is a little hacky but I couldn't find a better way to pass
112      * the course id for each group id with the limitations of mforms.
113      *
114      * The group id options are rendered with a value like:
115      * "<courseid>-<groupid>"
116      * E.g.
117      * For a group with id 10 in a course with id 3 the value of the
118      * option will be 3-10.
119      *
120      * @method parseGroupSelect
121      * @param {object} formElement The root form element
122      */
123     var parseGroupSelect = function(formElement) {
124         formElement.find(SELECTORS.EVENT_GROUP_ID)
125             .find(SELECTORS.SELECT_OPTION)
126             .each(function(index, element) {
127                 element = $(element);
128                 var value = element.attr('value');
129                 var splits = value.split('-');
130                 var courseId = splits[0];
132                 element.attr('data-course-id', courseId);
133             });
134     };
136     /**
137      * Listen for when the user changes the group course when configuring
138      * a group event and filter the options in the group select to only
139      * show the groups available within the course the user has selected.
140      *
141      * @method addCourseGroupSelectListeners
142      * @param {object} formElement The root form element
143      */
144     var addCourseGroupSelectListeners = function(formElement) {
145         var courseGroupSelect = formElement.find(SELECTORS.EVENT_GROUP_COURSE_ID);
146         var groupSelect = formElement.find(SELECTORS.EVENT_GROUP_ID);
147         var groupSelectOptions = groupSelect.find(SELECTORS.SELECT_OPTION);
148         var filterGroupSelectOptions = function() {
149             var selectedCourseId = courseGroupSelect.val();
150             var selectedIndex = null;
152             groupSelectOptions.each(function(index, element) {
153                 element = $(element);
155                 if (element.attr('data-course-id') == selectedCourseId) {
156                     element.removeClass('hidden');
157                     element.prop('disabled', false);
159                     if (selectedIndex === null || element.attr('selected')) {
160                         selectedIndex = index;
161                     }
162                 } else {
163                     element.addClass('hidden');
164                     element.prop('disabled', true);
165                 }
166             });
168             groupSelect.prop('selectedIndex', selectedIndex);
169         };
171         courseGroupSelect.on('change', filterGroupSelectOptions);
172         filterGroupSelectOptions();
173     };
175     /**
176      * Initialise all of the form enhancements.
177      *
178      * @method init
179      * @param {string} formId The value of the form's id attribute
180      * @param {bool} hasError If the form has errors rendered form the server.
181      */
182     var init = function(formId, hasError) {
183         var formElement = $('#' + formId);
185         listenForShowHideEvents(formElement);
186         destroyOldMoreLessToggle(formElement);
187         parseGroupSelect(formElement);
188         addCourseGroupSelectListeners(formElement);
190         // If we know that the form has been rendered with server side
191         // errors then we need to display all of the elements in the form
192         // in case one of those elements has the error.
193         if (hasError) {
194             showAdvancedElements(formElement);
195         } else {
196             hideAdvancedElements(formElement);
197         }
198     };
200     return {
201         init: init,
202         events: EVENTS,
203     };
204 });