weekly release 3.5dev
[moodle.git] / question / amd / src / edit_tags.js
CommitLineData
fd5e2ead
SL
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/>.
15
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 */
23define([
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',
d1db765a 32 'core_question/selectors',
fd5e2ead
SL
33 ],
34 function(
35 $,
36 Fragment,
37 Str,
38 ModalEvents,
39 ModalFactory,
40 Notification,
41 CustomEvents,
d1db765a
SL
42 Repository,
43 QuestionSelectors
fd5e2ead
SL
44 ) {
45
fd5e2ead
SL
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) {
d1db765a 53 root.find(QuestionSelectors.actions.save).prop('disabled', false);
fd5e2ead
SL
54 };
55
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) {
d1db765a 63 root.find(QuestionSelectors.actions.save).prop('disabled', true);
fd5e2ead
SL
64 };
65
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 };
76
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) {
d1db765a 84 var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
fd5e2ead
SL
85
86 loadingIconContainer.removeClass('hidden');
87 };
88
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) {
d1db765a 96 var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon);
fd5e2ead
SL
97
98 loadingIconContainer.addClass('hidden');
99 };
100
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 },
d1db765a 112 [root, QuestionSelectors.actions.edittags]
fd5e2ead
SL
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);
123
124 modal.getRoot().on(ModalEvents.save, function(e) {
125 var form = modal.getBody().find('form');
126 form.submit();
127 e.preventDefault();
128 });
129
130 modal.getRoot().on('submit', 'form', function(e) {
131 save(modal, root).then(function() {
132 modal.hide();
133 return;
134 }).fail(Notification.exception);
135
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 });
141
142 return modal;
143 });
144
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.
d1db765a 148 root.on(CustomEvents.events.activate, QuestionSelectors.actions.edittags, function(e) {
fd5e2ead
SL
149 var currentTarget = $(e.currentTarget);
150
151 var questionId = currentTarget.data('questionid'),
e2795e86 152 canTag = !!currentTarget.data('cantag'),
fd5e2ead
SL
153 contextId = currentTarget.data('contextid');
154
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);
161
162 var args = {
163 id: questionId
164 };
165
166 var tagsFragment = Fragment.loadFragment('question', 'tags_form', contextId, args);
167 modal.setBody(tagsFragment);
168
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);
180
181 // Show or hide the save button depending on whether the user
182 // has the capability to edit the tags.
e2795e86 183 if (canTag) {
d1db765a 184 modal.getRoot().find(QuestionSelectors.actions.save).show();
fd5e2ead 185 } else {
d1db765a 186 modal.getRoot().find(QuestionSelectors.actions.save).hide();
fd5e2ead
SL
187 }
188
189 return modal;
190 }).fail(Notification.exception);
191
192 e.preventDefault();
193 });
194 };
195
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);
208
209 var formData = getFormData(modal);
210
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 };
222
223 return {
224 init: function(root) {
225 root = $(root);
226 registerEventListeners(root);
227 }
228 };
229});