on-demand release 4.0dev+
[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  * @deprecated since Moodle 4.0
20  * @todo Final deprecation on Moodle 4.4 MDL-72438
21  * @module     core_question/edit_tags
22  * @copyright  2018 Simey Lameze <simey@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
25 define([
26             'jquery',
27             'core/fragment',
28             'core/str',
29             'core/modal_events',
30             'core/modal_factory',
31             'core/notification',
32             'core/custom_interaction_events',
33             'core_question/repository',
34             'core_question/selectors',
35         ],
36         function(
37             $,
38             Fragment,
39             Str,
40             ModalEvents,
41             ModalFactory,
42             Notification,
43             CustomEvents,
44             Repository,
45             QuestionSelectors
46         ) {
48     /**
49      * Enable the save button in the footer.
50      *
51      * @param {object} root The container element.
52      * @method enableSaveButton
53      */
54     var enableSaveButton = function(root) {
55         root.find(QuestionSelectors.actions.save).prop('disabled', false);
56     };
58     /**
59      * Disable the save button in the footer.
60      *
61      * @param {object} root The container element.
62      * @method disableSaveButton
63      */
64     var disableSaveButton = function(root) {
65         root.find(QuestionSelectors.actions.save).prop('disabled', true);
66     };
68     /**
69      * Get the serialised form data.
70      *
71      * @method getFormData
72      * @param {object} modal The modal object.
73      * @return {string} serialised form data
74      */
75     var getFormData = function(modal) {
76         return modal.getBody().find('form').serialize();
77     };
79     /**
80      * Set the element state to loading.
81      *
82      * @param {object} root The container element
83      * @method startLoading
84      */
85     var startLoading = function(root) {
86         var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
88         loadingIconContainer.removeClass('hidden');
89     };
91     /**
92      * Remove the loading state from the element.
93      *
94      * @param {object} root The container element
95      * @method stopLoading
96      */
97     var stopLoading = function(root) {
98         var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
100         loadingIconContainer.addClass('hidden');
101     };
103     /**
104      * Set the context Id data attribute on the modal.
105      *
106      * @param {Promise} modal The modal promise.
107      * @param {int} contextId The context id.
108      */
109     var setContextId = function(modal, contextId) {
110         modal.getBody().attr('data-contextid', contextId);
111     };
113     /**
114      * Get the context Id data attribute value from the modal body.
115      *
116      * @param {Promise} modal The modal promise.
117      * @return {int} The context id.
118      */
119     var getContextId = function(modal) {
120         return modal.getBody().data('contextid');
121     };
123     /**
124      * Set the question Id data attribute on the modal.
125      *
126      * @param {Promise} modal The modal promise.
127      * @param {int} questionId The question Id.
128      */
129     var setQuestionId = function(modal, questionId) {
130         modal.getBody().attr('data-questionid', questionId);
131     };
133     /**
134      * Get the question Id data attribute value from the modal body.
135      *
136      * @param {Promise} modal The modal promise.
137      * @return {int} The question Id.
138      */
139     var getQuestionId = function(modal) {
140         return modal.getBody().data('questionid');
141     };
143     /**
144      * Register event listeners for the module.
145      *
146      * @param {object} root The calendar root element
147      */
148     var registerEventListeners = function(root) {
149         var modalPromise = ModalFactory.create(
150             {
151                 type: ModalFactory.types.SAVE_CANCEL,
152                 large: false
153             },
154             [root, QuestionSelectors.actions.edittags]
155         ).then(function(modal) {
156             // All of this code only executes once, when the modal is
157             // first created. This allows us to add any code that should
158             // only be run once, such as adding event handlers to the modal.
159             Str.get_string('questiontags', 'question')
160                 .then(function(string) {
161                     modal.setTitle(string);
162                     return string;
163                 })
164                 .fail(Notification.exception);
166             modal.getRoot().on(ModalEvents.save, function(e) {
167                 var form = modal.getBody().find('form');
168                 form.submit();
169                 e.preventDefault();
170             });
172             modal.getRoot().on('submit', 'form', function(e) {
173                 save(modal, root).then(function() {
174                     modal.hide();
175                     location.reload();
176                     return;
177                 }).fail(Notification.exception);
179                 // Stop the form from actually submitting and prevent it's
180                 // propagation because we have already handled the event.
181                 e.preventDefault();
182                 e.stopPropagation();
183             });
185             return modal;
186         });
188         // We need to add an event handler to the tags link because there are
189         // multiple links on the page and without adding a listener we don't know
190         // which one the user clicked on the show the modal.
191         root.on(CustomEvents.events.activate, QuestionSelectors.actions.edittags, function(e) {
192             var currentTarget = $(e.currentTarget);
194             var questionId = currentTarget.data('questionid'),
195                 canTag = !!currentTarget.data('cantag'),
196                 contextId = currentTarget.data('contextid');
198             // This code gets called each time the user clicks the tag link
199             // so we can use it to reload the contents of the tag modal.
200             modalPromise.then(function(modal) {
201                 // Display spinner and disable save button.
202                 disableSaveButton(root);
203                 startLoading(root);
205                 var args = {
206                     id: questionId
207                 };
209                 var tagsFragment = Fragment.loadFragment('question', 'tags_form', contextId, args);
210                 modal.setBody(tagsFragment);
212                 tagsFragment.then(function() {
213                         enableSaveButton(root);
214                         return;
215                     })
216                     .always(function() {
217                         // Always hide the loading spinner when the request
218                         // has completed.
219                         stopLoading(root);
220                         return;
221                     })
222                 .fail(Notification.exception);
224                 // Show or hide the save button depending on whether the user
225                 // has the capability to edit the tags.
226                 if (canTag) {
227                     modal.getRoot().find(QuestionSelectors.actions.save).show();
228                 } else {
229                     modal.getRoot().find(QuestionSelectors.actions.save).hide();
230                 }
232                 setQuestionId(modal, questionId);
233                 setContextId(modal, contextId);
235                 return modal;
236             }).fail(Notification.exception);
238             e.preventDefault();
239         });
240     };
242     /**
243      * Send the form data to the server to save question tags.
244      *
245      * @method save
246      * @param {object} modal The modal object.
247      * @param {object} root The container element.
248      * @return {object} A promise
249      */
250     var save = function(modal, root) {
251         // Display spinner and disable save button.
252         disableSaveButton(root);
253         startLoading(root);
255         var formData = getFormData(modal);
256         var questionId = getQuestionId(modal);
257         var contextId = getContextId(modal);
259         // Send the form data to the server for processing.
260         return Repository.submitTagCreateUpdateForm(questionId, contextId, formData)
261             .always(function() {
262                 // Regardless of success or error we should always stop
263                 // the loading icon and re-enable the buttons.
264                 stopLoading(root);
265                 enableSaveButton(root);
266                 return;
267             })
268             .fail(Notification.exception);
269     };
271     return {
272         init: function(root) {
273             window.console.warn('warn: The core_question/repository has been deprecated.' +
274                 'Please use qbank_tagquestion/repository instead.');
275             root = $(root);
276             registerEventListeners(root);
277         }
278     };
279 });