Merge branch 'master_MDL-71614-previewquestion' of https://github.com/catalyst/moodle-MDL-70329

This commit is contained in:
Sara Arjona 2021-09-08 09:29:22 +02:00
commit 5c78efaaea
45 changed files with 1633 additions and 216 deletions

View File

@ -1946,6 +1946,7 @@ class core_plugin_manager {
'exportquestions',
'importquestions',
'managecategories',
'previewquestion',
'tagquestion',
'viewcreator',
'viewquestionname',

View File

@ -757,55 +757,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();
}
/**
@ -2143,8 +2122,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 {

View File

@ -80,6 +80,11 @@ information provided here is intended especially for developers.
- question_category_options() => qbank_managecategories\helper::question_category_options()
- question_add_context_in_key() => qbank_managecategories\helper::question_add_context_in_key()
- question_fix_top_names() => qbank_managecategories\helper::question_fix_top_names()
* 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.

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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 <http://www.gnu.org/licenses/>.
/**
* Javascript for preview.
*
* @module qbank_preview/preview
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @author Safat Shahin <safatshahin@catalyst-au.net>
* @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]);
});
}
};

View File

@ -0,0 +1,96 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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'));
}
}

View File

@ -0,0 +1,250 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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];
}
}

View File

@ -0,0 +1,68 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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);
}
}

View File

@ -0,0 +1,34 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace qbank_previewquestion;
/**
* Class columns is the entrypoint for the columns.
*
* @package qbank_previewquestion
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @author Safat Shahin <safatshahin@catalyst-au.net>
* @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)
];
}
}

View File

@ -0,0 +1,62 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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];
}
}
}

View File

@ -0,0 +1,32 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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';
}
}

View File

@ -0,0 +1,141 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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;
}
}

View File

@ -0,0 +1,27 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component qbank_previewquestion, language 'en'
*
* @package qbank_previewquestion
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @author Safat Shahin <safatshahin@catalyst-au.net>
* @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.';

View File

@ -0,0 +1,315 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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 <safatshahin@catalyst-au.net> 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();

View File

@ -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 <http://www.gnu.org/licenses/>.
}}
{{!
@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": "<div>question html</div>",
"restartdisabled": "disabled='disabled'",
"finishdisabled": "disabled='disabled'",
"filldisabled": "disabled='disabled'",
"techinfo": "<div>Behaviour being used: Deferred feedback</div>",
"redirecturl": "/",
"exporttoxml": "Download this question in Moodle XML format",
"comments": "html from comments api",
"extrapreviewelements": "<div>callback to get html from plugins need to show info in preview</div>"
}
]
}
}}
<form id="responseform" method="post" action="{{{actionurl}}}" enctype="multipart/form-data" autocomplete="off">
<div>
<input type="hidden" name="sesskey" value="{{session}}">
<input type="hidden" name="slots" value="{{slot}}">
<input type="hidden" name="scrollpos" value="" id="scrollpos">
</div>
{{{question}}}
<div id="previewcontrols" class="controls input-group">
<input type="submit" name="restart" value="{{#str}} restart, question{{/str}}" class="btn btn-secondary" {{{restartdisabled}}}>
<input type="submit" name="save" value="{{#str}} save, question{{/str}}" class="btn btn-secondary" {{{finishdisabled}}}>
<input type="submit" name="fill" value="{{#str}} fillincorrect, question{{/str}}" class="btn btn-secondary" {{{filldisabled}}}>
<input type="submit" name="finish" value="{{#str}} submitandfinish, question{{/str}}" class="btn btn-secondary" {{{finishdisabled}}}>
{{^redirect}}
<input type="button" name="close" value="{{#str}} closepreview, question{{/str}}" class="btn btn-secondary" id="close-previewquestion-page">
{{/redirect}}
{{#redirect}}
<a href="{{{redirecturl}}}" class="btn btn-secondary">{{#str}} closepreview, question{{/str}}</a>
{{/redirect}}
</div>
</form>
{{{techinfo}}}
{{{exporttoxml}}}
{{#comments}}
<div class="row">
<div class="col-6 text-left">
{{{options}}}
</div>
<div class="col-6 question-comment-view">
{{{comments}}}
</div>
</div>
{{/comments}}
{{^comments}}
{{{options}}}
{{/comments}}
{{#extrapreviewelements}}
{{{extrapreviewelements}}}
{{/extrapreviewelements}}

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,159 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safatshahin@catalyst-au.net>
* @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("<div class='comment-area'>", $comment);
} else {
$this->assertEquals('', $comment);
}
}
}

View File

@ -0,0 +1,31 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version information for qbank_previewquestion.
*
* @package qbank_previewquestion
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @author Safat Shahin <safatshahin@catalyst-au.net>
* @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;

View File

@ -674,8 +674,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());
}

View File

@ -244,7 +244,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);
/**

View File

@ -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
);
}
/**

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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"

View File

@ -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 <br>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

View File

@ -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"

View File

@ -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"

View File

@ -258,17 +258,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);

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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:

View File

@ -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:

View File

@ -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"

View File

@ -9,10 +9,16 @@ This files describes API changes for code that uses the question API.
2) submit_tags_form and associated external services for question tag, tags_form in question/type,
core_question_output_fragment_tags_form method in lib is deprecated and moved to the tagquestion plugin.
2) Function question_get_export_single_question_url() in questionlib has been deprecated
3) Function question_get_export_single_question_url() in questionlib has been deprecated
and moved to qbank_exporttoxml plugin, the new location is:
qbank_exporttoxml\helper::question_get_export_single_question_url().
4) 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 ==
1) For years, the ..._questions_in_use callback has been the right way for plugins to

View File

@ -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 || {};

View File

@ -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 || {};

View File

@ -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 || {};