MDL-62746 tag: Convert YUI modals to AMD modals
authorJun Pataleta <jun@moodle.com>
Wed, 20 Jun 2018 04:07:12 +0000 (12:07 +0800)
committerJun Pataleta <jun@moodle.com>
Fri, 6 Jul 2018 04:34:23 +0000 (12:34 +0800)
lib/amd/build/tag.min.js
lib/amd/src/tag.js
tag/manage.php
tag/templates/add_tag_collection.mustache [new file with mode: 0644]
tag/templates/add_tags.mustache [new file with mode: 0644]
tag/templates/combine_tags.mustache [new file with mode: 0644]
tag/tests/behat/edit_tag.feature

index ba25521..432ce12 100644 (file)
Binary files a/lib/amd/build/tag.min.js and b/lib/amd/build/tag.min.js differ
index 730e5cf..e6b12f1 100644 (file)
@@ -22,8 +22,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @since      3.0
  */
-define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/yui'],
-        function($, ajax, templates, notification, str, Y) {
+define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/modal_factory', 'core/modal_events'],
+        function($, ajax, templates, notification, str, ModalFactory, ModalEvents) {
     return /** @alias module:core/tag */ {
 
         /**
@@ -142,56 +142,61 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
                     return;
                 }
                 var tempElement = $("<input type='hidden'/>").attr('name', this.name);
+                var saveButtonText = '';
+                var tagOptions = [];
+                tags.each(function() {
+                    var tagid = $(this).val(),
+                        tagname = $('.inplaceeditable[data-itemtype=tagname][data-itemid=' + tagid + ']').attr('data-value');
+                    tagOptions.push({
+                        id: tagid,
+                        name: tagname
+                    });
+                });
+
                 str.get_strings([
                     {key: 'combineselected', component: 'tag'},
-                    {key: 'selectmaintag', component: 'tag'},
-                    {key: 'continue'},
-                    {key: 'cancel'},
-                ]).done(function(s) {
-                    var el = $('<div><form id="combinetags_form">' +
-                        '<div class="description"></div><div class="form-group options"></div>' +
-                        '<div class="form-group">' +
-                        '   <input type="submit" class="btn btn-primary" id="combinetags_submit"/>' +
-                        '   <input type="button" class="btn btn-secondary" id="combinetags_cancel"/>' +
-                        '</div>' +
-                        '</form></div>');
-                    el.find('.description').html(s[1]);
-                    el.find('#combinetags_submit').attr('value', s[2]);
-                    el.find('#combinetags_cancel').attr('value', s[3]);
-                    var fldset = el.find('.options');
-                    tags.each(function() {
-                        var tagid = $(this).val(),
-                            tagname = $('.inplaceeditable[data-itemtype=tagname][data-itemid=' + tagid + ']').attr('data-value');
-                        var option = '<div class="form-check">' +
-                            '   <input type="radio" class="form-check-input" name="maintag" ' +
-                            '       id="combinetags_maintag_' + tagid + '" value="' + tagid + '"/>' +
-                            '   <label class="form-check-label" for="combinetags_maintag_' + tagid + '">' + tagname + '</label>' +
-                            '</div>';
-                        fldset.append($(option));
+                    {key: 'continue'}
+                ]).then(function(langStrings) {
+                    var modalTitle = langStrings[0];
+                    saveButtonText = langStrings[1];
+                    var templateContext = {
+                        tags: tagOptions
+                    };
+                    return ModalFactory.create({
+                        title: modalTitle,
+                        body: templates.render('core_tag/combine_tags', templateContext),
+                        type: ModalFactory.types.SAVE_CANCEL
                     });
-                    // TODO: MDL-57778 Convert to core/modal.
-                    Y.use('moodle-core-notification-dialogue', function() {
-                        var panel = new M.core.dialogue({
-                            draggable: true,
-                            modal: true,
-                            closeButton: true,
-                            headerContent: s[0],
-                            bodyContent: el.html()
-                        });
-                        panel.show();
-                        $('#combinetags_form input[type=radio]').first().focus().prop('checked', true);
-                        $('#combinetags_form #combinetags_cancel').on('click', function() {
-                            panel.destroy();
-                        });
-                        $('#combinetags_form').on('submit', function() {
-                            tempElement.appendTo(form);
-                            var maintag = $('input[name=maintag]:checked', '#combinetags_form').val();
-                            $("<input type='hidden'/>").attr('name', 'maintag').attr('value', maintag).appendTo(form);
-                            form.submit();
-                            return false;
-                        });
+                }).then(function(modal) {
+                    modal.setSaveButtonText(saveButtonText);
+
+                    // Handle save event.
+                    modal.getRoot().on(ModalEvents.save, function(e) {
+                        e.preventDefault();
+
+                        // Append this temp element in the form in the tags list, not the form in the modal. Confusing, right?!?
+                        tempElement.appendTo(form);
+                        // Get the selected tag from the modal.
+                        var maintag = $('input[name=maintag]:checked', '#combinetags_form').val();
+                        // Append this in the tags list form.
+                        $("<input type='hidden'/>").attr('name', 'maintag').attr('value', maintag).appendTo(form);
+                        // Submit the tags list form.
+                        form.submit();
                     });
-                });
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+
+                    modal.show();
+                    // Tick the first option.
+                    $('#combinetags_form input[type=radio]').first().focus().prop('checked', true);
+
+                    return;
+
+                }).catch(notification.exception);
             });
 
             // When user changes tag name to some name that already exists suggest to combine the tags.
@@ -218,43 +223,69 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
             // Form for adding standard tags.
             $('body').on('click', 'a[data-action=addstandardtag]', function(e) {
                 e.preventDefault();
+
+                var saveButtonText = '';
                 str.get_strings([
                     {key: 'addotags', component: 'tag'},
-                    {key: 'inputstandardtags', component: 'tag'},
-                    {key: 'continue'},
-                    {key: 'cancel'},
-                ]).done(function(s) {
-                    var el = $('<div><form id="addtags_form" method="POST">' +
-                        '<input type="hidden" name="action" value="addstandardtag"/>' +
-                        '<input type="hidden" name="sesskey" value="' + M.cfg.sesskey + '"/>' +
-                        '<div class="form-group">' +
-                        '   <label for="id_tagslist">' + s[1] + '</label>' +
-                        '   <input type="text" id="id_tagslist" class="form-control" name="tagslist"/>' +
-                        '</div>' +
-                        '<div class="form-group">' +
-                        '   <input type="submit" class="btn btn-primary" id="addtags_submit"/>' +
-                        '   <input type="button" class="btn btn-secondary" id="addtags_cancel"/>' +
-                        '</div>' +
-                        '</form></div>');
-                    el.find('#addtags_form').attr('action', window.location.href);
-                    el.find('#addtags_submit').attr('value', s[2]);
-                    el.find('#addtags_cancel').attr('value', s[3]);
-                    // TODO: MDL-57778 Convert to core/modal.
-                    Y.use('moodle-core-notification-dialogue', function() {
-                        var panel = new M.core.dialogue({
-                            draggable: true,
-                            modal: true,
-                            closeButton: true,
-                            headerContent: s[0],
-                            bodyContent: el.html()
-                        });
-                        panel.show();
-                        $('#addtags_form input[type=text]').focus();
-                        $('#addtags_form #addtags_cancel').on('click', function() {
-                            panel.destroy();
+                    {key: 'continue'}
+                ]).then(function(langStrings) {
+                    var modalTitle = langStrings[0];
+                    saveButtonText = langStrings[1];
+                    var templateContext = {
+                        actionurl: window.location.href,
+                        sesskey: M.cfg.sesskey
+                    };
+                    return ModalFactory.create({
+                        title: modalTitle,
+                        body: templates.render('core_tag/add_tags', templateContext),
+                        type: ModalFactory.types.SAVE_CANCEL
+                    });
+                }).then(function(modal) {
+                    modal.setSaveButtonText(saveButtonText);
+
+                    // Handle save event.
+                    modal.getRoot().on(ModalEvents.save, function(e) {
+                        var tagsInput = $(e.currentTarget).find('#id_tagslist');
+                        var name = tagsInput.val().trim();
+
+                        // Set the text field's value to the trimmed value.
+                        tagsInput.val(name);
+
+                        // Add submit event listener to the form.
+                        var tagsForm = $('#addtags_form');
+                        tagsForm.on('submit', function(e) {
+                            // Validate the form.
+                            var form = $('#addtags_form');
+                            if (form[0].checkValidity() === false) {
+                                e.preventDefault();
+                                e.stopPropagation();
+                            }
+                            form.addClass('was-validated');
+
+                            // BS2 compatibility.
+                            $('[data-region="tagslistinput"]').addClass('error');
+                            var errorMessage = $('#id_tagslist_error_message');
+                            errorMessage.removeAttr('hidden');
+                            errorMessage.addClass('help-block');
                         });
+
+                        // Try to submit the form.
+                        tagsForm.submit();
+
+                        return false;
                     });
-                });
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+
+                    modal.show();
+
+                    return;
+
+                }).catch(notification.exception);
             });
         },
 
@@ -292,58 +323,74 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
 
             $('body').on('click', '.addtagcoll > a', function(e) {
                 e.preventDefault();
-                var href = $(this).attr('data-url') + '&sesskey=' + M.cfg.sesskey;
-                str.get_strings([
-                        {key: 'addtagcoll', component: 'tag'},
-                        {key: 'name'},
-                        {key: 'searchable', component: 'tag'},
-                        {key: 'create'},
-                        {key: 'cancel'},
-                    ]).done(function(s) {
-                        var el = $('<div><form id="addtagcoll_form">' +
-                            '<div class="form-group">' +
-                            '   <label for="addtagcoll_name"></label> ' +
-                            '   <input id="addtagcoll_name" type="text" class="form-control"/>  ' +
-                            '</div>' +
-                            '<div class="form-group form-check">' +
-                            '   <input id="addtagcoll_searchable" type="checkbox" value="1" checked class="form-check-input"/>' +
-                            '   <label for="addtagcoll_searchable" class="form-check-label"></label>' +
-                            '</div>' +
-                            '<div class="form-group">' +
-                            '   <input type="submit" class="btn btn-primary" id="addtagcoll_submit"/>' +
-                            '   <input type="button" class="btn btn-secondary" id="addtagcoll_cancel"/>' +
-                            '</div>' +
-                            '</form></div>');
-                        el.find('label[for="addtagcoll_name"]').html(s[1]);
-                        el.find('label[for="addtagcoll_searchable"]').html(s[2]);
-                        el.find('#addtagcoll_submit').attr('value', s[3]);
-                        el.find('#addtagcoll_cancel').attr('value', s[4]);
-                        // TODO: MDL-57778 Convert to core/modal.
-                        Y.use('moodle-core-notification-dialogue', function() {
-                            var panel = new M.core.dialogue({
-                                draggable: true,
-                                modal: true,
-                                closeButton: true,
-                                headerContent: s[0],
-                                bodyContent: el.html()
-                            });
-                            panel.show();
-                            $('#addtagcoll_form #addtagcoll_name').focus();
-                            $('#addtagcoll_form #addtagcoll_cancel').on('click', function() {
-                                panel.destroy();
-                            });
-                            $('#addtagcoll_form').on('submit', function() {
-                                var name = $('#addtagcoll_form #addtagcoll_name').val();
-                                var searchable = $('#addtagcoll_form #addtagcoll_searchable').prop('checked') ? 1 : 0;
-                                if (String(name).length > 0) {
-                                    window.location.href = href + "&name=" + encodeURIComponent(name) + "&searchable=" + searchable;
-                                }
-                                return false;
-                            });
-                        });
+                var keys = [
+                    {
+                        key: 'addtagcoll',
+                        component: 'tag'
+                    },
+                    {
+                        key: 'create'
                     }
-                );
+                ];
+
+                var href = $(this).attr('data-url');
+                var saveButtonText = '';
+                str.get_strings(keys).then(function(langStrings) {
+                    var modalTitle = langStrings[0];
+                    saveButtonText = langStrings[1];
+                    var templateContext = {
+                        actionurl: href,
+                        sesskey: M.cfg.sesskey
+                    };
+                    return ModalFactory.create({
+                        title: modalTitle,
+                        body: templates.render('core_tag/add_tag_collection', templateContext),
+                        type: ModalFactory.types.SAVE_CANCEL
+                    });
+                }).then(function(modal) {
+                    modal.setSaveButtonText(saveButtonText);
+
+                    // Handle save event.
+                    modal.getRoot().on(ModalEvents.save, function(e) {
+                        var collectionInput = $(e.currentTarget).find('#addtagcoll_name');
+                        var name = collectionInput.val().trim();
+                        // Set the text field's value to the trimmed value.
+                        collectionInput.val(name);
+
+                        // Add submit event listener to the form.
+                        var form = $('#addtagcoll_form');
+                        form.on('submit', function(e) {
+                            // Validate the form.
+                            if (form[0].checkValidity() === false) {
+                                e.preventDefault();
+                                e.stopPropagation();
+                            }
+                            form.addClass('was-validated');
+
+                            // BS2 compatibility.
+                            $('[data-region="addtagcoll_nameinput"]').addClass('error');
+                            var errorMessage = $('#id_addtagcoll_name_error_message');
+                            errorMessage.removeAttr('hidden');
+                            errorMessage.addClass('help-block');
+                        });
+
+                        // Try to submit the form.
+                        form.submit();
+
+                        return false;
+                    });
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+
+                    modal.show();
+
+                    return;
 
+                }).catch(notification.exception);
             });
 
             $('body').on('click', '.tag-collections-table .action_delete', function(e) {
index dfc6496..3f75762 100644 (file)
@@ -81,7 +81,7 @@ switch($action) {
     case 'colladd':
         require_sesskey();
         $name = required_param('name', PARAM_NOTAGS);
-        $searchable = required_param('searchable', PARAM_BOOL);
+        $searchable = optional_param('searchable', false, PARAM_BOOL);
         core_tag_collection::create(array('name' => $name, 'searchable' => $searchable));
         redirect($manageurl);
         break;
diff --git a/tag/templates/add_tag_collection.mustache b/tag/templates/add_tag_collection.mustache
new file mode 100644 (file)
index 0000000..7d766ce
--- /dev/null
@@ -0,0 +1,61 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_tag/add_tag_collection
+
+    Renders the form for adding tag collections.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * sesskey string The session key
+
+    Example context (json):
+    {
+        "actionurl" : "#",
+        "sesskey" : "UniqueSesskey1a2b3c"
+    }
+
+}}
+<form id="addtagcoll_form" method="post" action="{{actionurl}}" class="needs-validation">
+    <input type="hidden" name="sesskey" value="{{sesskey}}"/>
+    <div class="form-group control-group" data-region="addtagcoll_nameinput">
+        <label for="addtagcoll_name">
+            {{#str}}name{{/str}}
+            <span>
+                <abbr class="initialism text-danger" title="{{#str}}required{{/str}}">
+                    {{#pix}}req, core, {{#str}}required{{/str}}{{/pix}}
+                </abbr>
+            </span>
+        </label>
+        {{! Enclosing these controls in a div with the controls class for BS2 compatibility when showing validation errors.}}
+        <div class="controls">
+            <input id="addtagcoll_name" type="text" class="form-control" name="name" aria-required="true" required/>
+            <div class="form-control-feedback invalid-feedback" id="id_addtagcoll_name_error_message" hidden="hidden">
+                {{#str}}required{{/str}}
+            </div>
+        </div>
+    </div>
+    <div class="form-group form-check">
+        <input id="addtagcoll_searchable" name="searchable" type="checkbox" value="1" checked class="form-check-input"/>
+        <label for="addtagcoll_searchable" class="form-check-label">{{#str}}searchable, tag{{/str}}</label>
+    </div>
+</form>
diff --git a/tag/templates/add_tags.mustache b/tag/templates/add_tags.mustache
new file mode 100644 (file)
index 0000000..be3cb6f
--- /dev/null
@@ -0,0 +1,58 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_tag/add_tags
+
+    Renders the form for adding tags.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * sesskey string The session key
+
+    Example context (json):
+    {
+        "actionurl" : "#",
+        "sesskey" : "UniqueSesskey1a2b3c"
+    }
+
+}}
+<form id="addtags_form" method="post" action="{{actionurl}}" class="needs-validation">
+    <input type="hidden" name="action" value="addstandardtag"/>
+    <input type="hidden" name="sesskey" value="{{sesskey}}"/>
+    <div class="form-group control-group" data-region="tagslistinput">
+        <label for="id_tagslist">
+            {{#str}}inputstandardtags, tag{{/str}}
+            <span>
+                <abbr class="initialism text-danger" title="{{#str}}required{{/str}}">
+                    {{#pix}}req, core, {{#str}}required{{/str}}{{/pix}}
+                </abbr>
+            </span>
+        </label>
+        {{! Enclosing these controls in a div with the controls class for BS2 compatibility when showing validation errors.}}
+        <div class="controls">
+            <input type="text" id="id_tagslist" class="form-control" name="tagslist" aria-required="true" required />
+            <div class="form-control-feedback invalid-feedback" id="id_tagslist_error_message" hidden>
+                {{#str}}required{{/str}}
+            </div>
+        </div>
+    </div>
+</form>
diff --git a/tag/templates/combine_tags.mustache b/tag/templates/combine_tags.mustache
new file mode 100644 (file)
index 0000000..835dcf0
--- /dev/null
@@ -0,0 +1,60 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_tag/combine_tags
+
+    Renders the form for combining tags.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * tags Array The list of tags to combine.
+
+    Example context (json):
+    {
+        "tags": [
+            {
+                "id": 1,
+                "name": "Cat"
+            },
+            {
+                "id": 2,
+                "name": "Dog"
+            },
+            {
+                "id": 3,
+                "name": "Mouse"
+            }
+        ]
+    }
+
+}}
+<form id="combinetags_form">
+    <div class="description">{{#str}}selectmaintag, tag{{/str}}</div>
+    <div class="form-group options form-inline">
+        {{#tags}}
+            <div class="form-check w-100 justify-content-start">
+                <input type="radio" class="form-check-input" name="maintag" id="combinetags_maintag_{{id}}" value="{{id}}"/>
+                <label class="form-check-label" for="combinetags_maintag_{{id}}">{{name}}</label>
+            </div>
+        {{/tags}}
+    </div>
+</form>
index 342b401..29ce521 100644 (file)
@@ -222,7 +222,7 @@ Feature: Users can edit tags to add description or rename
       | Select tag Turtle | 1 |
     And I press "Combine selected"
     And I should see "Select the tag that will be used after combining"
-    And I click on "//form[@id='combinetags_form']//input[@type='radio'][3]" "xpath_element"
+    And I click on "Turtle" "radio" in the "#combinetags_form" "css_element"
     And I press "Continue"
     Then I should see "Tags are combined"
     And I should not see "Dog"