From 0d55b26da8368da1c79d4e034015cfb9163078c0 Mon Sep 17 00:00:00 2001 From: Safat Shahin Date: Wed, 2 Jun 2021 12:36:52 +1000 Subject: [PATCH] MDL-71614 qbank_previewquestion: Add Preview question plugin to core This implementation will introduce a qbank plugin "previewquestion" which will view the preview question action in the question bank actions by replacing the core classes, scripts and yui modules. This plugin will also replace the preview option in the edit question form. Having this plugin will give users the flexibility of enabling or disabling this feature from the question bank view. This change will also allow other qbank plugins to add elements or information in the preview question page by implementing a callback. It also changes the pop up to page redirect from base view page to make sure any changes in preview reflects in the base view, for example, comments added and the number of comments in the comments colum changes while back from the preview page. Other locations like edit and qtype plugins where the preview is implemented, stays the same. Co-Authored-By: Guillermo Gomez Arias Co-Authored-By: Safat Shahin --- lib/classes/plugin_manager.php | 1 + lib/questionlib.php | 60 ++-- lib/upgrade.txt | 5 + .../previewquestion/amd/build/preview.min.js | 2 + .../amd/build/preview.min.js.map | 1 + .../bank/previewquestion/amd/src/preview.js | 117 +++++++ .../classes/form/preview_options_form.php | 96 ++++++ .../bank/previewquestion/classes/helper.php | 250 ++++++++++++++ .../classes/output/renderer.php | 68 ++++ .../classes/plugin_feature.php | 34 ++ .../classes/preview_action_column.php | 62 ++++ .../classes/privacy/provider.php | 32 ++ .../classes/question_preview_options.php | 141 ++++++++ .../lang/en/qbank_previewquestion.php | 27 ++ question/bank/previewquestion/preview.php | 315 ++++++++++++++++++ .../templates/preview_question.mustache | 89 +++++ .../tests/behat/preview_question.feature | 8 +- .../behat/preview_question_action.feature | 50 +++ .../previewquestion/tests/helper_test.php | 159 +++++++++ question/bank/previewquestion/version.php | 31 ++ question/classes/local/bank/view.php | 5 + question/editlib.php | 2 +- question/engine/renderer.php | 25 +- question/preview.php | 6 +- question/previewlib.php | 110 +++--- question/qengine.js | 18 + .../ddimageortext/tests/behat/preview.feature | 8 +- .../type/ddmarker/tests/behat/preview.feature | 16 +- .../type/ddwtos/tests/behat/preview.feature | 22 +- .../description/tests/behat/preview.feature | 3 +- question/type/edit_question_form.php | 12 +- .../essay/tests/behat/max_file_size.feature | 6 +- .../type/essay/tests/behat/preview.feature | 9 +- .../gapselect/tests/behat/basic_test.feature | 3 +- question/type/match/tests/behat/edit.feature | 1 - .../type/match/tests/behat/preview.feature | 9 +- .../multichoice/tests/behat/preview.feature | 12 +- .../numerical/tests/behat/preview.feature | 3 +- .../type/shortanswer/tests/behat/edit.feature | 1 - .../shortanswer/tests/behat/preview.feature | 3 - .../truefalse/tests/behat/preview.feature | 6 +- question/upgrade.txt | 5 + .../moodle-question-preview-debug.js | 5 + .../moodle-question-preview.js | 3 + question/yui/src/preview/js/preview.js | 5 + 45 files changed, 1631 insertions(+), 215 deletions(-) create mode 100644 question/bank/previewquestion/amd/build/preview.min.js create mode 100644 question/bank/previewquestion/amd/build/preview.min.js.map create mode 100644 question/bank/previewquestion/amd/src/preview.js create mode 100644 question/bank/previewquestion/classes/form/preview_options_form.php create mode 100644 question/bank/previewquestion/classes/helper.php create mode 100644 question/bank/previewquestion/classes/output/renderer.php create mode 100644 question/bank/previewquestion/classes/plugin_feature.php create mode 100644 question/bank/previewquestion/classes/preview_action_column.php create mode 100644 question/bank/previewquestion/classes/privacy/provider.php create mode 100644 question/bank/previewquestion/classes/question_preview_options.php create mode 100644 question/bank/previewquestion/lang/en/qbank_previewquestion.php create mode 100644 question/bank/previewquestion/preview.php create mode 100644 question/bank/previewquestion/templates/preview_question.mustache rename question/{ => bank/previewquestion}/tests/behat/preview_question.feature (93%) create mode 100644 question/bank/previewquestion/tests/behat/preview_question_action.feature create mode 100644 question/bank/previewquestion/tests/helper_test.php create mode 100644 question/bank/previewquestion/version.php diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index b8da2e822d1..dc01a60e4d8 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1943,6 +1943,7 @@ class core_plugin_manager { 'editquestion', 'exportquestions', 'importquestions', + 'previewquestion', 'viewcreator', 'viewquestionname', 'viewquestiontext', diff --git a/lib/questionlib.php b/lib/questionlib.php index f9dcf74e3fc..73659ef3918 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -759,55 +759,34 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte * @param object $context context to run the preview in (affects things like * filter settings, theme, lang, etc.) Defaults to $PAGE->context. * @return moodle_url the URL. + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::question_preview_url() + * @todo MDL-71679 uncomment the debug messages after implementing the changes in mod_quiz. + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function question_preview_url($questionid, $preferredbehaviour = null, $maxmark = null, $displayoptions = null, $variant = null, $context = null) { + // Debugging message will be re-added after implementing the changes in mod_quiz. + // ...debugging('Function question_preview_url() has been deprecated and moved to qbank_previewquestion plugin, + // Please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER);. - $params = array('id' => $questionid); - - if (is_null($context)) { - global $PAGE; - $context = $PAGE->context; - } - if ($context->contextlevel == CONTEXT_MODULE) { - $params['cmid'] = $context->instanceid; - } else if ($context->contextlevel == CONTEXT_COURSE) { - $params['courseid'] = $context->instanceid; - } - - if (!is_null($preferredbehaviour)) { - $params['behaviour'] = $preferredbehaviour; - } - - if (!is_null($maxmark)) { - $params['maxmark'] = format_float($maxmark, -1); - } - - if (!is_null($displayoptions)) { - $params['correctness'] = $displayoptions->correctness; - $params['marks'] = $displayoptions->marks; - $params['markdp'] = $displayoptions->markdp; - $params['feedback'] = (bool) $displayoptions->feedback; - $params['generalfeedback'] = (bool) $displayoptions->generalfeedback; - $params['rightanswer'] = (bool) $displayoptions->rightanswer; - $params['history'] = (bool) $displayoptions->history; - } - - if ($variant) { - $params['variant'] = $variant; - } - - return new moodle_url('/question/preview.php', $params); + return \qbank_previewquestion\helper::question_preview_url($questionid, $preferredbehaviour = null, + $maxmark = null, $displayoptions = null, $variant = null, $context = null); } /** * @return array that can be passed as $params to the {@link popup_action} constructor. + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::question_preview_popup_params() + * @todo MDL-71679 uncomment the debug messages after implementing the changes to mod_quiz. + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function question_preview_popup_params() { - return array( - 'height' => 600, - 'width' => 800, - ); + // Debugging message will be re-added after implementing the changes in mod_quiz. + // ...debugging('Function question_preview_popup_params() has been deprecated and moved to qbank_previewquestion plugin, + // Please use qbank_previewquestion\helper::question_preview_popup_params() instead.', DEBUG_DEVELOPER);. + + return \qbank_previewquestion\helper::question_preview_popup_params(); } /** @@ -2255,8 +2234,7 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f } if ($module === 'core_question_preview') { - require_once($CFG->dirroot . '/question/previewlib.php'); - return question_preview_question_pluginfile($course, $context, + return qbank_previewquestion\helper::question_preview_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } else { diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 22419ffe8c1..8d5e7e8b49f 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -69,6 +69,11 @@ information provided here is intended especially for developers. rendered. The default icon for "select" types has also changed to a dropdown caret ("t/expanded"). * The function message_send() in messagelib.php now returns false if there is an error sending the message to the message processor (MDL-70046). +* Following methods are now deprecated in questionlib and moved to the new qbank_previewquestion plugin: + - question_preview_url() is moved to qbank_previewquestion\helper::question_preview_url() + - question_preview_popup_params() is moved to \qbank_previewquestion\helper::question_preview_popup_params() + Calling these functions in the question will point to the plugin, but the deprecation message will be activated in MDL-72004. + The deprecated codes are removed from the questionlib for those two methods. === 3.11.2 === * For security reasons, filelib has been updated so all requests now use emulated redirects. diff --git a/question/bank/previewquestion/amd/build/preview.min.js b/question/bank/previewquestion/amd/build/preview.min.js new file mode 100644 index 00000000000..a1668b6ede1 --- /dev/null +++ b/question/bank/previewquestion/amd/build/preview.min.js @@ -0,0 +1,2 @@ +define ("qbank_previewquestion/preview",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);a.init=function init(a){if(!a){var b=document.getElementById("close-previewquestion-page");b.onclick=function(){window.close()}}c("responseform")};var c=function(a){var b=document.getElementById(a);if(b){d(b);e(b);f(".questionflagsavebutton",b);g(b)}},d=function(a){a.setAttribute("autocomplete","off")},e=function(a){a.addEventListener("submit",function(){(0,b.default)(this).submit(function(){return!1});return!0})},f=function(a,b){b.querySelectorAll(a).forEach(function(a){return a.remove()})},g=function(a){var b=window.location.href.match(/^.*[?&]scrollpos=(\d*)(?:&|$|#).*$/,"$1");if(b){window.scrollTo(0,b[1]);a.addEventListener("DOMContentLoaded",function(){window.scrollTo(0,b[1])})}}}); +//# sourceMappingURL=preview.min.js.map diff --git a/question/bank/previewquestion/amd/build/preview.min.js.map b/question/bank/previewquestion/amd/build/preview.min.js.map new file mode 100644 index 00000000000..4d8aced4c84 --- /dev/null +++ b/question/bank/previewquestion/amd/build/preview.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/preview.js"],"names":["init","redirect","closeButton","document","getElementById","onclick","window","close","setupQuestionForm","formElement","form","autocompleteOff","preventRepeatSubmission","removeClass","scrollToSavedPos","setAttribute","addEventListener","submit","classname","querySelectorAll","forEach","e","remove","matches","location","href","match","scrollTo"],"mappings":"uJAwBA,uD,OAQoB,QAAPA,CAAAA,IAAO,CAACC,CAAD,CAAc,CAC9B,GAAI,CAACA,CAAL,CAAe,CACX,GAAIC,CAAAA,CAAW,CAAGC,QAAQ,CAACC,cAAT,CAAwB,4BAAxB,CAAlB,CACAF,CAAW,CAACG,OAAZ,CAAsB,UAAM,CACxBC,MAAM,CAACC,KAAP,EACH,CACJ,CAEDC,CAAiB,CAAC,cAAD,CACpB,C,IAQKA,CAAAA,CAAiB,CAAG,SAACC,CAAD,CAAiB,CACvC,GAAIC,CAAAA,CAAI,CAAGP,QAAQ,CAACC,cAAT,CAAwBK,CAAxB,CAAX,CACA,GAAIC,CAAJ,CAAU,CAENC,CAAe,CAACD,CAAD,CAAf,CAEAE,CAAuB,CAACF,CAAD,CAAvB,CAEAG,CAAW,CAAC,yBAAD,CAA4BH,CAA5B,CAAX,CAEAI,CAAgB,CAACJ,CAAD,CACnB,CACJ,C,CAQKC,CAAe,CAAG,SAACD,CAAD,CAAU,CAC9BA,CAAI,CAACK,YAAL,CAAkB,cAAlB,CAAkC,KAAlC,CACH,C,CAQKH,CAAuB,CAAG,SAACF,CAAD,CAAU,CACtCA,CAAI,CAACM,gBAAL,CAAsB,QAAtB,CAAgC,UAAW,CACvC,cAAE,IAAF,EAAQC,MAAR,CAAe,UAAW,CACtB,QACH,CAFD,EAGA,QACH,CALD,CAMH,C,CASKJ,CAAW,CAAG,SAACK,CAAD,CAAYR,CAAZ,CAAqB,CACrCA,CAAI,CAACS,gBAAL,CAAsBD,CAAtB,EAAiCE,OAAjC,CAAyC,SAAAC,CAAC,QAAIA,CAAAA,CAAC,CAACC,MAAF,EAAJ,CAA1C,CACH,C,CASKR,CAAgB,CAAG,SAACJ,CAAD,CAAU,CAC/B,GAAIa,CAAAA,CAAO,CAAGjB,MAAM,CAACkB,QAAP,CAAgBC,IAAhB,CAAqBC,KAArB,CAA2B,oCAA3B,CAAiE,IAAjE,CAAd,CACA,GAAIH,CAAJ,CAAa,CAGTjB,MAAM,CAACqB,QAAP,CAAgB,CAAhB,CAAmBJ,CAAO,CAAC,CAAD,CAA1B,EACAb,CAAI,CAACM,gBAAL,CAAsB,kBAAtB,CAA0C,UAAM,CAC5CV,MAAM,CAACqB,QAAP,CAAgB,CAAhB,CAAmBJ,CAAO,CAAC,CAAD,CAA1B,CACH,CAFD,CAGH,CACJ,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript for preview.\n *\n * @module qbank_preview/preview\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Safat Shahin \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n\n/**\n * Set up the actions.\n *\n * @method init\n * @param {bool} redirect Redirect.\n */\nexport const init = (redirect) => {\n if (!redirect) {\n let closeButton = document.getElementById('close-previewquestion-page');\n closeButton.onclick = () => {\n window.close();\n };\n }\n // Set up the form to be displayed.\n setupQuestionForm('responseform');\n};\n\n/**\n * Set up the form element to be displayed.\n *\n * @method setupQuestionForm\n * @param {string} formElement The form element.\n */\nconst setupQuestionForm = (formElement) => {\n let form = document.getElementById(formElement);\n if (form) {\n // Turning off browser autocomplete.\n autocompleteOff(form);\n // Stop a question form being submitted more than once.\n preventRepeatSubmission(form);\n // Removes any '.questionflagsavebutton's, since we have JavaScript to toggle.\n removeClass('.questionflagsavebutton', form);\n // Scroll to the position indicated by scrollpos= in the URL, if it is there.\n scrollToSavedPos(form);\n }\n};\n\n/**\n * Set the autocomplete off.\n *\n * @method autocompleteOff\n * @param {object} form The form element.\n */\nconst autocompleteOff = (form) => {\n form.setAttribute(\"autocomplete\", \"off\");\n};\n\n/**\n * Event handler to stop a question form being submitted more than once.\n *\n * @method preventRepeatSubmission\n * @param {object} form The form element.\n */\nconst preventRepeatSubmission = (form) => {\n form.addEventListener(\"submit\", function() {\n $(this).submit(function() {\n return false;\n });\n return true;\n });\n};\n\n/**\n * Removes a class inside an element.\n *\n * @method removeClass\n * @param {string} classname Class name.\n * @param {object} form The form element.\n */\nconst removeClass = (classname, form) => {\n form.querySelectorAll(classname).forEach(e => e.remove());\n};\n\n/**\n * If there is a parameter like scrollpos=123 in the URL, scroll to that saved position.\n * (Note: Moodle 4.0 and above do NOT support Internet Explorer 11 and below.)\n *\n * @method scrollToSavedPos\n * @param {object} form The form element.\n */\nconst scrollToSavedPos = (form) => {\n let matches = window.location.href.match(/^.*[?&]scrollpos=(\\d*)(?:&|$|#).*$/, '$1');\n if (matches) {\n // DOMContentLoaded is the effective one here. I am leaving the immediate call to\n // window.scrollTo in case it reduces flicker.\n window.scrollTo(0, matches[1]);\n form.addEventListener(\"DOMContentLoaded\", () => {\n window.scrollTo(0, matches[1]);\n });\n }\n};\n"],"file":"preview.min.js"} \ No newline at end of file diff --git a/question/bank/previewquestion/amd/src/preview.js b/question/bank/previewquestion/amd/src/preview.js new file mode 100644 index 00000000000..bef98bef3c8 --- /dev/null +++ b/question/bank/previewquestion/amd/src/preview.js @@ -0,0 +1,117 @@ +// 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 . + +/** + * Javascript for preview. + * + * @module qbank_preview/preview + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import $ from 'jquery'; + +/** + * Set up the actions. + * + * @method init + * @param {bool} redirect Redirect. + */ +export const init = (redirect) => { + if (!redirect) { + let closeButton = document.getElementById('close-previewquestion-page'); + closeButton.onclick = () => { + window.close(); + }; + } + // Set up the form to be displayed. + setupQuestionForm('responseform'); +}; + +/** + * Set up the form element to be displayed. + * + * @method setupQuestionForm + * @param {string} formElement The form element. + */ +const setupQuestionForm = (formElement) => { + let form = document.getElementById(formElement); + if (form) { + // Turning off browser autocomplete. + autocompleteOff(form); + // Stop a question form being submitted more than once. + preventRepeatSubmission(form); + // Removes any '.questionflagsavebutton's, since we have JavaScript to toggle. + removeClass('.questionflagsavebutton', form); + // Scroll to the position indicated by scrollpos= in the URL, if it is there. + scrollToSavedPos(form); + } +}; + +/** + * Set the autocomplete off. + * + * @method autocompleteOff + * @param {object} form The form element. + */ +const autocompleteOff = (form) => { + form.setAttribute("autocomplete", "off"); +}; + +/** + * Event handler to stop a question form being submitted more than once. + * + * @method preventRepeatSubmission + * @param {object} form The form element. + */ +const preventRepeatSubmission = (form) => { + form.addEventListener("submit", function() { + $(this).submit(function() { + return false; + }); + return true; + }); +}; + +/** + * Removes a class inside an element. + * + * @method removeClass + * @param {string} classname Class name. + * @param {object} form The form element. + */ +const removeClass = (classname, form) => { + form.querySelectorAll(classname).forEach(e => e.remove()); +}; + +/** + * If there is a parameter like scrollpos=123 in the URL, scroll to that saved position. + * (Note: Moodle 4.0 and above do NOT support Internet Explorer 11 and below.) + * + * @method scrollToSavedPos + * @param {object} form The form element. + */ +const scrollToSavedPos = (form) => { + let matches = window.location.href.match(/^.*[?&]scrollpos=(\d*)(?:&|$|#).*$/, '$1'); + if (matches) { + // DOMContentLoaded is the effective one here. I am leaving the immediate call to + // window.scrollTo in case it reduces flicker. + window.scrollTo(0, matches[1]); + form.addEventListener("DOMContentLoaded", () => { + window.scrollTo(0, matches[1]); + }); + } +}; diff --git a/question/bank/previewquestion/classes/form/preview_options_form.php b/question/bank/previewquestion/classes/form/preview_options_form.php new file mode 100644 index 00000000000..40e24c6db40 --- /dev/null +++ b/question/bank/previewquestion/classes/form/preview_options_form.php @@ -0,0 +1,96 @@ +. + +namespace qbank_previewquestion\form; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . '/formslib.php'); + +use moodleform; +use question_display_options; +use question_engine; + +/** + * Settings form for the preview options. + * + * @package qbank_previewquestion + * @copyright 2009 The Open University + * @author 2021 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class preview_options_form extends moodleform { + + public function definition() { + $mform = $this->_form; + + $hiddenorvisible = [ + question_display_options::HIDDEN => get_string('notshown', 'question'), + question_display_options::VISIBLE => get_string('shown', 'question'), + ]; + + $mform->addElement('header', 'attemptoptionsheader', get_string('attemptoptions', 'question')); + + $behaviours = question_engine::get_behaviour_options( + $this->_customdata['quba']->get_preferred_behaviour()); + $mform->addElement('select', 'behaviour', + get_string('howquestionsbehave', 'question'), $behaviours); + $mform->addHelpButton('behaviour', 'howquestionsbehave', 'question'); + + $mform->addElement('float', 'maxmark', get_string('markedoutof', 'question'), ['size' => '5']); + + if ($this->_customdata['maxvariant'] > 1) { + $variants = range(1, $this->_customdata['maxvariant']); + $mform->addElement('select', 'variant', get_string('questionvariant', 'question'), + array_combine($variants, $variants)); + } + $mform->setType('variant', PARAM_INT); + + $mform->addElement('submit', 'saverestart', + get_string('restartwiththeseoptions', 'question')); + + $mform->addElement('header', 'displayoptionsheader', get_string('displayoptions', 'question')); + + $mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'), + $hiddenorvisible); + + $marksoptions = [ + question_display_options::HIDDEN => get_string('notshown', 'question'), + question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'), + question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'), + ]; + $mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions); + + $mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'), + question_engine::get_dp_options()); + + $mform->addElement('select', 'feedback', + get_string('specificfeedback', 'question'), $hiddenorvisible); + + $mform->addElement('select', 'generalfeedback', + get_string('generalfeedback', 'question'), $hiddenorvisible); + + $mform->addElement('select', 'rightanswer', + get_string('rightanswer', 'question'), $hiddenorvisible); + + $mform->addElement('select', 'history', + get_string('responsehistory', 'question'), $hiddenorvisible); + + $mform->addElement('submit', 'saveupdate', + get_string('updatedisplayoptions', 'question')); + } + +} diff --git a/question/bank/previewquestion/classes/helper.php b/question/bank/previewquestion/classes/helper.php new file mode 100644 index 00000000000..3e7e2e7631f --- /dev/null +++ b/question/bank/previewquestion/classes/helper.php @@ -0,0 +1,250 @@ +. + +namespace qbank_previewquestion; + +use context; +use moodle_url; +use question_display_options; +use question_engine; +use stdClass; + +/** + * Class helper contains all the helper functions. + * + * @package qbank_previewquestion + * @copyright 2010 The Open University + * @author 2021 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class helper { + + /** + * Called via pluginfile.php -> question_pluginfile to serve files belonging to + * a question in a question_attempt when that attempt is a preview. + * + * @param stdClass $course course settings object + * @param stdClass $context context object + * @param string $component the name of the component we are serving files for. + * @param string $filearea the name of the file area. + * @param int $qubaid the question_usage this image belongs to. + * @param int $slot the relevant slot within the usage. + * @param array $args the remaining bits of the file path. + * @param bool $forcedownload whether the user must be forced to download the file. + * @param array $fileoptions + * @return void false if file not found, does not return if found - justsend the file + */ + public static function question_preview_question_pluginfile($course, $context, $component, + $filearea, $qubaid, $slot, $args, $forcedownload, $fileoptions): void { + global $USER, $DB, $CFG; + + list($context, $course, $cm) = get_context_info_array($context->id); + require_login($course, false, $cm); + + $quba = question_engine::load_questions_usage_by_activity($qubaid); + + if (!question_has_capability_on($quba->get_question($slot, false), 'use')) { + send_file_not_found(); + } + + $options = new question_display_options(); + $options->feedback = question_display_options::VISIBLE; + $options->numpartscorrect = question_display_options::VISIBLE; + $options->generalfeedback = question_display_options::VISIBLE; + $options->rightanswer = question_display_options::VISIBLE; + $options->manualcomment = question_display_options::VISIBLE; + $options->history = question_display_options::VISIBLE; + if (!$quba->check_file_access($slot, $options, $component, + $filearea, $args, $forcedownload)) { + send_file_not_found(); + } + + $fs = get_file_storage(); + $relativepath = implode('/', $args); + $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}"; + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + send_file_not_found(); + } + + send_stored_file($file, 0, 0, $forcedownload, $fileoptions); + } + + /** + * The the URL to use for actions relating to this preview. + * + * @param int $questionid the question being previewed. + * @param int $qubaid the id of the question usage for this preview. + * @param question_preview_options $options the options in use. + * @param context $context + * @param moodle_url $returnurl + * @return moodle_url + */ + public static function question_preview_action_url($questionid, $qubaid, + question_preview_options $options, $context, $returnurl = null): moodle_url { + $params = [ + 'id' => $questionid, + 'previewid' => $qubaid, + ]; + if ($context->contextlevel == CONTEXT_MODULE) { + $params['cmid'] = $context->instanceid; + } else if ($context->contextlevel == CONTEXT_COURSE) { + $params['courseid'] = $context->instanceid; + } + if ($returnurl !== null) { + $params['returnurl'] = $returnurl; + } + $params = array_merge($params, $options->get_url_params()); + return new moodle_url('/question/bank/previewquestion/preview.php', $params); + } + + /** + * The the URL to use for actions relating to this preview. + * @param int $questionid the question being previewed. + * @param context $context the current moodle context. + * @param int $previewid optional previewid to sign post saved previewed answers. + * @param moodle_url $returnurl + * @return moodle_url + */ + public static function question_preview_form_url($questionid, $context, $previewid = null, $returnurl = null): moodle_url { + $params = [ + 'id' => $questionid, + ]; + if ($context->contextlevel == CONTEXT_MODULE) { + $params['cmid'] = $context->instanceid; + } else if ($context->contextlevel == CONTEXT_COURSE) { + $params['courseid'] = $context->instanceid; + } + if ($previewid) { + $params['previewid'] = $previewid; + } + if ($returnurl !== null) { + $params['returnurl'] = $returnurl; + } + return new moodle_url('/question/bank/previewquestion/preview.php', $params); + } + + /** + * Delete the current preview, if any, and redirect to start a new preview. + * @param int $previewid + * @param int $questionid + * @param object $displayoptions + * @param object $context + * @param moodle_url $returnurl + */ + public static function restart_preview($previewid, $questionid, $displayoptions, $context, $returnurl = null): void { + global $DB; + + if ($previewid) { + $transaction = $DB->start_delegated_transaction(); + question_engine::delete_questions_usage_by_activity($previewid); + $transaction->allow_commit(); + } + redirect(self::question_preview_url($questionid, $displayoptions->behaviour, + $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context, $returnurl)); + } + + /** + * Generate the URL for starting a new preview of a given question with the given options. + * @param integer $questionid the question to preview. + * @param string $preferredbehaviour the behaviour to use for the preview. + * @param float $maxmark the maximum to mark the question out of. + * @param question_display_options $displayoptions the display options to use. + * @param int $variant the variant of the question to preview. If null, one will + * be picked randomly. + * @param object $context context to run the preview in (affects things like + * filter settings, theme, lang, etc.) Defaults to $PAGE->context. + * @param moodle_url $returnurl + * @return moodle_url the URL. + */ + public static function question_preview_url($questionid, $preferredbehaviour = null, + $maxmark = null, $displayoptions = null, $variant = null, $context = null, $returnurl = null): moodle_url { + + $params = ['id' => $questionid]; + + if (is_null($context)) { + global $PAGE; + $context = $PAGE->context; + } + if ($context->contextlevel == CONTEXT_MODULE) { + $params['cmid'] = $context->instanceid; + } else if ($context->contextlevel == CONTEXT_COURSE) { + $params['courseid'] = $context->instanceid; + } + + if (!is_null($preferredbehaviour)) { + $params['behaviour'] = $preferredbehaviour; + } + + if (!is_null($maxmark)) { + $params['maxmark'] = format_float($maxmark, -1); + } + + if (!is_null($displayoptions)) { + $params['correctness'] = $displayoptions->correctness; + $params['marks'] = $displayoptions->marks; + $params['markdp'] = $displayoptions->markdp; + $params['feedback'] = (bool) $displayoptions->feedback; + $params['generalfeedback'] = (bool) $displayoptions->generalfeedback; + $params['rightanswer'] = (bool) $displayoptions->rightanswer; + $params['history'] = (bool) $displayoptions->history; + } + + if (!is_null($returnurl)) { + $params['returnurl'] = $returnurl; + } + + if ($variant) { + $params['variant'] = $variant; + } + + return new moodle_url('/question/bank/previewquestion/preview.php', $params); + } + + /** + * Popup params for the question preview. + * @return array that can be passed as $params to the {@see popup_action} constructor. + */ + public static function question_preview_popup_params(): array { + return [ + 'height' => 600, + 'width' => 800, + ]; + } + + /** + * Get the extra elements for preview from qbank plugins. + * + * @param \question_definition $question + * @param int $courseid + * @return array + */ + public static function get_preview_extra_elements(\question_definition $question, int $courseid): array { + $plugintype = 'qbank'; + $functionname = 'preview_display'; + $extrahtml = []; + $comment = ''; + $plugins = get_plugin_list_with_function($plugintype, $functionname); + foreach ($plugins as $componentname => $plugin) { + $pluginhtml = component_callback($componentname, $functionname, [$question, $courseid]); + if ($componentname === 'qbank_comment') { + $comment = $pluginhtml; + continue; + } + $extrahtml[] = $pluginhtml; + } + return [$comment, $extrahtml]; + } +} diff --git a/question/bank/previewquestion/classes/output/renderer.php b/question/bank/previewquestion/classes/output/renderer.php new file mode 100644 index 00000000000..38af4566a39 --- /dev/null +++ b/question/bank/previewquestion/classes/output/renderer.php @@ -0,0 +1,68 @@ +. + +namespace qbank_previewquestion\output; + +use context; +use qbank_previewquestion\helper; + +/** + * Class renderer for rendering preview url + * + * @package qbank_previewquestion + * @copyright 2009 The Open University + * @author 2021 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Render an icon, optionally with the word 'Preview' beside it, to preview a given question. + * + * @param int $questionid the id of the question to be previewed. + * @param context $context the context in which the preview is happening. + * Must be a course or category context. + * @param bool $showlabel if true, show the word 'Preview' after the icon. + * If false, just show the icon. + */ + public function question_preview_link($questionid, context $context, $showlabel) { + if ($showlabel) { + $alt = ''; + $label = get_string('preview'); + $attributes = []; + } else { + $alt = get_string('preview'); + $label = ''; + $attributes = ['title' => $alt]; + } + + $image = $this->pix_icon('t/preview', $alt, '', ['class' => 'iconsmall']); + $link = helper::question_preview_url($questionid, null, null, null, null, $context); + $action = new \popup_action('click', $link, 'questionpreview', helper::question_preview_popup_params()); + + return $this->action_link($link, $image . $label, $action, $attributes); + } + + /** + * Render the preview page. + * + * @param array $previewdata + */ + public function render_preview_page($previewdata) { + return $this->render_from_template('qbank_previewquestion/preview_question', $previewdata); + } + +} diff --git a/question/bank/previewquestion/classes/plugin_feature.php b/question/bank/previewquestion/classes/plugin_feature.php new file mode 100644 index 00000000000..1414dc49046 --- /dev/null +++ b/question/bank/previewquestion/classes/plugin_feature.php @@ -0,0 +1,34 @@ +. + +namespace qbank_previewquestion; + +/** + * Class columns is the entrypoint for the columns. + * + * @package qbank_previewquestion + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class plugin_feature extends \core_question\local\bank\plugin_features_base{ + + public function get_question_columns($qbank): array { + return [ + new preview_action_column($qbank) + ]; + } +} diff --git a/question/bank/previewquestion/classes/preview_action_column.php b/question/bank/previewquestion/classes/preview_action_column.php new file mode 100644 index 00000000000..b191fe3de71 --- /dev/null +++ b/question/bank/previewquestion/classes/preview_action_column.php @@ -0,0 +1,62 @@ +. + +namespace qbank_previewquestion; + +use core_question\local\bank\menu_action_column_base; + +/** + * Question bank columns for the preview action icon. + * + * @package qbank_previewquestion + * @copyright 2009 Tim Hunt + * @author 2021 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class preview_action_column extends menu_action_column_base { + + /** + * @var string store this lang string for performance. + */ + protected $strpreview; + + public function init(): void { + parent::init(); + $this->strpreview = get_string('preview'); + } + + public function get_name(): string { + return 'previewaction'; + } + + protected function get_url_icon_and_label(\stdClass $question): array { + if (!\question_bank::is_qtype_installed($question->qtype)) { + // It sometimes happens that people end up with junk questions + // in their question bank of a type that is no longer installed. + // We cannot do most actions on them, because that leads to errors. + return [null, null, null]; + } + + if (question_has_capability_on($question, 'use')) { + $context = $this->qbank->get_most_specific_context(); + $url = helper::question_preview_url($question->id, null, null, + null, null, $context, $this->qbank->returnurl); + return [$url, 't/preview', $this->strpreview]; + } else { + return [null, null, null]; + } + } +} diff --git a/question/bank/previewquestion/classes/privacy/provider.php b/question/bank/previewquestion/classes/privacy/provider.php new file mode 100644 index 00000000000..9378360a7c8 --- /dev/null +++ b/question/bank/previewquestion/classes/privacy/provider.php @@ -0,0 +1,32 @@ +. + +namespace qbank_previewquestion\privacy; + +/** + * Privacy Subsystem for qbank_previewquestion implementing null_provider. + * + * @package qbank_previewquestion + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\null_provider { + + public static function get_reason(): string { + return 'privacy:metadata'; + } +} diff --git a/question/bank/previewquestion/classes/question_preview_options.php b/question/bank/previewquestion/classes/question_preview_options.php new file mode 100644 index 00000000000..77c9cd4e628 --- /dev/null +++ b/question/bank/previewquestion/classes/question_preview_options.php @@ -0,0 +1,141 @@ +. + +namespace qbank_previewquestion; + +use question_display_options; + +/** + * Displays question preview options as default and set the options. + * + * Setting default, getting and setting user preferences in question preview options. + * + * @package qbank_previewquestion + * @copyright 2010 The Open University + * @author 2021 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_preview_options extends question_display_options { + + /** @var string the behaviour to use for this preview. */ + public $behaviour; + + /** @var number the maximum mark to use for this preview. */ + public $maxmark; + + /** @var int the variant of the question to preview. */ + public $variant; + + /** @var string prefix to append to field names to get user_preference names. */ + const OPTIONPREFIX = 'question_preview_options_'; + + /** + * Constructor. + * @param \stdClass $question + */ + public function __construct($question) { + $this->behaviour = 'deferredfeedback'; + $this->maxmark = $question->defaultmark; + $this->variant = null; + $this->correctness = self::VISIBLE; + $this->marks = self::MARK_AND_MAX; + $this->markdp = get_config('quiz', 'decimalpoints'); + $this->feedback = self::VISIBLE; + $this->numpartscorrect = $this->feedback; + $this->generalfeedback = self::VISIBLE; + $this->rightanswer = self::VISIBLE; + $this->history = self::HIDDEN; + $this->flags = self::HIDDEN; + $this->manualcomment = self::HIDDEN; + } + + /** + * Names of the options we store in the user preferences table. + * @return array + */ + protected function get_user_pref_fields(): array { + return ['behaviour', 'correctness', 'marks', 'markdp', 'feedback', 'generalfeedback', 'rightanswer', 'history']; + } + + /** + * Names and param types of the options we read from the request. + * @return array + */ + protected function get_field_types(): array { + return [ + 'behaviour' => PARAM_ALPHA, + 'maxmark' => PARAM_LOCALISEDFLOAT, + 'variant' => PARAM_INT, + 'correctness' => PARAM_BOOL, + 'marks' => PARAM_INT, + 'markdp' => PARAM_INT, + 'feedback' => PARAM_BOOL, + 'generalfeedback' => PARAM_BOOL, + 'rightanswer' => PARAM_BOOL, + 'history' => PARAM_BOOL, + ]; + } + + /** + * Load the value of the options from the user_preferences table. + */ + public function load_user_defaults(): void { + $defaults = get_config('question_preview'); + foreach ($this->get_user_pref_fields() as $field) { + $this->$field = get_user_preferences( + self::OPTIONPREFIX . $field, $defaults->$field); + } + $this->numpartscorrect = $this->feedback; + } + + /** + * Save a change to the user's preview options to the database. + * @param object $newoptions + */ + public function save_user_preview_options($newoptions): void { + foreach ($this->get_user_pref_fields() as $field) { + if (isset($newoptions->$field)) { + set_user_preference(self::OPTIONPREFIX . $field, $newoptions->$field); + } + } + } + + /** + * Set the value of any fields included in the request. + */ + public function set_from_request(): void { + foreach ($this->get_field_types() as $field => $type) { + $this->$field = optional_param($field, $this->$field, $type); + } + $this->numpartscorrect = $this->feedback; + } + + /** + * Parameters needed in the URL when continuing this preview. + * + * @return array URL fragment. + */ + public function get_url_params(): array { + $params = []; + foreach ($this->get_field_types() as $field => $notused) { + if ($field === 'behaviour' || $field === 'maxmark' || is_null($this->$field)) { + continue; + } + $params[$field] = $this->$field; + } + return $params; + } +} diff --git a/question/bank/previewquestion/lang/en/qbank_previewquestion.php b/question/bank/previewquestion/lang/en/qbank_previewquestion.php new file mode 100644 index 00000000000..b101c55e6e1 --- /dev/null +++ b/question/bank/previewquestion/lang/en/qbank_previewquestion.php @@ -0,0 +1,27 @@ +. + +/** + * Strings for component qbank_previewquestion, language 'en' + * + * @package qbank_previewquestion + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['pluginname'] = 'Preview question'; +$string['privacy:metadata'] = 'Preview question plugin does not store any user data.'; diff --git a/question/bank/previewquestion/preview.php b/question/bank/previewquestion/preview.php new file mode 100644 index 00000000000..4dab1afdc46 --- /dev/null +++ b/question/bank/previewquestion/preview.php @@ -0,0 +1,315 @@ +. + +/** + * This page displays a preview of a question + * + * The preview uses the option settings from the activity within which the question + * is previewed or the default settings if no activity is specified. The question session + * information is stored in the session as an array of subsequent states rather + * than in the database. + * + * @package qbank_previewquestion + * @copyright Alex Smith {@link http://maths.york.ac.uk/serving_maths} + * @author 2021 Safat Shahin and numerous contributors. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../../config.php'); +require_once($CFG->libdir . '/questionlib.php'); + +use qbank_previewquestion\form\preview_options_form; +use qbank_previewquestion\question_preview_options; +use qbank_previewquestion\helper; + +/** + * The maximum number of variants previewable. If there are more variants than this for a question + * then we only allow the selection of the first x variants. + * + * @var integer + */ +define('QUESTION_PREVIEW_MAX_VARIANTS', 100); + +\core_question\local\bank\helper::require_plugin_enabled('qbank_previewquestion'); + +// Get and validate question id. +$id = required_param('id', PARAM_INT); +$returnurl = optional_param('returnurl', null, PARAM_RAW); +$question = question_bank::load_question($id); + +if ($returnurl) { + $returnurl = new moodle_url($returnurl); +} + +// Were we given a particular context to run the question in? +// This affects things like filter settings, or forced theme or language. +if ($cmid = optional_param('cmid', 0, PARAM_INT)) { + $cm = get_coursemodule_from_id(false, $cmid); + require_login($cm->course, false, $cm); + $context = context_module::instance($cmid); + +} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) { + require_login($courseid); + $context = context_course::instance($courseid); + +} else { + require_login(); + $category = $DB->get_record('question_categories', ['id' => $question->category], '*', MUST_EXIST); + $context = context::instance_by_id($category->contextid); + $PAGE->set_context($context); + // Note that in the other cases, require_login will set the correct page context. +} +question_require_capability_on($question, 'use'); +$PAGE->set_pagelayout('popup'); + +// Get and validate display options. +$maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS); +$options = new question_preview_options($question); +$options->load_user_defaults(); +$options->set_from_request(); +$PAGE->set_url(helper::question_preview_url($id, $options->behaviour, $options->maxmark, + $options, $options->variant, $context)); + +// Get and validate existing preview, or start a new one. +$previewid = optional_param('previewid', 0, PARAM_INT); + +if ($previewid) { + try { + $quba = question_engine::load_questions_usage_by_activity($previewid); + + } catch (Exception $e) { + // This may not seem like the right error message to display, but + // actually from the user point of view, it makes sense. + throw new moodle_exception('submissionoutofsequencefriendlymessage', 'question', + helper::question_preview_url($question->id, $options->behaviour, + $options->maxmark, $options, $options->variant, $context), null, $e); + } + + if ($quba->get_owning_context()->instanceid != $USER->id) { + throw new moodle_exception('notyourpreview', 'question'); + } + + $slot = $quba->get_first_question_number(); + $usedquestion = $quba->get_question($slot, false); + if ($usedquestion->id != $question->id) { + throw new moodle_exception('questionidmismatch', 'question'); + } + $question = $usedquestion; + $options->variant = $quba->get_variant($slot); + +} else { + $quba = question_engine::make_questions_usage_by_activity( + 'core_question_preview', context_user::instance($USER->id)); + $quba->set_preferred_behaviour($options->behaviour); + $slot = $quba->add_question($question, $options->maxmark); + + if ($options->variant) { + $options->variant = min($maxvariant, max(1, $options->variant)); + } else { + $options->variant = rand(1, $maxvariant); + } + + $quba->start_question($slot, $options->variant); + + $transaction = $DB->start_delegated_transaction(); + question_engine::save_questions_usage_by_activity($quba); + $transaction->allow_commit(); +} +$options->behaviour = $quba->get_preferred_behaviour(); +$options->maxmark = $quba->get_question_max_mark($slot); + +// Create the settings form, and initialise the fields. +$optionsform = new preview_options_form(helper::question_preview_form_url($question->id, $context, $previewid, $returnurl), + ['quba' => $quba, 'maxvariant' => $maxvariant]); +$optionsform->set_data($options); + +// Process change of settings, if that was requested. +if ($newoptions = $optionsform->get_submitted_data()) { + // Set user preferences. + $options->save_user_preview_options($newoptions); + if (!isset($newoptions->variant)) { + $newoptions->variant = $options->variant; + } + if (isset($newoptions->saverestart)) { + helper::restart_preview($previewid, $question->id, $newoptions, $context, $returnurl); + } +} + +// Prepare a URL that is used in various places. +$actionurl = helper::question_preview_action_url($question->id, $quba->get_id(), $options, $context, $returnurl); + +// Process any actions from the buttons at the bottom of the form. +if (data_submitted() && confirm_sesskey()) { + + try { + + if (optional_param('restart', false, PARAM_BOOL)) { + helper::restart_preview($previewid, $question->id, $options, $context, $returnurl); + + } else if (optional_param('fill', null, PARAM_BOOL)) { + $correctresponse = $quba->get_correct_response($slot); + if (!is_null($correctresponse)) { + $quba->process_action($slot, $correctresponse); + + $transaction = $DB->start_delegated_transaction(); + question_engine::save_questions_usage_by_activity($quba); + $transaction->allow_commit(); + } + redirect($actionurl); + + } else if (optional_param('finish', null, PARAM_BOOL)) { + $quba->process_all_actions(); + $quba->finish_all_questions(); + + $transaction = $DB->start_delegated_transaction(); + question_engine::save_questions_usage_by_activity($quba); + $transaction->allow_commit(); + redirect($actionurl); + + } else { + $quba->process_all_actions(); + + $transaction = $DB->start_delegated_transaction(); + question_engine::save_questions_usage_by_activity($quba); + $transaction->allow_commit(); + + $scrollpos = optional_param('scrollpos', '', PARAM_RAW); + if ($scrollpos !== '') { + $actionurl->param('scrollpos', (int) $scrollpos); + } + redirect($actionurl); + } + + } catch (question_out_of_sequence_exception $e) { + throw new moodle_exception('submissionoutofsequencefriendlymessage', 'question', $actionurl); + + } catch (Exception $e) { + // This sucks, if we display our own custom error message, there is no way + // to display the original stack trace. + $debuginfo = ''; + if (!empty($e->debuginfo)) { + $debuginfo = $e->debuginfo; + } + throw new moodle_exception('errorprocessingresponses', 'question', $actionurl, + $e->getMessage(), $debuginfo); + } +} + +if ($question->length) { + $displaynumber = '1'; +} else { + $displaynumber = 'i'; +} +$restartdisabled = []; +$finishdisabled = []; +$filldisabled = []; +if ($quba->get_question_state($slot)->is_finished()) { + $finishdisabled = ['disabled' => 'disabled']; + $filldisabled = ['disabled' => 'disabled']; +} +// If question type cannot give us a correct response, disable this button. +if (is_null($quba->get_correct_response($slot))) { + $filldisabled = ['disabled' => 'disabled']; +} +if (!$previewid) { + $restartdisabled = ['disabled' => 'disabled']; +} + +// Prepare technical info to be output. +$qa = $quba->get_question_attempt($slot); +$technical = []; +$technical[] = get_string('behaviourbeingused', 'question', + question_engine::get_behaviour_name($qa->get_behaviour_name())); +$technical[] = get_string('technicalinfominfraction', 'question', $qa->get_min_fraction()); +$technical[] = get_string('technicalinfomaxfraction', 'question', $qa->get_max_fraction()); +$technical[] = get_string('technicalinfovariant', 'question', $qa->get_variant()); +$technical[] = get_string('technicalinfoquestionsummary', 'question', s($qa->get_question_summary())); +$technical[] = get_string('technicalinforightsummary', 'question', s($qa->get_right_answer_summary())); +$technical[] = get_string('technicalinforesponsesummary', 'question', s($qa->get_response_summary())); +$technical[] = get_string('technicalinfostate', 'question', '' . $qa->get_state()); + +// Start output. +$title = get_string('previewquestion', 'question', format_string($question->name)); +$headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot); +$PAGE->set_title($title); +$PAGE->set_heading($title); +echo $OUTPUT->header(); + +$previewdata = []; +$previewdata['actionurl'] = $actionurl; +$previewdata['session'] = sesskey(); +$previewdata['slot'] = $slot; +// Output of the question. +$previewdata['question'] = $quba->render_question($slot, $options, $displaynumber); +$previewdata['restartdisabled'] = html_writer::attributes($restartdisabled); +$previewdata['finishdisabled'] = html_writer::attributes($finishdisabled); +$previewdata['filldisabled'] = html_writer::attributes($filldisabled); +// Output the technical info. +$previewdata['techinfo'] = print_collapsible_region_start('', 'techinfo', get_string('technicalinfo', 'question'), + 'core_question_preview_techinfo_collapsed', true, true, $OUTPUT->help_icon('technicalinfo', 'question')); +foreach ($technical as $info) { + $previewdata['techinfo'] .= html_writer::tag('p', $info, ['class' => 'notifytiny']); +} +$previewdata['techinfo'] .= print_collapsible_region_end(true); + +// Output a link to export this single question. +if (question_has_capability_on($question, 'view')) { + if (class_exists('qbank_exporttoxml\\exporttoxml_helper')) { + if (\core\plugininfo\qbank::is_plugin_enabled('qbank_exporttoxml')) { + $exportfunction = '\\qbank_exporttoxml\\exporttoxml_helper::question_get_export_single_question_url'; + $previewdata['exporttoxml'] = html_writer::link($exportfunction($question), + get_string('exportonequestion', 'question')); + } + } else { + $exportfunction = 'question_get_export_single_question_url'; + $previewdata['exporttoxml'] = html_writer::link($exportfunction($question), + get_string('exportonequestion', 'question')); + } +} + +// Display the settings form. +$previewdata['options'] = $optionsform->render(); + +list($comment, $extraelements) = helper::get_preview_extra_elements($question, $COURSE->id); + +if (!empty($comment)) { + $previewdata['comments'] = $comment; +} + +if (!empty($extraelements)) { + $elements = []; + foreach ($extraelements as $extraelement) { + $element = new stdClass(); + $element->extrapreviewelements = $extraelement; + $elements[] = $element; + } + $previewdata['extrapreviewelements'] = $elements; +} + +$previewdata['redirect'] = false; +if (!is_null($returnurl)) { + $previewdata['redirect'] = true; + $previewdata['redirecturl'] = $returnurl; +} + +echo $PAGE->get_renderer('qbank_previewquestion')->render_preview_page($previewdata); + +// Log the preview of this question. +$event = \core\event\question_viewed::create_from_question_instance($question, $context); +$event->trigger(); + +$PAGE->requires->js_call_amd('qbank_previewquestion/preview', 'init', [$previewdata['redirect']]); +echo $OUTPUT->footer(); diff --git a/question/bank/previewquestion/templates/preview_question.mustache b/question/bank/previewquestion/templates/preview_question.mustache new file mode 100644 index 00000000000..1f2bdf05de0 --- /dev/null +++ b/question/bank/previewquestion/templates/preview_question.mustache @@ -0,0 +1,89 @@ +{{! + 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 . +}} +{{! + @template qbank_previewquestion/preview_question + + The preview page for the question type preview. + * actionurl - Url to post to + * session - Moodle session + * slot - The identifying number of the first question that was added to this usage + * question - The html of the actual question from the engine + * restartdisabled - The attributes to enable or disable the button, same for finishdisabled and filldisabled + * techinfo - Technical information like fraction, state, behaviour etc + * exporttoxml - Link to export the question to xml + * redirecturl - Url to the base view + * comments - Comments api html + * extrapreviewelements - Any plugin implementing the callback and sending extra html to view something in the preview page + + Example context (json): + { + "previewdata": [ + { + "actionurl": "/", + "session": "E2PwCfrnzz", + "slot": "1", + "question": "
question html
", + "restartdisabled": "disabled='disabled'", + "finishdisabled": "disabled='disabled'", + "filldisabled": "disabled='disabled'", + "techinfo": "
Behaviour being used: Deferred feedback
", + "redirecturl": "/", + "exporttoxml": "Download this question in Moodle XML format", + "comments": "html from comments api", + "extrapreviewelements": "
callback to get html from plugins need to show info in preview
" + } + ] + } +}} +
+
+ + + +
+ {{{question}}} +
+ + + + + {{^redirect}} + + {{/redirect}} + {{#redirect}} + {{#str}} closepreview, question{{/str}} + {{/redirect}} +
+
+{{{techinfo}}} +{{{exporttoxml}}} +{{#comments}} +
+
+ {{{options}}} +
+
+ {{{comments}}} +
+
+{{/comments}} +{{^comments}} + {{{options}}} +{{/comments}} +{{#extrapreviewelements}} + {{{extrapreviewelements}}} +{{/extrapreviewelements}} diff --git a/question/tests/behat/preview_question.feature b/question/bank/previewquestion/tests/behat/preview_question.feature similarity index 93% rename from question/tests/behat/preview_question.feature rename to question/bank/previewquestion/tests/behat/preview_question.feature index e3630e34a39..9d1c6903c75 100644 --- a/question/tests/behat/preview_question.feature +++ b/question/bank/previewquestion/tests/behat/preview_question.feature @@ -1,4 +1,4 @@ -@core @core_question @javascript @_switch_window +@qbank @qbank_previewquestion @javascript Feature: A teacher can preview questions in the question bank In order to ensure the questions are properly created As a teacher @@ -11,6 +11,9 @@ Feature: A teacher can preview questions in the question bank And the following "courses" exist: | fullname | shortname | format | | Course 1 | C1 | weeks | + And the following "activities" exist: + | activity | name | course | idnumber | + | quiz | Test quiz | C1 | quiz1 | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | @@ -21,10 +24,9 @@ Feature: A teacher can preview questions in the question bank | questioncategory | qtype | name | | Test questions | numerical | Test question to be previewed | And I log in as "teacher1" - And I am on "Course 1" course homepage + And I am on the "Test quiz" "quiz activity" page And I navigate to "Question bank > Questions" in current page administration When I choose "Preview" action for "Test question to be previewed" in the question bank - And I switch to "questionpreview" window Scenario: Question preview shows the question and other information Then the state of "What is pi to two d.p.?" question is shown as "Not yet answered" diff --git a/question/bank/previewquestion/tests/behat/preview_question_action.feature b/question/bank/previewquestion/tests/behat/preview_question_action.feature new file mode 100644 index 00000000000..c720b06a845 --- /dev/null +++ b/question/bank/previewquestion/tests/behat/preview_question_action.feature @@ -0,0 +1,50 @@ +@qbank @qbank_previewquestion +Feature: Use the qbank plugin manager page for previewquestion + In order to check the plugin behaviour with enable and disable + + Background: + Given the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "activities" exist: + | activity | name | course | idnumber | + | quiz | Test quiz | C1 | quiz1 | + And the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | + | Test questions | truefalse | First question | Answer the first question | + + @javascript + Scenario: Enable/disable previewquestion column from the base view + Given I log in as "admin" + When I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I should see "Preview question" + And I click on "Disable" "link" in the "Preview question" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank > Questions" in current page administration + And I click on "#action-menu-toggle-2" "css_element" in the "First question" "table_row" + Then I should not see "Preview" in the "region-main" "region" + And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I click on "Enable" "link" in the "Preview question" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank > Questions" in current page administration + And I click on "#action-menu-toggle-2" "css_element" in the "First question" "table_row" + And I should see "Preview" in the "region-main" "region" + + Scenario: Enable/disable preview button from question edit form + Given I log in as "admin" + When I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I should see "Preview question" + And I click on "Disable" "link" in the "Preview question" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank > Questions" in current page administration + And I choose "Edit question" action for "First question" in the question bank + Then I should not see "Preview" in the "region-main" "region" + And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I click on "Enable" "link" in the "Preview question" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank > Questions" in current page administration + And I choose "Edit question" action for "First question" in the question bank + And I should see "Preview" in the "region-main" "region" diff --git a/question/bank/previewquestion/tests/helper_test.php b/question/bank/previewquestion/tests/helper_test.php new file mode 100644 index 00000000000..33214dcc110 --- /dev/null +++ b/question/bank/previewquestion/tests/helper_test.php @@ -0,0 +1,159 @@ +. + +namespace qbank_previewquestion; + +use core\plugininfo\qbank; + +/** + * Helper tests for question preview. + * + * @package qbank_previewquestion + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \qbank_previewquestion\helper + */ +class helper_test extends \advanced_testcase { + + /** + * @var bool|\context|\context_course $context + */ + public $context; + + /** + * @var object $questiondata; + */ + public $questiondata; + + /** + * @var \question_usage_by_activity $quba + */ + public $quba; + + /** + * @var question_preview_options $options + */ + public $options; + + /** + * @var \moodle_url $returnurl + */ + public $returnurl; + + /** + * Test set up. + * + * This is executed before running any test in this file. + */ + public function setUp(): void { + global $USER; + $this->resetAfterTest(); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $questiongenerator = $generator->get_plugin_generator('core_question'); + // Create a course. + $course = $generator->create_course(); + $this->context = \context_course::instance($course->id); + // Create a question in the default category. + $contexts = new \question_edit_contexts($this->context); + $cat = question_make_default_categories($contexts->all()); + $this->questiondata = $questiongenerator->create_question('numerical', null, + ['name' => 'Example question', 'category' => $cat->id]); + $this->quba = \question_engine::make_questions_usage_by_activity('core_question_preview', \context_user::instance($USER->id)); + $this->options = new question_preview_options($this->questiondata); + $this->options->load_user_defaults(); + $this->options->set_from_request(); + $this->returnurl = new \moodle_url('/question/edit.php'); + } + + /** + * Test the preview action url from the helper class. + * + * @covers ::question_preview_action_url + */ + public function test_question_preview_action_url() { + $actionurl = helper::question_preview_action_url($this->questiondata->id, $this->quba->get_id(), $this->options, + $this->context, $this->returnurl); + $params = [ + 'id' => $this->questiondata->id, + 'previewid' => $this->quba->get_id(), + 'returnurl' => $this->returnurl, + 'courseid' => $this->context->instanceid + ]; + $params = array_merge($params, $this->options->get_url_params()); + $expectedurl = new \moodle_url('/question/bank/previewquestion/preview.php', $params); + $this->assertEquals($expectedurl, $actionurl); + } + + /** + * Test the preview form url from the helper class. + * + * @covers ::question_preview_form_url + */ + public function test_question_preview_form_url() { + $formurl = helper::question_preview_form_url($this->questiondata->id, $this->context, $this->quba->get_id(), $this->returnurl); + $params = [ + 'id' => $this->questiondata->id, + 'previewid' => $this->quba->get_id(), + 'returnurl' => $this->returnurl, + 'courseid' => $this->context->instanceid + ]; + $expectedurl = new \moodle_url('/question/bank/previewquestion/preview.php', $params); + $this->assertEquals($expectedurl, $formurl); + } + + /** + * Test the preview url from the helper class. + * + * @covers ::question_preview_url + */ + public function test_question_preview_url() { + $previewurl = helper::question_preview_url($this->questiondata->id, $this->options->behaviour, $this->options->maxmark, + $this->options, $this->options->variant, $this->context); + $params = [ + 'id' => $this->questiondata->id, + 'behaviour' => $this->options->behaviour, + 'maxmark' => $this->options->maxmark, + 'courseid' => $this->context->instanceid + ]; + // Extra params for options. + $params['correctness'] = $this->options->correctness; + $params['marks'] = $this->options->marks; + $params['markdp'] = $this->options->markdp; + $params['feedback'] = (bool) $this->options->feedback; + $params['generalfeedback'] = (bool) $this->options->generalfeedback; + $params['rightanswer'] = (bool) $this->options->rightanswer; + $params['history'] = (bool) $this->options->history; + $expectedurl = new \moodle_url('/question/bank/previewquestion/preview.php', $params); + $this->assertEquals($expectedurl, $previewurl); + } + + /** + * Test the preview comment callback if available. + * + * @covers ::get_preview_extra_elements + */ + public function test_get_preview_extra_elements() { + $question = \question_bank::load_question($this->questiondata->id); + list($comment, $extraelements) = helper::get_preview_extra_elements($question, $this->context->instanceid); + if (qbank::is_plugin_enabled('qbank_comment')) { + $this->assertEquals("
", $comment); + } else { + $this->assertEquals('', $comment); + } + } +} diff --git a/question/bank/previewquestion/version.php b/question/bank/previewquestion/version.php new file mode 100644 index 00000000000..26ff9eb295f --- /dev/null +++ b/question/bank/previewquestion/version.php @@ -0,0 +1,31 @@ +. + +/** + * Version information for qbank_previewquestion. + * + * @package qbank_previewquestion + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->component = 'qbank_previewquestion'; +$plugin->version = 2021072200; +$plugin->requires = 2021052500; +$plugin->maturity = MATURITY_STABLE; diff --git a/question/classes/local/bank/view.php b/question/classes/local/bank/view.php index 5865cacde30..859abe5df32 100644 --- a/question/classes/local/bank/view.php +++ b/question/classes/local/bank/view.php @@ -673,8 +673,13 @@ class view { * Get the URL to preview a question. * @param \stdClass $questiondata the data defining the question. * @return \moodle_url the URL. + * @deprecated since Moodle 4.0 + * @see \qbank_previewquestion\helper::question_preview_url() + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ public function preview_question_url($questiondata) { + debugging('Function preview_question_url() has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER); return question_preview_url($questiondata->id, null, null, null, null, $this->get_most_specific_context()); } diff --git a/question/editlib.php b/question/editlib.php index 0d5fabab652..84d36949b73 100644 --- a/question/editlib.php +++ b/question/editlib.php @@ -242,7 +242,7 @@ class_alias('qbank_editquestion\copy_action_column', 'question_bank_copy_action_ * @deprecated since Moodle 2.7 MDL-40457 * @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins. */ -class_alias('core_question\bank\preview_action_column', 'question_bank_preview_action_column', true); +class_alias('qbank_previewquestion\preview_action_column', 'question_bank_preview_action_column', true); /** diff --git a/question/engine/renderer.php b/question/engine/renderer.php index 44009073c86..9c98fca4bce 100644 --- a/question/engine/renderer.php +++ b/question/engine/renderer.php @@ -48,24 +48,19 @@ class core_question_renderer extends plugin_renderer_base { * Must be a course or category context. * @param bool $showlabel if true, show the word 'Preview' after the icon. * If false, just show the icon. + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\output\renderer + * @todo MDL-71679 uncomment the debugging message after implementing the changes in mod_quiz + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ public function question_preview_link($questionid, context $context, $showlabel) { - if ($showlabel) { - $alt = ''; - $label = get_string('preview'); - $attributes = array(); - } else { - $alt = get_string('preview'); - $label = ''; - $attributes = array('title' => $alt); - } + // Debugging message will be re-added after implementing the changes in mod_quiz. + // ...debugging('Function question_preview_link() has been deprecated and moved to qbank_previewquestion plugin, + // Please use qbank_previewquestion renderer.', DEBUG_DEVELOPER);. - $image = $this->pix_icon('t/preview', $alt, '', array('class' => 'iconsmall')); - $link = question_preview_url($questionid, null, null, null, null, $context); - $action = new popup_action('click', $link, 'questionpreview', - question_preview_popup_params()); - - return $this->action_link($link, $image . $label, $action, $attributes); + return $this->page->get_renderer('qbank_previewquestion')->question_preview_link( + $questionid, $context, $showlabel + ); } /** diff --git a/question/preview.php b/question/preview.php index 899da99c711..924cbcf98a3 100644 --- a/question/preview.php +++ b/question/preview.php @@ -69,7 +69,7 @@ $PAGE->set_pagelayout('popup'); // Get and validate display options. $maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS); -$options = new question_preview_options($question); +$options = new qbank_previewquestion\question_preview_options($question); $options->load_user_defaults(); $options->set_from_request(); $PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark, @@ -136,7 +136,7 @@ if ($newoptions = $optionsform->get_submitted_data()) { $newoptions->variant = $options->variant; } if (isset($newoptions->saverestart)) { - restart_preview($previewid, $question->id, $newoptions, $context); + qbank_previewquestion\helper::restart_preview($previewid, $question->id, $newoptions, $context); } } @@ -149,7 +149,7 @@ if (data_submitted() && confirm_sesskey()) { try { if (optional_param('restart', false, PARAM_BOOL)) { - restart_preview($previewid, $question->id, $options, $context); + qbank_previewquestion\helper::restart_preview($previewid, $question->id, $options, $context); } else if (optional_param('fill', null, PARAM_BOOL)) { $correctresponse = $quba->get_correct_response($slot); diff --git a/question/previewlib.php b/question/previewlib.php index 5c842a2d5bd..ae447ed57fd 100644 --- a/question/previewlib.php +++ b/question/previewlib.php @@ -17,7 +17,7 @@ /** * Library functions used by question/preview.php. * - * @package moodlecore + * @package core_question * @subpackage questionengine * @copyright 2010 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later @@ -34,9 +34,15 @@ require_once($CFG->libdir . '/formslib.php'); * * @copyright 2009 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\form\preview_options_form + * @todo MDL-71679 class renaming */ class preview_options_form extends moodleform { + public function definition() { + debugging('Class preview_options_form has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\form\preview_options_form instead.', DEBUG_DEVELOPER); $mform = $this->_form; $hiddenofvisible = array( @@ -99,11 +105,15 @@ class preview_options_form extends moodleform { /** - * Displays question preview options as default and set the options + * Displays question preview options as default and set the options. + * * Setting default, getting and setting user preferences in question preview options. * * @copyright 2010 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\output\question_preview_options + * @todo MDL-71679 class renaming */ class question_preview_options extends question_display_options { /** @var string the behaviour to use for this preview. */ @@ -120,8 +130,11 @@ class question_preview_options extends question_display_options { /** * Constructor. + * @param stdClass $question */ public function __construct($question) { + debugging('Class question_preview_options has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\question_preview_options instead.', DEBUG_DEVELOPER); $this->behaviour = 'deferredfeedback'; $this->maxmark = $question->defaultmark; $this->variant = null; @@ -228,42 +241,18 @@ class question_preview_options extends question_display_options { * @param int $slot the relevant slot within the usage. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. - * @param array $options additional options affecting the file serving - * @return bool false if file not found, does not return if found - justsend the file + * @param array $fileoptions + * @return void false if file not found, does not return if found - justsend the file + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::question_preview_question_pluginfile() + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function question_preview_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $fileoptions) { - global $USER, $DB, $CFG; - - list($context, $course, $cm) = get_context_info_array($context->id); - require_login($course, false, $cm); - - $quba = question_engine::load_questions_usage_by_activity($qubaid); - - if (!question_has_capability_on($quba->get_question($slot, false), 'use')) { - send_file_not_found(); - } - - $options = new question_display_options(); - $options->feedback = question_display_options::VISIBLE; - $options->numpartscorrect = question_display_options::VISIBLE; - $options->generalfeedback = question_display_options::VISIBLE; - $options->rightanswer = question_display_options::VISIBLE; - $options->manualcomment = question_display_options::VISIBLE; - $options->history = question_display_options::VISIBLE; - if (!$quba->check_file_access($slot, $options, $component, - $filearea, $args, $forcedownload)) { - send_file_not_found(); - } - - $fs = get_file_storage(); - $relativepath = implode('/', $args); - $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}"; - if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { - send_file_not_found(); - } - - send_stored_file($file, 0, 0, $forcedownload, $fileoptions); + debugging('Function question_preview_question_pluginfile() has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\helper::question_preview_question_pluginfile() instead.', DEBUG_DEVELOPER); + qbank_previewquestion\helper::question_preview_question_pluginfile($course, $context, + $component, $filearea, $qubaid, $slot, $args, $forcedownload, $fileoptions); } /** @@ -271,20 +260,16 @@ function question_preview_question_pluginfile($course, $context, $component, * @param int $questionid the question being previewed. * @param int $qubaid the id of the question usage for this preview. * @param question_preview_options $options the options in use. + * @param context $context + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::question_preview_action_url() + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function question_preview_action_url($questionid, $qubaid, question_preview_options $options, $context) { - $params = array( - 'id' => $questionid, - 'previewid' => $qubaid, - ); - if ($context->contextlevel == CONTEXT_MODULE) { - $params['cmid'] = $context->instanceid; - } else if ($context->contextlevel == CONTEXT_COURSE) { - $params['courseid'] = $context->instanceid; - } - $params = array_merge($params, $options->get_url_params()); - return new moodle_url('/question/preview.php', $params); + debugging('Function question_preview_action_url() has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\helper::question_preview_action_url() instead.', DEBUG_DEVELOPER); + qbank_previewquestion\helper::question_preview_action_url($questionid, $qubaid, $options, $context); } /** @@ -292,20 +277,14 @@ function question_preview_action_url($questionid, $qubaid, * @param int $questionid the question being previewed. * @param context $context the current moodle context. * @param int $previewid optional previewid to sign post saved previewed answers. + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::question_preview_form_url() + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function question_preview_form_url($questionid, $context, $previewid = null) { - $params = array( - 'id' => $questionid, - ); - if ($context->contextlevel == CONTEXT_MODULE) { - $params['cmid'] = $context->instanceid; - } else if ($context->contextlevel == CONTEXT_COURSE) { - $params['courseid'] = $context->instanceid; - } - if ($previewid) { - $params['previewid'] = $previewid; - } - return new moodle_url('/question/preview.php', $params); + debugging('Function question_preview_form_url() has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\helper::question_preview_form_url() instead.', DEBUG_DEVELOPER); + qbank_previewquestion\helper::question_preview_form_url($questionid, $context, $previewid); } /** @@ -314,15 +293,12 @@ function question_preview_form_url($questionid, $context, $previewid = null) { * @param int $questionid * @param object $displayoptions * @param object $context + * @deprecated since Moodle 4.0 + * @see qbank_previewquestion\helper::restart_preview() + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ function restart_preview($previewid, $questionid, $displayoptions, $context) { - global $DB; - - if ($previewid) { - $transaction = $DB->start_delegated_transaction(); - question_engine::delete_questions_usage_by_activity($previewid); - $transaction->allow_commit(); - } - redirect(question_preview_url($questionid, $displayoptions->behaviour, - $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context)); + debugging('Function restart_preview() has been deprecated and moved to qbank_previewquestion plugin, + please use qbank_previewquestion\helper::restart_preview() instead.', DEBUG_DEVELOPER); + qbank_previewquestion\helper::restart_preview($previewid, $questionid, $displayoptions, $context); } diff --git a/question/qengine.js b/question/qengine.js index f8e0cafe930..6a89679e730 100644 --- a/question/qengine.js +++ b/question/qengine.js @@ -80,8 +80,14 @@ M.core_scroll_manager.save_scroll_action = function(e) { /** * If there is a parameter like scrollpos=123 in the URL, scroll to that saved position. + * @deprecated since Moodle 4.0 + * @see question\bank\qbank_previewquestion\amd\src + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ M.core_scroll_manager.scroll_to_saved_pos = function(Y) { + Y.log("The scroll_to_saved_pos function has been deprecated. " + + "Please use scrollToSavedPos() in qbank_preview/preview.js instead.", 'moodle-core-notification', 'warn'); + var matches = window.location.href.match(/^.*[?&]scrollpos=(\d*)(?:&|$|#).*$/, '$1'); if (matches) { // onDOMReady is the effective one here. I am leaving the immediate call to @@ -153,8 +159,14 @@ M.core_question_engine.init_submit_button = function(Y, button) { * 5. Prevent the user from repeatedly submitting the form. * @param Y the Yahoo object. Needs to have the DOM and Event modules loaded. * @param form something that can be passed to Y.one, to find the form element. + * @deprecated since Moodle 4.0 + * @see question\bank\qbank_previewquestion\amd\src + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ M.core_question_engine.init_form = function(Y, form) { + Y.log("The core_question_engine.init_form function has been deprecated. " + + "Please use setupQuestionForm() in qbank_preview/preview.js instead.", 'moodle-core-notification', 'warn'); + Y.one(form).setAttribute('autocomplete', 'off'); Y.on('submit', M.core_question_engine.prevent_repeat_submission, form, form, Y); @@ -175,8 +187,14 @@ M.core_question_engine.init_form = function(Y, form) { * Event handler to stop a question form being submitted more than once. * @param e the form submit event. * @param form the form element. + * @deprecated since Moodle 4.0 + * @see question\bank\qbank_previewquestion\amd\src + * @todo Final deprecation on Moodle 4.4 MDL-72438 */ M.core_question_engine.prevent_repeat_submission = function(e, Y) { + Y.log("The prevent_repeat_submission function has been deprecated. " + + "Please use preventRepeatSubmission in qbank_preview/preview.js instead.", 'moodle-core-notification', 'warn'); + if (M.core_question_engine.questionformalreadysubmitted) { e.halt(); return; diff --git a/question/type/ddimageortext/tests/behat/preview.feature b/question/type/ddimageortext/tests/behat/preview.feature index 4a286418840..cff7bfc8bf3 100644 --- a/question/type/ddimageortext/tests/behat/preview.feature +++ b/question/type/ddimageortext/tests/behat/preview.feature @@ -27,7 +27,6 @@ Feature: Preview a drag-drop onto image question @javascript @_bug_phantomjs Scenario: Preview a question using the mouse. When I choose "Preview" action for "Drag onto image" in the question bank - And I switch to "questionpreview" window # Increase window size and wait 2 seconds to ensure elements are placed properly by js. # Keep window large else drag will scroll the window to find element. And I change window size to "medium" @@ -44,15 +43,12 @@ Feature: Preview a drag-drop onto image question And I press "Submit and finish" Then the state of "Identify the features" question is shown as "Correct" And I should see "Mark 1.00 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question using the keyboard. When I choose "Preview" action for "Drag onto image" in the question bank - And I switch to "questionpreview" window # Increase window size and wait 2 seconds to ensure elements are placed properly by js. - And I change window size to "medium" - And I wait "2" seconds And I type " " on place "1" in the drag and drop onto image question And I type " " on place "2" in the drag and drop onto image question And I type " " on place "3" in the drag and drop onto image question @@ -64,4 +60,4 @@ Feature: Preview a drag-drop onto image question And I press "Submit and finish" Then the state of "Identify the features" question is shown as "Correct" And I should see "Mark 1.00 out of 1.00" - And I switch to the main window + And I press "Close preview" diff --git a/question/type/ddmarker/tests/behat/preview.feature b/question/type/ddmarker/tests/behat/preview.feature index 2bf86b85e82..a57b440a291 100644 --- a/question/type/ddmarker/tests/behat/preview.feature +++ b/question/type/ddmarker/tests/behat/preview.feature @@ -27,11 +27,6 @@ Feature: Preview a drag-drop marker question @javascript @_bug_phantomjs Scenario: Preview a question using the mouse. When I choose "Preview" action for "Drag markers" in the question bank - And I switch to "questionpreview" window - # Increase window size and wait 2 seconds to ensure elements are placed properly by js. - # Keep window large else drag will scroll the window to find element. - And I change window size to "large" - And I wait "2" seconds # Odd, but the
s go to nothing, not a space. And I drag "OU" to "345,230" in the drag and drop markers question And I drag "Railway station" to "262,197" in the drag and drop markers question @@ -40,28 +35,21 @@ Feature: Preview a drag-drop marker question And I press "Submit and finish" Then the state of "Please place the markers on the map of Milton Keynes" question is shown as "Correct" And I should see "Mark 1.00 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question using the keyboard. When I choose "Preview" action for "Drag markers" in the question bank - And I switch to "questionpreview" window - # Increase window size and wait 2 seconds to ensure elements are placed properly by js. - # Keep window large else drag will scroll the window to find element. - And I change window size to "medium" - And I wait "2" seconds And I type "up" "88" times on marker "Railway station" in the drag and drop markers question And I type "right" "26" times on marker "Railway station" in the drag and drop markers question And I press "Submit and finish" Then the state of "Please place the markers on the map of Milton Keynes" question is shown as "Partially correct" And I should see "Mark 0.25 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question in responsive mode. When I choose "Preview" action for "Drag markers" in the question bank - And I switch to "questionpreview" window - And I change window size to "large" And I drag "OU" to "345,230" in the drag and drop markers question And I drag "Railway station" to "262,197" in the drag and drop markers question And I drag "Railway station" to "334,319" in the drag and drop markers question diff --git a/question/type/ddwtos/tests/behat/preview.feature b/question/type/ddwtos/tests/behat/preview.feature index 3f2bb01bbe4..46cd2ef6a02 100644 --- a/question/type/ddwtos/tests/behat/preview.feature +++ b/question/type/ddwtos/tests/behat/preview.feature @@ -28,42 +28,35 @@ Feature: Preview a drag-drop into text question @javascript @_bug_phantomjs Scenario: Preview a question using the mouse. When I choose "Preview" action for "Drag to text" in the question bank - And I switch to "questionpreview" window - # Increase window size and wait 2 seconds to ensure elements are placed properly by js. - # Keep window large else drag will scroll the window to find element. - And I change window size to "medium" - And I wait "2" seconds And I drag "quick" to space "1" in the drag and drop into text question And I drag "fox" to space "2" in the drag and drop into text question And I drag "assiduous" to space "3" in the drag and drop into text question And I press "Submit and finish" Then the state of "The" question is shown as "Partially correct" And I should see "Mark 0.67 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question using the keyboard & submit incomplete. When I choose "Preview" action for "Drag to text" in the question bank - And I switch to "questionpreview" window And I type " " into space "1" in the drag and drop onto image question And I type " " into space "2" in the drag and drop onto image question And I type " " into space "3" in the drag and drop onto image question And I press "Save" Then the state of "The" question is shown as "Incomplete answer" And I should see "Please put an answer in each box." - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question using the keyboard. When I choose "Preview" action for "Drag to text" in the question bank - And I switch to "questionpreview" window And I type " " into space "1" in the drag and drop onto image question And I type " " into space "2" in the drag and drop onto image question And I type " " into space "3" in the drag and drop onto image question And I press "Submit and finish" Then the state of "The" question is shown as "Incorrect" And I should see "Mark 0.00 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a question that uses strange group numbers using the keyboard. @@ -72,24 +65,19 @@ Feature: Preview a drag-drop into text question | Test questions | ddwtos | Funny groups | oddgroups | And I reload the page When I choose "Preview" action for "Funny groups" in the question bank - And I switch to "questionpreview" window And I type " " into space "1" in the drag and drop onto image question And I type " " into space "2" in the drag and drop onto image question And I type " " into space "3" in the drag and drop onto image question And I press "Submit and finish" Then the state of "The" question is shown as "Correct" And I should see "Mark 1.00 out of 1.00" - And I switch to the main window + And I press "Close preview" @javascript Scenario: Preview a infinite question. When I choose "Preview" action for "Drag to text infinite" in the question bank - And I switch to "questionpreview" window - # Increase window size. - # Keep window large else drag will scroll the window to find element. - And I change window size to "medium" And I press "Fill in correct responses" Then I should see "Option1" in the home area of drag and drop into text question And I should see "Option2" in the home area of drag and drop into text question And I should see "Option3" in the home area of drag and drop into text question - And I switch to the main window + And I press "Close preview" diff --git a/question/type/description/tests/behat/preview.feature b/question/type/description/tests/behat/preview.feature index 13b4660369c..e4698a1c10b 100644 --- a/question/type/description/tests/behat/preview.feature +++ b/question/type/description/tests/behat/preview.feature @@ -27,8 +27,7 @@ Feature: Preview a Description question @javascript @_switch_window Scenario: Preview a Description question and submit a correct response. When I choose "Preview" action for "description-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I should see "Here is some information about the questions you are about to attempt." - And I switch to the main window + And I press "Close preview" diff --git a/question/type/edit_question_form.php b/question/type/edit_question_form.php index 384e689128b..c4d2969dfa7 100644 --- a/question/type/edit_question_form.php +++ b/question/type/edit_question_form.php @@ -256,17 +256,11 @@ abstract class question_edit_form extends question_wizard_form { $buttonarray[] = $mform->createElement('submit', 'updatebutton', get_string('savechangesandcontinueediting', 'question')); if ($this->can_preview()) { - // Todo MDL-72004 changes for class renaming and default sort. - if (class_exists('qbank_previewquestion\\preview_action_column')) { - if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) { - $previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link( - $this->question->id, $this->context, true); - } - } else { - $previewlink = $PAGE->get_renderer('core_question')->question_preview_link( + if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) { + $previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link( $this->question->id, $this->context, true); + $buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink); } - $buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink); } $mform->addGroup($buttonarray, 'updatebuttonar', '', array(' '), false); diff --git a/question/type/essay/tests/behat/max_file_size.feature b/question/type/essay/tests/behat/max_file_size.feature index 6f2f75b08da..584ec92db2a 100644 --- a/question/type/essay/tests/behat/max_file_size.feature +++ b/question/type/essay/tests/behat/max_file_size.feature @@ -27,15 +27,13 @@ I need to choose the appropriate maxbytes for attachments @javascript @_switch_window Scenario: Preview an Essay question and see the allowed maximum file sizes and number of attachments. When I choose "Preview" action for "essay-1-512KB" in the question bank - And I switch to "questionpreview" window Then I should see "Please write a story about a frog." And I should see "Maximum file size: 512KB, maximum number of files: 1" - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview an Essay question with Course upload limit and see the allowed maximum file size. When I choose "Preview" action for "essay-1-max" in the question bank - And I switch to "questionpreview" window Then I should see "Please write a story about a frog." And I should see "Maximum file size: 1MB, maximum number of files: 1" - And I switch to the main window + And I press "Close preview" diff --git a/question/type/essay/tests/behat/preview.feature b/question/type/essay/tests/behat/preview.feature index 142425c67f5..acd0272ffc2 100644 --- a/question/type/essay/tests/behat/preview.feature +++ b/question/type/essay/tests/behat/preview.feature @@ -29,27 +29,24 @@ Feature: Preview Essay questions @javascript @_switch_window Scenario: Preview an Essay question that uses the HTML editor. When I choose "Preview" action for "essay-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I should see "Please write a story about a frog." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview an Essay question that uses the HTML editor with embedded files. When I choose "Preview" action for "essay-002" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I should see "Please write a story about a frog." And I should see "You can drag and drop files here to add them." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview an Essay question that uses a plain text area. When I choose "Preview" action for "essay-003" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I should see "Please write a story about a frog." - And I switch to the main window + And I press "Close preview" diff --git a/question/type/gapselect/tests/behat/basic_test.feature b/question/type/gapselect/tests/behat/basic_test.feature index b2301ad35f0..6b6a4acacc5 100644 --- a/question/type/gapselect/tests/behat/basic_test.feature +++ b/question/type/gapselect/tests/behat/basic_test.feature @@ -39,7 +39,6 @@ Feature: Test all the basic functionality of this question type # Preview it. When I choose "Preview" action for "Select missing words 001" in the question bank - And I switch to "questionpreview" window # Gaps (drop-down menus) do not have labels. ids and names are generated # dynamically and therefore not reliable, i.e. this is an accessibility bug @@ -122,7 +121,7 @@ Feature: Test all the basic functionality of this question type Then I should see "Your answer is incorrect" And I should see "The cat sat on the mat" And I should see "The correct answer is: The [cat] [sat] on the [mat]." - And I switch to the main window + And I press "Close preview" # Backup the course and restore it. When I log out diff --git a/question/type/match/tests/behat/edit.feature b/question/type/match/tests/behat/edit.feature index 3f6e383d12c..0033ab46ae2 100644 --- a/question/type/match/tests/behat/edit.feature +++ b/question/type/match/tests/behat/edit.feature @@ -43,7 +43,6 @@ Feature: Test editing a Matching question And I press "id_submitbutton" Then I should see "Edited Matching name" When I choose "Preview" action for "Edited Matching name" in the question bank - And I switch to "questionpreview" window Then I should see "frog" And I should see "dog" And I should see "newt" diff --git a/question/type/match/tests/behat/preview.feature b/question/type/match/tests/behat/preview.feature index fc2b90c0d1f..9294014f0a4 100644 --- a/question/type/match/tests/behat/preview.feature +++ b/question/type/match/tests/behat/preview.feature @@ -31,7 +31,6 @@ Feature: Preview a Matching question | Shuffle | 0 | And I press "id_submitbutton" When I choose "Preview" action for "matching-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I set the field with xpath "//table[@class='answer']//td[@class='control']//select[contains(@id, '1_sub0')]" to "amphibian" @@ -40,7 +39,7 @@ Feature: Preview a Matching question And I press "Check" Then I should see "Well done!" And I should see "General feedback." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a Matching question and submit a partially correct response. @@ -49,7 +48,6 @@ Feature: Preview a Matching question | Shuffle | 0 | And I press "id_submitbutton" When I choose "Preview" action for "matching-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I set the field with xpath "//table[@class='answer']//td[@class='control']//select[contains(@id, '1_sub0')]" to "amphibian" @@ -58,7 +56,7 @@ Feature: Preview a Matching question And I press "Check" Then I should see "Parts, but only parts, of your response are correct." And I should see "General feedback." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a Matching question and submit an incorrect response. @@ -67,7 +65,6 @@ Feature: Preview a Matching question | Shuffle | 0 | And I press "id_submitbutton" When I choose "Preview" action for "matching-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I set the field with xpath "//table[@class='answer']//td[@class='control']//select[contains(@id, '1_sub0')]" to "mammal" @@ -76,4 +73,4 @@ Feature: Preview a Matching question And I press "Check" Then I should see "That is not right at all." And I should see "General feedback." - And I switch to the main window + And I press "Close preview" diff --git a/question/type/multichoice/tests/behat/preview.feature b/question/type/multichoice/tests/behat/preview.feature index 39e5a1775b5..f0d6d402e74 100644 --- a/question/type/multichoice/tests/behat/preview.feature +++ b/question/type/multichoice/tests/behat/preview.feature @@ -28,7 +28,6 @@ Feature: Preview a Multiple choice question @javascript @_switch_window Scenario: Preview a Multiple choice question and submit a partially correct response. When I choose "Preview" action for "Multi-choice-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "One" "qtype_multichoice > Answer" @@ -38,12 +37,11 @@ Feature: Preview a Multiple choice question And I should see "Two is even" And I should see "Mark 0.50 out of 1.00" And I should see "Parts, but only parts, of your response are correct." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a Multiple choice question and submit a correct response. When I choose "Preview" action for "Multi-choice-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "One" "qtype_multichoice > Answer" @@ -55,12 +53,11 @@ Feature: Preview a Multiple choice question And I should see "Well done!" And I should see "The odd numbers are One and Three." And I should see "The correct answers are: One, Three" - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a Multiple choice question and submit a correct response. When I choose "Preview" action for "Multi-choice-002" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "One" "qtype_multichoice > Answer" @@ -69,16 +66,15 @@ Feature: Preview a Multiple choice question And I should see "Mark 1.00 out of 1.00" And I should see "Well done!" And I should see "The correct answer is: One" - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a multiple choice question (single response) and clear a previous selected option. When I choose "Preview" action for "Multi-choice-002" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "One" "qtype_multichoice > Answer" Then I should see "Clear my choice" And I click on "Clear my choice" "text" And I should not see "Clear my choice" - And I switch to the main window + And I press "Close preview" diff --git a/question/type/numerical/tests/behat/preview.feature b/question/type/numerical/tests/behat/preview.feature index 747b9c360c2..78544fc7a65 100644 --- a/question/type/numerical/tests/behat/preview.feature +++ b/question/type/numerical/tests/behat/preview.feature @@ -31,7 +31,6 @@ Feature: Preview a Numerical question @javascript @_switch_window Scenario: Preview a Numerical question and submit a correct response. When I choose "Preview" action for "Numerical-001" in the question bank - And I switch to "questionpreview" window Then I should see "What is pi to two d.p.?" When I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" @@ -48,4 +47,4 @@ Feature: Preview a Numerical question And I press "Check" Then I should see "Very good." And I should see "Mark 1#00 out of 1#00" - And I switch to the main window + And I press "Close preview" diff --git a/question/type/shortanswer/tests/behat/edit.feature b/question/type/shortanswer/tests/behat/edit.feature index 996eb12003e..ccca1e979fa 100644 --- a/question/type/shortanswer/tests/behat/edit.feature +++ b/question/type/shortanswer/tests/behat/edit.feature @@ -43,7 +43,6 @@ Feature: Test editing a Short answer question And I press "id_submitbutton" Then I should see "Edited shortanswer-001 name" When I choose "Preview" action for "Edited shortanswer-001" in the question bank - And I switch to "questionpreview" window Then I should see "Name an amphibian:" # Set behaviour options And I set the following fields to these values: diff --git a/question/type/shortanswer/tests/behat/preview.feature b/question/type/shortanswer/tests/behat/preview.feature index 2772c38cfc5..b0e7d63ca1e 100644 --- a/question/type/shortanswer/tests/behat/preview.feature +++ b/question/type/shortanswer/tests/behat/preview.feature @@ -27,7 +27,6 @@ Feature: Preview a Short answer question @javascript @_switch_window Scenario: Preview a Short answer question with correct answer When I choose "Preview" action for "shortanswer-001" in the question bank - And I switch to "questionpreview" window Then I should see "Name an amphibian:" # Set behaviour options And I set the following fields to these values: @@ -42,7 +41,6 @@ Feature: Preview a Short answer question @javascript @_switch_window Scenario: Preview a Short answer question with almost correct answer When I choose "Preview" action for "shortanswer-001" in the question bank - And I switch to "questionpreview" window Then I should see "Name an amphibian:" # Set behaviour options And I set the following fields to these values: @@ -57,7 +55,6 @@ Feature: Preview a Short answer question @javascript @_switch_window Scenario: Preview a Short answer question with incorrect answer When I choose "Preview" action for "shortanswer-001" in the question bank - And I switch to "questionpreview" window Then I should see "Name an amphibian:" # Set behaviour options And I set the following fields to these values: diff --git a/question/type/truefalse/tests/behat/preview.feature b/question/type/truefalse/tests/behat/preview.feature index 83baede4749..b0300d6e4b3 100644 --- a/question/type/truefalse/tests/behat/preview.feature +++ b/question/type/truefalse/tests/behat/preview.feature @@ -27,19 +27,17 @@ Feature: Preview a Trtue/False question @javascript @_switch_window Scenario: Preview a True/False question and submit a correct response. When I choose "Preview" action for "true-false-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "True" "radio" And I press "Check" And I should see "This is the right answer." And I should see "The correct answer is 'True'." - And I switch to the main window + And I press "Close preview" @javascript @_switch_window Scenario: Preview a True/False question and submit an incorrect response. When I choose "Preview" action for "true-false-001" in the question bank - And I switch to "questionpreview" window And I set the field "How questions behave" to "Immediate feedback" And I press "Start again with these options" And I click on "False" "radio" @@ -47,4 +45,4 @@ Feature: Preview a Trtue/False question And I should see "This is the wrong answer." And I should see "You should have selected true." And I should see "The correct answer is 'True'." - And I switch to the main window + And I press "Close preview" diff --git a/question/upgrade.txt b/question/upgrade.txt index f2b7fedbf61..56d076b6e17 100644 --- a/question/upgrade.txt +++ b/question/upgrade.txt @@ -6,6 +6,11 @@ This files describes API changes for code that uses the question API. are divided in two different parts, base classes and feature classes. All the base classes are moved classes/local/bank and all the feature classes will be moved to the plugin for that feature. +2) The following methods are deprecated in previewlib and moved to the previewquestion plugin: + restart_preview(), question_preview_form_url(), question_preview_action_url(), + question_preview_question_pluginfile() + The following classes are deprecated in previewlib and moves the previewquestion plugin: + question_preview_options, preview_options_form. === 3.9 == diff --git a/question/yui/build/moodle-question-preview/moodle-question-preview-debug.js b/question/yui/build/moodle-question-preview/moodle-question-preview-debug.js index d338ff09477..28e4a52e1f5 100644 --- a/question/yui/build/moodle-question-preview/moodle-question-preview-debug.js +++ b/question/yui/build/moodle-question-preview/moodle-question-preview-debug.js @@ -23,9 +23,14 @@ YUI.add('moodle-question-preview', function (Y, NAME) { /** * JavaScript required by the question preview pop-up. * + * @deprecated since Moodle 4.0 + * @todo Final deprecation on Moodle 4.4 MDL-72438 * @module moodle-question-preview */ +Y.log("The moodle-question-preview module has been deprecated. " + + "Please use moodle-qbank_previewquestion-preview instead.", 'moodle-core-notification', 'warn'); + M.question = M.question || {}; M.question.preview = M.question.preview || {}; diff --git a/question/yui/build/moodle-question-preview/moodle-question-preview.js b/question/yui/build/moodle-question-preview/moodle-question-preview.js index d338ff09477..797d83a9c35 100644 --- a/question/yui/build/moodle-question-preview/moodle-question-preview.js +++ b/question/yui/build/moodle-question-preview/moodle-question-preview.js @@ -23,9 +23,12 @@ YUI.add('moodle-question-preview', function (Y, NAME) { /** * JavaScript required by the question preview pop-up. * + * @deprecated since Moodle 4.0 + * @todo Final deprecation on Moodle 4.4 MDL-72438 * @module moodle-question-preview */ + M.question = M.question || {}; M.question.preview = M.question.preview || {}; diff --git a/question/yui/src/preview/js/preview.js b/question/yui/src/preview/js/preview.js index ebfd0f42c56..e1a49be5745 100644 --- a/question/yui/src/preview/js/preview.js +++ b/question/yui/src/preview/js/preview.js @@ -21,9 +21,14 @@ /** * JavaScript required by the question preview pop-up. * + * @deprecated since Moodle 4.0 + * @todo Final deprecation on Moodle 4.4 MDL-72438 * @module moodle-question-preview */ +Y.log("The moodle-question-preview module has been deprecated. " + + "Please use moodle-qbank_previewquestion-preview instead.", 'moodle-core-notification', 'warn'); + M.question = M.question || {}; M.question.preview = M.question.preview || {};