MDL-62746 tag: Convert YUI modals to AMD modals
[moodle.git] / lib / amd / src / tag.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  * AJAX helper for the tag management page.
18  *
19  * @module     core/tag
20  * @package    core_tag
21  * @copyright  2015 Marina Glancy
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  * @since      3.0
24  */
25 define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/modal_factory', 'core/modal_events'],
26         function($, ajax, templates, notification, str, ModalFactory, ModalEvents) {
27     return /** @alias module:core/tag */ {
29         /**
30          * Initialises tag index page.
31          *
32          * @method initTagindexPage
33          */
34         initTagindexPage: function() {
35             // Click handler for changing tag type.
36             $('body').delegate('.tagarea[data-ta] a[data-quickload=1]', 'click', function(e) {
37                 e.preventDefault();
38                 var target = $(this),
39                     query = target[0].search.replace(/^\?/, ''),
40                     tagarea = target.closest('.tagarea[data-ta]'),
41                     args = query.split('&').reduce(function(s, c) {
42                       var t = c.split('=');
43                       s[t[0]] = decodeURIComponent(t[1]);
44                       return s;
45                     }, {});
47                 var promises = ajax.call([{
48                     methodname: 'core_tag_get_tagindex',
49                     args: {tagindex: args}
50                 }], true);
52                 $.when.apply($, promises)
53                     .done(function(data) {
54                         templates.render('core_tag/index', data).done(function(html) {
55                             tagarea.replaceWith(html);
56                         });
57                     });
58             });
59         },
61         /**
62          * Initialises tag management page.
63          *
64          * @method initManagePage
65          */
66         initManagePage: function() {
68             // Set cell 'time modified' to 'now' when any of the element is updated in this row.
69             $('body').on('updated', '[data-inplaceeditable]', function(e) {
70                 str.get_string('selecttag', 'core_tag', e.ajaxreturn.value)
71                     .then(function(s) {
72                         return $('label[for="tagselect' + e.ajaxreturn.itemid + '"]').html(s);
73                     })
74                     .fail(notification.exception);
75                 str.get_string('now').done(function(s) {
76                     $(e.target).closest('tr').find('td.col-timemodified').html(s);
77                 });
78                 if (e.ajaxreturn.itemtype === 'tagflag') {
79                     var row = $(e.target).closest('tr');
80                     if (e.ajaxreturn.value === '0') {
81                         row.removeClass('flagged-tag');
82                     } else {
83                         row.addClass('flagged-tag');
84                     }
85                 }
86             });
88             // Confirmation for single tag delete link.
89             $('.tag-management-table').delegate('a.tagdelete', 'click', function(e) {
90                 e.preventDefault();
91                 var href = $(this).attr('href');
92                 str.get_strings([
93                         {key: 'delete'},
94                         {key: 'confirmdeletetag', component: 'tag'},
95                         {key: 'yes'},
96                         {key: 'no'},
97                     ]).done(function(s) {
98                         notification.confirm(s[0], s[1], s[2], s[3], function() {
99                             window.location.href = href;
100                         });
101                     }
102                 );
103             });
105             // Confirmation for bulk tag delete button.
106             $("#tag-management-delete").click(function(e) {
107                 var form = $(this).closest('form').get(0),
108                     cnt = $(form).find("input[type=checkbox]:checked").length;
109                 if (!cnt) {
110                     return;
111                 }
112                 var tempElement = $("<input type='hidden'/>").attr('name', this.name);
113                 e.preventDefault();
114                 str.get_strings([
115                         {key: 'delete'},
116                         {key: 'confirmdeletetags', component: 'tag'},
117                         {key: 'yes'},
118                         {key: 'no'},
119                     ]).done(function(s) {
120                         notification.confirm(s[0], s[1], s[2], s[3], function() {
121                             tempElement.appendTo(form);
122                             form.submit();
123                         });
124                     }
125                 );
126             });
128             // Confirmation for bulk tag combine button.
129             $("#tag-management-combine").click(function(e) {
130                 e.preventDefault();
131                 var form = $(this).closest('form').get(0),
132                     tags = $(form).find("input[type=checkbox]:checked");
133                 if (tags.length <= 1) {
134                     str.get_strings([
135                         {key: 'combineselected', component: 'tag'},
136                         {key: 'selectmultipletags', component: 'tag'},
137                         {key: 'ok'},
138                     ]).done(function(s) {
139                             notification.alert(s[0], s[1], s[2]);
140                         }
141                     );
142                     return;
143                 }
144                 var tempElement = $("<input type='hidden'/>").attr('name', this.name);
145                 var saveButtonText = '';
146                 var tagOptions = [];
147                 tags.each(function() {
148                     var tagid = $(this).val(),
149                         tagname = $('.inplaceeditable[data-itemtype=tagname][data-itemid=' + tagid + ']').attr('data-value');
150                     tagOptions.push({
151                         id: tagid,
152                         name: tagname
153                     });
154                 });
156                 str.get_strings([
157                     {key: 'combineselected', component: 'tag'},
158                     {key: 'continue'}
159                 ]).then(function(langStrings) {
160                     var modalTitle = langStrings[0];
161                     saveButtonText = langStrings[1];
162                     var templateContext = {
163                         tags: tagOptions
164                     };
165                     return ModalFactory.create({
166                         title: modalTitle,
167                         body: templates.render('core_tag/combine_tags', templateContext),
168                         type: ModalFactory.types.SAVE_CANCEL
169                     });
170                 }).then(function(modal) {
171                     modal.setSaveButtonText(saveButtonText);
173                     // Handle save event.
174                     modal.getRoot().on(ModalEvents.save, function(e) {
175                         e.preventDefault();
177                         // Append this temp element in the form in the tags list, not the form in the modal. Confusing, right?!?
178                         tempElement.appendTo(form);
179                         // Get the selected tag from the modal.
180                         var maintag = $('input[name=maintag]:checked', '#combinetags_form').val();
181                         // Append this in the tags list form.
182                         $("<input type='hidden'/>").attr('name', 'maintag').attr('value', maintag).appendTo(form);
183                         // Submit the tags list form.
184                         form.submit();
185                     });
187                     // Handle hidden event.
188                     modal.getRoot().on(ModalEvents.hidden, function() {
189                         // Destroy when hidden.
190                         modal.destroy();
191                     });
193                     modal.show();
194                     // Tick the first option.
195                     $('#combinetags_form input[type=radio]').first().focus().prop('checked', true);
197                     return;
199                 }).catch(notification.exception);
200             });
202             // When user changes tag name to some name that already exists suggest to combine the tags.
203             $('body').on('updatefailed', '[data-inplaceeditable][data-itemtype=tagname]', function(e) {
204                 var exception = e.exception; // The exception object returned by the callback.
205                 var newvalue = e.newvalue; // The value that user tried to udpated the element to.
206                 var tagid = $(e.target).attr('data-itemid');
207                 if (exception.errorcode === 'namesalreadybeeingused') {
208                     e.preventDefault(); // This will prevent default error dialogue.
209                     str.get_strings([
210                         {key: 'nameuseddocombine', component: 'tag'},
211                         {key: 'yes'},
212                         {key: 'cancel'},
213                     ]).done(function(s) {
214                         notification.confirm(e.message, s[0], s[1], s[2], function() {
215                             window.location.href = window.location.href + "&newname=" + encodeURIComponent(newvalue) +
216                                 "&tagid=" + encodeURIComponent(tagid) +
217                                 '&action=renamecombine&sesskey=' + M.cfg.sesskey;
218                         });
219                     });
220                 }
221             });
223             // Form for adding standard tags.
224             $('body').on('click', 'a[data-action=addstandardtag]', function(e) {
225                 e.preventDefault();
227                 var saveButtonText = '';
228                 str.get_strings([
229                     {key: 'addotags', component: 'tag'},
230                     {key: 'continue'}
231                 ]).then(function(langStrings) {
232                     var modalTitle = langStrings[0];
233                     saveButtonText = langStrings[1];
234                     var templateContext = {
235                         actionurl: window.location.href,
236                         sesskey: M.cfg.sesskey
237                     };
238                     return ModalFactory.create({
239                         title: modalTitle,
240                         body: templates.render('core_tag/add_tags', templateContext),
241                         type: ModalFactory.types.SAVE_CANCEL
242                     });
243                 }).then(function(modal) {
244                     modal.setSaveButtonText(saveButtonText);
246                     // Handle save event.
247                     modal.getRoot().on(ModalEvents.save, function(e) {
248                         var tagsInput = $(e.currentTarget).find('#id_tagslist');
249                         var name = tagsInput.val().trim();
251                         // Set the text field's value to the trimmed value.
252                         tagsInput.val(name);
254                         // Add submit event listener to the form.
255                         var tagsForm = $('#addtags_form');
256                         tagsForm.on('submit', function(e) {
257                             // Validate the form.
258                             var form = $('#addtags_form');
259                             if (form[0].checkValidity() === false) {
260                                 e.preventDefault();
261                                 e.stopPropagation();
262                             }
263                             form.addClass('was-validated');
265                             // BS2 compatibility.
266                             $('[data-region="tagslistinput"]').addClass('error');
267                             var errorMessage = $('#id_tagslist_error_message');
268                             errorMessage.removeAttr('hidden');
269                             errorMessage.addClass('help-block');
270                         });
272                         // Try to submit the form.
273                         tagsForm.submit();
275                         return false;
276                     });
278                     // Handle hidden event.
279                     modal.getRoot().on(ModalEvents.hidden, function() {
280                         // Destroy when hidden.
281                         modal.destroy();
282                     });
284                     modal.show();
286                     return;
288                 }).catch(notification.exception);
289             });
290         },
292         /**
293          * Initialises tag collection management page.
294          *
295          * @method initManageCollectionsPage
296          */
297         initManageCollectionsPage: function() {
298             $('body').on('updated', '[data-inplaceeditable]', function(e) {
299                 var ajaxreturn = e.ajaxreturn,
300                     areaid, collid, isenabled;
301                 if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareaenable') {
302                     areaid = $(this).attr('data-itemid');
303                     $(".tag-collections-table ul[data-collectionid] li[data-areaid=" + areaid + "]").hide();
304                     isenabled = ajaxreturn.value;
305                     if (isenabled === '1') {
306                         $(this).closest('tr').removeClass('dimmed_text');
307                         collid = $(this).closest('tr').find('[data-itemtype="tagareacollection"]').attr("data-value");
308                         $(".tag-collections-table ul[data-collectionid=" + collid + "] li[data-areaid=" + areaid + "]").show();
309                     } else {
310                         $(this).closest('tr').addClass('dimmed_text');
311                     }
312                 }
313                 if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareacollection') {
314                     areaid = $(this).attr('data-itemid');
315                     $(".tag-collections-table ul[data-collectionid] li[data-areaid=" + areaid + "]").hide();
316                     collid = $(this).attr('data-value');
317                     isenabled = $(this).closest('tr').find('[data-itemtype="tagareaenable"]').attr("data-value");
318                     if (isenabled === "1") {
319                         $(".tag-collections-table ul[data-collectionid=" + collid + "] li[data-areaid=" + areaid + "]").show();
320                     }
321                 }
322             });
324             $('body').on('click', '.addtagcoll > a', function(e) {
325                 e.preventDefault();
326                 var keys = [
327                     {
328                         key: 'addtagcoll',
329                         component: 'tag'
330                     },
331                     {
332                         key: 'create'
333                     }
334                 ];
336                 var href = $(this).attr('data-url');
337                 var saveButtonText = '';
338                 str.get_strings(keys).then(function(langStrings) {
339                     var modalTitle = langStrings[0];
340                     saveButtonText = langStrings[1];
341                     var templateContext = {
342                         actionurl: href,
343                         sesskey: M.cfg.sesskey
344                     };
345                     return ModalFactory.create({
346                         title: modalTitle,
347                         body: templates.render('core_tag/add_tag_collection', templateContext),
348                         type: ModalFactory.types.SAVE_CANCEL
349                     });
350                 }).then(function(modal) {
351                     modal.setSaveButtonText(saveButtonText);
353                     // Handle save event.
354                     modal.getRoot().on(ModalEvents.save, function(e) {
355                         var collectionInput = $(e.currentTarget).find('#addtagcoll_name');
356                         var name = collectionInput.val().trim();
357                         // Set the text field's value to the trimmed value.
358                         collectionInput.val(name);
360                         // Add submit event listener to the form.
361                         var form = $('#addtagcoll_form');
362                         form.on('submit', function(e) {
363                             // Validate the form.
364                             if (form[0].checkValidity() === false) {
365                                 e.preventDefault();
366                                 e.stopPropagation();
367                             }
368                             form.addClass('was-validated');
370                             // BS2 compatibility.
371                             $('[data-region="addtagcoll_nameinput"]').addClass('error');
372                             var errorMessage = $('#id_addtagcoll_name_error_message');
373                             errorMessage.removeAttr('hidden');
374                             errorMessage.addClass('help-block');
375                         });
377                         // Try to submit the form.
378                         form.submit();
380                         return false;
381                     });
383                     // Handle hidden event.
384                     modal.getRoot().on(ModalEvents.hidden, function() {
385                         // Destroy when hidden.
386                         modal.destroy();
387                     });
389                     modal.show();
391                     return;
393                 }).catch(notification.exception);
394             });
396             $('body').on('click', '.tag-collections-table .action_delete', function(e) {
397                 e.preventDefault();
398                 var href = $(this).attr('data-url') + '&sesskey=' + M.cfg.sesskey;
399                 str.get_strings([
400                         {key: 'delete'},
401                         {key: 'suredeletecoll', component: 'tag', param: $(this).attr('data-collname')},
402                         {key: 'yes'},
403                         {key: 'no'},
404                     ]).done(function(s) {
405                         notification.confirm(s[0], s[1], s[2], s[3], function() {
406                             window.location.href = href;
407                         });
408                     }
409                 );
410             });
411         }
412     };
413 });