From fd5e2ead955330a4324e1fd0f86d1da263324c41 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Wed, 31 Jan 2018 13:46:30 +0800 Subject: [PATCH] MDL-61133 core_question: add new question tags modal --- lang/en/question.php | 1 + question/amd/build/edit_tags.min.js | Bin 0 -> 1677 bytes question/amd/build/repository.min.js | Bin 0 -> 193 bytes question/amd/src/edit_tags.js | 233 +++++++++++++++++++++++++++ question/amd/src/repository.js | 48 ++++++ question/classes/bank/view.php | 4 +- 6 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 question/amd/build/edit_tags.min.js create mode 100644 question/amd/build/repository.min.js create mode 100644 question/amd/src/edit_tags.js create mode 100644 question/amd/src/repository.js diff --git a/lang/en/question.php b/lang/en/question.php index b3c377dc7d9..140d4a87355 100644 --- a/lang/en/question.php +++ b/lang/en/question.php @@ -269,6 +269,7 @@ $string['questionsinuse'] = '(* Questions marked by an asterisk are already in u $string['questionsmovedto'] = 'Questions still in use moved to "{$a}" in the parent course category.'; $string['questionsrescuedfrom'] = 'Questions saved from context {$a}.'; $string['questionsrescuedfrominfo'] = 'These questions (some of which may be hidden) were saved when context {$a} was deleted because they are still used by some quizzes or other activities.'; +$string['questiontags'] = 'Question tags'; $string['questiontype'] = 'Question type'; $string['questionuse'] = 'Use question in this activity'; $string['questionvariant'] = 'Question variant'; diff --git a/question/amd/build/edit_tags.min.js b/question/amd/build/edit_tags.min.js new file mode 100644 index 0000000000000000000000000000000000000000..859ba137d2881ce94d442e5e8e618dec526dd2f6 GIT binary patch literal 1677 zcmbVMT~FIE6#XlZ7i`Ix@!BeyO8F2Pf@ze!AQUff#q;1+#Y1$r| zCieY2=iI9x(It@Q;PuxW>@r}1G#1VhE7Af=xBjl3UB4Dai9CV@-qyQkiIC0=F-qff zqNQ-!lxssdubn9(T{^I6jW@fIBCMkJ$7dEQQ|m6?3rpr@XG{c(nPiFqOIXS>+AM@U z(qS{3+&o5ixA)&hC(lYaaoPtD15nyIk=DV>345IUyoxTKX0wO;eY09Dz?DnN|wQ0ArN@5<@8UDS#OQtXRxL;L?I{KpMBKUlD;-_ZU-xyzs=+cc~|ksg!?1+2@I1Z#bDnqZqx#Aw$)rp*S_8r)2~ z97s%A+#<9>=Op3qA))eGrK|(~hcOO;HziTr>uFFe2J^XqE$dy8Xh07FQh2_0OP6I z82ibC59e*i`5tS6Hg6=OtiZ>(hrH2h1T9lx%yT2u^=h#VNfAUZhNwrX!D9m5KWQ4i)B41k2Yn0@mVJ6*KMI3S`u|;-U%K3&8(-AiGyUy0|IJUH4Gds zQI8X)7?U! literal 0 HcmV?d00001 diff --git a/question/amd/build/repository.min.js b/question/amd/build/repository.min.js new file mode 100644 index 0000000000000000000000000000000000000000..35de00b2255d5ab020f45ed511ad4e30260cc387 GIT binary patch literal 193 zcmYMsK?=e!5QX8Zl&o3^>N>@h;0bgUN|>h8+R`LCNkj>`yRA~(J%0FJhy7@=lx%uL zq&MSCJHkCo@L~<`qt#(_wglc*=?PTm. + +/** + * A javascript module to handle question tags editing. + * + * @module core_question/edit_tags + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define([ + 'jquery', + 'core/fragment', + 'core/str', + 'core/modal_events', + 'core/modal_factory', + 'core/notification', + 'core/custom_interaction_events', + 'core_question/repository', + ], + function( + $, + Fragment, + Str, + ModalEvents, + ModalFactory, + Notification, + CustomEvents, + Repository + ) { + + var SELECTORS = { + TAGS_LINK: '[data-action="edittags"]', + SAVE_BUTTON: '[data-action="save"]', + LOADING_ICON: '[data-region="overlay-icon-container"]', + }; + + /** + * Enable the save button in the footer. + * + * @param {object} root The container element. + * @method enableSaveButton + */ + var enableSaveButton = function(root) { + root.find(SELECTORS.SAVE_BUTTON).prop('disabled', false); + }; + + /** + * Disable the save button in the footer. + * + * @param {object} root The container element. + * @method disableSaveButton + */ + var disableSaveButton = function(root) { + root.find(SELECTORS.SAVE_BUTTON).prop('disabled', true); + }; + + /** + * Get the serialised form data. + * + * @method getFormData + * @param {object} modal The modal object. + * @return {string} serialised form data + */ + var getFormData = function(modal) { + return modal.getBody().find('form').serialize(); + }; + + /** + * Set the element state to loading. + * + * @param {object} root The container element + * @method startLoading + */ + var startLoading = function(root) { + var loadingIconContainer = root.find(SELECTORS.LOADING_ICON); + + loadingIconContainer.removeClass('hidden'); + }; + + /** + * Remove the loading state from the element. + * + * @param {object} root The container element + * @method stopLoading + */ + var stopLoading = function(root) { + var loadingIconContainer = root.find(SELECTORS.LOADING_ICON); + + loadingIconContainer.addClass('hidden'); + }; + + /** + * Register event listeners for the module. + * + * @param {object} root The calendar root element + */ + var registerEventListeners = function(root) { + var modalPromise = ModalFactory.create( + { + type: ModalFactory.types.SAVE_CANCEL, + large: false + }, + [root, SELECTORS.TAGS_LINK] + ).then(function(modal) { + // All of this code only executes once, when the modal is + // first created. This allows us to add any code that should + // only be run once, such as adding event handlers to the modal. + Str.get_string('questiontags', 'question') + .then(function(string) { + modal.setTitle(string); + return string; + }) + .fail(Notification.exception); + + modal.getRoot().on(ModalEvents.save, function(e) { + var form = modal.getBody().find('form'); + form.submit(); + e.preventDefault(); + }); + + modal.getRoot().on('submit', 'form', function(e) { + save(modal, root).then(function() { + modal.hide(); + return; + }).fail(Notification.exception); + + // Stop the form from actually submitting and prevent it's + // propagation because we have already handled the event. + e.preventDefault(); + e.stopPropagation(); + }); + + return modal; + }); + + // We need to add an event handler to the tags link because there are + // multiple links on the page and without adding a listener we don't know + // which one the user clicked on the show the modal. + root.on(CustomEvents.events.activate, SELECTORS.TAGS_LINK, function(e) { + var currentTarget = $(e.currentTarget); + + var questionId = currentTarget.data('questionid'), + canEdit = !!currentTarget.data('canedit'), + contextId = currentTarget.data('contextid'); + + // This code gets called each time the user clicks the tag link + // so we can use it to reload the contents of the tag modal. + modalPromise.then(function(modal) { + // Display spinner and disable save button. + disableSaveButton(root); + startLoading(root); + + var args = { + id: questionId + }; + + var tagsFragment = Fragment.loadFragment('question', 'tags_form', contextId, args); + modal.setBody(tagsFragment); + + tagsFragment.then(function() { + enableSaveButton(root); + return; + }) + .always(function() { + // Always hide the loading spinner when the request + // has completed. + stopLoading(root); + return; + }) + .fail(Notification.exception); + + // Show or hide the save button depending on whether the user + // has the capability to edit the tags. + if (canEdit) { + modal.getRoot().find(SELECTORS.SAVE_BUTTON).show(); + } else { + modal.getRoot().find(SELECTORS.SAVE_BUTTON).hide(); + } + + return modal; + }).fail(Notification.exception); + + e.preventDefault(); + }); + }; + + /** + * Send the form data to the server to save question tags. + * + * @method save + * @param {object} modal The modal object. + * @param {object} root The container element. + * @return {object} A promise + */ + var save = function(modal, root) { + // Display spinner and disable save button. + disableSaveButton(root); + startLoading(root); + + var formData = getFormData(modal); + + // Send the form data to the server for processing. + return Repository.submitTagCreateUpdateForm(formData) + .always(function() { + // Regardless of success or error we should always stop + // the loading icon and re-enable the buttons. + stopLoading(root); + enableSaveButton(root); + return; + }) + .fail(Notification.exception); + }; + + return { + init: function(root) { + root = $(root); + registerEventListeners(root); + } + }; +}); diff --git a/question/amd/src/repository.js b/question/amd/src/repository.js new file mode 100644 index 00000000000..42e72726bf4 --- /dev/null +++ b/question/amd/src/repository.js @@ -0,0 +1,48 @@ +// 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 . + +/** + * A javascript module to handle question ajax actions. + * + * @module core_question/repository + * @class repository + * @package core_question + * @copyright 2017 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/ajax'], function($, Ajax) { + + /** + * Submit the form data for the question tags form. + * + * @method submitTagCreateUpdateForm + * @param {string} formdata The URL encoded values from the form + * @return {promise} + */ + var submitTagCreateUpdateForm = function(formdata) { + var request = { + methodname: 'core_question_submit_tags_form', + args: { + formdata: formdata + } + }; + + return Ajax.call([request])[0]; + }; + + return { + submitTagCreateUpdateForm: submitTagCreateUpdateForm + }; +}); diff --git a/question/classes/bank/view.php b/question/classes/bank/view.php index edeef005c5c..bc65791426c 100644 --- a/question/classes/bank/view.php +++ b/question/classes/bank/view.php @@ -480,6 +480,8 @@ class view { $this->baseurl, $cat, $this->cm, null, $page, $perpage, $showhidden, $showquestiontext, $this->contexts->having_cap('moodle/question:add')); + + $PAGE->requires->js_call_amd('core_question/edit_tags', 'init', ['#questionscontainer']); } protected function print_choose_category_message($categoryandcontext) { @@ -701,7 +703,7 @@ class view { echo ''; echo \html_writer::input_hidden_params($this->baseurl); - echo '
'; + echo '
'; $this->start_table(); $rowcount = 0; foreach ($questions as $question) { -- 2.43.0