From f31804c01c0463ad35f1d4cfd6f435cbdabb35e9 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Tue, 9 Jan 2018 08:27:46 +0800 Subject: [PATCH 1/6] MDL-61133 core_output: add fontawesome mapping for tags icon --- lib/classes/output/icon_system_fontawesome.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/classes/output/icon_system_fontawesome.php b/lib/classes/output/icon_system_fontawesome.php index d7e858a42b1..d91d0c73479 100644 --- a/lib/classes/output/icon_system_fontawesome.php +++ b/lib/classes/output/icon_system_fontawesome.php @@ -372,6 +372,7 @@ class icon_system_fontawesome extends icon_system_font { 'core:t/switch_minus' => 'fa-minus', 'core:t/switch_plus' => 'fa-plus', 'core:t/switch_whole' => 'fa-square-o', + 'core:t/tags' => 'fa-tags', 'core:t/unblock' => 'fa-commenting', 'core:t/unlocked' => 'fa-unlock-alt', 'core:t/unlock' => 'fa-lock', From d587dc6f6f6e6e2951fb5aa95b83098924c2b65f Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Wed, 31 Jan 2018 13:38:23 +0800 Subject: [PATCH 2/6] MDL-61133 core_question: add tags column class to question list --- question/classes/bank/tags_action_column.php | 86 ++++++++++++++++++++ question/classes/bank/view.php | 7 +- 2 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 question/classes/bank/tags_action_column.php diff --git a/question/classes/bank/tags_action_column.php b/question/classes/bank/tags_action_column.php new file mode 100644 index 00000000000..5f49808d55c --- /dev/null +++ b/question/classes/bank/tags_action_column.php @@ -0,0 +1,86 @@ +. + +/** + * The question tags column subclass. + * + * @package core_question + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core_question\bank; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Action to add and remove tags to questions. + * + * @package core_question + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tags_action_column extends action_column_base { + + /** + * Return the name for this column. + * + * @return string + */ + public function get_name() { + return 'tagsaction'; + } + + /** + * Display tags column content. + * + * @param object $question The question database record. + * @param string $rowclasses + */ + protected function display_content($question, $rowclasses) { + global $DB; + + if (\core_tag_tag::is_enabled('core_question', 'question') && + question_has_capability_on($question, 'view')) { + + $canedit = question_has_capability_on($question, 'edit'); + $category = $DB->get_record('question_categories', ['id' => $question->category], 'contextid'); + $url = $this->qbank->edit_question_url($question->id); + + $this->print_tag_icon($question->id, $url, $canedit, $category->contextid); + } + } + + /** + * Build and print the tags icon. + * + * @param int $id The question ID. + * @param string $url Editing question url. + * @param bool $canedit Whether the user can edit questions or not. + * @param int $contextid Question category context ID. + */ + protected function print_tag_icon($id, $url, $canedit, $contextid) { + global $OUTPUT; + + $params = [ + 'data-action' => 'edittags', + 'data-canedit' => $canedit, + 'data-contextid' => $contextid, + 'data-questionid' => $id + ]; + + echo \html_writer::link($url, $OUTPUT->pix_icon('t/tags', get_string('managetags', 'tag')), $params); + } +} diff --git a/question/classes/bank/view.php b/question/classes/bank/view.php index 8c4142b580c..edeef005c5c 100644 --- a/question/classes/bank/view.php +++ b/question/classes/bank/view.php @@ -124,10 +124,9 @@ class view { if (empty($CFG->questionbankcolumns)) { $questionbankcolumns = array('checkbox_column', 'question_type_column', - 'question_name_column', 'edit_action_column', 'copy_action_column', - 'preview_action_column', 'delete_action_column', - 'creator_name_column', - 'modifier_name_column'); + 'question_name_column', 'tags_action_column', 'edit_action_column', + 'copy_action_column', 'preview_action_column', 'delete_action_column', + 'creator_name_column', 'modifier_name_column'); } else { $questionbankcolumns = explode(',', $CFG->questionbankcolumns); } From 680d5c5be62da6bcc4162d45870be132f500a96a Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Wed, 31 Jan 2018 13:40:46 +0800 Subject: [PATCH 3/6] MDL-61133 core_question: new submit_tags_form webservice --- lib/db/services.php | 7 ++++ question/classes/external.php | 75 +++++++++++++++++++++++++++++++++++ version.php | 2 +- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lib/db/services.php b/lib/db/services.php index e8e422792ea..3a712b77726 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1114,6 +1114,13 @@ $functions = array( 'capabilities' => 'moodle/question:flag', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), + 'core_question_submit_tags_form' => array( + 'classname' => 'core_question_external', + 'methodname' => 'submit_tags_form', + 'description' => 'Update the question tags.', + 'type' => 'write', + 'ajax' => true, + ), 'core_rating_get_item_ratings' => array( 'classname' => 'core_rating_external', 'methodname' => 'get_item_ratings', diff --git a/question/classes/external.php b/question/classes/external.php index dae3272acc2..6210ff7f3a7 100644 --- a/question/classes/external.php +++ b/question/classes/external.php @@ -114,4 +114,79 @@ class core_question_external extends external_api { ) ); } + + /** + * Returns description of method parameters. + * + * @return external_function_parameters. + */ + public static function submit_tags_form_parameters() { + return new external_function_parameters([ + 'formdata' => new external_value(PARAM_RAW, 'The data from the tag form'), + ]); + } + + /** + * Handles the tags form submission. + * + * @param string $formdata The question tag form data in a URI encoded param string + * @return array The created or modified question tag + * @throws moodle_exception + */ + public static function submit_tags_form($formdata) { + global $USER, $DB, $CFG; + + $data = []; + $result = ['status' => false]; + + // Parameter validation. + $params = self::validate_parameters(self::submit_tags_form_parameters(), ['formdata' => $formdata]); + $context = \context_user::instance($USER->id); + + self::validate_context($context); + parse_str($params['formdata'], $data); + + if (!empty($data['id'])) { + $questionid = clean_param($data['id'], PARAM_INT); + $question = $DB->get_record('question', array('id' => $questionid)); + + require_once($CFG->libdir . '/questionlib.php'); + $canedit = question_has_capability_on($question, 'edit'); + + require_once($CFG->dirroot . '/question/type/tags_form.php'); + $mform = new \core_question\form\tags(null, null, 'post', '', null, $canedit, $data); + + if ($validateddata = $mform->get_data()) { + // Due to a mform bug, if there's no tags set on the tag element, it submits the name as the value. + // The only way to discover is checking if the tag element is an array. + if ($canedit) { + if (is_array($validateddata->tags)) { + $categorycontext = context::instance_by_id($validateddata->contextid); + + core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id, + $categorycontext, $validateddata->tags); + + $result['status'] = true; + } else { + // If the tags element is not array, this means we don't have any tags to be set. + // This is the only way to assume the user removed all tags from the question. + core_tag_tag::remove_all_item_tags('core_question', 'question', $validateddata->id); + + $result['status'] = true; + } + } + } + } + + return $result; + } + + /** + * Returns description of method result value. + */ + public static function submit_tags_form_returns() { + return new external_single_structure([ + 'status' => new external_value(PARAM_BOOL, 'status: true if success') + ]); + } } diff --git a/version.php b/version.php index a8826708737..2bdfd579954 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2018020100.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2018020100.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. From 7f4b6dfe70f07f32193916d97ae04bc7ab7f059c Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Wed, 31 Jan 2018 13:43:05 +0800 Subject: [PATCH 4/6] MDL-61133 core_question: tags form and fragment callback --- question/lib.php | 67 +++++++++++++++++++++++++++++++++++++ question/type/tags_form.php | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 question/lib.php create mode 100644 question/type/tags_form.php diff --git a/question/lib.php b/question/lib.php new file mode 100644 index 00000000000..5c04b33831d --- /dev/null +++ b/question/lib.php @@ -0,0 +1,67 @@ +. + +/** + * Question related functions. + * + * This file was created just because Fragment API expects callbacks to be defined on lib.php. + * + * Please, do not add new functions to this file. + * + * @package core_question + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question tags fragment callback. + * + * @param array $args Arguments to the form. + * @return null|string The rendered form. + */ +function core_question_output_fragment_tags_form($args) { + + if (!empty($args['id'])) { + global $CFG, $DB; + require_once($CFG->dirroot . '/question/type/tags_form.php'); + require_once($CFG->libdir . '/questionlib.php'); + $id = clean_param($args['id'], PARAM_INT); + + $question = $DB->get_record('question', ['id' => $id]); + $category = $DB->get_record('question_categories', array('id' => $question->category)); + $context = \context::instance_by_id($category->contextid); + + $toform = new stdClass(); + $toform->id = $question->id; + $toform->questioncategory = $category->name; + $toform->questionname = $question->name; + $toform->categoryid = $category->id; + $toform->contextid = $category->contextid; + $toform->context = $context->get_context_name(); + + if (core_tag_tag::is_enabled('core_question', 'question')) { + $toform->tags = core_tag_tag::get_item_tags_array('core_question', 'question', $question->id); + } + + $canedit = question_has_capability_on($question, 'edit'); + $mform = new \core_question\form\tags(null, null, 'post', '', null, $canedit, $toform); + $mform->set_data($toform); + + return $mform->render(); + } +} diff --git a/question/type/tags_form.php b/question/type/tags_form.php new file mode 100644 index 00000000000..f2a59c66df7 --- /dev/null +++ b/question/type/tags_form.php @@ -0,0 +1,61 @@ +. + +/** + * The mform to manage question tags. + * + * @package core_question + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_question\form; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/lib/formslib.php'); + +/** + * The mform class for manage question tags. + * + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tags extends \moodleform { + + /** + * The form definition + */ + public function definition() { + $mform = $this->_form; + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'categoryid'); + $mform->setType('categoryid', PARAM_INT); + + $mform->addElement('hidden', 'contextid'); + $mform->setType('contextid', PARAM_INT); + + $mform->addElement('static', 'questionname', get_string('questionname', 'question')); + $mform->addElement('static', 'questioncategory', get_string('categorycurrent', 'question')); + $mform->addElement('static', 'context', ''); + + $mform->addElement('tags', 'tags', get_string('tags'), + ['itemtype' => 'question', 'component' => 'core_question']); + } +} From fd5e2ead955330a4324e1fd0f86d1da263324c41 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Wed, 31 Jan 2018 13:46:30 +0800 Subject: [PATCH 5/6] MDL-61133 core_question: add new question tags modal --- lang/en/question.php | 1 + question/amd/build/edit_tags.min.js | 1 + question/amd/build/repository.min.js | 1 + question/amd/src/edit_tags.js | 233 +++++++++++++++++++++++++++ question/amd/src/repository.js | 48 ++++++ question/classes/bank/view.php | 4 +- 6 files changed, 287 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 00000000000..859ba137d28 --- /dev/null +++ b/question/amd/build/edit_tags.min.js @@ -0,0 +1 @@ +define(["jquery","core/fragment","core/str","core/modal_events","core/modal_factory","core/notification","core/custom_interaction_events","core_question/repository"],function(a,b,c,d,e,f,g,h){var i={TAGS_LINK:'[data-action="edittags"]',SAVE_BUTTON:'[data-action="save"]',LOADING_ICON:'[data-region="overlay-icon-container"]'},j=function(a){a.find(i.SAVE_BUTTON).prop("disabled",!1)},k=function(a){a.find(i.SAVE_BUTTON).prop("disabled",!0)},l=function(a){return a.getBody().find("form").serialize()},m=function(a){var b=a.find(i.LOADING_ICON);b.removeClass("hidden")},n=function(a){var b=a.find(i.LOADING_ICON);b.addClass("hidden")},o=function(h){var l=e.create({type:e.types.SAVE_CANCEL,large:!1},[h,i.TAGS_LINK]).then(function(a){return c.get_string("questiontags","question").then(function(b){return a.setTitle(b),b}).fail(f.exception),a.getRoot().on(d.save,function(b){var c=a.getBody().find("form");c.submit(),b.preventDefault()}),a.getRoot().on("submit","form",function(b){p(a,h).then(function(){a.hide()}).fail(f.exception),b.preventDefault(),b.stopPropagation()}),a});h.on(g.events.activate,i.TAGS_LINK,function(c){var d=a(c.currentTarget),e=d.data("questionid"),g=!!d.data("canedit"),o=d.data("contextid");l.then(function(a){k(h),m(h);var c={id:e},d=b.loadFragment("question","tags_form",o,c);return a.setBody(d),d.then(function(){j(h)}).always(function(){n(h)}).fail(f.exception),g?a.getRoot().find(i.SAVE_BUTTON).show():a.getRoot().find(i.SAVE_BUTTON).hide(),a}).fail(f.exception),c.preventDefault()})},p=function(a,b){k(b),m(b);var c=l(a);return h.submitTagCreateUpdateForm(c).always(function(){n(b),j(b)}).fail(f.exception)};return{init:function(b){b=a(b),o(b)}}}); \ No newline at end of file diff --git a/question/amd/build/repository.min.js b/question/amd/build/repository.min.js new file mode 100644 index 00000000000..35de00b2255 --- /dev/null +++ b/question/amd/build/repository.min.js @@ -0,0 +1 @@ +define(["jquery","core/ajax"],function(a,b){var c=function(a){var c={methodname:"core_question_submit_tags_form",args:{formdata:a}};return b.call([c])[0]};return{submitTagCreateUpdateForm:c}}); \ No newline at end of file diff --git a/question/amd/src/edit_tags.js b/question/amd/src/edit_tags.js new file mode 100644 index 00000000000..592a3c62333 --- /dev/null +++ b/question/amd/src/edit_tags.js @@ -0,0 +1,233 @@ +// 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 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) { From d1db765a64c36b87644ad79157cc25650946a2a7 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Tue, 6 Feb 2018 10:24:22 +0800 Subject: [PATCH 6/6] MDL-61133 core_question: move all selectors to a new module --- question/amd/build/edit_tags.min.js | 2 +- question/amd/build/selectors.min.js | 1 + question/amd/src/edit_tags.js | 26 ++++++++++------------ question/amd/src/selectors.js | 34 +++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 question/amd/build/selectors.min.js create mode 100644 question/amd/src/selectors.js diff --git a/question/amd/build/edit_tags.min.js b/question/amd/build/edit_tags.min.js index 859ba137d28..cf0aed5387c 100644 --- a/question/amd/build/edit_tags.min.js +++ b/question/amd/build/edit_tags.min.js @@ -1 +1 @@ -define(["jquery","core/fragment","core/str","core/modal_events","core/modal_factory","core/notification","core/custom_interaction_events","core_question/repository"],function(a,b,c,d,e,f,g,h){var i={TAGS_LINK:'[data-action="edittags"]',SAVE_BUTTON:'[data-action="save"]',LOADING_ICON:'[data-region="overlay-icon-container"]'},j=function(a){a.find(i.SAVE_BUTTON).prop("disabled",!1)},k=function(a){a.find(i.SAVE_BUTTON).prop("disabled",!0)},l=function(a){return a.getBody().find("form").serialize()},m=function(a){var b=a.find(i.LOADING_ICON);b.removeClass("hidden")},n=function(a){var b=a.find(i.LOADING_ICON);b.addClass("hidden")},o=function(h){var l=e.create({type:e.types.SAVE_CANCEL,large:!1},[h,i.TAGS_LINK]).then(function(a){return c.get_string("questiontags","question").then(function(b){return a.setTitle(b),b}).fail(f.exception),a.getRoot().on(d.save,function(b){var c=a.getBody().find("form");c.submit(),b.preventDefault()}),a.getRoot().on("submit","form",function(b){p(a,h).then(function(){a.hide()}).fail(f.exception),b.preventDefault(),b.stopPropagation()}),a});h.on(g.events.activate,i.TAGS_LINK,function(c){var d=a(c.currentTarget),e=d.data("questionid"),g=!!d.data("canedit"),o=d.data("contextid");l.then(function(a){k(h),m(h);var c={id:e},d=b.loadFragment("question","tags_form",o,c);return a.setBody(d),d.then(function(){j(h)}).always(function(){n(h)}).fail(f.exception),g?a.getRoot().find(i.SAVE_BUTTON).show():a.getRoot().find(i.SAVE_BUTTON).hide(),a}).fail(f.exception),c.preventDefault()})},p=function(a,b){k(b),m(b);var c=l(a);return h.submitTagCreateUpdateForm(c).always(function(){n(b),j(b)}).fail(f.exception)};return{init:function(b){b=a(b),o(b)}}}); \ No newline at end of file +define(["jquery","core/fragment","core/str","core/modal_events","core/modal_factory","core/notification","core/custom_interaction_events","core_question/repository","core_question/selectors"],function(a,b,c,d,e,f,g,h,i){var j=function(a){a.find(i.actions.save).prop("disabled",!1)},k=function(a){a.find(i.actions.save).prop("disabled",!0)},l=function(a){return a.getBody().find("form").serialize()},m=function(a){var b=a.find(i.containers.loadingIcon);b.removeClass("hidden")},n=function(a){var b=a.find(i.containers.loadingIcon);b.addClass("hidden")},o=function(h){var l=e.create({type:e.types.SAVE_CANCEL,large:!1},[h,i.actions.edittags]).then(function(a){return c.get_string("questiontags","question").then(function(b){return a.setTitle(b),b}).fail(f.exception),a.getRoot().on(d.save,function(b){var c=a.getBody().find("form");c.submit(),b.preventDefault()}),a.getRoot().on("submit","form",function(b){p(a,h).then(function(){a.hide()}).fail(f.exception),b.preventDefault(),b.stopPropagation()}),a});h.on(g.events.activate,i.actions.edittags,function(c){var d=a(c.currentTarget),e=d.data("questionid"),g=!!d.data("canedit"),o=d.data("contextid");l.then(function(a){k(h),m(h);var c={id:e},d=b.loadFragment("question","tags_form",o,c);return a.setBody(d),d.then(function(){j(h)}).always(function(){n(h)}).fail(f.exception),g?a.getRoot().find(i.actions.save).show():a.getRoot().find(i.actions.save).hide(),a}).fail(f.exception),c.preventDefault()})},p=function(a,b){k(b),m(b);var c=l(a);return h.submitTagCreateUpdateForm(c).always(function(){n(b),j(b)}).fail(f.exception)};return{init:function(b){b=a(b),o(b)}}}); \ No newline at end of file diff --git a/question/amd/build/selectors.min.js b/question/amd/build/selectors.min.js new file mode 100644 index 00000000000..ffe642d53c1 --- /dev/null +++ b/question/amd/build/selectors.min.js @@ -0,0 +1 @@ +define([],function(){return{actions:{save:'[data-action="save"]',edittags:'[data-action="edittags"]'},containers:{loadingIcon:'[data-region="overlay-icon-container"]'}}}); \ No newline at end of file diff --git a/question/amd/src/edit_tags.js b/question/amd/src/edit_tags.js index 592a3c62333..83d5f9a36de 100644 --- a/question/amd/src/edit_tags.js +++ b/question/amd/src/edit_tags.js @@ -29,6 +29,7 @@ define([ 'core/notification', 'core/custom_interaction_events', 'core_question/repository', + 'core_question/selectors', ], function( $, @@ -38,15 +39,10 @@ define([ ModalFactory, Notification, CustomEvents, - Repository + Repository, + QuestionSelectors ) { - 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. * @@ -54,7 +50,7 @@ define([ * @method enableSaveButton */ var enableSaveButton = function(root) { - root.find(SELECTORS.SAVE_BUTTON).prop('disabled', false); + root.find(QuestionSelectors.actions.save).prop('disabled', false); }; /** @@ -64,7 +60,7 @@ define([ * @method disableSaveButton */ var disableSaveButton = function(root) { - root.find(SELECTORS.SAVE_BUTTON).prop('disabled', true); + root.find(QuestionSelectors.actions.save).prop('disabled', true); }; /** @@ -85,7 +81,7 @@ define([ * @method startLoading */ var startLoading = function(root) { - var loadingIconContainer = root.find(SELECTORS.LOADING_ICON); + var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon); loadingIconContainer.removeClass('hidden'); }; @@ -97,7 +93,7 @@ define([ * @method stopLoading */ var stopLoading = function(root) { - var loadingIconContainer = root.find(SELECTORS.LOADING_ICON); + var loadingIconContainer = root.find(QuestionSelectors.containers.loadingIcon); loadingIconContainer.addClass('hidden'); }; @@ -113,7 +109,7 @@ define([ type: ModalFactory.types.SAVE_CANCEL, large: false }, - [root, SELECTORS.TAGS_LINK] + [root, QuestionSelectors.actions.edittags] ).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 @@ -149,7 +145,7 @@ define([ // 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) { + root.on(CustomEvents.events.activate, QuestionSelectors.actions.edittags, function(e) { var currentTarget = $(e.currentTarget); var questionId = currentTarget.data('questionid'), @@ -185,9 +181,9 @@ define([ // 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(); + modal.getRoot().find(QuestionSelectors.actions.save).show(); } else { - modal.getRoot().find(SELECTORS.SAVE_BUTTON).hide(); + modal.getRoot().find(QuestionSelectors.actions.save).hide(); } return modal; diff --git a/question/amd/src/selectors.js b/question/amd/src/selectors.js new file mode 100644 index 00000000000..438ecea36a8 --- /dev/null +++ b/question/amd/src/selectors.js @@ -0,0 +1,34 @@ +// 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 . + +/** + * The purpose of this module is to centralize selectors related to question. + * + * @module core_question/question_selectors + * @package core_question + * @copyright 2018 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define([], function() { + return { + actions: { + save: '[data-action="save"]', + edittags: '[data-action="edittags"]', + }, + containers: { + loadingIcon: '[data-region="overlay-icon-container"]', + }, + }; +});