Merge branch 'MDL-60547-master' of git://github.com/cescobedo/moodle
[moodle.git] / question / amd / src / edit_tags.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 handle question tags editing.
18  *
19  * @module     core_question/edit_tags
20  * @copyright  2018 Simey Lameze <simey@moodle.com>
21  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22  */
23 define([
24             'jquery',
25             'core/fragment',
26             'core/str',
27             'core/modal_events',
28             'core/modal_factory',
29             'core/notification',
30             'core/custom_interaction_events',
31             'core_question/repository',
32             'core_question/selectors',
33         ],
34         function(
35             $,
36             Fragment,
37             Str,
38             ModalEvents,
39             ModalFactory,
40             Notification,
41             CustomEvents,
42             Repository,
43             QuestionSelectors
44         ) {
46     /**
47      * Enable the save button in the footer.
48      *
49      * @param {object} root The container element.
50      * @method enableSaveButton
51      */
52     var enableSaveButton = function(root) {
53         root.find(QuestionSelectors.actions.save).prop('disabled', false);
54     };
56     /**
57      * Disable the save button in the footer.
58      *
59      * @param {object} root The container element.
60      * @method disableSaveButton
61      */
62     var disableSaveButton = function(root) {
63         root.find(QuestionSelectors.actions.save).prop('disabled', true);
64     };
66     /**
67      * Get the serialised form data.
68      *
69      * @method getFormData
70      * @param {object} modal The modal object.
71      * @return {string} serialised form data
72      */
73     var getFormData = function(modal) {
74         return modal.getBody().find('form').serialize();
75     };
77     /**
78      * Set the element state to loading.
79      *
80      * @param {object} root The container element
81      * @method startLoading
82      */
83     var startLoading = function(root) {
84         var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
86         loadingIconContainer.removeClass('hidden');
87     };
89     /**
90      * Remove the loading state from the element.
91      *
92      * @param {object} root The container element
93      * @method stopLoading
94      */
95     var stopLoading = function(root) {
96         var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
98         loadingIconContainer.addClass('hidden');
99     };
101     /**
102      * Register event listeners for the module.
103      *
104      * @param {object} root The calendar root element
105      */
106     var registerEventListeners = function(root) {
107         var modalPromise = ModalFactory.create(
108             {
109                 type: ModalFactory.types.SAVE_CANCEL,
110                 large: false
111             },
112             [root, QuestionSelectors.actions.edittags]
113         ).then(function(modal) {
114             // All of this code only executes once, when the modal is
115             // first created. This allows us to add any code that should
116             // only be run once, such as adding event handlers to the modal.
117             Str.get_string('questiontags', 'question')
118                 .then(function(string) {
119                     modal.setTitle(string);
120                     return string;
121                 })
122                 .fail(Notification.exception);
124             modal.getRoot().on(ModalEvents.save, function(e) {
125                 var form = modal.getBody().find('form');
126                 form.submit();
127                 e.preventDefault();
128             });
130             modal.getRoot().on('submit', 'form', function(e) {
131                 save(modal, root).then(function() {
132                     modal.hide();
133                     return;
134                 }).fail(Notification.exception);
136                 // Stop the form from actually submitting and prevent it's
137                 // propagation because we have already handled the event.
138                 e.preventDefault();
139                 e.stopPropagation();
140             });
142             return modal;
143         });
145         // We need to add an event handler to the tags link because there are
146         // multiple links on the page and without adding a listener we don't know
147         // which one the user clicked on the show the modal.
148         root.on(CustomEvents.events.activate, QuestionSelectors.actions.edittags, function(e) {
149             var currentTarget = $(e.currentTarget);
151             var questionId = currentTarget.data('questionid'),
152                 canTag = !!currentTarget.data('cantag'),
153                 contextId = currentTarget.data('contextid');
155             // This code gets called each time the user clicks the tag link
156             // so we can use it to reload the contents of the tag modal.
157             modalPromise.then(function(modal) {
158                 // Display spinner and disable save button.
159                 disableSaveButton(root);
160                 startLoading(root);
162                 var args = {
163                     id: questionId
164                 };
166                 var tagsFragment = Fragment.loadFragment('question', 'tags_form', contextId, args);
167                 modal.setBody(tagsFragment);
169                 tagsFragment.then(function() {
170                         enableSaveButton(root);
171                         return;
172                     })
173                     .always(function() {
174                         // Always hide the loading spinner when the request
175                         // has completed.
176                         stopLoading(root);
177                         return;
178                     })
179                 .fail(Notification.exception);
181                 // Show or hide the save button depending on whether the user
182                 // has the capability to edit the tags.
183                 if (canTag) {
184                     modal.getRoot().find(QuestionSelectors.actions.save).show();
185                 } else {
186                     modal.getRoot().find(QuestionSelectors.actions.save).hide();
187                 }
189                 return modal;
190             }).fail(Notification.exception);
192             e.preventDefault();
193         });
194     };
196     /**
197      * Send the form data to the server to save question tags.
198      *
199      * @method save
200      * @param {object} modal The modal object.
201      * @param {object} root The container element.
202      * @return {object} A promise
203      */
204     var save = function(modal, root) {
205         // Display spinner and disable save button.
206         disableSaveButton(root);
207         startLoading(root);
209         var formData = getFormData(modal);
211         // Send the form data to the server for processing.
212         return Repository.submitTagCreateUpdateForm(formData)
213             .always(function() {
214                 // Regardless of success or error we should always stop
215                 // the loading icon and re-enable the buttons.
216                 stopLoading(root);
217                 enableSaveButton(root);
218                 return;
219             })
220             .fail(Notification.exception);
221     };
223     return {
224         init: function(root) {
225             root = $(root);
226             registerEventListeners(root);
227         }
228     };
229 });