MDL-71378 mod_qbank: Implement add to quiz bank sharing UI
This commit is contained in:
@@ -98,6 +98,7 @@ will have their sharing status changed to the same sharing status as the categor
|
||||
on upgrading to Moodle 1.9. The following categories will have their sharing status changed. Questions which are
|
||||
affected will continue to work in all existing quizzes until you remove them from these quizzes.</p>';
|
||||
$string['cwrqpfsnoprob'] = 'No question categories in your site are affected by the \'Random questions selecting questions from sub categories\' issue.';
|
||||
$string['defaultbank'] = '{$a->coursename} course question bank';
|
||||
$string['defaultcreated'] = 'Default course question bank created';
|
||||
$string['defaultfor'] = 'Default for {$a}';
|
||||
$string['defaultinfofor'] = 'The default category for questions shared in context \'{$a}\'.';
|
||||
@@ -272,6 +273,7 @@ $string['novirtualquestiontype'] = 'No virtual question type for question type {
|
||||
$string['numqas'] = 'No. question attempts';
|
||||
$string['numquestions'] = 'No. questions';
|
||||
$string['numquestionsandhidden'] = '{$a->numquestions} (+{$a->numhidden} hidden +{$a->numdraft} draft)';
|
||||
$string['otherquestionbank'] = 'Other question banks';
|
||||
$string['page-question-x'] = 'Any question page';
|
||||
$string['page-question-edit'] = 'Question editing page';
|
||||
$string['page-question-category'] = 'Question category page';
|
||||
@@ -313,6 +315,8 @@ $string['questiontags'] = 'Question tags';
|
||||
$string['questiontype'] = 'Question type';
|
||||
$string['questionuse'] = 'Use question in this activity';
|
||||
$string['questionvariant'] = 'Question variant';
|
||||
$string['quizquestionbank'] = "This quiz question bank";
|
||||
$string['recentlyviewedquestionbanks'] = 'Recently viewed question banks';
|
||||
$string['reviewresponse'] = 'Review response';
|
||||
$string['save'] = 'Save';
|
||||
$string['savechangesandcontinueediting'] = 'Save changes and continue editing';
|
||||
@@ -324,6 +328,7 @@ $string['selectquestionsforbulk'] = 'Select questions for bulk actions';
|
||||
$string['shareincontext'] = 'Share in context for {$a}';
|
||||
$string['stoponerror'] = 'Stop on error';
|
||||
$string['stoponerror_help'] = 'This setting determines whether the import process stops when an error is detected, resulting in no questions being imported, or whether any questions containing errors are ignored and any valid questions are imported.';
|
||||
$string['switchbank'] = 'Switch bank';
|
||||
$string['tofilecategory'] = 'Write category to file';
|
||||
$string['tofilecontext'] = 'Write context to file';
|
||||
$string['topfor'] = 'Top for {$a}';
|
||||
|
||||
@@ -822,3 +822,114 @@ function moodle_process_email($modargs, $body) {
|
||||
// Maybe more later?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default category for a module context.
|
||||
* If no categories exist yet then default ones are created in all contexts.
|
||||
*
|
||||
* @param array $contexts The context objects.
|
||||
* @return stdClass|null The default category - the category in the first module context supplied in $contexts
|
||||
*/
|
||||
#[\core\attribute\deprecated('This method should not be used', since: '5.0', mdl: 'MDL-71378')]
|
||||
function question_make_default_categories($contexts): object {
|
||||
global $DB;
|
||||
static $preferredlevels = [
|
||||
CONTEXT_COURSE => 4,
|
||||
CONTEXT_MODULE => 3,
|
||||
CONTEXT_COURSECAT => 2,
|
||||
CONTEXT_SYSTEM => 1,
|
||||
];
|
||||
|
||||
$toreturn = null;
|
||||
$preferredness = 0;
|
||||
// If it already exists, just return it.
|
||||
foreach ($contexts as $key => $context) {
|
||||
$topcategory = question_get_top_category($context->id, true);
|
||||
if (!$exists = $DB->record_exists("question_categories",
|
||||
['contextid' => $context->id, 'parent' => $topcategory->id])) {
|
||||
// Otherwise, we need to make one.
|
||||
$category = new stdClass();
|
||||
$contextname = $context->get_context_name(false, true);
|
||||
// Max length of name field is 255.
|
||||
$category->name = shorten_text(get_string('defaultfor', 'question', $contextname), 255);
|
||||
$category->info = get_string('defaultinfofor', 'question', $contextname);
|
||||
$category->contextid = $context->id;
|
||||
$category->parent = $topcategory->id;
|
||||
// By default, all categories get this number, and are sorted alphabetically.
|
||||
$category->sortorder = 999;
|
||||
$category->stamp = make_unique_id_code();
|
||||
$category->id = $DB->insert_record('question_categories', $category);
|
||||
} else {
|
||||
$category = question_get_default_category($context->id, true);
|
||||
}
|
||||
$thispreferredness = $preferredlevels[$context->contextlevel];
|
||||
if (has_any_capability(['moodle/question:usemine', 'moodle/question:useall'], $context)) {
|
||||
$thispreferredness += 10;
|
||||
}
|
||||
if ($thispreferredness > $preferredness) {
|
||||
$toreturn = $category;
|
||||
$preferredness = $thispreferredness;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($toreturn)) {
|
||||
$toreturn = clone($toreturn);
|
||||
}
|
||||
return $toreturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* All question categories and their questions are deleted for this course.
|
||||
*
|
||||
* @param stdClass $course an object representing the activity
|
||||
* @param bool $notused this argument is not used any more. Kept for backwards compatibility.
|
||||
* @return bool always true.
|
||||
*/
|
||||
#[\core\attribute\deprecated('This method should not be used', since: '5.0', mdl: 'MDL-71378')]
|
||||
function question_delete_course($course, $notused = false): bool {
|
||||
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
|
||||
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
question_delete_context($coursecontext->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Category is about to be deleted,
|
||||
* 1/ All question categories and their questions are deleted for this course category.
|
||||
* 2/ All questions are moved to new category
|
||||
*
|
||||
* @param stdClass|core_course_category $category course category object
|
||||
* @param stdClass|core_course_category $newcategory empty means everything deleted, otherwise id of
|
||||
* category where content moved
|
||||
* @param bool $notused this argument is no longer used. Kept for backwards compatibility.
|
||||
* @return boolean
|
||||
*/
|
||||
#[\core\attribute\deprecated('This method should not be used', since: '5.0', mdl: 'MDL-71378')]
|
||||
function question_delete_course_category($category, $newcategory, $notused = false): bool {
|
||||
global $DB;
|
||||
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
|
||||
|
||||
$context = context_coursecat::instance($category->id);
|
||||
if (empty($newcategory)) {
|
||||
question_delete_context($context->id);
|
||||
|
||||
} else {
|
||||
// Move question categories to the new context.
|
||||
if (!$newcontext = context_coursecat::instance($newcategory->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only move question categories if there is any question category at all!
|
||||
if ($topcategory = question_get_top_category($context->id)) {
|
||||
$newtopcategory = question_get_top_category($newcontext->id, true);
|
||||
|
||||
question_move_category_to_context($topcategory->id, $context->id, $newcontext->id);
|
||||
$DB->set_field('question_categories', 'parent', $newtopcategory->id, ['parent' => $topcategory->id]);
|
||||
// Now delete the top category.
|
||||
$DB->delete_records('question_categories', ['id' => $topcategory->id]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+38
-64
@@ -1176,20 +1176,48 @@ function sort_categories_by_tree(&$categories, $id = 0, $level = 1): array {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default category for the context.
|
||||
* Get the default category for the context. Optionally create one if it does not exist.
|
||||
*
|
||||
* @param integer $contextid a context id.
|
||||
* @return object|bool the default question category for that context, or false if none.
|
||||
* @param int $contextid a context id.
|
||||
* @param bool $createifnotexists create the default catagory if it does not exist.
|
||||
* @return stdClass|bool the default question category for that context, or false if none.
|
||||
*/
|
||||
function question_get_default_category($contextid) {
|
||||
function question_get_default_category($contextid, bool $createifnotexists = false) {
|
||||
global $DB;
|
||||
$category = $DB->get_records_select('question_categories', 'contextid = ? AND parent <> 0',
|
||||
[$contextid], 'id', '*', 0, 1);
|
||||
if (!empty($category)) {
|
||||
return reset($category);
|
||||
} else {
|
||||
|
||||
$context = \core\context::instance_by_id($contextid);
|
||||
if ($context->contextlevel !== CONTEXT_MODULE) {
|
||||
debugging(
|
||||
"Invalid context level {$context->contextlevel} for default category. Please use CONTEXT_MODULE",
|
||||
DEBUG_DEVELOPER
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$defaultcats = $DB->get_records_select('question_categories', 'contextid = ? AND parent <> 0', [$contextid], 'id', '*', 0, 1);
|
||||
|
||||
$defaultcat = reset($defaultcats);
|
||||
|
||||
if (empty($defaultcat) && $createifnotexists) {
|
||||
|
||||
// We need to make a top category first if it doesn't exist.
|
||||
$topcategory = question_get_top_category($context->id, true);
|
||||
|
||||
// We don't have one, so we need to make one.
|
||||
$defaultcat = new stdClass();
|
||||
$contextname = $context->get_context_name(false, true);
|
||||
// Max length of name field is 255.
|
||||
$defaultcat->name = shorten_text(get_string('defaultfor', 'question', $contextname), 255);
|
||||
$defaultcat->info = get_string('defaultinfofor', 'question', $contextname);
|
||||
$defaultcat->contextid = $context->id;
|
||||
$defaultcat->parent = $topcategory->id;
|
||||
// By default, all categories get this number, and are sorted alphabetically.
|
||||
$defaultcat->sortorder = 999;
|
||||
$defaultcat->stamp = make_unique_id_code();
|
||||
$defaultcat->id = $DB->insert_record('question_categories', $defaultcat);
|
||||
}
|
||||
|
||||
return $defaultcat;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1240,60 +1268,6 @@ function question_get_top_categories_for_contexts($contextids): array {
|
||||
return $topcategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default category in the most specific context.
|
||||
* If no categories exist yet then default ones are created in all contexts.
|
||||
*
|
||||
* @param array $contexts The context objects for this context and all parent contexts.
|
||||
* @return object The default category - the category in the course context
|
||||
*/
|
||||
function question_make_default_categories($contexts): object {
|
||||
global $DB;
|
||||
static $preferredlevels = array(
|
||||
CONTEXT_COURSE => 4,
|
||||
CONTEXT_MODULE => 3,
|
||||
CONTEXT_COURSECAT => 2,
|
||||
CONTEXT_SYSTEM => 1,
|
||||
);
|
||||
|
||||
$toreturn = null;
|
||||
$preferredness = 0;
|
||||
// If it already exists, just return it.
|
||||
foreach ($contexts as $key => $context) {
|
||||
$topcategory = question_get_top_category($context->id, true);
|
||||
if (!$exists = $DB->record_exists("question_categories",
|
||||
array('contextid' => $context->id, 'parent' => $topcategory->id))) {
|
||||
// Otherwise, we need to make one.
|
||||
$category = new stdClass();
|
||||
$contextname = $context->get_context_name(false, true);
|
||||
// Max length of name field is 255.
|
||||
$category->name = shorten_text(get_string('defaultfor', 'question', $contextname), 255);
|
||||
$category->info = get_string('defaultinfofor', 'question', $contextname);
|
||||
$category->contextid = $context->id;
|
||||
$category->parent = $topcategory->id;
|
||||
// By default, all categories get this number, and are sorted alphabetically.
|
||||
$category->sortorder = 999;
|
||||
$category->stamp = make_unique_id_code();
|
||||
$category->id = $DB->insert_record('question_categories', $category);
|
||||
} else {
|
||||
$category = question_get_default_category($context->id);
|
||||
}
|
||||
$thispreferredness = $preferredlevels[$context->contextlevel];
|
||||
if (has_any_capability(array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
|
||||
$thispreferredness += 10;
|
||||
}
|
||||
if ($thispreferredness > $preferredness) {
|
||||
$toreturn = $category;
|
||||
$preferredness = $thispreferredness;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($toreturn)) {
|
||||
$toreturn = clone($toreturn);
|
||||
}
|
||||
return $toreturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of categories.
|
||||
*
|
||||
@@ -1512,7 +1486,7 @@ function question_edit_url($context) {
|
||||
return false;
|
||||
}
|
||||
$baseurl = $CFG->wwwroot . '/question/edit.php?';
|
||||
$defaultcategory = question_get_default_category($context->id);
|
||||
$defaultcategory = question_get_default_category($context->id, true);
|
||||
if ($defaultcategory) {
|
||||
$baseurl .= 'cat=' . $defaultcategory->id . ',' . $context->id . '&';
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
define("mod_quiz/add_question_modal",["exports","core/modal"],(function(_exports,_modal){var obj;
|
||||
define("mod_quiz/add_question_modal",["exports","core/modal","core/fragment","core/str","core/form-autocomplete"],(function(_exports,_modal,Fragment,_str,_formAutocomplete){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Contain the logic for the add random question modal.
|
||||
*
|
||||
* @module mod_quiz/add_question_modal
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=(obj=_modal)&&obj.__esModule?obj:{default:obj};class AddQuestionModal extends _modal.default{configure(modalConfig){modalConfig.large=!0,modalConfig.show=!0,modalConfig.removeOnClose=!0,this.setContextId(modalConfig.contextId),this.setAddOnPageId(modalConfig.addOnPage),super.configure(modalConfig)}constructor(root){super(root),this.contextId=null,this.addOnPageId=null}setContextId(id){this.contextId=id}getContextId(){return this.contextId}setAddOnPageId(id){this.addOnPageId=id}getAddOnPageId(){return this.addOnPageId}}return _exports.default=AddQuestionModal,_exports.default}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=_interopRequireDefault(_modal),Fragment=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Fragment),_formAutocomplete=_interopRequireDefault(_formAutocomplete);class AddQuestionModal extends _modal.default{configure(modalConfig){modalConfig.large=!0,modalConfig.show=!0,modalConfig.removeOnClose=!0,this.setContextId(modalConfig.contextId),this.setAddOnPageId(modalConfig.addOnPage),this.quizCmId=modalConfig.quizCmId,this.bankCmId=modalConfig.bankCmId,this.originalTitle=modalConfig.title,super.configure(modalConfig)}constructor(root){super(root),this.contextId=null,this.addOnPageId=null}setContextId(id){this.contextId=id}getContextId(){return this.contextId}setAddOnPageId(id){this.addOnPageId=id}getAddOnPageId(){return this.addOnPageId}async handleSwitchBankContentReload(Selector){var _document$querySelect;this.setTitle((0,_str.getString)("selectquestionbank","mod_quiz"));const el=document.createElement("button");el.classList.add("btn","btn-primary"),el.textContent=await(0,_str.getString)("gobacktoquiz","mod_quiz"),el.setAttribute("data-action","go-back"),el.setAttribute("value",this.bankCmId),this.setFooter(el),this.setBody(Fragment.loadFragment("mod_quiz","switch_question_bank",this.getContextId(),{quizcmid:this.quizCmId,bankcmid:this.bankCmId}));const placeholder=await(0,_str.getString)("searchbyname","mod_quiz");return await this.getBodyPromise(),await _formAutocomplete.default.enhance(Selector,!1,"",placeholder,!1,!0,"",!0),null===(_document$querySelect=document.querySelector(".search-banks .form-autocomplete-selection"))||void 0===_document$querySelect||_document$querySelect.classList.add("d-none"),this}}return _exports.default=AddQuestionModal,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=add_question_modal.min.js.map
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -22,6 +22,9 @@
|
||||
*/
|
||||
|
||||
import Modal from 'core/modal';
|
||||
import * as Fragment from 'core/fragment';
|
||||
import {getString} from 'core/str';
|
||||
import AutoComplete from 'core/form-autocomplete';
|
||||
|
||||
export default class AddQuestionModal extends Modal {
|
||||
configure(modalConfig) {
|
||||
@@ -36,6 +39,14 @@ export default class AddQuestionModal extends Modal {
|
||||
this.setContextId(modalConfig.contextId);
|
||||
this.setAddOnPageId(modalConfig.addOnPage);
|
||||
|
||||
// Store the quiz module id for when we need to POST to the quiz.
|
||||
// This is because the URL cmid param will change during filter operations as we will be in another bank context.
|
||||
this.quizCmId = modalConfig.quizCmId;
|
||||
this.bankCmId = modalConfig.bankCmId;
|
||||
|
||||
// Store the original title of the modal, so we can revert back to it once we have switched to another bank.
|
||||
this.originalTitle = modalConfig.title;
|
||||
|
||||
// Apply standard configuration.
|
||||
super.configure(modalConfig);
|
||||
}
|
||||
@@ -89,4 +100,49 @@ export default class AddQuestionModal extends Modal {
|
||||
return this.addOnPageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the modal with a list of banks to switch to and enhance the standard selects to Autocomplete fields.
|
||||
*
|
||||
* @param {String} Selector for the original select element.
|
||||
* @return {Promise} Modal.
|
||||
*/
|
||||
async handleSwitchBankContentReload(Selector) {
|
||||
this.setTitle(getString('selectquestionbank', 'mod_quiz'));
|
||||
|
||||
// Create a 'Go back' button and set it in the footer.
|
||||
const el = document.createElement('button');
|
||||
el.classList.add('btn', 'btn-primary');
|
||||
el.textContent = await getString('gobacktoquiz', 'mod_quiz');
|
||||
el.setAttribute('data-action', 'go-back');
|
||||
el.setAttribute('value', this.bankCmId);
|
||||
this.setFooter(el);
|
||||
|
||||
this.setBody(
|
||||
Fragment.loadFragment(
|
||||
'mod_quiz',
|
||||
'switch_question_bank',
|
||||
this.getContextId(),
|
||||
{
|
||||
'quizcmid': this.quizCmId,
|
||||
'bankcmid': this.bankCmId,
|
||||
})
|
||||
);
|
||||
const placeholder = await getString('searchbyname', 'mod_quiz');
|
||||
await this.getBodyPromise();
|
||||
await AutoComplete.enhance(
|
||||
Selector,
|
||||
false,
|
||||
'',
|
||||
placeholder,
|
||||
false,
|
||||
true,
|
||||
'',
|
||||
true
|
||||
);
|
||||
|
||||
// Hide the selection element as we don't need it.
|
||||
document.querySelector('.search-banks .form-autocomplete-selection')?.classList.add('d-none');
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import {call as fetchMany} from 'core/ajax';
|
||||
import Pending from 'core/pending';
|
||||
|
||||
const SELECTORS = {
|
||||
ANCHOR: 'a[href]',
|
||||
EXISTING_CATEGORY_CONTAINER: '[data-region="existing-category-container"]',
|
||||
EXISTING_CATEGORY_TAB: '#id_existingcategoryheader',
|
||||
NEW_CATEGORY_CONTAINER: '[data-region="new-category-container"]',
|
||||
@@ -47,6 +48,10 @@ const SELECTORS = {
|
||||
FILTER_CONDITION_ELEMENT: '[data-filtercondition]',
|
||||
FORM_ELEMENT: '#add_random_question_form',
|
||||
MESSAGE_INPUT: '[name="message"]',
|
||||
SWITCH_TO_OTHER_BANK: 'button[data-action="switch-question-bank"]',
|
||||
NEW_BANKMOD_ID: 'data-newmodid',
|
||||
BANK_SEARCH: '#searchbanks',
|
||||
GO_BACK_BUTTON: 'button[data-action="go-back"]',
|
||||
};
|
||||
|
||||
export default class ModalAddRandomQuestion extends Modal {
|
||||
@@ -57,12 +62,20 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
* Create the add random question modal.
|
||||
*
|
||||
* @param {Number} contextId Current context id.
|
||||
* @param {Number} bankCmId Current question bank course module id.
|
||||
* @param {string} category Category id and category context id comma separated.
|
||||
* @param {string} returnUrl URL to return to after form submission.
|
||||
* @param {Number} cmid Current course module id.
|
||||
* @param {Number} quizCmId Current quiz course module id.
|
||||
* @param {boolean} showNewCategory Display the New category tab when selecting random questions.
|
||||
*/
|
||||
static init(contextId, category, returnUrl, cmid, showNewCategory = true) {
|
||||
static init(
|
||||
contextId,
|
||||
bankCmId,
|
||||
category,
|
||||
returnUrl,
|
||||
quizCmId,
|
||||
showNewCategory = true
|
||||
) {
|
||||
const selector = '.menu [data-action="addarandomquestion"]';
|
||||
document.addEventListener('click', (e) => {
|
||||
const trigger = e.target.closest(selector);
|
||||
@@ -73,10 +86,11 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
|
||||
ModalAddRandomQuestion.create({
|
||||
contextId,
|
||||
bankCmId,
|
||||
category,
|
||||
returnUrl,
|
||||
cmid,
|
||||
|
||||
quizCmId,
|
||||
showNewCategory,
|
||||
title: trigger.dataset.header,
|
||||
addOnPage: trigger.dataset.addonpage,
|
||||
|
||||
@@ -96,7 +110,7 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
super(root);
|
||||
this.category = null;
|
||||
this.returnUrl = null;
|
||||
this.cmid = null;
|
||||
this.quizCmId = null;
|
||||
this.loadedForm = false;
|
||||
}
|
||||
|
||||
@@ -105,7 +119,7 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
|
||||
this.setCategory(modalConfig.category);
|
||||
this.setReturnUrl(modalConfig.returnUrl);
|
||||
this.setCMID(modalConfig.cmid);
|
||||
this.showNewCategory = modalConfig.showNewCategory;
|
||||
|
||||
super.configure(modalConfig);
|
||||
}
|
||||
@@ -163,26 +177,6 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
return this.returnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the course module id for the form.
|
||||
*
|
||||
* @method setCMID
|
||||
* @param {Number} id
|
||||
*/
|
||||
setCMID(id) {
|
||||
this.cmid = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the course module id for the form.
|
||||
*
|
||||
* @method getCMID
|
||||
* @return {Number}
|
||||
*/
|
||||
getCMID() {
|
||||
return this.cmid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a given form element inside (a child of) a given tab element.
|
||||
*
|
||||
@@ -241,10 +235,10 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
* @return {promise} Resolved with form HTML and JS.
|
||||
*/
|
||||
loadForm() {
|
||||
const cmid = this.getCMID();
|
||||
const cat = this.getCategory();
|
||||
const addonpage = this.getAddOnPageId();
|
||||
const returnurl = this.getReturnUrl();
|
||||
const quizcmid = this.quizCmId;
|
||||
const bankcmid = this.bankCmId;
|
||||
|
||||
return Fragment.loadFragment(
|
||||
'mod_quiz',
|
||||
@@ -252,70 +246,133 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
this.getContextId(),
|
||||
{
|
||||
addonpage,
|
||||
cat,
|
||||
returnurl,
|
||||
cmid,
|
||||
quizcmid,
|
||||
bankcmid,
|
||||
}
|
||||
)
|
||||
.then((html, js) =>{
|
||||
const form = $(html);
|
||||
const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB);
|
||||
const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);
|
||||
const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB);
|
||||
const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);
|
||||
.then((html, js) => {
|
||||
const form = $(html);
|
||||
const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB);
|
||||
const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);
|
||||
const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB);
|
||||
const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);
|
||||
|
||||
// Transform the form into tabs for better rendering in the modal.
|
||||
this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab);
|
||||
this.moveContentIntoTab(newCategoryTabContent, newCategoryTab);
|
||||
this.moveTabsIntoTabContent(form);
|
||||
// Transform the form into tabs for better rendering in the modal.
|
||||
this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab);
|
||||
this.moveContentIntoTab(newCategoryTabContent, newCategoryTab);
|
||||
this.moveTabsIntoTabContent(form);
|
||||
|
||||
Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);
|
||||
return;
|
||||
})
|
||||
.then(() => {
|
||||
// Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
|
||||
// page once the modal is hidden.
|
||||
FormChangeChecker.disableAllChecks();
|
||||
Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);
|
||||
return;
|
||||
})
|
||||
.then(() => {
|
||||
// Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
|
||||
// page once the modal is hidden.
|
||||
FormChangeChecker.disableAllChecks();
|
||||
|
||||
// Add question to quiz.
|
||||
this.getBody()[0].addEventListener('click', (e) => {
|
||||
const button = e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT);
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
// Add question to quiz.
|
||||
this.getBody()[0].addEventListener('click', (e) => {
|
||||
const button = e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT);
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
// Add Random questions if the add random button was clicked.
|
||||
const addRandomButton = e.target.closest(SELECTORS.ADD_RANDOM_BUTTON);
|
||||
if (addRandomButton) {
|
||||
const randomcount = document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value;
|
||||
const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition;
|
||||
// Intercept the submission to adjust the POST params so that the quiz mod id is set and not the bank module id.
|
||||
document.querySelector('#questionscontainer input[name="cmid"]').setAttribute('name', this.quizCmId);
|
||||
|
||||
this.addQuestions(cmid, addonpage, randomcount, filtercondition, '', '');
|
||||
return;
|
||||
}
|
||||
// Add new category if the add category button was clicked.
|
||||
const addCategoryButton = e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON);
|
||||
if (addCategoryButton) {
|
||||
this.addQuestions(
|
||||
cmid,
|
||||
addonpage,
|
||||
1,
|
||||
'',
|
||||
document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,
|
||||
document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value
|
||||
);
|
||||
return;
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(Notification.exception);
|
||||
// Add Random questions if the add random button was clicked.
|
||||
const addRandomButton = e.target.closest(SELECTORS.ADD_RANDOM_BUTTON);
|
||||
if (addRandomButton) {
|
||||
const randomcount = document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value;
|
||||
const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition;
|
||||
|
||||
this.addQuestions(quizcmid, addonpage, randomcount, filtercondition, '', '');
|
||||
return;
|
||||
}
|
||||
// Add new category if the add category button was clicked.
|
||||
const addCategoryButton = e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON);
|
||||
if (addCategoryButton) {
|
||||
this.addQuestions(
|
||||
quizcmid,
|
||||
addonpage,
|
||||
1,
|
||||
'',
|
||||
document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,
|
||||
document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value
|
||||
);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
this.getModal().on('click', SELECTORS.SWITCH_TO_OTHER_BANK, () => {
|
||||
this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH)
|
||||
.then(function(ModalQuizQuestionBank) {
|
||||
$(SELECTORS.BANK_SEARCH)?.on('change', (e) => {
|
||||
const bankCmId = $(e.currentTarget).val();
|
||||
// Have to recreate the modal as we have already used the body for the switch bank content.
|
||||
if (bankCmId > 0) {
|
||||
ModalAddRandomQuestion.create({
|
||||
'contextId': ModalQuizQuestionBank.getContextId(),
|
||||
'bankCmId': bankCmId,
|
||||
'category': ModalQuizQuestionBank.getCategory(),
|
||||
'returnUrl': ModalQuizQuestionBank.getReturnUrl(),
|
||||
'quizCmId': ModalQuizQuestionBank.quizCmId,
|
||||
'title': ModalQuizQuestionBank.originalTitle,
|
||||
'addOnPage': ModalQuizQuestionBank.getAddOnPageId(),
|
||||
'templateContext': {hidden: ModalQuizQuestionBank.showNewCategory},
|
||||
'showNewCategory': ModalQuizQuestionBank.showNewCategory,
|
||||
}).catch(Notification.exception);
|
||||
|
||||
return ModalQuizQuestionBank;
|
||||
}
|
||||
});
|
||||
})
|
||||
.then((ModalQuizQuestionBank) => ModalQuizQuestionBank.destroy());
|
||||
});
|
||||
|
||||
this.getModal().on('click', SELECTORS.GO_BACK_BUTTON, (e) => {
|
||||
const anchorElement = $(e.currentTarget);
|
||||
// Have to recreate the modal as we have already used the body for the switch bank content.
|
||||
ModalAddRandomQuestion.create({
|
||||
'contextId': this.getContextId(),
|
||||
'bankCmId': anchorElement.attr('value'),
|
||||
'category': this.getCategory(),
|
||||
'returnUrl': this.getReturnUrl(),
|
||||
'quizCmId': this.quizCmId,
|
||||
'title': this.originalTitle,
|
||||
'addOnPage': this.getAddOnPageId(),
|
||||
'templateContext': {hidden: this.showNewCategory},
|
||||
'showNewCategory': this.showNewCategory,
|
||||
}).then(this.destroy()).catch(Notification.exception);
|
||||
});
|
||||
|
||||
this.getModal().on('click', SELECTORS.ANCHOR, (e) => {
|
||||
const anchorElement = $(e.currentTarget);
|
||||
// Have to recreate the modal as we have already used the body for the switch bank content.
|
||||
if (anchorElement.closest('a[' + SELECTORS.NEW_BANKMOD_ID + ']').length) {
|
||||
ModalAddRandomQuestion.create({
|
||||
'contextId': this.getContextId(),
|
||||
'bankCmId': anchorElement.attr(SELECTORS.NEW_BANKMOD_ID),
|
||||
'category': this.getCategory(),
|
||||
'returnUrl': this.getReturnUrl(),
|
||||
'quizCmId': this.quizCmId,
|
||||
'title': this.originalTitle,
|
||||
'addOnPage': this.getAddOnPageId(),
|
||||
'templateContext': {hidden: this.showNewCategory},
|
||||
'showNewCategory': this.showNewCategory,
|
||||
}).then(this.destroy()).catch(Notification.exception);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(Notification.exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call web service function to add random questions
|
||||
*
|
||||
* @param {number} cmid course module id
|
||||
* @param {number} quizcmid the course module id of the quiz to add questions to.
|
||||
* @param {number} addonpage the page where random questions will be added to
|
||||
* @param {number} randomcount Number of random questions
|
||||
* @param {string} filtercondition Filter condition
|
||||
@@ -323,7 +380,7 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
* @param {string} parentcategory parent category of new category
|
||||
*/
|
||||
async addQuestions(
|
||||
cmid,
|
||||
quizcmid,
|
||||
addonpage,
|
||||
randomcount,
|
||||
filtercondition,
|
||||
@@ -335,7 +392,7 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
const call = {
|
||||
methodname: 'mod_quiz_add_random_questions',
|
||||
args: {
|
||||
cmid,
|
||||
cmid: quizcmid,
|
||||
addonpage,
|
||||
randomcount,
|
||||
filtercondition,
|
||||
@@ -364,6 +421,7 @@ export default class ModalAddRandomQuestion extends Modal {
|
||||
super.show(this);
|
||||
|
||||
if (!this.loadedForm) {
|
||||
this.tabHtml = this.getBody();
|
||||
this.loadForm(window.location.search);
|
||||
this.loadedForm = true;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import Modal from './add_question_modal';
|
||||
import * as Fragment from 'core/fragment';
|
||||
import * as FormChangeChecker from 'core_form/changechecker';
|
||||
import * as ModalEvents from 'core/modal_events';
|
||||
import * as Notification from 'core/notification';
|
||||
|
||||
const SELECTORS = {
|
||||
ADD_TO_QUIZ_CONTAINER: 'td.addtoquizaction',
|
||||
@@ -33,6 +33,12 @@ const SELECTORS = {
|
||||
PREVIEW_CONTAINER: 'td.previewquestionaction',
|
||||
ADD_QUESTIONS_FORM: 'form#questionsubmit',
|
||||
SORTERS: '.sorters',
|
||||
SWITCH_TO_OTHER_BANK: 'button[data-action="switch-question-bank"]',
|
||||
NEW_BANKMOD_ID: 'data-newmodid',
|
||||
BANK_SEARCH: '#searchbanks',
|
||||
GO_BACK_BUTTON: 'button[data-action="go-back"]',
|
||||
ADD_ON_PAGE_FORM_ELEMENT: 'input[name="addonpage"]',
|
||||
CMID_FORM_ELEMENT: 'form#questionsubmit input[name="cmid"]',
|
||||
};
|
||||
|
||||
export default class ModalQuizQuestionBank extends Modal {
|
||||
@@ -41,9 +47,11 @@ export default class ModalQuizQuestionBank extends Modal {
|
||||
/**
|
||||
* Create the question bank modal.
|
||||
*
|
||||
* @param {Number} contextId Current context id.
|
||||
* @param {Number} contextId Current module context id.
|
||||
* @param {Number} bankCmId Current question bank course module id.
|
||||
* @param {Number} quizCmId Current quiz course module id.
|
||||
*/
|
||||
static init(contextId) {
|
||||
static init(contextId, bankCmId, quizCmId) {
|
||||
const selector = '.menu [data-action="questionbank"]';
|
||||
document.addEventListener('click', (e) => {
|
||||
const trigger = e.target.closest(selector);
|
||||
@@ -54,6 +62,8 @@ export default class ModalQuizQuestionBank extends Modal {
|
||||
|
||||
ModalQuizQuestionBank.create({
|
||||
contextId,
|
||||
quizCmId,
|
||||
bankCmId,
|
||||
title: trigger.dataset.header,
|
||||
addOnPage: trigger.dataset.addonpage,
|
||||
templateContext: {
|
||||
@@ -90,13 +100,17 @@ export default class ModalQuizQuestionBank extends Modal {
|
||||
* @param {string} querystring URL encoded string.
|
||||
*/
|
||||
reloadBodyContent(querystring) {
|
||||
// Load the question bank fragment to be displayed in the modal.
|
||||
// Load the question bank fragment to be displayed in the modal and hide the 'go back' button.
|
||||
this.hideFooter();
|
||||
this.setTitle(this.originalTitle);
|
||||
this.setBody(Fragment.loadFragment(
|
||||
'mod_quiz',
|
||||
'quiz_question_bank',
|
||||
this.getContextId(),
|
||||
{
|
||||
querystring,
|
||||
quizcmid: this.quizCmId,
|
||||
bankcmid: this.bankCmId,
|
||||
}
|
||||
));
|
||||
}
|
||||
@@ -112,11 +126,12 @@ export default class ModalQuizQuestionBank extends Modal {
|
||||
handleAddToQuizEvent(e, anchorElement) {
|
||||
// If the user clicks the plus icon to add the question to the page
|
||||
// directly then we need to intercept the click in order to adjust the
|
||||
// href and include the correct add on page id before the page is
|
||||
// href and include the correct add on page id and cmid before the page is
|
||||
// redirected.
|
||||
const href = new URL(anchorElement.attr('href'));
|
||||
const href = new URL(anchorElement.getAttribute('href'));
|
||||
href.searchParams.set('addonpage', this.getAddOnPageId());
|
||||
anchorElement.attr('href', href);
|
||||
href.searchParams.set('cmid', this.quizCmId);
|
||||
anchorElement.setAttribute('href', href);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,38 +145,68 @@ export default class ModalQuizQuestionBank extends Modal {
|
||||
|
||||
this.getModal().on('submit', SELECTORS.ADD_QUESTIONS_FORM, (e) => {
|
||||
// If the user clicks on the "Add selected questions to the quiz" button to add some questions to the page
|
||||
// then we need to intercept the submit in order to include the correct "add on page id" before the form is
|
||||
// submitted.
|
||||
const formElement = $(e.currentTarget);
|
||||
// then we need to intercept the submit in order to include the correct "add on page id"
|
||||
// and the quizmod id before the form is submitted.
|
||||
const formElement = e.currentTarget;
|
||||
document.querySelector(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).setAttribute('value', this.getAddOnPageId());
|
||||
|
||||
$('<input />').attr('type', 'hidden')
|
||||
.attr('name', "addonpage")
|
||||
.attr('value', this.getAddOnPageId())
|
||||
.appendTo(formElement);
|
||||
// We also need to set the form cmid & action as the quiz modid as this could be coming from a module that isn't a quiz.
|
||||
document.querySelector(SELECTORS.CMID_FORM_ELEMENT).setAttribute('value', this.quizCmId);
|
||||
const actionUrl = new URL(formElement.getAttribute('action'));
|
||||
actionUrl.searchParams.set('cmid', this.quizCmId);
|
||||
formElement.setAttribute('action', actionUrl.toString());
|
||||
});
|
||||
|
||||
this.getModal().on('click', SELECTORS.SWITCH_TO_OTHER_BANK, () => {
|
||||
this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH)
|
||||
.then(function(ModalQuizQuestionBank) {
|
||||
document.querySelector(SELECTORS.BANK_SEARCH)?.addEventListener('change', (e) => {
|
||||
const bankCmId = e.currentTarget.value;
|
||||
if (bankCmId > 0) {
|
||||
ModalQuizQuestionBank.bankCmId = bankCmId;
|
||||
ModalQuizQuestionBank.reloadBodyContent(window.location.search);
|
||||
}
|
||||
});
|
||||
document.querySelector(SELECTORS.GO_BACK_BUTTON).addEventListener('click', (e) => {
|
||||
ModalQuizQuestionBank.bankCmId = e.currentTarget.value;
|
||||
ModalQuizQuestionBank.reloadBodyContent(window.location.search);
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(Notification.exception);
|
||||
});
|
||||
|
||||
this.getModal().on('click', SELECTORS.ANCHOR, (e) => {
|
||||
const anchorElement = $(e.currentTarget);
|
||||
const anchorElement = e.currentTarget;
|
||||
|
||||
// If the anchor element was the add to quiz link.
|
||||
if (anchorElement.closest(SELECTORS.ADD_TO_QUIZ_CONTAINER).length) {
|
||||
if (anchorElement.closest(SELECTORS.ADD_TO_QUIZ_CONTAINER)) {
|
||||
this.handleAddToQuizEvent(e, anchorElement);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the anchor element was a preview question link.
|
||||
if (anchorElement.closest(SELECTORS.PREVIEW_CONTAINER).length) {
|
||||
if (anchorElement.closest(SELECTORS.PREVIEW_CONTAINER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sorting links have their own handler.
|
||||
if (anchorElement.closest(SELECTORS.SORTERS).length) {
|
||||
if (anchorElement.closest(SELECTORS.SORTERS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (anchorElement.closest('a[' + SELECTORS.NEW_BANKMOD_ID + ']')) {
|
||||
this.bankCmId = anchorElement.getAttribute(SELECTORS.NEW_BANKMOD_ID);
|
||||
|
||||
// We need to clear the filter as we are about to reload the content.
|
||||
const url = new URL(location.href);
|
||||
url.searchParams.delete('filter');
|
||||
history.pushState({}, '', url);
|
||||
}
|
||||
|
||||
// Anything else means reload the pop-up contents.
|
||||
e.preventDefault();
|
||||
this.reloadBodyContent(anchorElement.prop('search'));
|
||||
this.reloadBodyContent(anchorElement.search);
|
||||
});
|
||||
|
||||
// Disable the form change checker when the body is rendered.
|
||||
|
||||
@@ -52,8 +52,14 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
* @param array $pagevars the variables from {@link question_edit_setup()}.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function edit_page(\mod_quiz\quiz_settings $quizobj, structure $structure,
|
||||
\core_question\local\bank\question_edit_contexts $contexts, \moodle_url $pageurl, array $pagevars) {
|
||||
public function edit_page(
|
||||
\mod_quiz\quiz_settings $quizobj,
|
||||
structure $structure,
|
||||
\core_question\local\bank\question_edit_contexts $contexts,
|
||||
\moodle_url $pageurl,
|
||||
array $pagevars,
|
||||
) {
|
||||
|
||||
$output = '';
|
||||
|
||||
// Page title.
|
||||
@@ -111,11 +117,14 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
if ($structure->can_be_edited()) {
|
||||
$thiscontext = $contexts->lowest();
|
||||
$this->page->requires->js_call_amd('mod_quiz/modal_quiz_question_bank', 'init', [
|
||||
$thiscontext->id
|
||||
$thiscontext->id,
|
||||
$quizobj->get_cm()->id,
|
||||
$quizobj->get_cm()->id,
|
||||
]);
|
||||
|
||||
$this->page->requires->js_call_amd('mod_quiz/modal_add_random_question', 'init', [
|
||||
$thiscontext->id,
|
||||
$quizobj->get_cm()->id,
|
||||
$pagevars['cat'],
|
||||
$pageurl->out_as_local_url(true),
|
||||
$pageurl->param('cmid'),
|
||||
@@ -1060,9 +1069,10 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
*/
|
||||
public function random_question(structure $structure, $slotnumber, $pageurl) {
|
||||
$question = $structure->get_question_in_slot($slotnumber);
|
||||
$bankcontext = \context::instance_by_id($question->contextid);
|
||||
$slot = $structure->get_slot_by_number($slotnumber);
|
||||
$editurl = new \moodle_url('/mod/quiz/editrandom.php',
|
||||
['returnurl' => $pageurl->out_as_local_url(), 'slotid' => $slot->id]);
|
||||
['returnurl' => $pageurl->out_as_local_url(), 'slotid' => $slot->id, 'bankcmid' => $bankcontext->instanceid]);
|
||||
|
||||
$temp = clone($question);
|
||||
$temp->questiontext = '';
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace mod_quiz\question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\output\datafilter;
|
||||
use core\output\html_writer;
|
||||
use core_question\local\bank\column_base;
|
||||
use core_question\local\bank\condition;
|
||||
use core_question\local\bank\column_manager_base;
|
||||
use core_question\local\bank\question_version_status;
|
||||
use mod_quiz\question\bank\filter\custom_category_condition;
|
||||
use qbank_managecategories\category_condition;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
/**
|
||||
@@ -58,6 +58,13 @@ class custom_view extends \core_question\local\bank\view {
|
||||
*/
|
||||
public $component = 'mod_quiz';
|
||||
|
||||
/**
|
||||
* Determine if the 'switch question bank' button must be displayed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $requirebankswitch;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param \core_question\local\bank\question_edit_contexts $contexts
|
||||
@@ -83,9 +90,10 @@ class custom_view extends \core_question\local\bank\view {
|
||||
|
||||
$this->init_columns($this->wanted_columns(), $this->heading_column());
|
||||
parent::__construct($contexts, $pageurl, $course, $cm, $params, $extraparams);
|
||||
[$this->quiz, ] = get_module_from_cmid($cm->id);
|
||||
[$this->quiz, ] = get_module_from_cmid($extraparams['quizcmid']);
|
||||
$this->set_quiz_has_attempts(quiz_has_attempts($this->quiz->id));
|
||||
$this->pagesize = self::DEFAULT_PAGE_SIZE;
|
||||
$this->requirebankswitch = $extraparams['requirebankswitch'] ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,4 +308,45 @@ class custom_view extends \core_question\local\bank\view {
|
||||
public function get_quiz() {
|
||||
return $this->quiz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the question bank interface.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display(): void {
|
||||
$editcontexts = $this->contexts->having_one_edit_tab_cap('questions');
|
||||
|
||||
echo \html_writer::start_div('questionbankwindow boxwidthwide boxaligncenter', [
|
||||
'data-component' => 'core_question',
|
||||
'data-callback' => 'display_question_bank',
|
||||
'data-contextid' => $editcontexts[array_key_last($editcontexts)]->id,
|
||||
]);
|
||||
|
||||
// Show the 'switch question bank' button.
|
||||
echo $this->display_bank_switch();
|
||||
|
||||
// Show the filters and search options.
|
||||
$this->wanted_filters();
|
||||
// Continues with list of questions.
|
||||
$this->display_question_list();
|
||||
echo \html_writer::end_div();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current bank header and bank switch button.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function display_bank_switch(): string {
|
||||
global $OUTPUT;
|
||||
|
||||
if (!$this->requirebankswitch) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cminfo = \cm_info::create($this->cm);
|
||||
|
||||
return $OUTPUT->render_from_template('mod_quiz/switch_bank_header', ['currentbank' => $cminfo->get_formatted_name()]);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ $quizobj = new quiz_settings($quiz, $cm, $course);
|
||||
$structure = $quizobj->get_structure();
|
||||
$gradecalculator = $quizobj->get_grade_calculator();
|
||||
|
||||
$defaultcategoryobj = question_make_default_categories($contexts->all());
|
||||
$defaultcategoryobj = question_get_default_category($contexts->lowest()->id, true);
|
||||
$defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
|
||||
|
||||
$quizhasattempts = quiz_has_attempts($quiz->id);
|
||||
|
||||
@@ -31,6 +31,7 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/lib.php');
|
||||
|
||||
$slotid = required_param('slotid', PARAM_INT);
|
||||
$bankcmid = required_param('bankcmid', PARAM_INT);
|
||||
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
|
||||
|
||||
// Get the quiz slot.
|
||||
@@ -60,11 +61,13 @@ $filterconditions = json_decode($setreference->filtercondition, true);
|
||||
$params = $filterconditions;
|
||||
$params['cmid'] = $cm->id;
|
||||
$extraparams['view'] = random_question_view::class;
|
||||
$extraparams['requirebankswitch'] = false;
|
||||
$extraparams['quizcmid'] = $quizobj->get_cm()->id;
|
||||
|
||||
// Build required parameters.
|
||||
[$contexts, $thispageurl, $cm, $pagevars, $extraparams] = build_required_parameters_for_custom_view($params, $extraparams);
|
||||
|
||||
$thiscontext = $quizobj->get_context();
|
||||
$thiscontext = context_module::instance($bankcmid);
|
||||
$contexts = new core_question\local\bank\question_edit_contexts($thiscontext);
|
||||
|
||||
// Create the editing form.
|
||||
|
||||
@@ -125,6 +125,7 @@ $string['back'] = 'Back to preview question';
|
||||
$string['backtocourse'] = 'Back to the course';
|
||||
$string['backtoquestionlist'] = 'Back to question list';
|
||||
$string['backtoquiz'] = 'Back to quiz editing';
|
||||
$string['banknotfound'] = 'Question bank not found, please search again';
|
||||
$string['bestgrade'] = 'Best grade';
|
||||
$string['bothattempts'] = 'Show students with and without attempts';
|
||||
$string['browsersecurity'] = 'Browser security';
|
||||
@@ -249,6 +250,7 @@ $string['createfirst'] = 'You must create some short-answer questions first.';
|
||||
$string['createmultiple'] = 'Add several random questions to quiz';
|
||||
$string['createnewquestion'] = 'Create new question';
|
||||
$string['createquestionandadd'] = 'Create a new question and add it to the quiz.';
|
||||
$string['currentbank'] = 'Current bank: {$a}';
|
||||
$string['custom'] = 'Custom format';
|
||||
$string['dataitemneed'] = 'You need to add at least one set of data items to get a valid question';
|
||||
$string['datasetdefinitions'] = 'Reusable dataset definitions for category {$a}';
|
||||
@@ -981,6 +983,7 @@ $string['savingnewmaximumgrade'] = 'Saving new maximum grade.';
|
||||
$string['score'] = 'Raw score';
|
||||
$string['scores'] = 'Scores';
|
||||
$string['search:activity'] = 'Quiz - activity information';
|
||||
$string['searchbyname'] = 'Search by name...';
|
||||
$string['sectionheadingedit'] = 'Edit heading \'{$a}\'';
|
||||
$string['sectionheadingremove'] = 'Remove heading \'{$a}\'';
|
||||
$string['sectionnoname'] = 'Untitled section';
|
||||
@@ -993,6 +996,7 @@ $string['selectedattempts'] = 'Selected attempts...';
|
||||
$string['selectmultipleitems'] = 'Select multiple items';
|
||||
$string['selectmultipletoolbar'] = 'Select multiple toolbar';
|
||||
$string['selectnone'] = 'Deselect all';
|
||||
$string['selectquestionbank'] = 'Select question bank';
|
||||
$string['selectquestionslot'] = 'Select question {$a}';
|
||||
$string['selectquestiontype'] = '-- Select question type --';
|
||||
$string['sendnotificationopendatesoon'] = 'Notify user of an approaching quiz open date';
|
||||
|
||||
+38
-10
@@ -25,7 +25,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
use core_question\local\bank\question_bank_helper;
|
||||
use qbank_managecategories\helper;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@@ -254,7 +254,7 @@ function quiz_update_effective_access($quiz, $userid) {
|
||||
|
||||
if (!empty($groupings[0])) {
|
||||
// Select all overrides that apply to the User's groups.
|
||||
list($extra, $params) = $DB->get_in_or_equal(array_values($groupings[0]));
|
||||
[$extra, $params] = $DB->get_in_or_equal(array_values($groupings[0]));
|
||||
$sql = "SELECT * FROM {quiz_overrides}
|
||||
WHERE groupid $extra AND quiz = ?";
|
||||
$params[] = $quiz->id;
|
||||
@@ -537,7 +537,7 @@ function quiz_get_user_attempts($quizids, $userid, $status = 'finished', $includ
|
||||
}
|
||||
|
||||
$quizids = (array) $quizids;
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($quizids, SQL_PARAMS_NAMED);
|
||||
[$insql, $inparams] = $DB->get_in_or_equal($quizids, SQL_PARAMS_NAMED);
|
||||
$params += $inparams;
|
||||
$params['userid'] = $userid;
|
||||
|
||||
@@ -1581,7 +1581,7 @@ function quiz_num_attempt_summary($quiz, $cm, $returnzero = false, $currentgroup
|
||||
[$quiz->id, $currentgroup]);
|
||||
return get_string('attemptsnumthisgroup', 'quiz', $a);
|
||||
} else if ($groups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid)) {
|
||||
list($usql, $params) = $DB->get_in_or_equal(array_keys($groups));
|
||||
[$usql, $params] = $DB->get_in_or_equal(array_keys($groups));
|
||||
$a->group = $DB->count_records_sql('SELECT COUNT(DISTINCT qa.id) FROM ' .
|
||||
'{quiz_attempts} qa JOIN ' .
|
||||
'{groups_members} gm ON qa.userid = gm.userid ' .
|
||||
@@ -1873,7 +1873,7 @@ function quiz_check_updates_since(cm_info $cm, $from, $filter = []) {
|
||||
$quizobj->preload_questions();
|
||||
$questionids = array_keys($quizobj->get_questions(null, false));
|
||||
if (!empty($questionids)) {
|
||||
list($questionsql, $params) = $DB->get_in_or_equal($questionids, SQL_PARAMS_NAMED);
|
||||
[$questionsql, $params] = $DB->get_in_or_equal($questionids, SQL_PARAMS_NAMED);
|
||||
$select = 'id ' . $questionsql . ' AND (timemodified > :time1 OR timecreated > :time2)';
|
||||
$params['time1'] = $from;
|
||||
$params['time2'] = $from;
|
||||
@@ -1911,7 +1911,7 @@ function quiz_check_updates_since(cm_info $cm, $from, $filter = []) {
|
||||
if (empty($groupusers)) {
|
||||
return $updates;
|
||||
}
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
|
||||
[$insql, $inparams] = $DB->get_in_or_equal($groupusers);
|
||||
$select .= ' AND userid ' . $insql;
|
||||
$params = array_merge($params, $inparams);
|
||||
}
|
||||
@@ -2329,9 +2329,15 @@ function mod_quiz_output_fragment_quiz_question_bank($args): string {
|
||||
$querystring = parse_url($args['querystring'], PHP_URL_QUERY);
|
||||
parse_str($querystring, $params);
|
||||
|
||||
// Load the bank we are looking at rather than always the quiz module itself.
|
||||
$params['cmid'] = clean_param($args['bankcmid'], PARAM_INT);
|
||||
|
||||
$viewclass = \mod_quiz\question\bank\custom_view::class;
|
||||
$extraparams['view'] = $viewclass;
|
||||
|
||||
// We need the quiz modid to POST back to.
|
||||
$extraparams['quizcmid'] = clean_param($args['quizcmid'], PARAM_INT);
|
||||
|
||||
// Build required parameters.
|
||||
[$contexts, $thispageurl, $cm, $pagevars, $extraparams] =
|
||||
build_required_parameters_for_custom_view($params, $extraparams);
|
||||
@@ -2347,15 +2353,31 @@ function mod_quiz_output_fragment_quiz_question_bank($args): string {
|
||||
return $renderer->question_bank_contents($questionbank, $pagevars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the output for the question bank and category chooser.
|
||||
*
|
||||
* @param array $args provided by the AJAX request.
|
||||
* @return string html to render to the modal.
|
||||
*/
|
||||
function mod_quiz_output_fragment_switch_question_bank($args): string {
|
||||
global $USER, $COURSE, $OUTPUT;
|
||||
|
||||
$quizcmid = clean_param($args['quizcmid'], PARAM_INT);
|
||||
|
||||
$switchbankwidget = new \core_question\output\switch_question_bank($quizcmid, $COURSE->id, $USER->id);
|
||||
|
||||
return $OUTPUT->render($switchbankwidget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the add random question in a fragment output. This allows the
|
||||
* form to be rendered in javascript, for example inside a modal.
|
||||
*
|
||||
* The required arguments as keys in the $args array are:
|
||||
* cat {string} The category and category context ids comma separated.
|
||||
* addonpage {int} The page id to add this question to.
|
||||
* returnurl {string} URL to return to after form submission.
|
||||
* cmid {int} The course module id the questions are being added to.
|
||||
* quizcmid {int} The quiz course module id the questions are being added to.
|
||||
* bankcmid {int} The question bank course module id the questions are being added from.
|
||||
*
|
||||
* @param array $args The fragment arguments.
|
||||
* @return string The rendered mform fragment.
|
||||
@@ -2364,6 +2386,8 @@ function mod_quiz_output_fragment_add_random_question_form($args) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$extraparams = [];
|
||||
$extraparams['quizcmid'] = clean_param($args['quizcmid'], PARAM_INT);
|
||||
$extraparams['cmid'] = clean_param($args['bankcmid'], PARAM_INT);
|
||||
|
||||
// Build required parameters.
|
||||
[$contexts, $thispageurl, $cm, $pagevars, $extraparams] =
|
||||
@@ -2478,12 +2502,14 @@ function mod_quiz_output_fragment_question_data(array $args): string {
|
||||
$thispageurl = new \moodle_url('/mod/quiz/edit.php', ['cmid' => $cmid]);
|
||||
$thiscontext = \context_module::instance($cmid);
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($thiscontext);
|
||||
$defaultcategory = question_make_default_categories($contexts->all());
|
||||
$defaultcategory = question_get_default_category($contexts->lowest()->id, true);
|
||||
$params['cat'] = implode(',', [$defaultcategory->id, $defaultcategory->contextid]);
|
||||
|
||||
$course = get_course($params['courseid']);
|
||||
[, $cm] = get_module_from_cmid($cmid);
|
||||
// The viewing bank mod id.
|
||||
[, $cm] = get_module_from_cmid(clean_param($args['cmid'], PARAM_INT));
|
||||
$params['tabname'] = 'questions';
|
||||
$extraparams['quizcmid'] = clean_param($args['quizcmid'], PARAM_INT);
|
||||
|
||||
// Custom question bank View.
|
||||
$viewclass = clean_param($args['view'], PARAM_NOTAGS);
|
||||
@@ -2517,6 +2543,8 @@ function build_required_parameters_for_custom_view(array $params, array $extrapa
|
||||
// Add cmid so we can retrieve later in extra params.
|
||||
$extraparams['cmid'] = $cmid;
|
||||
|
||||
$extraparams['requirebankswitch'] = !empty(question_bank_helper::get_activity_types_with_shareable_questions());
|
||||
|
||||
return [$contexts, $thispageurl, $cm, $pagevars, $extraparams];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{{!
|
||||
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 mod_quiz/switch_bank_header
|
||||
|
||||
Template for showing the currently selected bank as a header with a switch bank button.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* title A cleaned string (use clean_text()) to display.
|
||||
* body HTML content for the boday
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"currentbank": "Quiz 1"
|
||||
}
|
||||
}}
|
||||
<div class="d-flex align-items-center">
|
||||
<h5>{{#str}}currentbank, mod_quiz, {{currentbank}} {{/str}}</h5>
|
||||
<button data-action="switch-question-bank" type="button" class="btn btn-secondary ml-auto mb-2" id="switch-question-bank">{{#str}}switchbank, core_question{{/str}}</button>
|
||||
</div>
|
||||
@@ -18,16 +18,17 @@ Feature: Allow students to redo questions in a practice quiz, without starting a
|
||||
| student | C1 | student |
|
||||
| teacher | C1 | teacher |
|
||||
| editor | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | preferredbehaviour | canredoquestions |
|
||||
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | 1 |
|
||||
| qbank | Qbank 1 | | C1 | qbank1 | | |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | qbank1 | Test questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
| Test questions | truefalse | TF2 | Second question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | preferredbehaviour | canredoquestions |
|
||||
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | 1 |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page | maxmark |
|
||||
| TF1 | 1 | 2 |
|
||||
@@ -193,6 +194,8 @@ Feature: Allow students to redo questions in a practice quiz, without starting a
|
||||
And I am on the "Quiz 2" "mod_quiz > Edit" page logged in as "admin"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I click on "Switch bank" "button"
|
||||
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
|
||||
And I press "Add random question"
|
||||
And user "student" has started an attempt at quiz "Quiz 2" randomised as follows:
|
||||
| slot | actualquestion |
|
||||
|
||||
@@ -8,18 +8,18 @@ Feature: Backup and restore of quizzes
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | For testing backup | C1 | quiz1 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | Test questions |
|
||||
And the following config values are set as admin:
|
||||
| enableasyncbackup | 0 |
|
||||
And I log in as "admin"
|
||||
|
||||
@javascript
|
||||
Scenario: Duplicate a quiz with two questions
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | For testing backup | C1 | quiz1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
@@ -37,9 +37,6 @@ Feature: Backup and restore of quizzes
|
||||
|
||||
@javascript
|
||||
Scenario: Backup and restore a course containing a quiz with user data.
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | For testing backup | C1 | quiz1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
|
||||
@@ -15,8 +15,9 @@ Feature: Edit quiz page - adding things
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
|
||||
| qbank | Qbank 1 | Question bank 1 for testing the Add menu | C1 | qbank1 |
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
|
||||
@javascript
|
||||
@@ -99,12 +100,22 @@ Feature: Edit quiz page - adding things
|
||||
in various categories and add them to the question bank.
|
||||
|
||||
# Create a couple of sub categories.
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | questioncategory | name |
|
||||
| Course | C1 | Default for C1 | Subcat 1 |
|
||||
| Course | C1 | Default for C1 | Subcat 2 |
|
||||
When I am on "Course 1" course homepage
|
||||
And I navigate to "Question bank" in current page administration
|
||||
When I am on the "Course 1" "core_question > course question categories" page
|
||||
Then I should see "Add category"
|
||||
And I follow "Add category"
|
||||
Then I set the field "Parent category" to "Default for Bank 1"
|
||||
And I set the field "Name" to "Subcat 1"
|
||||
And I set the field "Category info" to "This is sub category 1"
|
||||
And I press "id_submitbutton"
|
||||
And I should see "Subcat 1"
|
||||
|
||||
And I follow "Add category"
|
||||
Then I set the field "Parent category" to "Default for C1"
|
||||
And I set the field "Name" to "Subcat 2"
|
||||
And I set the field "Category info" to "This is sub category 2"
|
||||
And I press "id_submitbutton"
|
||||
And I should see "Subcat 2"
|
||||
|
||||
And I select "Questions" from the "Question bank tertiary navigation" singleselect
|
||||
And I should see "Question bank"
|
||||
|
||||
|
||||
@@ -15,15 +15,19 @@ Feature: Adding questions to a quiz from the question bank
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
|
||||
| qbank | Qbank 1 | Question bank 1 for testing the Add menu | C1 | qbank1 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | Test questions |
|
||||
| Activity module | qbank1 | Qbank questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext | idnumber |
|
||||
| Test questions | essay | question 01 name | admin | Question 01 text | |
|
||||
| Test questions | essay | question 02 name | teacher1 | Question 02 text | qidnum |
|
||||
| questioncategory | qtype | name | user | questiontext | idnumber |
|
||||
| Test questions | essay | question 01 name | admin | Question 01 text | |
|
||||
| Test questions | essay | question 02 name | teacher1 | Question 02 text | qidnum |
|
||||
| Qbank questions | essay | question 03 name | teacher1 | Question 03 text | q3idnum |
|
||||
| Qbank questions | essay | question 04 name | teacher1 | Question 04 text | q4idnum |
|
||||
|
||||
Scenario: The questions can be filtered by tag
|
||||
Given I am on the "question 01 name" "core_question > edit" page logged in as teacher1
|
||||
@@ -44,10 +48,30 @@ Feature: Adding questions to a quiz from the question bank
|
||||
And I should see "question 01 name" in the "categoryquestions" "table"
|
||||
And I should not see "question 02 name" in the "categoryquestions" "table"
|
||||
|
||||
Scenario: The questions can be filtered by tag on a shared question bank
|
||||
Given I am on the "question 03 name" "core_question > edit" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Tags | qbanktag1 |
|
||||
And I press "Save changes"
|
||||
And I am on the "question 04 name" "core_question > edit" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Tags | qbanktag2 |
|
||||
And I press "Save changes"
|
||||
When I am on the "Quiz 1" "mod_quiz > Edit" page
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "from question bank"
|
||||
And I click on "Switch bank" "button"
|
||||
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
|
||||
Then I should see "qbanktag1" in the "question 03 name" "table_row"
|
||||
And I should see "qbanktag2" in the "question 04 name" "table_row"
|
||||
And I apply question bank filter "Tag" with value "qbanktag1"
|
||||
And I should see "question 03 name" in the "categoryquestions" "table"
|
||||
And I should not see "question 04 name" in the "categoryquestions" "table"
|
||||
|
||||
Scenario: The question modal can be paginated
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | My collection |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | My collection |
|
||||
And 45 "questions" exist with the following data:
|
||||
| questioncategory | My collection |
|
||||
| qtype | essay |
|
||||
@@ -83,8 +107,8 @@ Feature: Adding questions to a quiz from the question bank
|
||||
|
||||
Scenario: After closing and reopening the modal, it still works
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | My collection |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | My collection |
|
||||
And the following "question" exists:
|
||||
| questioncategory | My collection |
|
||||
| qtype | essay |
|
||||
@@ -131,6 +155,20 @@ Feature: Adding questions to a quiz from the question bank
|
||||
Then I should see "question 01 name" on quiz page "1"
|
||||
And I should see "question 02 name" on quiz page "2"
|
||||
|
||||
Scenario: Adding a question to quiz from a shared question bank
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
When I open the "last" add to quiz menu
|
||||
And I follow "from question bank"
|
||||
Then I should see "Current bank: Quiz 1"
|
||||
And I should see "question 01 name"
|
||||
And I click on "Switch bank" "button"
|
||||
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
|
||||
And I should see "question 03 name"
|
||||
But I should not see "question 01 name"
|
||||
And I click on "Select" "checkbox" in the "question 03 name" "table_row"
|
||||
And I click on "Add selected questions to the quiz" "button"
|
||||
And I should see "question 03 name"
|
||||
|
||||
@javascript
|
||||
Scenario: Validate the sorting while adding questions from question bank
|
||||
Given the following "questions" exist:
|
||||
|
||||
@@ -15,15 +15,17 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 |
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 |
|
||||
| qbank | Qbank 1 | Question bank 1 for testing the Add menu | C1 | qbank1 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Questions Category 1 |
|
||||
| Course | C1 | Questions Category 2 |
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | Questions Category 1 |
|
||||
| Activity module | quiz1 | Questions Category 2 |
|
||||
| Activity module | qbank1 | Qbank questions |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name | questioncategory |
|
||||
| Course | C1 | Subcategory | Questions Category 1 |
|
||||
| contextlevel | reference | name | questioncategory |
|
||||
| Activity module | quiz1 | Subcategory | Questions Category 1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext |
|
||||
| Questions Category 1 | essay | question 1 name | admin | Question 1 text |
|
||||
@@ -31,13 +33,15 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
| Subcategory | essay | question 3 name | teacher1 | Question 3 text |
|
||||
| Subcategory | essay | question 4 name | teacher1 | Question 4 text |
|
||||
| Questions Category 1 | essay | "listen" & "answer" | teacher1 | Question 5 text |
|
||||
| Qbank questions | essay | Qbank question 1 | teacher1 | Qbank question |
|
||||
And the following "core_question > Tags" exist:
|
||||
| question | tag |
|
||||
| question 1 name | foo |
|
||||
| question 2 name | bar |
|
||||
| question 3 name | foo |
|
||||
| question 4 name | bar |
|
||||
| "listen" & "answer" | foo |
|
||||
| question | tag |
|
||||
| question 1 name | foo |
|
||||
| question 2 name | bar |
|
||||
| question 3 name | foo |
|
||||
| question 4 name | bar |
|
||||
| "listen" & "answer" | foo |
|
||||
| Qbank question 1 | qbanktag |
|
||||
|
||||
Scenario: Available tags are shown in the autocomplete tag field
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
@@ -70,6 +74,21 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
And I should not see "question 2 name"
|
||||
And I should not see "question 4 name"
|
||||
|
||||
Scenario: Questions can be filtered by tags on a shared question bank
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
When I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
Then I click on "Switch bank" "button"
|
||||
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
|
||||
And I apply question bank filter "Category" with value "Qbank questions"
|
||||
And I apply question bank filter "Tag" with value "qbanktag"
|
||||
And I click on "Apply filters" "button"
|
||||
And I wait until the page is ready
|
||||
And I should see "Qbank question 1"
|
||||
And I should not see "question 3 name"
|
||||
And I should not see "question 2 name"
|
||||
And I should not see "question 4 name"
|
||||
|
||||
Scenario: A random question can be added to the quiz
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I open the "last" add to quiz menu
|
||||
@@ -100,23 +119,6 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
And I should see "\"listen\" & \"answer\""
|
||||
And I should see "question 3 name"
|
||||
|
||||
Scenario: A random question from the course's top category can be added to the quiz
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I apply question bank filter "Category" with value "Top for Course 1"
|
||||
And I set the field "Also show questions from subcategories" to "1"
|
||||
And I click on "Apply filters" "button"
|
||||
And I apply question bank filter "Tag" with value "foo"
|
||||
And I select "1" from the "randomcount" singleselect
|
||||
When I press "Add random question"
|
||||
Then I should see "Random (Any category in this course) based on filter condition with tags: foo" on quiz page "1"
|
||||
And I click on "Configure question" "link" in the "Random (Any category in this course) based on filter condition with tags: foo" "list_item"
|
||||
And I should see "Top for Course 1"
|
||||
And I should see "foo"
|
||||
And I should see "question 1 name"
|
||||
And I should see "\"listen\" & \"answer\""
|
||||
|
||||
Scenario: A random question from the quiz's top category can be added to the quiz
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
@@ -144,88 +146,11 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
And I should see "quiz 1 question 1 name"
|
||||
And I should not see "quiz 1 question 2 name"
|
||||
|
||||
Scenario: A random question from the course category's top category can be added to the quiz.
|
||||
Given the following "system role assigns" exist:
|
||||
| user | role | contextlevel |
|
||||
| teacher1 | editingteacher | Category |
|
||||
And the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Category 1 | 0 | CAT1 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Category | CAT1 | Default for Category 1 |
|
||||
And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
|
||||
# Create a question in the 'Default for Category 1' category.
|
||||
And I press "Create a new question ..."
|
||||
And I set the field "item_qtype_essay" to "1"
|
||||
And I click on "Add" "button" in the "Choose a question type to add" "dialogue"
|
||||
And I set the field "Category" to "Default for Category 1"
|
||||
And I set the field "Question name" to "default for category 1 question 1 name"
|
||||
And I set the field "Question text" to "Default for Category 1 question 1 text"
|
||||
And I press "id_submitbutton"
|
||||
# Create a second question in the 'Default for Category 1' category.
|
||||
And I press "Create a new question ..."
|
||||
And I set the field "item_qtype_essay" to "1"
|
||||
And I click on "Add" "button" in the "Choose a question type to add" "dialogue"
|
||||
And I set the field "Category" to "Default for Category 1"
|
||||
And I set the field "Question name" to "default for category 1 question 2 name"
|
||||
And I set the field "Question text" to "Default for Category 1 question 2 text"
|
||||
And I press "id_submitbutton"
|
||||
# Add a tag to the second question.
|
||||
And I choose "Manage tags" action for "default for category 1 question 2 name" in the question bank
|
||||
And I set the field "Tags" to "bar"
|
||||
And I click on "Save changes" "button" in the "Question tags" "dialogue"
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I apply question bank filter "Category" with value "Top for Category 1"
|
||||
And I set the field "Also show questions from subcategories" to "1"
|
||||
And I click on "Apply filters" "button"
|
||||
And I apply question bank filter "Tag" with value "bar"
|
||||
And I select "1" from the "randomcount" singleselect
|
||||
When I press "Add random question"
|
||||
Then I should see "Random (Any category inside course category Category 1) based on filter condition with tags: bar" on quiz page "1"
|
||||
And I click on "Configure question" "link" in the "Random (Any category inside course category Category 1) based on filter condition with tags: bar" "list_item"
|
||||
And I should see "Top for Category 1"
|
||||
And I should see "bar"
|
||||
And I should see "default for category 1 question 2 name"
|
||||
And I should not see "default for category 1 question 1 name"
|
||||
|
||||
Scenario: A random question from the system's top category can be added to the quiz
|
||||
Given the following "system role assigns" exist:
|
||||
| user | role | contextlevel |
|
||||
| teacher1 | editingteacher | System |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| System | | System category |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext |
|
||||
| System category | essay | system question 1 name | admin | System question 1 text |
|
||||
| System category | essay | system question 2 name | admin | System question 2 text |
|
||||
And the following "core_question > Tags" exist:
|
||||
| question | tag |
|
||||
| system question 1 name | foo |
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "admin"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I apply question bank filter "Category" with value "Top for System"
|
||||
And I set the field "Also show questions from subcategories" to "1"
|
||||
And I click on "Apply filters" "button"
|
||||
And I apply question bank filter "Tag" with value "foo"
|
||||
And I select "1" from the "randomcount" singleselect
|
||||
When I press "Add random question"
|
||||
Then I should see "Random (Any system-level category) based on filter condition with tags: foo" on quiz page "1"
|
||||
And I click on "Configure question" "link" in the "Random (Any system-level category) based on filter condition with tags: foo" "list_item"
|
||||
And I should see "Top for System"
|
||||
And I should see "foo"
|
||||
And I should see "system question 1 name"
|
||||
And I should not see "system question 2 name"
|
||||
|
||||
Scenario: A random question from a top category, excluding subcategories, shows an indicator of being faulty
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I apply question bank filter "Category" with value "Top for Course 1"
|
||||
And I apply question bank filter "Category" with value "Top for Quiz 1"
|
||||
And I set the field "Also show questions from subcategories" to "0"
|
||||
And I click on "Apply filters" "button"
|
||||
And I apply question bank filter "Tag" with value "foo"
|
||||
@@ -245,6 +170,26 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
And I press "Apply filters"
|
||||
Then I should see "question 3 name"
|
||||
|
||||
Scenario: A random question can be added to the quiz from a shared question bank
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I open the "last" add to quiz menu
|
||||
And I follow "a random question"
|
||||
And I should see "Current bank: Quiz 1"
|
||||
And I should see "question 1 name"
|
||||
And I click on "Switch bank" "button"
|
||||
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
|
||||
And I should see "Current bank: Qbank 1"
|
||||
And I should see "Qbank question 1"
|
||||
And I should not see "question 1 name"
|
||||
When I apply question bank filter "Tag" with value "qbanktag"
|
||||
And I select "1" from the "randomcount" singleselect
|
||||
And I press "Add random question"
|
||||
Then I should see "Random (Qbank questions) based on filter condition with tags: qbanktag" on quiz page "1"
|
||||
And I click on "Configure question" "link" in the "Random (Qbank questions) based on filter condition with tags: qbank" "list_item"
|
||||
And I should see "Qbank questions"
|
||||
And I should see "qbanktag"
|
||||
And I should see "Qbank question 1"
|
||||
|
||||
Scenario: Teacher without moodle/question:useall should not see the add a random question menu item
|
||||
Given the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
@@ -262,7 +207,7 @@ Feature: Adding random questions to a quiz based on category and tags
|
||||
And "Help with Parent category" "icon" should exist in the "Random question using a new category" "fieldset"
|
||||
And I set the following fields to these values:
|
||||
| Name | New Random category |
|
||||
| Parent category | Default for Quiz 1 |
|
||||
| Parent category | Questions Category 1 |
|
||||
And I press "Create category and add random question"
|
||||
And I should see "Random (New Random category) based on filter condition" on quiz page "1"
|
||||
And I click on "Configure question" "link" in the "Random (New Random category) based on filter condition" "list_item"
|
||||
|
||||
@@ -18,9 +18,9 @@ Feature: Editing random questions already in a quiz based on category and tags
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Questions Category 1|
|
||||
| Course | C1 | Questions Category 2|
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | quiz1 | Questions Category 1|
|
||||
| Activity module | quiz1 | Questions Category 2|
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext |
|
||||
| Questions Category 1 | essay | question 1 name | admin | Question 1 text |
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
@mod @mod_qbank @javascript
|
||||
Feature: Switching question bank when adding questions to a quiz
|
||||
In order to re-use questions
|
||||
As a teacher
|
||||
I want to be able to switch to other banks I have access to.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | weeks |
|
||||
| Course 2 | C2 | weeks |
|
||||
| Course 3 | C3 | weeks |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teacher1 | C2 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
|
||||
| qbank | Qbank 1 | Question bank 1 for testing the Add menu | C1 | qbank1 |
|
||||
| qbank | Qbank 2 | Question bank 2 for testing the Add menu | C1 | qbank2 |
|
||||
| qbank | Qbank 3 | Question bank 3 for testing the Add menu | C2 | qbank3 |
|
||||
| qbank | Qbank 4 | Question bank 4 for testing the Add menu | C3 | qbank4 |
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | qbank1 | Test questions 1 |
|
||||
| Activity module | qbank2 | Test questions 2 |
|
||||
| Activity module | qbank3 | Test questions 3 |
|
||||
| Activity module | qbank4 | Test questions 4 |
|
||||
| Activity module | quiz1 | Test questions 5 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext | idnumber |
|
||||
| Test questions 1 | essay | question 01 name | admin | Question 01 text | qidnum1 |
|
||||
| Test questions 2 | essay | question 02 name | teacher1 | Question 02 text | qidnum2 |
|
||||
| Test questions 3 | essay | question 03 name | teacher1 | Question 03 text | qidnum3 |
|
||||
| Test questions 4 | essay | question 04 name | admin | Question 04 text | qidnum4 |
|
||||
| Test questions 5 | essay | question 05 name | teacher1 | Question 05 text | qidnum5 |
|
||||
And I log in as "teacher1"
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page
|
||||
|
||||
Scenario: Switching to another bank shows the expected banks
|
||||
When I open the "last" add to quiz menu
|
||||
And I follow "from question bank"
|
||||
When I click on "Switch bank" "button"
|
||||
Then I should see "Quiz 1"
|
||||
And I should see "Qbank 1"
|
||||
And I should see "Qbank 2"
|
||||
But I should not see "Qbank 3"
|
||||
|
||||
Scenario: Searching for another shared bank shows the expected bank
|
||||
When I open the "last" add to quiz menu
|
||||
And I follow "from question bank"
|
||||
When I click on "Switch bank" "button"
|
||||
And I open the autocomplete suggestions list
|
||||
Then "Qbank 3" "autocomplete_suggestions" should exist
|
||||
But "Qbank 4" "autocomplete_suggestions" should not exist
|
||||
And I click on "C2 - Qbank 3" item in the autocomplete list
|
||||
And I should see "Current bank: Qbank 3"
|
||||
And I should see "Test questions 3"
|
||||
|
||||
Scenario: Viewing question banks not in the current course show as recently accessed
|
||||
Given I am on the "qbank1" "Activity" page
|
||||
And I am on the "qbank2" "Activity" page
|
||||
And I am on the "qbank3" "Activity" page
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page
|
||||
When I open the "last" add to quiz menu
|
||||
And I follow "from question bank"
|
||||
And I click on "Switch bank" "button"
|
||||
Then I should see "Qbank 3"
|
||||
But I should not see "Qbank 4"
|
||||
@@ -49,8 +49,7 @@ class quiz_question_bank_view_test extends \advanced_testcase {
|
||||
|
||||
// Create a question in the default category.
|
||||
$contexts = new question_edit_contexts($context);
|
||||
question_make_default_categories($contexts->all());
|
||||
$cat = question_get_default_category($context->id);
|
||||
$cat = question_get_default_category($context->id, true);
|
||||
$questiondata = $questiongenerator->create_question('numerical', null,
|
||||
['name' => 'Example question', 'category' => $cat->id]);
|
||||
|
||||
@@ -68,7 +67,7 @@ class quiz_question_bank_view_test extends \advanced_testcase {
|
||||
'qbshowtext' => false,
|
||||
'tabname' => 'editq'
|
||||
];
|
||||
$extraparams = ['cmid' => $cm->id];
|
||||
$extraparams = ['cmid' => $cm->id, 'quizcmid' => $cm->id];
|
||||
$view = new custom_view($contexts, new \moodle_url('/'), $course, $cm, $params, $extraparams);
|
||||
ob_start();
|
||||
$view->display();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -34,7 +34,8 @@ import Fragment from 'core/fragment';
|
||||
* @param {String} defaultcourseid Course ID for the default course to pass back to the view.
|
||||
* @param {String} defaultcategoryid Question bank category ID for the default course to pass back to the view.
|
||||
* @param {Number} perpage The number of questions to display per page.
|
||||
* @param {Number} contextId Context ID of the question bank view.
|
||||
* @param {Number} bankContextId Context ID of the question bank being filtered.
|
||||
* @param {Number} quizCmId Course module ID of the quiz as the viewing context.
|
||||
* @param {string} component Frankenstyle name of the component for the fragment API callback (e.g. core_question)
|
||||
* @param {string} callback Name of the callback for the fragment API (e.g question_data)
|
||||
* @param {string} view The class name of the question bank view class used for this page.
|
||||
@@ -47,7 +48,8 @@ export const init = (
|
||||
defaultcourseid,
|
||||
defaultcategoryid,
|
||||
perpage,
|
||||
contextId,
|
||||
bankContextId,
|
||||
quizCmId,
|
||||
component,
|
||||
callback,
|
||||
view,
|
||||
@@ -115,7 +117,8 @@ export const init = (
|
||||
// Load questions for first page.
|
||||
viewData.filter = JSON.stringify(filterdata);
|
||||
viewData.sortdata = JSON.stringify(sortData);
|
||||
Fragment.loadFragment(component, callback, contextId, viewData)
|
||||
viewData.quizcmid = quizCmId;
|
||||
Fragment.loadFragment(component, callback, bankContextId, viewData)
|
||||
// Render questions for first page and pagination.
|
||||
.then((questionhtml, jsfooter) => {
|
||||
const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);
|
||||
|
||||
@@ -86,11 +86,12 @@ class helper_test extends \advanced_testcase {
|
||||
|
||||
// Create a course.
|
||||
$this->course = $generator->create_course();
|
||||
$this->context = \context_course::instance($this->course->id);
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['name' => 'QBANK 1', 'course' => $this->course->id]);
|
||||
$this->context = \context_module::instance($qbank->cmid);
|
||||
|
||||
// Create a question in the default category.
|
||||
$this->contexts = new question_edit_contexts($this->context);
|
||||
$this->cat = question_make_default_categories($this->contexts->all());
|
||||
$this->cat = question_get_default_category($this->contexts->lowest()->id, true);
|
||||
$this->questiondata1 = $questiongenerator->create_question('numerical', null,
|
||||
['name' => 'Example question', 'category' => $this->cat->id]);
|
||||
|
||||
@@ -211,13 +212,12 @@ class helper_test extends \advanced_testcase {
|
||||
*/
|
||||
public function test_get_displaydata(): void {
|
||||
$this->helper_setup();
|
||||
$coursecontext = \context_course::instance($this->course->id);
|
||||
$contexts = new question_edit_contexts($coursecontext);
|
||||
$contexts = new question_edit_contexts($this->context);
|
||||
$addcontexts = $contexts->having_cap('moodle/question:add');
|
||||
$url = new \moodle_url('/question/bank/bulkmove/move.php');
|
||||
$displaydata = \qbank_bulkmove\helper::get_displaydata($addcontexts, $url, $url);
|
||||
$this->assertStringContainsString('Test question category 1', $displaydata['categorydropdown']);
|
||||
$this->assertStringContainsString('Default for Category 1', $displaydata['categorydropdown']);
|
||||
$this->assertStringContainsString('Default for QBANK 1', $displaydata['categorydropdown']);
|
||||
$this->assertEquals($url, $displaydata ['moveurl']);
|
||||
$this->assertEquals($url, $displaydata ['returnurl']);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use core_question\local\bank\column_base;
|
||||
use core_question\local\bank\column_manager_base;
|
||||
use core_question\local\bank\question_edit_contexts;
|
||||
use core_question\local\bank\view;
|
||||
use core_question\local\bank\question_bank_helper;
|
||||
use qbank_columnsortorder\local\bank\column_action_move;
|
||||
use qbank_columnsortorder\local\bank\column_action_remove;
|
||||
use qbank_columnsortorder\local\bank\column_action_resize;
|
||||
@@ -172,9 +173,11 @@ class column_manager extends column_manager_base {
|
||||
*/
|
||||
public function get_questionbank(): view {
|
||||
$course = (object) ['id' => 0];
|
||||
$context = context_system::instance();
|
||||
$previewbank = question_bank_helper::get_preview_open_instance_type(true);
|
||||
$cm = $previewbank->get_course_module_record();
|
||||
$context = \context_module::instance($previewbank->id);
|
||||
$contexts = new question_edit_contexts($context);
|
||||
$category = question_make_default_categories($contexts->all());
|
||||
$category = question_get_default_category($contexts->lowest()->id, true);
|
||||
$params = ['cat' => $category->id . ',' . $context->id];
|
||||
// Dummy call to get the objects without error.
|
||||
$questionbank = new preview_view(
|
||||
|
||||
@@ -47,8 +47,9 @@ class column_manager_test extends advanced_testcase {
|
||||
*/
|
||||
protected static function get_question_bank(): view {
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$questionbank = new view(
|
||||
new question_edit_contexts(context_course::instance($course->id)),
|
||||
new question_edit_contexts(\context_module::instance($qbank->cmid)),
|
||||
new moodle_url('/'),
|
||||
$course
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ use cache;
|
||||
use comment;
|
||||
use context;
|
||||
use context_course;
|
||||
use context_module;
|
||||
use core_question_generator;
|
||||
use stdClass;
|
||||
|
||||
@@ -63,11 +64,12 @@ class comment_created_deleted_test extends advanced_testcase {
|
||||
|
||||
// Create a course.
|
||||
$this->course = $generator->create_course();
|
||||
$this->context = context_course::instance($this->course->id);
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $this->course->id]);
|
||||
$this->context = context_module::instance($qbank->cmid);
|
||||
|
||||
// Create a question in the default category.
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($this->context);
|
||||
$cat = question_make_default_categories($contexts->all());
|
||||
$cat = question_get_default_category($contexts->lowest()->id, true);
|
||||
$this->questiondata = $questiongenerator->create_question('numerical', null,
|
||||
['name' => 'Example question', 'category' => $cat->id]);
|
||||
|
||||
|
||||
@@ -60,11 +60,12 @@ class helper_test extends \advanced_testcase {
|
||||
$questiongenerator = $generator->get_plugin_generator('core_question');
|
||||
// Create a course.
|
||||
$course = $generator->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$this->courseid = $course->id;
|
||||
$this->context = \context_course::instance($course->id);
|
||||
$this->context = \context_module::instance($qbank->cmid);
|
||||
// Create a question in the default category.
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($this->context);
|
||||
$cat = question_make_default_categories($contexts->all());
|
||||
$cat = question_get_default_category($contexts->lowest()->id, true);
|
||||
$question = $questiongenerator->create_question('numerical', null,
|
||||
['name' => 'Example question', 'category' => $cat->id]);
|
||||
$this->questiondata = question_bank::load_question($question->id);
|
||||
|
||||
@@ -88,26 +88,30 @@ class question_category_object_test extends \advanced_testcase {
|
||||
parent::setUp();
|
||||
self::setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
$this->context = context_course::instance(SITEID);
|
||||
$contexts = new question_edit_contexts($this->context);
|
||||
$this->topcat = question_get_top_category($this->context->id, true);
|
||||
|
||||
// Set up tests in a quiz context.
|
||||
$this->course = $this->getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $this->course->id]);
|
||||
$qbankcontext = context_module::instance($qbank->cmid);
|
||||
$this->quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $this->course->id]);
|
||||
$this->qcontexts = new question_edit_contexts(context_module::instance($this->quiz->cmid));
|
||||
|
||||
$contexts = new question_edit_contexts($qbankcontext);
|
||||
$this->topcat = question_get_top_category($qbankcontext->id, true);
|
||||
$this->resetDebugging();
|
||||
$this->qcobject = new question_category_object(null,
|
||||
new moodle_url('/question/bank/managecategories/category.php', ['courseid' => SITEID]),
|
||||
new moodle_url('/question/bank/managecategories/category.php', ['cmid' => $qbank->cmid]),
|
||||
$contexts->having_one_edit_tab_cap('categories'), 0, null, 0,
|
||||
$contexts->having_cap('moodle/question:add'));
|
||||
$contexts->having_cap('moodle/question:add')
|
||||
);
|
||||
$this->assertDebuggingCalled(
|
||||
'Deprecation: qbank_managecategories\question_category_object::__construct has been deprecated since 4.5. ' .
|
||||
'API properly divided between qbank_managecategories and core_question. ' .
|
||||
'Use \qbank_managecategories\question_categories or \core_question\category_manager instead. ' .
|
||||
'See MDL-72397 for more information.',
|
||||
);
|
||||
// Set up tests in a quiz context.
|
||||
$this->course = $this->getDataGenerator()->create_course();
|
||||
$this->quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $this->course->id]);
|
||||
$this->qcontexts = new question_edit_contexts(context_module::instance($this->quiz->cmid));
|
||||
|
||||
$this->defaultcategoryobj = question_make_default_categories([$this->qcontexts->lowest()]);
|
||||
$this->defaultcategoryobj = question_get_default_category($this->qcontexts->lowest()->id, true);
|
||||
$this->defaultcategory = $this->defaultcategoryobj->id . ',' . $this->defaultcategoryobj->contextid;
|
||||
|
||||
$this->resetDebugging();
|
||||
|
||||
@@ -73,10 +73,12 @@ class qbank_preview_helper_test extends \advanced_testcase {
|
||||
$questiongenerator = $generator->get_plugin_generator('core_question');
|
||||
// Create a course.
|
||||
$course = $generator->create_course();
|
||||
$qbank = $generator->create_module('qbank', ['course' => $course->id]);
|
||||
$qbankcontext = \context_module::instance($qbank->cmid);
|
||||
$this->context = context_course::instance($course->id);
|
||||
// Create a question in the default category.
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($this->context);
|
||||
$cat = question_make_default_categories($contexts->all());
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($qbankcontext);
|
||||
$cat = question_get_default_category($contexts->lowest()->id, true);
|
||||
$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',
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@ $PAGE->set_heading(format_string($course->fullname, true, ['context' => $coursec
|
||||
if ($createdefault) {
|
||||
require_sesskey();
|
||||
question_bank_helper::create_default_open_instance(
|
||||
$course,
|
||||
get_string('defaultbank', 'core_question', ['coursename' => $course->fullname])
|
||||
$course,
|
||||
get_string('defaultbank', 'core_question', ['coursename' => $course->fullname])
|
||||
);
|
||||
\core\notification::add(get_string('defaultcreated', 'question'), \core\notification::SUCCESS);
|
||||
redirect($pageurl);
|
||||
|
||||
@@ -1169,6 +1169,7 @@ class view {
|
||||
echo \html_writer::start_tag('form', ['action' => $this->baseurl, 'method' => 'post', 'id' => 'questionsubmit']);
|
||||
echo \html_writer::start_tag('fieldset', ['class' => 'invisiblefieldset', 'style' => "display: block;"]);
|
||||
echo \html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()]);
|
||||
echo \html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'addonpage']);
|
||||
echo \html_writer::input_hidden_params($this->baseurl);
|
||||
|
||||
$filtercondition = json_encode($this->get_pagevars());
|
||||
|
||||
@@ -131,6 +131,7 @@ class question_bank_filter_ui extends datafilter {
|
||||
'categoryid' => $defaultcategory->id,
|
||||
'perpage' => $this->additionalparams['perpage'] ?? 0,
|
||||
'contextid' => $this->context->id,
|
||||
'quizcmid' => $this->extraparams['quizcmid'] ?? $this->cmid,
|
||||
'component' => $this->component,
|
||||
'callback' => $this->callback,
|
||||
'view' => str_replace('\\', '\\\\', $this->view),
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_question output class.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Simon Adams <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\output;
|
||||
|
||||
use cm_info;
|
||||
use core_question\local\bank\question_bank_helper;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Get the switch question bank rendered content. Displays lists of shared banks the viewing user has access to.
|
||||
*/
|
||||
class switch_question_bank implements \renderable, \templatable {
|
||||
|
||||
/**
|
||||
* Instantiate the output class.
|
||||
*
|
||||
* @param int $quizcmid quiz course module id.
|
||||
* @param int $courseid of the current course.
|
||||
* @param int $userid of the user viewing the page.
|
||||
*/
|
||||
public function __construct(
|
||||
/** @var int quiz course module id */
|
||||
private readonly int $quizcmid,
|
||||
/** @var int id of the current course */
|
||||
private readonly int $courseid,
|
||||
/** @var int id of the user viewing the page */
|
||||
private readonly int $userid
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of question banks the user has access to for the template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return array
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
|
||||
[, $cm] = get_module_from_cmid($this->quizcmid);
|
||||
$cminfo = cm_info::create($cm);
|
||||
|
||||
$sharedbanks = question_bank_helper::get_activity_instances_with_shareable_questions(
|
||||
notincourseids: [$this->courseid],
|
||||
havingcap: ['moodle/question:managecategory']
|
||||
);
|
||||
$coursesharedbanks = question_bank_helper::get_activity_instances_with_shareable_questions(
|
||||
incourseids: [$this->courseid],
|
||||
havingcap: ['moodle/question:managecategory']
|
||||
);
|
||||
$recentlyviewedbanks = question_bank_helper::get_recently_used_open_banks($this->userid);
|
||||
|
||||
return [
|
||||
'quizname' => $cminfo->get_formatted_name(),
|
||||
'quizcmid' => $this->quizcmid,
|
||||
'hascoursesharedbanks' => !empty($coursesharedbanks),
|
||||
'coursesharedbanks' => $coursesharedbanks,
|
||||
'hasrecentlyviewedbanks' => !empty($recentlyviewedbanks),
|
||||
'recentlyviewedbanks' => $recentlyviewedbanks,
|
||||
'hassharedbanks' => !empty($sharedbanks),
|
||||
'sharedbanks' => $sharedbanks,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -89,5 +89,6 @@ $category->id = $categoryid;
|
||||
$catcontext = context::instance_by_id($contextid);
|
||||
$event = question_category_viewed::create_from_question_category_instance($category, $catcontext);
|
||||
$event->trigger();
|
||||
\core_question\local\bank\question_bank_helper::add_bank_context_to_recently_viewed($catcontext);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -307,7 +307,7 @@ function question_build_edit_resources($edittab, $baseurl, $params,
|
||||
$pagevars['qperpage'] = $qperpage ?? $defaultquestionsperpage;
|
||||
}
|
||||
|
||||
$defaultcategory = question_make_default_categories($contexts->all());
|
||||
$defaultcategory = question_get_default_category($contexts->lowest()->id, true);
|
||||
|
||||
$contextlistarr = [];
|
||||
foreach ($contexts->having_one_edit_tab_cap($edittab) as $context){
|
||||
|
||||
@@ -158,6 +158,26 @@ class qformat_xml_import_export_test extends advanced_testcase {
|
||||
$this->assert_category_has_parent('Alpha', 'top');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check importing categories that were in a now deprecated context.
|
||||
*
|
||||
* @return void
|
||||
* @covers \qformat_default::importprocess()
|
||||
*/
|
||||
public function test_deprecated_category_import(): void {
|
||||
$this->resetAfterTest();
|
||||
self::setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qformat = $this->create_qformat('deprecated_category.xml', $course);
|
||||
$cat = question_get_default_category($qformat->contexts[0]->id, true);
|
||||
$qformat->setCategory($cat);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Alpha', 'This is Alpha category for test', FORMAT_MOODLE, 'alpha-idnumber');
|
||||
$this->assert_category_has_parent('Alpha', 'top');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check importing nested categories.
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"categoryid": "2",
|
||||
"perpage": "100",
|
||||
"contextid": "3",
|
||||
"quizcmid": "4",
|
||||
"component": "core_quiz",
|
||||
"callback": "get_question_data",
|
||||
"view": "\\\\core\\\\question\\\\local\\\\bank\\\\view",
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
{{#js}}
|
||||
require(['core_question/filter'], function(Filter) {
|
||||
Filter.init('core-filter-{{uniqid}}', {{courseid}}, {{categoryid}}, {{perpage}}, {{contextid}},
|
||||
Filter.init('core-filter-{{uniqid}}', {{courseid}}, {{categoryid}}, {{perpage}}, {{contextid}}, {{quizcmid}},
|
||||
'{{component}}', '{{callback}}', '{{view}}', {{cmid}}, '{{{pagevars}}}', '{{{extraparams}}}');
|
||||
});
|
||||
{{/js}}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_question/switch_question_bank
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"quizname": "Quiz 1",
|
||||
"quizcmid": 1,
|
||||
"hascoursesharedbanks": true,
|
||||
"coursesharedbanks": [
|
||||
{
|
||||
"name": "Question bank 1",
|
||||
"modid": "2",
|
||||
"contextid": 2,
|
||||
"coursenamebankname": "c1 - Question bank 1",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
},
|
||||
{
|
||||
"name": "Question bank 2",
|
||||
"modid": "3",
|
||||
"contextid": 3,
|
||||
"coursenamebankname": "c1 - Question bank 2",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
}
|
||||
],
|
||||
"hasrecentlyviewedbanks": true,
|
||||
"recentlyviewedbanks": [
|
||||
{
|
||||
"name": "Question bank 3",
|
||||
"modid": "4",
|
||||
"contextid": 4,
|
||||
"coursenamebankname": "c2 - Question bank 4",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
},
|
||||
{
|
||||
"name": "Question bank 4",
|
||||
"modid": "6",
|
||||
"contextid": 6,
|
||||
"coursenamebankname": "c3 - Question bank 5",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
}
|
||||
],
|
||||
"hassharedbanks": true,
|
||||
"sharedbanks": [
|
||||
{
|
||||
"name": "Question bank 1",
|
||||
"modid": "2",
|
||||
"contextid": 2,
|
||||
"coursenamebankname": "c1 - Question bank 1",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
},
|
||||
{
|
||||
"name": "Question bank 2",
|
||||
"modid": "3",
|
||||
"contextid": 3,
|
||||
"coursenamebankname": "c1 - Question bank 2",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
},
|
||||
{
|
||||
"name": "Question bank 3",
|
||||
"modid": "4",
|
||||
"contextid": 4,
|
||||
"coursenamebankname": "c2 - Question bank 4",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
},
|
||||
{
|
||||
"name": "Question bank 4",
|
||||
"modid": "6",
|
||||
"contextid": 6,
|
||||
"coursenamebankname": "c3 - Question bank 5",
|
||||
"cminfo": {},
|
||||
"questioncategories": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="quiz-bank">
|
||||
<h5>{{#str}}quizquestionbank, core_question{{/str}}</h5>
|
||||
<a href="#" class="ms-3" data-newmodid="{{quizcmid}}">{{quizname}}</a>
|
||||
</div>
|
||||
|
||||
<hr class="w-75">
|
||||
|
||||
{{#hascoursesharedbanks}}
|
||||
<div class="course-shared-banks">
|
||||
<h5>{{#str}}banksincourse, core_question{{/str}}</h5>
|
||||
{{#coursesharedbanks}}
|
||||
<ul class="list-unstyled ms-3">
|
||||
<li>
|
||||
<a href="#" data-newmodid="{{modid}}">{{name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{/coursesharedbanks}}
|
||||
</div>
|
||||
<hr class="w-75">
|
||||
{{/hascoursesharedbanks}}
|
||||
|
||||
{{#hasrecentlyviewedbanks}}
|
||||
<div class="recently-viewed-banks">
|
||||
<h5>{{#str}}recentlyviewedquestionbanks, core_question{{/str}}</h5>
|
||||
{{#recentlyviewedbanks}}
|
||||
<ul class="list-unstyled ms-3">
|
||||
<li>
|
||||
<a href="#" data-newmodid="{{modid}}">{{coursenamebankname}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{/recentlyviewedbanks}}
|
||||
</div>
|
||||
<hr class="w-75">
|
||||
{{/hasrecentlyviewedbanks}}
|
||||
|
||||
{{#hassharedbanks}}
|
||||
<div class="search-banks">
|
||||
<h5>{{#str}}otherquestionbank, core_question{{/str}}</h5>
|
||||
<select class="custom-select" id="searchbanks">
|
||||
<option value=""></option>
|
||||
{{#sharedbanks}}
|
||||
<option value="{{modid}}">{{{coursenamebankname}}}</option>
|
||||
{{/sharedbanks}}
|
||||
</select>
|
||||
</div>
|
||||
{{/hassharedbanks}}
|
||||
@@ -59,7 +59,7 @@ class events_test extends \advanced_testcase {
|
||||
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
|
||||
|
||||
$defaultcategory = question_make_default_categories([$contexts->lowest()]);
|
||||
$defaultcategory = question_get_default_category($contexts->lowest()->id, true);
|
||||
|
||||
$category = $questiongenerator->create_question_category([
|
||||
'name' => 'newcategory',
|
||||
@@ -103,7 +103,7 @@ class events_test extends \advanced_testcase {
|
||||
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
|
||||
|
||||
$defaultcategory = question_make_default_categories([$contexts->lowest()]);
|
||||
$defaultcategory = question_get_default_category($contexts->lowest()->id, true);
|
||||
|
||||
$category = $questiongenerator->create_question_category([
|
||||
'name' => 'newcategory',
|
||||
|
||||
@@ -44,11 +44,13 @@ class edit_form_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
|
||||
$syscontext = \context_system::instance();
|
||||
$category = question_make_default_categories(array($syscontext));
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$bankcontext = \context_module::instance($qbank->cmid);
|
||||
$category = question_get_default_category($bankcontext->id, true);
|
||||
$fakequestion = new \stdClass();
|
||||
$fakequestion->qtype = 'ddimageortext';
|
||||
$fakequestion->contextid = $syscontext->id;
|
||||
$fakequestion->contextid = $bankcontext->id;
|
||||
$fakequestion->createdby = 2;
|
||||
$fakequestion->category = $category->id;
|
||||
$fakequestion->questiontext = 'Test question';
|
||||
@@ -60,7 +62,7 @@ class edit_form_test extends \advanced_testcase {
|
||||
$fakequestion->inputs = null;
|
||||
|
||||
$form = new qtype_ddimageortext_edit_form(new \moodle_url('/'), $fakequestion, $category,
|
||||
new \core_question\local\bank\question_edit_contexts($syscontext));
|
||||
new \core_question\local\bank\question_edit_contexts($bankcontext));
|
||||
|
||||
return [$form, $category];
|
||||
}
|
||||
|
||||
@@ -44,11 +44,13 @@ class edit_form_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
|
||||
$syscontext = \context_system::instance();
|
||||
$category = question_make_default_categories(array($syscontext));
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$bankcontext = \context_module::instance($qbank->cmid);
|
||||
$category = question_get_default_category($bankcontext->id, true);
|
||||
$fakequestion = new \stdClass();
|
||||
$fakequestion->qtype = 'ddmarker';
|
||||
$fakequestion->contextid = $syscontext->id;
|
||||
$fakequestion->contextid = $bankcontext->id;
|
||||
$fakequestion->createdby = 2;
|
||||
$fakequestion->category = $category->id;
|
||||
$fakequestion->questiontext = 'Test question';
|
||||
@@ -60,7 +62,7 @@ class edit_form_test extends \advanced_testcase {
|
||||
$fakequestion->inputs = null;
|
||||
|
||||
$form = new qtype_ddmarker_edit_form(new \moodle_url('/'), $fakequestion, $category,
|
||||
new \core_question\local\bank\question_edit_contexts($syscontext));
|
||||
new \core_question\local\bank\question_edit_contexts($bankcontext));
|
||||
|
||||
return [$form, $category];
|
||||
}
|
||||
|
||||
@@ -44,11 +44,13 @@ class edit_form_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
|
||||
$syscontext = \context_system::instance();
|
||||
$category = question_make_default_categories(array($syscontext));
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$bankcontext = \context_module::instance($qbank->cmid);
|
||||
$category = question_get_default_category($bankcontext->id, true);
|
||||
$fakequestion = new \stdClass();
|
||||
$fakequestion->qtype = 'ddwtos'; // Does not actually matter if this is wrong.
|
||||
$fakequestion->contextid = $syscontext->id;
|
||||
$fakequestion->contextid = $bankcontext->id;
|
||||
$fakequestion->createdby = 2;
|
||||
$fakequestion->category = $category->id;
|
||||
$fakequestion->questiontext = 'Test [[1]] question [[2]]';
|
||||
@@ -60,7 +62,7 @@ class edit_form_test extends \advanced_testcase {
|
||||
$fakequestion->inputs = null;
|
||||
|
||||
$form = new $classname(new \moodle_url('/'), $fakequestion, $category,
|
||||
new \core_question\local\bank\question_edit_contexts($syscontext));
|
||||
new \core_question\local\bank\question_edit_contexts($bankcontext));
|
||||
|
||||
return [$form, $category];
|
||||
}
|
||||
|
||||
@@ -45,11 +45,13 @@ class edit_form_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
|
||||
$syscontext = \context_system::instance();
|
||||
$category = question_make_default_categories(array($syscontext));
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$bankcontext = \context_module::instance($qbank->cmid);
|
||||
$category = question_get_default_category($bankcontext->id, true);
|
||||
$fakequestion = new \stdClass();
|
||||
$fakequestion->qtype = 'essay';
|
||||
$fakequestion->contextid = $syscontext->id;
|
||||
$fakequestion->contextid = $bankcontext->id;
|
||||
$fakequestion->createdby = $USER->id;
|
||||
$fakequestion->category = $category->id;
|
||||
$fakequestion->questiontext = 'please writer an assay about ...';
|
||||
@@ -64,7 +66,7 @@ class edit_form_test extends \advanced_testcase {
|
||||
new \moodle_url('/'),
|
||||
$fakequestion,
|
||||
$category,
|
||||
new \core_question\local\bank\question_edit_contexts($syscontext)
|
||||
new \core_question\local\bank\question_edit_contexts($bankcontext)
|
||||
);
|
||||
|
||||
return [$form, $category];
|
||||
|
||||
@@ -45,7 +45,7 @@ class restore_test extends \restore_date_testcase {
|
||||
$course = $generator->create_course();
|
||||
$qbank = $generator->create_module('qbank', ['course' => $course->id]);
|
||||
$context = \context_module::instance($qbank->cmid);
|
||||
$category = question_make_default_categories([$context]);
|
||||
$category = question_get_default_category($context->id, true);
|
||||
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$essay = $questiongenerator->create_question('essay', null, array('category' => $category->id));
|
||||
|
||||
@@ -63,7 +63,7 @@ class restore_test extends \restore_date_testcase {
|
||||
$newqbank = reset($newqbanks);
|
||||
|
||||
// Verify that the restored question has options.
|
||||
$newcategory = question_make_default_categories([\context_module::instance($newqbank->id)]);
|
||||
$newcategory = question_make_default_category(\context_module::instance($newqbank->id));
|
||||
$newessay = $DB->get_record_sql('SELECT q.*
|
||||
FROM {question} q
|
||||
JOIN {question_versions} qv ON qv.questionid = q.id
|
||||
|
||||
@@ -80,11 +80,13 @@ class edit_form_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
|
||||
$syscontext = \context_system::instance();
|
||||
$category = question_make_default_categories(array($syscontext));
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
|
||||
$bankcontext = \context_module::instance($qbank->cmid);
|
||||
$category = question_get_default_category($bankcontext->id, true);
|
||||
$fakequestion = new \stdClass();
|
||||
$fakequestion->qtype = 'gapselect'; // Does not actually matter if this is wrong.
|
||||
$fakequestion->contextid = $syscontext->id;
|
||||
$fakequestion->contextid = $bankcontext->id;
|
||||
$fakequestion->createdby = 2;
|
||||
$fakequestion->category = $category->id;
|
||||
$fakequestion->questiontext = 'Test [[1]] question [[2]]';
|
||||
@@ -96,7 +98,7 @@ class edit_form_test extends \advanced_testcase {
|
||||
$fakequestion->inputs = null;
|
||||
|
||||
$form = new $classname(new \moodle_url('/'), $fakequestion, $category,
|
||||
new \core_question\local\bank\question_edit_contexts($syscontext));
|
||||
new \core_question\local\bank\question_edit_contexts($bankcontext));
|
||||
|
||||
return [$form, $category];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user