Merge branch 'MDL-74054-master-fixes' of https://github.com/marxjohnson/moodle
This commit is contained in:
@@ -28,7 +28,9 @@ namespace mod_quiz\question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\output\datafilter;
|
||||
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;
|
||||
@@ -79,7 +81,7 @@ class custom_view extends \core_question\local\bank\view {
|
||||
}
|
||||
}
|
||||
|
||||
$this->init_required_columns();
|
||||
$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->set_quiz_has_attempts(quiz_has_attempts($this->quiz->id));
|
||||
@@ -87,55 +89,42 @@ class custom_view extends \core_question\local\bank\view {
|
||||
}
|
||||
|
||||
/**
|
||||
* Init required columns.
|
||||
* Just use the base column manager in this view.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init_required_columns(): void {
|
||||
// Override core columns.
|
||||
$this->corequestionbankcolumns = [
|
||||
'add_action_column',
|
||||
'checkbox_column',
|
||||
'question_type_column',
|
||||
'question_name_text_column',
|
||||
'preview_action_column'
|
||||
];
|
||||
protected function init_column_manager(): void {
|
||||
$this->columnmanager = new column_manager_base();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class for each question bank columns.
|
||||
* Don't display plugin controls.
|
||||
*
|
||||
* @return array
|
||||
* @param \core\context $context
|
||||
* @param int $categoryid
|
||||
* @return string
|
||||
*/
|
||||
protected function get_class_for_columns(): array {
|
||||
protected function get_plugin_controls(\core\context $context, int $categoryid): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function get_question_bank_plugins(): array {
|
||||
$questionbankclasscolumns = [];
|
||||
if (question_get_display_preference('qbshowtext', 0, PARAM_INT, new \moodle_url(''))) {
|
||||
$this->corequestionbankcolumns[] = 'question_text_row';
|
||||
}
|
||||
foreach ($this->corequestionbankcolumns as $fullname) {
|
||||
$shortname = $fullname;
|
||||
if (class_exists('mod_quiz\\question\\bank\\' . $fullname)) {
|
||||
$fullname = 'mod_quiz\\question\\bank\\' . $fullname;
|
||||
$questionbankclasscolumns[$shortname] = new $fullname($this);
|
||||
} else if (class_exists('core_question\\local\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\local\\bank\\' . $fullname;
|
||||
$questionbankclasscolumns[$shortname] = new $fullname($this);
|
||||
} else {
|
||||
$questionbankclasscolumns[$shortname] = '';
|
||||
$customviewcolumns = [
|
||||
'mod_quiz\question\bank\add_action_column' . column_base::ID_SEPARATOR . 'add_action_column',
|
||||
'core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column',
|
||||
'qbank_viewquestiontype\question_type_column' . column_base::ID_SEPARATOR . 'question_type_column',
|
||||
'mod_quiz\question\bank\question_name_text_column' . column_base::ID_SEPARATOR . 'question_name_text_column',
|
||||
'mod_quiz\question\bank\preview_action_column' . column_base::ID_SEPARATOR . 'preview_action_column',
|
||||
];
|
||||
|
||||
foreach ($customviewcolumns as $columnid) {
|
||||
[$columnclass, $columnname] = explode(column_base::ID_SEPARATOR, $columnid, 2);
|
||||
if (class_exists($columnclass)) {
|
||||
$questionbankclasscolumns[$columnid] = $columnclass::from_column_name($this, $columnname);
|
||||
}
|
||||
}
|
||||
return $questionbankclasscolumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of qbank plugins with available objects for features.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_question_bank_plugins(): array {
|
||||
// The view is too crowded, exclude some columns.
|
||||
$questionbankclasscolumns = parent::get_question_bank_plugins();
|
||||
$questionbankclasscolumns = array_intersect_key($questionbankclasscolumns, array_flip($this->corequestionbankcolumns));
|
||||
return $questionbankclasscolumns;
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -2549,15 +2549,22 @@ 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());
|
||||
$params['cat'] = implode(',', [$defaultcategory->id, $defaultcategory->contextid]);
|
||||
|
||||
$course = get_course($params['courseid']);
|
||||
[, $cm] = get_module_from_cmid($cmid);
|
||||
$params['tabname'] = 'questions';
|
||||
|
||||
// Custom question bank View.
|
||||
$viewclass = clean_param($args['view'], PARAM_NOTAGS);
|
||||
$questionbank = new $viewclass($contexts, $thispageurl, $course, $cm, $params, $extraparams);
|
||||
|
||||
// Question table.
|
||||
return $questionbank->display_questions_table();
|
||||
$questionbank->add_standard_search_conditions();
|
||||
ob_start();
|
||||
$questionbank->display_question_list();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
-29
@@ -801,7 +801,7 @@ table.quizreviewsummary td.cell {
|
||||
margin: 0 0.2em;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit #categoryquestions .questionname,
|
||||
#page-mod-quiz-edit .question-bank-table .questionname,
|
||||
#page-mod-quiz-edit ul.slots li.activity div.activityinstance .questionname {
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
@@ -845,91 +845,105 @@ table.quizreviewsummary td.cell {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#categoryquestions .header {
|
||||
#page-mod-quiz-edit .question-bank-table {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit .question-bank-table .header {
|
||||
text-align: center;
|
||||
padding: 0 2px;
|
||||
border: 0 none;
|
||||
vertical-align: top;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#categoryquestions .header.checkbox {
|
||||
#page-mod-quiz-edit .question-bank-table .header.checkbox {
|
||||
vertical-align: bottom;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#categoryquestions .header.qtype {
|
||||
#page-mod-quiz-edit .question-bank-table .header.qtype .sorters {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#categoryquestions th .sorters {
|
||||
#page-mod-quiz-edit .question-bank-table th .sorters {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#categoryquestions td.modifiername,
|
||||
#categoryquestions td.creatorname,
|
||||
#categoryquestions td.questionlastused {
|
||||
#page-mod-quiz-edit .question-bank-table td.modifiername,
|
||||
#page-mod-quiz-edit .question-bank-table td.creatorname,
|
||||
#page-mod-quiz-edit .question-bank-table td.questionlastused {
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
#categoryquestions td.modifiername span.date,
|
||||
#categoryquestions td.creatorname span.date {
|
||||
#page-mod-quiz-edit .question-bank-table td.modifiername span.date,
|
||||
#page-mod-quiz-edit .question-bank-table td.creatorname span.date {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
table#categoryquestions {
|
||||
width: 100%;
|
||||
#page-mod-quiz-edit table.question-bank-table {
|
||||
table-layout: fixed;
|
||||
overflow-x: visible;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
#categoryquestions .iconcol {
|
||||
width: 15px;
|
||||
#page-mod-quiz-edit .question-bank-table .iconcol {
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
}
|
||||
#page-mod-quiz-edit .question-bank-table .iconcol .icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit .question-bank-table .checkbox {
|
||||
width: 32px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#categoryquestions .checkbox {
|
||||
width: 19px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#categoryquestions .editmenu {
|
||||
#page-mod-quiz-edit .question-bank-table .editmenu {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
#categoryquestions .qtype {
|
||||
#page-mod-quiz-edit .question-bank-table .qtype {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#categoryquestions .qtype {
|
||||
#page-mod-quiz-edit .question-bank-table .qtype {
|
||||
width: 28px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#categoryquestions .questiontext {
|
||||
#page-mod-quiz-edit .question-bank-table .questionnametext {
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit .question-bank-table .questiontext {
|
||||
position: relative;
|
||||
zoom: 1;
|
||||
padding-left: 0.3em;
|
||||
padding: 0.3em;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#categoryquestions .questionname {
|
||||
#page-mod-quiz-edit .question-bank-table .questionname {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
zoom: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#categoryquestions .questiontext p {
|
||||
#page-mod-quiz-edit .question-bank-table .questiontext p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit table#categoryquestions td,
|
||||
#page-mod-quiz-edit table#categoryquestions th {
|
||||
#page-mod-quiz-edit table.question-bank-table td,
|
||||
#page-mod-quiz-edit table.question-bank-table th {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
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
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
define("core_question/refresh_ui",["exports","core/fragment","core/templates"],(function(_exports,_fragment,_templates){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Question bank UI refresh utility
|
||||
*
|
||||
* @module core_question/refresh_ui
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_fragment=_interopRequireDefault(_fragment),_templates=_interopRequireDefault(_templates);var _default={refresh:(uiRoot,returnUrl)=>new Promise(((resolve,reject)=>{const fragmentData=uiRoot.dataset,viewData={},sortData={};returnUrl&&returnUrl.searchParams.forEach(((value,key)=>{const sortItem=key.match(/sortdata\[([^\]]+)\]/);sortItem?sortData[sortItem.pop()]=value:viewData[key]=value})),viewData.sortdata=JSON.stringify(sortData),_fragment.default.loadFragment(fragmentData.component,fragmentData.callback,fragmentData.contextid,viewData).then(((html,js)=>(_templates.default.replaceNode(uiRoot,html,js),resolve(),html))).catch(reject)}))};return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=refresh_ui.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"refresh_ui.min.js","sources":["../src/refresh_ui.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Question bank UI refresh utility\n *\n * @module core_question/refresh_ui\n * @copyright 2023 Catalyst IT Europe Ltd.\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Fragment from 'core/fragment';\nimport Templates from 'core/templates';\n\nexport default {\n /**\n * Reload the question bank UI, retaining the current filters and sort data.\n *\n * @param {Element} uiRoot The root element of the UI to be refreshed. Must contain \"component\", \"callback\" and \"contextid\" in\n * its data attributes, to be passed to the Fragment API.\n * @param {URL} returnUrl The url of the current page, containing filter and sort parameters.\n * @return {Promise} Resolved when the refresh is complete.\n */\n refresh: (uiRoot, returnUrl) => {\n return new Promise((resolve, reject) => {\n const fragmentData = uiRoot.dataset;\n const viewData = {};\n const sortData = {};\n if (returnUrl) {\n returnUrl.searchParams.forEach((value, key) => {\n // Match keys like 'sortdata[fieldname]' and convert them to an array,\n // because the fragment API doesn't like non-alphanum argument keys.\n const sortItem = key.match(/sortdata\\[([^\\]]+)\\]/);\n if (sortItem) {\n // The item returned by sortItem.pop() is the contents of the matching group, the field name.\n sortData[sortItem.pop()] = value;\n } else {\n viewData[key] = value;\n }\n });\n }\n viewData.sortdata = JSON.stringify(sortData);\n // We have to use then() there, as loadFragment doesn't appear to work with await.\n Fragment.loadFragment(fragmentData.component, fragmentData.callback, fragmentData.contextid, viewData)\n .then((html, js) => {\n Templates.replaceNode(uiRoot, html, js);\n resolve();\n return html;\n })\n .catch(reject);\n });\n }\n};\n"],"names":["refresh","uiRoot","returnUrl","Promise","resolve","reject","fragmentData","dataset","viewData","sortData","searchParams","forEach","value","key","sortItem","match","pop","sortdata","JSON","stringify","loadFragment","component","callback","contextid","then","html","js","replaceNode","catch"],"mappings":";;;;;;;4LA0Be,CASXA,QAAS,CAACC,OAAQC,YACP,IAAIC,SAAQ,CAACC,QAASC,gBACnBC,aAAeL,OAAOM,QACtBC,SAAW,GACXC,SAAW,GACbP,WACAA,UAAUQ,aAAaC,SAAQ,CAACC,MAAOC,aAG7BC,SAAWD,IAAIE,MAAM,wBACvBD,SAEAL,SAASK,SAASE,OAASJ,MAE3BJ,SAASK,KAAOD,SAI5BJ,SAASS,SAAWC,KAAKC,UAAUV,4BAE1BW,aAAad,aAAae,UAAWf,aAAagB,SAAUhB,aAAaiB,UAAWf,UACxFgB,MAAK,CAACC,KAAMC,yBACCC,YAAY1B,OAAQwB,KAAMC,IACpCtB,UACOqB,QAEVG,MAAMvB"}
|
||||
+20
-31
@@ -70,7 +70,10 @@ export const init = (
|
||||
|
||||
const filterSet = document.querySelector(`#${filterRegionId}`);
|
||||
|
||||
const filterCondition = {
|
||||
const viewData = {
|
||||
extraparams,
|
||||
cmid,
|
||||
view,
|
||||
cat: defaultcategoryid,
|
||||
courseid: defaultcourseid,
|
||||
filter: {},
|
||||
@@ -78,16 +81,15 @@ export const init = (
|
||||
qpage: 0,
|
||||
qperpage: perpage,
|
||||
sortdata: {},
|
||||
tabname: 'questions',
|
||||
lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null,
|
||||
};
|
||||
|
||||
let sortData = {};
|
||||
const defaultSort = document.querySelector(SELECTORS.QUESTION_TABLE)?.dataset?.defaultsort;
|
||||
if (defaultSort) {
|
||||
filterCondition.sortData = JSON.parse(defaultSort);
|
||||
sortData = JSON.parse(defaultSort);
|
||||
}
|
||||
|
||||
let filterQuery = '';
|
||||
|
||||
/**
|
||||
* Retrieve table data.
|
||||
*
|
||||
@@ -99,26 +101,20 @@ export const init = (
|
||||
// use the default category filter condition.
|
||||
if (filterdata) {
|
||||
// Main join types.
|
||||
filterCondition.jointype = parseInt(filterSet.dataset.filterverb, 10);
|
||||
viewData.jointype = parseInt(filterSet.dataset.filterverb, 10);
|
||||
delete filterdata.jointype;
|
||||
// Retrieve filter info.
|
||||
filterCondition.filter = filterdata;
|
||||
viewData.filter = filterdata;
|
||||
if (Object.keys(filterdata).length !== 0) {
|
||||
if (!isNaN(filterCondition.jointype)) {
|
||||
filterdata.jointype = filterCondition.jointype;
|
||||
if (!isNaN(viewData.jointype)) {
|
||||
filterdata.jointype = viewData.jointype;
|
||||
}
|
||||
updateUrlParams(filterdata);
|
||||
}
|
||||
}
|
||||
// Load questions for first page.
|
||||
const viewData = {
|
||||
view: view,
|
||||
cmid: cmid,
|
||||
filtercondition: JSON.stringify(filterCondition),
|
||||
extraparams: extraparams,
|
||||
filterquery: filterQuery,
|
||||
lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null
|
||||
};
|
||||
viewData.filter = JSON.stringify(filterdata);
|
||||
viewData.sortdata = JSON.stringify(sortData);
|
||||
Fragment.loadFragment(component, callback, contextId, viewData)
|
||||
// Render questions for first page and pagination.
|
||||
.then((questionhtml, jsfooter) => {
|
||||
@@ -129,7 +125,7 @@ export const init = (
|
||||
if (jsfooter === undefined) {
|
||||
jsfooter = '';
|
||||
}
|
||||
Templates.replaceNodeContents(questionscontainer, questionhtml, jsfooter);
|
||||
Templates.replaceNode(questionscontainer, questionhtml, jsfooter);
|
||||
// Resolve filter promise.
|
||||
if (pendingPromise) {
|
||||
pendingPromise.resolve();
|
||||
@@ -154,13 +150,6 @@ export const init = (
|
||||
const filterQuery = JSON.stringify(filters);
|
||||
url.searchParams.set('filter', filterQuery);
|
||||
history.pushState(filters, '', url);
|
||||
document.querySelectorAll(SELECTORS.BULK_ACTIONS).forEach(bulkAction => {
|
||||
const actionUrl = new URL(bulkAction.formAction);
|
||||
const returnUrl = new URL(actionUrl.searchParams.get('returnurl'));
|
||||
returnUrl.searchParams.set('filter', filterQuery);
|
||||
actionUrl.searchParams.set('returnurl', returnUrl);
|
||||
bulkAction.formAction = actionUrl;
|
||||
});
|
||||
const editSwitch = document.querySelector(SELECTORS.EDIT_SWITCH);
|
||||
if (editSwitch) {
|
||||
const editSwitchUrlInput = document.querySelector(SELECTORS.EDIT_SWITCH_URL);
|
||||
@@ -197,15 +186,15 @@ export const init = (
|
||||
const clearLink = e.target.closest(Selectors.filterset.actions.resetFilters);
|
||||
if (sortableLink) {
|
||||
e.preventDefault();
|
||||
const oldSort = filterCondition.sortdata;
|
||||
filterCondition.sortdata = {};
|
||||
filterCondition.sortdata[sortableLink.dataset.sortname] = sortableLink.dataset.sortorder;
|
||||
const oldSort = sortData;
|
||||
sortData = {};
|
||||
sortData[sortableLink.dataset.sortname] = sortableLink.dataset.sortorder;
|
||||
for (const sortname in oldSort) {
|
||||
if (sortname !== sortableLink.dataset.sortname) {
|
||||
filterCondition.sortdata[sortname] = oldSort[sortname];
|
||||
sortData[sortname] = oldSort[sortname];
|
||||
}
|
||||
}
|
||||
filterCondition.qpage = 0;
|
||||
viewData.qpage = 0;
|
||||
coreFilter.updateTableFromFilter();
|
||||
}
|
||||
if (paginationLink) {
|
||||
@@ -213,7 +202,7 @@ export const init = (
|
||||
const paginationURL = new URL(paginationLink.getAttribute("href"));
|
||||
const qpage = paginationURL.searchParams.get('qpage');
|
||||
if (paginationURL.search !== null) {
|
||||
filterCondition.qpage = qpage;
|
||||
viewData.qpage = qpage;
|
||||
coreFilter.updateTableFromFilter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Question bank UI refresh utility
|
||||
*
|
||||
* @module core_question/refresh_ui
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Fragment from 'core/fragment';
|
||||
import Templates from 'core/templates';
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Reload the question bank UI, retaining the current filters and sort data.
|
||||
*
|
||||
* @param {Element} uiRoot The root element of the UI to be refreshed. Must contain "component", "callback" and "contextid" in
|
||||
* its data attributes, to be passed to the Fragment API.
|
||||
* @param {URL} returnUrl The url of the current page, containing filter and sort parameters.
|
||||
* @return {Promise} Resolved when the refresh is complete.
|
||||
*/
|
||||
refresh: (uiRoot, returnUrl) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fragmentData = uiRoot.dataset;
|
||||
const viewData = {};
|
||||
const sortData = {};
|
||||
if (returnUrl) {
|
||||
returnUrl.searchParams.forEach((value, key) => {
|
||||
// Match keys like 'sortdata[fieldname]' and convert them to an array,
|
||||
// because the fragment API doesn't like non-alphanum argument keys.
|
||||
const sortItem = key.match(/sortdata\[([^\]]+)\]/);
|
||||
if (sortItem) {
|
||||
// The item returned by sortItem.pop() is the contents of the matching group, the field name.
|
||||
sortData[sortItem.pop()] = value;
|
||||
} else {
|
||||
viewData[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
viewData.sortdata = JSON.stringify(sortData);
|
||||
// We have to use then() there, as loadFragment doesn't appear to work with await.
|
||||
Fragment.loadFragment(fragmentData.component, fragmentData.callback, fragmentData.contextid, viewData)
|
||||
.then((html, js) => {
|
||||
Templates.replaceNode(uiRoot, html, js);
|
||||
resolve();
|
||||
return html;
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Actions controller
|
||||
*
|
||||
* Perform a synchronous action to modify the question bank UI and redirect back to the previous page.
|
||||
* These features are mostly progressively enhanced by actions.js and web services, but this remains as a fallback.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../../config.php');
|
||||
|
||||
$action = required_param('action', PARAM_TEXT);
|
||||
$global = optional_param('global', false, PARAM_BOOL);
|
||||
$returnurl = optional_param('returnurl', '/question/bank/columnsortorder/sortcolumns.php', PARAM_LOCALURL);
|
||||
|
||||
require_login();
|
||||
|
||||
if ($global) {
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
}
|
||||
|
||||
if ($action === 'debugreset' && $CFG->debug === DEBUG_DEVELOPER) {
|
||||
$columnmanager = new \qbank_columnsortorder\column_manager($global);
|
||||
$columnmanager::set_hidden_columns([], $global);
|
||||
$columnmanager::set_column_order([], $global);
|
||||
$columnmanager::set_column_size('', $global);
|
||||
redirect(new moodle_url($returnurl));
|
||||
}
|
||||
|
||||
require_sesskey();
|
||||
$columnmanager = new \qbank_columnsortorder\column_manager($global);
|
||||
switch ($action) {
|
||||
case 'add':
|
||||
case 'remove':
|
||||
$column = required_param('column', PARAM_RAW);
|
||||
[$columnclass, ] = explode(\core_question\local\bank\column_base::ID_SEPARATOR, $column);
|
||||
if (!class_exists($columnclass)) {
|
||||
throw new invalid_parameter_exception("'{$columnclass}' is not a valid column class.");
|
||||
}
|
||||
$hiddencolumns = $columnmanager->hiddencolumns;
|
||||
if ($action === 'add') {
|
||||
$key = array_search($column, $hiddencolumns);
|
||||
if ($key !== false) {
|
||||
unset($hiddencolumns[$key]);
|
||||
}
|
||||
} else {
|
||||
if (!in_array($column, $hiddencolumns)) {
|
||||
$hiddencolumns[] = $column;
|
||||
}
|
||||
}
|
||||
$columnmanager::set_hidden_columns($hiddencolumns, $global);
|
||||
break;
|
||||
|
||||
case 'savewidths':
|
||||
$rawwidths = optional_param_array('width', [], PARAM_INT);
|
||||
$widths = [];
|
||||
foreach (array_filter($rawwidths) as $escapedclass => $width) {
|
||||
$class = str_replace('__', '\\', $escapedclass);
|
||||
// Validate that the class exists and the width is valid.
|
||||
// Since the browser uses Constraint Validation to prevent the form being submitted with an invalid width,
|
||||
// the only way we'll get one here is if someone is messing around, so don't worry about re-displaying the
|
||||
// form with an error message, just ignore the invalid value.
|
||||
if (class_exists($class) && $width >= 10) {
|
||||
$widths[] = (object)[
|
||||
'column' => $class,
|
||||
'width' => $width,
|
||||
];
|
||||
}
|
||||
}
|
||||
$columnmanager::set_column_size(json_encode($widths), $global);
|
||||
break;
|
||||
|
||||
case 'reset':
|
||||
$columnmanager::set_hidden_columns(null, $global);
|
||||
$columnmanager::set_column_order(null, $global);
|
||||
$columnmanager::set_column_size(null, $global);
|
||||
break;
|
||||
}
|
||||
redirect(new moodle_url($returnurl));
|
||||
@@ -0,0 +1,11 @@
|
||||
define("qbank_columnsortorder/actions",["exports","core/sortable_list","jquery","qbank_columnsortorder/repository","core/notification","core_question/refresh_ui"],(function(_exports,_sortable_list,_jquery,repository,_notification,_refresh_ui){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}}
|
||||
/**
|
||||
* Common javascript for handling actions on the admin page and the user's view of the question bank.
|
||||
*
|
||||
* @module qbank_columnsortorder/actions
|
||||
* @copyright 2023 onwards Catalyst IT Europe Ltd
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setupSortableLists=_exports.setupActionButtons=_exports.getColumnOrder=_exports.SELECTORS=void 0,_sortable_list=_interopRequireDefault(_sortable_list),_jquery=_interopRequireDefault(_jquery),repository=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}(repository),_notification=_interopRequireDefault(_notification),_refresh_ui=_interopRequireDefault(_refresh_ui);const SELECTORS={columnList:".qbank-column-list",sortableColumn:".qbank-sortable-column",removeLink:"[data-action=remove]",moveHandler:"[data-drag-type=move]",addColumn:".addcolumn",addLink:"[data-action=add]",actionLink:".action-link"};_exports.SELECTORS=SELECTORS;_exports.setupSortableLists=function(listRoot){let vertical=arguments.length>1&&void 0!==arguments[1]&&arguments[1],global=arguments.length>2&&void 0!==arguments[2]&&arguments[2];const sortableList=new _sortable_list.default(listRoot,{moveHandlerSelector:SELECTORS.moveHandler,isHorizontal:!vertical});sortableList.getElementName=element=>Promise.resolve(element.data("name"));const sortableColumns=(0,_jquery.default)(SELECTORS.sortableColumn);return sortableColumns.on(_sortable_list.default.EVENTS.DROP,(()=>{repository.setColumnbankOrder(getColumnOrder(listRoot),global).catch(_notification.default.exception),listRoot.querySelectorAll(SELECTORS.sortableColumn).forEach((item=>item.classList.remove("active")))})),sortableColumns.on(_sortable_list.default.EVENTS.DRAGSTART,(event=>{event.currentTarget.classList.add("active")})),sortableColumns};_exports.setupActionButtons=function(uiRoot){let global=arguments.length>1&&void 0!==arguments[1]&&arguments[1];uiRoot.addEventListener("click",(async e=>{const actionLink=e.target.closest(SELECTORS.actionLink);if(actionLink)try{e.preventDefault();const action=actionLink.dataset.action;if("add"===action||"remove"===action){const hiddenColumns=[],addColumnList=document.querySelector(SELECTORS.addColumn);addColumnList&&addColumnList.querySelectorAll(SELECTORS.addLink).forEach((item=>{"add"===action&&item===actionLink||hiddenColumns.push(item.dataset.column)})),"remove"===action&&hiddenColumns.push(actionLink.dataset.column),await repository.setHiddenColumns(hiddenColumns,global)}else"reset"===action&&await repository.resetColumns(global);const actionUrl=new URL(actionLink.href),returnUrl=new URL(actionUrl.searchParams.get("returnurl").replaceAll("&","&"));await _refresh_ui.default.refresh(uiRoot,returnUrl)}catch(ex){await _notification.default.exception(ex)}}))};const getColumnOrder=listRoot=>{const columns=Array.from(listRoot.querySelectorAll("[data-columnid]")).map((column=>column.dataset.columnid));return columns.filter(((value,index)=>columns.indexOf(value)===index))};_exports.getColumnOrder=getColumnOrder}));
|
||||
|
||||
//# sourceMappingURL=actions.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
define("qbank_columnsortorder/admin_actions",["exports","qbank_columnsortorder/actions","qbank_columnsortorder/repository","core/notification","core/pending"],(function(_exports,actions,repository,_notification,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}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 _interopRequireWildcard(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]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
|
||||
/**
|
||||
* Javascript for handling actions on the admin page
|
||||
*
|
||||
* @module qbank_columnsortorder/admin_actions
|
||||
* @copyright 2023 onwards Catalyst IT Europe Ltd
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,actions=_interopRequireWildcard(actions),repository=_interopRequireWildcard(repository),_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending);_exports.init=id=>{const uiRoot=document.getElementById(id),listRoot=uiRoot.querySelector(actions.SELECTORS.columnList);actions.setupSortableLists(listRoot,!0,!0),actions.setupActionButtons(uiRoot,!0),(listRoot=>{listRoot.addEventListener("change",(async()=>{const pendingPromise=new _pending.default("saveWidths"),columns=listRoot.querySelectorAll(actions.SELECTORS.sortableColumn),widths=[];columns.forEach((column=>{const widthInput=column.querySelector(".width-input"),valid=widthInput.checkValidity();widthInput.closest(".has-validation").classList.add("was-validated"),valid&&widths.push({column:column.dataset.columnid,width:widthInput.value})})),await repository.setColumnSize(JSON.stringify(widths),!0).catch(_notification.default.exception),pendingPromise.resolve()}))})(listRoot)}}));
|
||||
|
||||
//# sourceMappingURL=admin_actions.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin_actions.min.js","sources":["../src/admin_actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript for handling actions on the admin page\n *\n * @module qbank_columnsortorder/admin_actions\n * @copyright 2023 onwards Catalyst IT Europe Ltd\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as actions from 'qbank_columnsortorder/actions';\nimport * as repository from 'qbank_columnsortorder/repository';\nimport Notification from \"core/notification\";\nimport Pending from 'core/pending';\n\n/**\n * Event handler to save the custom column widths when a field is edited.\n *\n * @param {Element} listRoot The root element of the list of columns.\n */\nconst setupSaveWidths = listRoot => {\n listRoot.addEventListener('change', async() => {\n const pendingPromise = new Pending('saveWidths');\n const columns = listRoot.querySelectorAll(actions.SELECTORS.sortableColumn);\n const widths = [];\n columns.forEach(column => {\n const widthInput = column.querySelector('.width-input');\n const valid = widthInput.checkValidity();\n widthInput.closest('.has-validation').classList.add('was-validated');\n if (!valid) {\n return;\n }\n widths.push({\n column: column.dataset.columnid,\n width: widthInput.value,\n });\n });\n await repository.setColumnSize(JSON.stringify(widths), true).catch(Notification.exception);\n pendingPromise.resolve();\n });\n};\n\n/**\n * Initialize module\n *\n * Set up event handlers for the action buttons, width fields and initialise column sorting.\n *\n * @param {String} id ID for the admin UI root element.\n */\nexport const init = id => {\n const uiRoot = document.getElementById(id);\n const listRoot = uiRoot.querySelector(actions.SELECTORS.columnList);\n actions.setupSortableLists(listRoot, true, true);\n actions.setupActionButtons(uiRoot, true);\n setupSaveWidths(listRoot);\n};\n"],"names":["id","uiRoot","document","getElementById","listRoot","querySelector","actions","SELECTORS","columnList","setupSortableLists","setupActionButtons","addEventListener","async","pendingPromise","Pending","columns","querySelectorAll","sortableColumn","widths","forEach","column","widthInput","valid","checkValidity","closest","classList","add","push","dataset","columnid","width","value","repository","setColumnSize","JSON","stringify","catch","Notification","exception","resolve","setupSaveWidths"],"mappings":";;;;;;;;sRA+DoBA,WACVC,OAASC,SAASC,eAAeH,IACjCI,SAAWH,OAAOI,cAAcC,QAAQC,UAAUC,YACxDF,QAAQG,mBAAmBL,UAAU,GAAM,GAC3CE,QAAQI,mBAAmBT,QAAQ,GAjCfG,CAAAA,WACpBA,SAASO,iBAAiB,UAAUC,gBAC1BC,eAAiB,IAAIC,iBAAQ,cAC7BC,QAAUX,SAASY,iBAAiBV,QAAQC,UAAUU,gBACtDC,OAAS,GACfH,QAAQI,SAAQC,eACNC,WAAaD,OAAOf,cAAc,gBAClCiB,MAAQD,WAAWE,gBACzBF,WAAWG,QAAQ,mBAAmBC,UAAUC,IAAI,iBAC/CJ,OAGLJ,OAAOS,KAAK,CACRP,OAAQA,OAAOQ,QAAQC,SACvBC,MAAOT,WAAWU,iBAGpBC,WAAWC,cAAcC,KAAKC,UAAUjB,SAAS,GAAMkB,MAAMC,sBAAaC,WAChFzB,eAAe0B,cAgBnBC,CAAgBpC"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("qbank_columnsortorder/repository",["exports","core/ajax"],(function(_exports,_ajax){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setHiddenColumns=_exports.setColumnbankOrder=_exports.setColumnSize=_exports.resetColumns=void 0;_exports.setHiddenColumns=function(columns){let global=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_ajax.call)([{methodname:"qbank_columnsortorder_set_hidden_columns",args:{columns:columns,global:global}}])[0]};_exports.setColumnbankOrder=function(columns){let global=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_ajax.call)([{methodname:"qbank_columnsortorder_set_columnbank_order",args:{columns:columns,global:global}}])[0]};_exports.setColumnSize=function(sizes){let global=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_ajax.call)([{methodname:"qbank_columnsortorder_set_column_size",args:{sizes:sizes,global:global}}])[0]};_exports.resetColumns=function(){let global=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Promise.all((0,_ajax.call)([{methodname:"qbank_columnsortorder_set_column_size",args:{global:global}},{methodname:"qbank_columnsortorder_set_columnbank_order",args:{global:global}},{methodname:"qbank_columnsortorder_set_hidden_columns",args:{global:global}}]))}}));
|
||||
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"repository.min.js","sources":["../src/repository.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * External function calls for qbank_columnsortorder\n *\n * @module qbank_columnsortorder/repository\n * @copyright 2023 Catalyst IT Europe Ltd.\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Save the list of hidden columns\n *\n * @param {String[]} columns List of hidden column names\n * @param {Boolean} global Set global config setting, rather than user preference\n * @return {Promise}\n */\nexport const setHiddenColumns = (columns, global = false) => fetchMany([{\n methodname: 'qbank_columnsortorder_set_hidden_columns',\n args: {\n columns,\n global,\n },\n}])[0];\n\n/**\n * Save the order of columns\n *\n * @param {String[]} columns List of column names in the desired order\n * @param {Boolean} global Set global config setting, rather than user preference\n * @return {Promise}\n */\nexport const setColumnbankOrder = (columns, global = false) => fetchMany([{\n methodname: 'qbank_columnsortorder_set_columnbank_order',\n args: {\n columns,\n global,\n },\n}])[0];\n\n/**\n * Save the column widths\n *\n * @param {String} sizes JSON string encoding an array of objects with \"column\" and \"width\" properties.\n * @param {Boolean} global Set global config setting, rather than user preference\n * @return {Promise}\n */\nexport const setColumnSize = (sizes, global = false) => fetchMany([{\n methodname: 'qbank_columnsortorder_set_column_size',\n args: {\n sizes,\n global,\n },\n}])[0];\n\n/**\n * Reset all settings.\n *\n * @param {Boolean} global Reset global config settings, rather than user preference\n * @return {Promise}\n */\nexport const resetColumns = (global = false) => Promise.all(\n fetchMany([\n {\n methodname: 'qbank_columnsortorder_set_column_size',\n args: {\n global,\n },\n },\n {\n methodname: 'qbank_columnsortorder_set_columnbank_order',\n args: {\n global,\n },\n },\n {\n methodname: 'qbank_columnsortorder_set_hidden_columns',\n args: {\n global,\n },\n },\n ])\n);\n"],"names":["columns","global","methodname","args","sizes","Promise","all"],"mappings":"wRAiCgC,SAACA,aAASC,sEAAmB,cAAU,CAAC,CACpEC,WAAY,2CACZC,KAAM,CACFH,QAAAA,QACAC,OAAAA,WAEJ,gCAS8B,SAACD,aAASC,sEAAmB,cAAU,CAAC,CACtEC,WAAY,6CACZC,KAAM,CACFH,QAAAA,QACAC,OAAAA,WAEJ,2BASyB,SAACG,WAAOH,sEAAmB,cAAU,CAAC,CAC/DC,WAAY,wCACZC,KAAM,CACFC,MAAAA,MACAH,OAAAA,WAEJ,0BAQwB,eAACA,sEAAmBI,QAAQC,KACpD,cAAU,CACN,CACIJ,WAAY,wCACZC,KAAM,CACFF,OAAAA,SAGR,CACIC,WAAY,6CACZC,KAAM,CACFF,OAAAA,SAGR,CACIC,WAAY,2CACZC,KAAM,CACFF,OAAAA"}
|
||||
@@ -1,10 +0,0 @@
|
||||
define("qbank_columnsortorder/sort_columns",["exports","core/ajax","core/notification","core/sortable_list","jquery"],(function(_exports,_ajax,_notification,_sortable_list,_jquery){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Javascript for sorting columns in question bank view.
|
||||
*
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_sortable_list=_interopRequireDefault(_sortable_list),_jquery=_interopRequireDefault(_jquery);const setOrder=columns=>(0,_ajax.call)([{methodname:"qbank_columnsortorder_set_columnbank_order",args:{columns:columns}}])[0],getColumnOrder=listRoot=>{const columns=Array.from(listRoot.querySelectorAll("[data-pluginname]")).map((column=>column.dataset.pluginname));return columns.filter(((value,index)=>columns.indexOf(value)===index))};_exports.init=id=>{(listRoot=>{new _sortable_list.default(".list",{moveHandlerSelector:".item"}),(0,_jquery.default)(".item").on(_sortable_list.default.EVENTS.DROP,(()=>{const columns=getColumnOrder(listRoot);setOrder(columns).catch(_notification.exception),listRoot.querySelectorAll(".item").forEach((item=>item.classList.remove("active")))})),(0,_jquery.default)(".item").on(_sortable_list.default.EVENTS.DRAGSTART,(event=>{event.currentTarget.classList.add("active")}))})(document.querySelector("#".concat(id)))}}));
|
||||
|
||||
//# sourceMappingURL=sort_columns.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"sort_columns.min.js","sources":["../src/sort_columns.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript for sorting columns in question bank view.\n *\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Ghaly Marc-Alexandre <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\nimport {exception as displayException} from 'core/notification';\nimport SortableList from 'core/sortable_list';\nimport jQuery from 'jquery';\n\n/**\n * Sets up sortable list in the column sort order page.\n * @param {Element} listRoot\n */\nconst setupSortableLists = (listRoot) => {\n new SortableList('.list', {\n moveHandlerSelector: '.item',\n });\n\n jQuery('.item').on(SortableList.EVENTS.DROP, () => {\n const columns = getColumnOrder(listRoot);\n setOrder(columns).catch(displayException);\n listRoot.querySelectorAll('.item').forEach(item => item.classList.remove('active'));\n });\n\n jQuery('.item').on(SortableList.EVENTS.DRAGSTART, (event) => {\n event.currentTarget.classList.add('active');\n });\n};\n\n/**\n * Call external function set_order - inserts the updated column in the config_plugins table.\n *\n * @param {String} columns String that contains column order.\n * @returns {Promise}\n */\nconst setOrder = columns => fetchMany([{\n methodname: 'qbank_columnsortorder_set_columnbank_order',\n args: {columns},\n}])[0];\n\n/**\n * Gets the newly reordered columns to display in the question bank view.\n * @param {Element} listRoot\n * @returns {Array}\n */\nconst getColumnOrder = listRoot => {\n const columns = Array.from(listRoot.querySelectorAll('[data-pluginname]'))\n .map(column => column.dataset.pluginname);\n\n return columns.filter((value, index) => columns.indexOf(value) === index);\n};\n\n/**\n * Initialize module\n * @param {String} id unique id for columns.\n */\nexport const init = id => {\n const listRoot = document.querySelector(`#${id}`);\n setupSortableLists(listRoot);\n};\n"],"names":["setOrder","columns","methodname","args","getColumnOrder","listRoot","Array","from","querySelectorAll","map","column","dataset","pluginname","filter","value","index","indexOf","id","SortableList","moveHandlerSelector","on","EVENTS","DROP","catch","displayException","forEach","item","classList","remove","DRAGSTART","event","currentTarget","add","setupSortableLists","document","querySelector"],"mappings":";;;;;;;sLAsDMA,SAAWC,UAAW,cAAU,CAAC,CACnCC,WAAY,6CACZC,KAAM,CAACF,QAAAA,YACP,GAOEG,eAAiBC,iBACbJ,QAAUK,MAAMC,KAAKF,SAASG,iBAAiB,sBAChDC,KAAIC,QAAUA,OAAOC,QAAQC,oBAE3BX,QAAQY,QAAO,CAACC,MAAOC,QAAUd,QAAQe,QAAQF,SAAWC,uBAOnDE,KA3CQZ,CAAAA,eACpBa,uBAAa,QAAS,CACtBC,oBAAqB,8BAGlB,SAASC,GAAGF,uBAAaG,OAAOC,MAAM,WACnCrB,QAAUG,eAAeC,UAC/BL,SAASC,SAASsB,MAAMC,yBACxBnB,SAASG,iBAAiB,SAASiB,SAAQC,MAAQA,KAAKC,UAAUC,OAAO,mCAGtE,SAASR,GAAGF,uBAAaG,OAAOQ,WAAYC,QAC/CA,MAAMC,cAAcJ,UAAUK,IAAI,cAiCtCC,CADiBC,SAASC,yBAAkBlB"}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,125 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Common javascript for handling actions on the admin page and the user's view of the question bank.
|
||||
*
|
||||
* @module qbank_columnsortorder/actions
|
||||
* @copyright 2023 onwards Catalyst IT Europe Ltd
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import SortableList from 'core/sortable_list';
|
||||
import $ from 'jquery';
|
||||
import * as repository from 'qbank_columnsortorder/repository';
|
||||
import Notification from "core/notification";
|
||||
import RefreshUi from 'core_question/refresh_ui';
|
||||
|
||||
export const SELECTORS = {
|
||||
columnList: '.qbank-column-list',
|
||||
sortableColumn: '.qbank-sortable-column',
|
||||
removeLink: '[data-action=remove]',
|
||||
moveHandler: '[data-drag-type=move]',
|
||||
addColumn: '.addcolumn',
|
||||
addLink: '[data-action=add]',
|
||||
actionLink: '.action-link',
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up sortable list in the column sort order page.
|
||||
*
|
||||
* @param {Element} listRoot Element containing the sortable list.
|
||||
* @param {Boolean} vertical Is the list in vertical orientation, rather than horizonal?
|
||||
* @param {Boolean} global Should changes be saved to global config, rather than user preferences?
|
||||
* @return {jQuery} sortable column elements, for attaching additional event listeners.
|
||||
*/
|
||||
export const setupSortableLists = (listRoot, vertical = false, global = false) => {
|
||||
const sortableList = new SortableList(listRoot, {
|
||||
moveHandlerSelector: SELECTORS.moveHandler,
|
||||
isHorizontal: !vertical,
|
||||
});
|
||||
sortableList.getElementName = element => Promise.resolve(element.data('name'));
|
||||
|
||||
const sortableColumns = $(SELECTORS.sortableColumn);
|
||||
|
||||
sortableColumns.on(SortableList.EVENTS.DROP, () => {
|
||||
repository.setColumnbankOrder(getColumnOrder(listRoot), global).catch(Notification.exception);
|
||||
listRoot.querySelectorAll(SELECTORS.sortableColumn).forEach(item => item.classList.remove('active'));
|
||||
});
|
||||
|
||||
sortableColumns.on(SortableList.EVENTS.DRAGSTART, (event) => {
|
||||
event.currentTarget.classList.add('active');
|
||||
});
|
||||
|
||||
return sortableColumns;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up event handlers for action buttons.
|
||||
*
|
||||
* For each action, call the web service to update the appropriate setting or user preference, then call the fragment to
|
||||
* refresh the view.
|
||||
*
|
||||
* @param {Element} uiRoot The root of the question bank UI.
|
||||
* @param {Boolean} global Should changes be saved to global config, rather than user preferences?
|
||||
*/
|
||||
export const setupActionButtons = (uiRoot, global = false) => {
|
||||
uiRoot.addEventListener('click', async(e) => {
|
||||
const actionLink = e.target.closest(SELECTORS.actionLink);
|
||||
if (!actionLink) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
e.preventDefault();
|
||||
const action = actionLink.dataset.action;
|
||||
if (action === 'add' || action === 'remove') {
|
||||
const hiddenColumns = [];
|
||||
const addColumnList = document.querySelector(SELECTORS.addColumn);
|
||||
if (addColumnList) {
|
||||
addColumnList.querySelectorAll(SELECTORS.addLink).forEach(item => {
|
||||
if (action === 'add' && item === actionLink) {
|
||||
return;
|
||||
}
|
||||
hiddenColumns.push(item.dataset.column);
|
||||
});
|
||||
}
|
||||
if (action === 'remove') {
|
||||
hiddenColumns.push(actionLink.dataset.column);
|
||||
}
|
||||
await repository.setHiddenColumns(hiddenColumns, global);
|
||||
} else if (action === 'reset') {
|
||||
await repository.resetColumns(global);
|
||||
}
|
||||
const actionUrl = new URL(actionLink.href);
|
||||
const returnUrl = new URL(actionUrl.searchParams.get('returnurl').replaceAll('&', '&'));
|
||||
await RefreshUi.refresh(uiRoot, returnUrl);
|
||||
} catch (ex) {
|
||||
await Notification.exception(ex);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the newly reordered columns to display in the question bank view.
|
||||
* @param {Element} listRoot
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getColumnOrder = listRoot => {
|
||||
const columns = Array.from(listRoot.querySelectorAll('[data-columnid]'))
|
||||
.map(column => column.dataset.columnid);
|
||||
|
||||
return columns.filter((value, index) => columns.indexOf(value) === index);
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Javascript for handling actions on the admin page
|
||||
*
|
||||
* @module qbank_columnsortorder/admin_actions
|
||||
* @copyright 2023 onwards Catalyst IT Europe Ltd
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import * as actions from 'qbank_columnsortorder/actions';
|
||||
import * as repository from 'qbank_columnsortorder/repository';
|
||||
import Notification from "core/notification";
|
||||
import Pending from 'core/pending';
|
||||
|
||||
/**
|
||||
* Event handler to save the custom column widths when a field is edited.
|
||||
*
|
||||
* @param {Element} listRoot The root element of the list of columns.
|
||||
*/
|
||||
const setupSaveWidths = listRoot => {
|
||||
listRoot.addEventListener('change', async() => {
|
||||
const pendingPromise = new Pending('saveWidths');
|
||||
const columns = listRoot.querySelectorAll(actions.SELECTORS.sortableColumn);
|
||||
const widths = [];
|
||||
columns.forEach(column => {
|
||||
const widthInput = column.querySelector('.width-input');
|
||||
const valid = widthInput.checkValidity();
|
||||
widthInput.closest('.has-validation').classList.add('was-validated');
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
widths.push({
|
||||
column: column.dataset.columnid,
|
||||
width: widthInput.value,
|
||||
});
|
||||
});
|
||||
await repository.setColumnSize(JSON.stringify(widths), true).catch(Notification.exception);
|
||||
pendingPromise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize module
|
||||
*
|
||||
* Set up event handlers for the action buttons, width fields and initialise column sorting.
|
||||
*
|
||||
* @param {String} id ID for the admin UI root element.
|
||||
*/
|
||||
export const init = id => {
|
||||
const uiRoot = document.getElementById(id);
|
||||
const listRoot = uiRoot.querySelector(actions.SELECTORS.columnList);
|
||||
actions.setupSortableLists(listRoot, true, true);
|
||||
actions.setupActionButtons(uiRoot, true);
|
||||
setupSaveWidths(listRoot);
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* External function calls for qbank_columnsortorder
|
||||
*
|
||||
* @module qbank_columnsortorder/repository
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {call as fetchMany} from 'core/ajax';
|
||||
|
||||
/**
|
||||
* Save the list of hidden columns
|
||||
*
|
||||
* @param {String[]} columns List of hidden column names
|
||||
* @param {Boolean} global Set global config setting, rather than user preference
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const setHiddenColumns = (columns, global = false) => fetchMany([{
|
||||
methodname: 'qbank_columnsortorder_set_hidden_columns',
|
||||
args: {
|
||||
columns,
|
||||
global,
|
||||
},
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Save the order of columns
|
||||
*
|
||||
* @param {String[]} columns List of column names in the desired order
|
||||
* @param {Boolean} global Set global config setting, rather than user preference
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const setColumnbankOrder = (columns, global = false) => fetchMany([{
|
||||
methodname: 'qbank_columnsortorder_set_columnbank_order',
|
||||
args: {
|
||||
columns,
|
||||
global,
|
||||
},
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Save the column widths
|
||||
*
|
||||
* @param {String} sizes JSON string encoding an array of objects with "column" and "width" properties.
|
||||
* @param {Boolean} global Set global config setting, rather than user preference
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const setColumnSize = (sizes, global = false) => fetchMany([{
|
||||
methodname: 'qbank_columnsortorder_set_column_size',
|
||||
args: {
|
||||
sizes,
|
||||
global,
|
||||
},
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Reset all settings.
|
||||
*
|
||||
* @param {Boolean} global Reset global config settings, rather than user preference
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const resetColumns = (global = false) => Promise.all(
|
||||
fetchMany([
|
||||
{
|
||||
methodname: 'qbank_columnsortorder_set_column_size',
|
||||
args: {
|
||||
global,
|
||||
},
|
||||
},
|
||||
{
|
||||
methodname: 'qbank_columnsortorder_set_columnbank_order',
|
||||
args: {
|
||||
global,
|
||||
},
|
||||
},
|
||||
{
|
||||
methodname: 'qbank_columnsortorder_set_hidden_columns',
|
||||
args: {
|
||||
global,
|
||||
},
|
||||
},
|
||||
])
|
||||
);
|
||||
@@ -1,79 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Javascript for sorting columns in question bank view.
|
||||
*
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {call as fetchMany} from 'core/ajax';
|
||||
import {exception as displayException} from 'core/notification';
|
||||
import SortableList from 'core/sortable_list';
|
||||
import jQuery from 'jquery';
|
||||
|
||||
/**
|
||||
* Sets up sortable list in the column sort order page.
|
||||
* @param {Element} listRoot
|
||||
*/
|
||||
const setupSortableLists = (listRoot) => {
|
||||
new SortableList('.list', {
|
||||
moveHandlerSelector: '.item',
|
||||
});
|
||||
|
||||
jQuery('.item').on(SortableList.EVENTS.DROP, () => {
|
||||
const columns = getColumnOrder(listRoot);
|
||||
setOrder(columns).catch(displayException);
|
||||
listRoot.querySelectorAll('.item').forEach(item => item.classList.remove('active'));
|
||||
});
|
||||
|
||||
jQuery('.item').on(SortableList.EVENTS.DRAGSTART, (event) => {
|
||||
event.currentTarget.classList.add('active');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Call external function set_order - inserts the updated column in the config_plugins table.
|
||||
*
|
||||
* @param {String} columns String that contains column order.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const setOrder = columns => fetchMany([{
|
||||
methodname: 'qbank_columnsortorder_set_columnbank_order',
|
||||
args: {columns},
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Gets the newly reordered columns to display in the question bank view.
|
||||
* @param {Element} listRoot
|
||||
* @returns {Array}
|
||||
*/
|
||||
const getColumnOrder = listRoot => {
|
||||
const columns = Array.from(listRoot.querySelectorAll('[data-pluginname]'))
|
||||
.map(column => column.dataset.pluginname);
|
||||
|
||||
return columns.filter((value, index) => columns.indexOf(value) === index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize module
|
||||
* @param {String} id unique id for columns.
|
||||
*/
|
||||
export const init = id => {
|
||||
const listRoot = document.querySelector(`#${id}`);
|
||||
setupSortableLists(listRoot);
|
||||
};
|
||||
@@ -0,0 +1,366 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Javascript for customising the user's view of the question bank
|
||||
*
|
||||
* @module qbank_columnsortorder/user_actions
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import * as actions from 'qbank_columnsortorder/actions';
|
||||
import * as repository from 'qbank_columnsortorder/repository';
|
||||
import {get_string as getString} from 'core/str';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import ModalSaveCancel from 'core/modal_save_cancel';
|
||||
import Notification from "core/notification";
|
||||
import SortableList from 'core/sortable_list';
|
||||
import Templates from "core/templates";
|
||||
|
||||
|
||||
const SELECTORS = {
|
||||
uiRoot: '.questionbankwindow',
|
||||
moveAction: '.menu-action[data-action=move]',
|
||||
resizeAction: '.menu-action[data-action=resize]',
|
||||
resizeHandle: '.qbank_columnsortorder-action-handle.resize',
|
||||
handleContainer: '.handle-container',
|
||||
headerContainer: '.header-container',
|
||||
tableColumn: identifier => `td[data-columnid="${identifier.replace(/["\\]/g, '\\$&')}"]`,
|
||||
};
|
||||
|
||||
/** To track mouse event on a table header */
|
||||
let currentHeader;
|
||||
|
||||
/** Current mouse x postion, to track mouse event on a table header */
|
||||
let currentX;
|
||||
|
||||
/**
|
||||
* Flag to temporarily prevent move and resize handles from being shown or hidden.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
let suspendShowHideHandles = false;
|
||||
|
||||
/**
|
||||
* Add handle containers for move and resize handles.
|
||||
*
|
||||
* @param {Element} uiRoot The root element of the quesiton bank UI.
|
||||
* @return {Promise} Resolved after the containers have been added to each column header.
|
||||
*/
|
||||
const addHandleContainers = uiRoot => {
|
||||
return new Promise((resolve) => {
|
||||
const headerContainers = uiRoot.querySelectorAll(SELECTORS.headerContainer);
|
||||
Templates.renderForPromise('qbank_columnsortorder/handle_container', {})
|
||||
.then(({html, js}) => {
|
||||
headerContainers.forEach(container => {
|
||||
Templates.prependNodeContents(container, html, js);
|
||||
});
|
||||
resolve();
|
||||
return headerContainers;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Render move handles in each container.
|
||||
*
|
||||
* This takes a list of the move actions rendered in each column header, and creates a corresponding drag handle for each.
|
||||
*
|
||||
* @param {NodeList} moveActions Menu actions for moving columns.
|
||||
*/
|
||||
const setUpMoveHandles = moveActions => {
|
||||
moveActions.forEach(moveAction => {
|
||||
const header = moveAction.closest('th');
|
||||
header.classList.add('qbank-sortable-column');
|
||||
const handleContainer = header.querySelector(SELECTORS.handleContainer);
|
||||
const context = {
|
||||
action: "move",
|
||||
dragtype: "move",
|
||||
target: '',
|
||||
title: moveAction.title,
|
||||
pixicon: "i/dragdrop",
|
||||
pixcomponent: "core",
|
||||
popup: true
|
||||
};
|
||||
return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)
|
||||
.then(({html, js}) => {
|
||||
Templates.prependNodeContents(handleContainer, html, js);
|
||||
return handleContainer;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialise the current column sizes.
|
||||
*
|
||||
* This finds the current width set in each column header's style property, and returns them encoded as a JSON string.
|
||||
*
|
||||
* @param {Element} uiRoot The root element of the quesiton bank UI.
|
||||
* @return {String} JSON array containing a list of objects with column and width properties.
|
||||
*/
|
||||
const serialiseColumnSizes = (uiRoot) => {
|
||||
const columnSizes = [];
|
||||
const tableHeaders = uiRoot.querySelectorAll('th');
|
||||
tableHeaders.forEach(header => {
|
||||
// Only get the width set via style attribute (set by move action).
|
||||
const width = parseInt(header.style.width);
|
||||
if (!width || isNaN(width)) {
|
||||
return;
|
||||
}
|
||||
columnSizes.push({
|
||||
column: header.dataset.columnid,
|
||||
width: width
|
||||
});
|
||||
});
|
||||
return JSON.stringify(columnSizes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Render resize handles in each container.
|
||||
*
|
||||
* This takes a list of the resize actions rendered in each column header, and creates a corresponding drag handle for each.
|
||||
* It also initialises the event handlers for the drag handles and resize modal.
|
||||
*
|
||||
* @param {Element} uiRoot Question bank UI root element.
|
||||
*/
|
||||
const setUpResizeHandles = (uiRoot) => {
|
||||
const resizeActions = uiRoot.querySelectorAll(SELECTORS.resizeAction);
|
||||
resizeActions.forEach(resizeAction => {
|
||||
const headerContainer = resizeAction.closest(SELECTORS.headerContainer);
|
||||
const handleContainer = headerContainer.querySelector(SELECTORS.handleContainer);
|
||||
const context = {
|
||||
action: "resize",
|
||||
target: '',
|
||||
title: resizeAction.title,
|
||||
pixicon: 'i/twoway',
|
||||
pixcomponent: 'core',
|
||||
popup: true
|
||||
};
|
||||
return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)
|
||||
.then(({html, js}) => {
|
||||
Templates.appendNodeContents(handleContainer, html, js);
|
||||
return handleContainer;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
|
||||
let moveTracker = false;
|
||||
let currentResizeHandle = null;
|
||||
// Start mouse event on headers.
|
||||
uiRoot.addEventListener('mousedown', e => {
|
||||
currentResizeHandle = e.target.closest(SELECTORS.resizeHandle);
|
||||
// Return if it is not ' resize' button.
|
||||
if (!currentResizeHandle) {
|
||||
return;
|
||||
}
|
||||
// Save current position.
|
||||
currentX = e.pageX;
|
||||
// Find the header.
|
||||
currentHeader = e.target.closest(actions.SELECTORS.sortableColumn);
|
||||
moveTracker = false;
|
||||
suspendShowHideHandles = true;
|
||||
});
|
||||
|
||||
// Resize column as the mouse move.
|
||||
document.addEventListener('mousemove', e => {
|
||||
if (!currentHeader || !currentResizeHandle || currentX === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent text selection as the handle is dragged.
|
||||
document.getSelection().removeAllRanges();
|
||||
|
||||
// Adjust the column width according the amount the handle was dragged.
|
||||
const offset = e.pageX - currentX;
|
||||
currentX = e.pageX;
|
||||
const newWidth = currentHeader.offsetWidth + offset;
|
||||
currentHeader.style.width = newWidth + 'px';
|
||||
moveTracker = true;
|
||||
});
|
||||
|
||||
// Set new size when mouse is up.
|
||||
document.addEventListener('mouseup', () => {
|
||||
if (!currentHeader || !currentResizeHandle || currentX === 0) {
|
||||
return;
|
||||
}
|
||||
if (moveTracker) {
|
||||
// If the mouse moved, we are changing the size by drag, so save the change.
|
||||
repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);
|
||||
} else {
|
||||
// If the mouse didn't move, display a modal to change the size using a form.
|
||||
showResizeModal(currentHeader, uiRoot);
|
||||
}
|
||||
currentHeader = null;
|
||||
currentResizeHandle = null;
|
||||
currentX = 0;
|
||||
moveTracker = false;
|
||||
suspendShowHideHandles = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for resize actions in each column header.
|
||||
*
|
||||
* This will listen for a click on any resize action, and activate the corresponding resize modal.
|
||||
*
|
||||
* @param {Element} uiRoot Question bank UI root element.
|
||||
*/
|
||||
const setUpResizeActions = uiRoot => {
|
||||
uiRoot.addEventListener('click', (e) => {
|
||||
const resizeAction = e.target.closest(SELECTORS.resizeAction);
|
||||
if (resizeAction) {
|
||||
e.preventDefault();
|
||||
const currentHeader = resizeAction.closest('th');
|
||||
showResizeModal(currentHeader, uiRoot);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a modal containing a number input for changing a column width without click-and-drag.
|
||||
*
|
||||
* @param {Element} currentHeader The header element that is being resized.
|
||||
* @param {Element} uiRoot The question bank UI root element.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const showResizeModal = async(currentHeader, uiRoot) => {
|
||||
const initialWidth = currentHeader.offsetWidth;
|
||||
|
||||
const modal = await ModalSaveCancel.create({
|
||||
title: getString('resizecolumn', 'qbank_columnsortorder', currentHeader.textContent),
|
||||
body: Templates.render('qbank_columnsortorder/resize_modal', {}),
|
||||
show: true,
|
||||
});
|
||||
const root = modal.getRoot();
|
||||
root.on(ModalEvents.cancel, () => {
|
||||
currentHeader.style.width = `${initialWidth}px`;
|
||||
});
|
||||
root.on(ModalEvents.save, () => {
|
||||
repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);
|
||||
});
|
||||
|
||||
const body = await modal.bodyPromise;
|
||||
const input = body.get(0).querySelector('input');
|
||||
input.value = initialWidth;
|
||||
|
||||
input.addEventListener('change', e => {
|
||||
const newWidth = e.target.value;
|
||||
currentHeader.style.width = `${newWidth}px`;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for move actions in each column header.
|
||||
*
|
||||
* This will listen for a click on any move action, pass the click to the corresponding move handle, causing its modal to be shown.
|
||||
*
|
||||
* @param {Element} uiRoot Question bank UI root element.
|
||||
*/
|
||||
const setUpMoveActions = uiRoot => {
|
||||
uiRoot.addEventListener('click', e => {
|
||||
const moveAction = e.target.closest(SELECTORS.moveAction);
|
||||
if (moveAction) {
|
||||
e.preventDefault();
|
||||
const sortableColumn = moveAction.closest(actions.SELECTORS.sortableColumn);
|
||||
const moveHandle = sortableColumn.querySelector(actions.SELECTORS.moveHandler);
|
||||
moveHandle.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for showing and hiding handles when the mouse is over a column header.
|
||||
*
|
||||
* Implementing this behaviour using the :hover CSS pseudoclass is not sufficient, as the mouse may move over the neighbouring
|
||||
* header while dragging, leading to some odd behaviour. This allows us to suspend the show/hide behaviour while a handle is being
|
||||
* dragged, and so keep the active handle visible until the drag is finished.
|
||||
*
|
||||
* @param {Element} uiRoot Question bank UI root element.
|
||||
*/
|
||||
const setupShowHideHandles = uiRoot => {
|
||||
let shownHeader = null;
|
||||
let tableHead = uiRoot.querySelector('thead');
|
||||
uiRoot.addEventListener('mouseover', e => {
|
||||
if (suspendShowHideHandles) {
|
||||
return;
|
||||
}
|
||||
const header = e.target.closest(actions.SELECTORS.sortableColumn);
|
||||
if (!header && !shownHeader) {
|
||||
return;
|
||||
}
|
||||
if (!header || header !== shownHeader) {
|
||||
tableHead.querySelector('.show-handles')?.classList.remove('show-handles');
|
||||
shownHeader = header;
|
||||
if (header) {
|
||||
header.classList.add('show-handles');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for sortable list DROP event.
|
||||
*
|
||||
* Find all table cells corresponding to the column of the dropped header, and move them to the new position.
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
const reorderColumns = event => {
|
||||
// Current header.
|
||||
const header = event.target;
|
||||
// Find the previous sibling of the header, which will be used when moving columns.
|
||||
const insertAfter = header.previousElementSibling;
|
||||
// Move columns.
|
||||
const uiRoot = document.querySelector(SELECTORS.uiRoot);
|
||||
const columns = uiRoot.querySelectorAll(SELECTORS.tableColumn(header.dataset.columnid));
|
||||
columns.forEach(column => {
|
||||
const row = column.parentElement;
|
||||
if (insertAfter) {
|
||||
// Find the column to insert after.
|
||||
const insertAfterColumn = row.querySelector(SELECTORS.tableColumn(insertAfter.dataset.columnid));
|
||||
// Insert the column.
|
||||
insertAfterColumn.after(column);
|
||||
} else {
|
||||
// Insert as the first child (first column in the table).
|
||||
row.insertBefore(column, row.firstChild);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize module
|
||||
*
|
||||
* Add containers for the drag handles to each column header, then render handles, enable show/hide behaviour, set up drag/drop
|
||||
* column sorting, then enable the move and resize modals to be triggered from menu actions.
|
||||
*/
|
||||
export const init = async() => {
|
||||
const uiRoot = document.getElementById('questionscontainer');
|
||||
await addHandleContainers(uiRoot);
|
||||
setUpMoveHandles(uiRoot.querySelectorAll(SELECTORS.moveAction));
|
||||
setUpResizeHandles(uiRoot);
|
||||
setupShowHideHandles(uiRoot);
|
||||
const sortableColumns = actions.setupSortableLists(uiRoot.querySelector(actions.SELECTORS.columnList));
|
||||
sortableColumns.on(SortableList.EVENTS.DROP, reorderColumns);
|
||||
sortableColumns.on(SortableList.EVENTS.DRAGSTART, () => {
|
||||
suspendShowHideHandles = true;
|
||||
});
|
||||
sortableColumns.on(SortableList.EVENTS.DRAGEND, () => {
|
||||
suspendShowHideHandles = false;
|
||||
});
|
||||
setUpMoveActions(uiRoot);
|
||||
setUpResizeActions(uiRoot);
|
||||
actions.setupActionButtons(uiRoot);
|
||||
};
|
||||
@@ -21,8 +21,14 @@ defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
|
||||
use context_system;
|
||||
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 qbank_columnsortorder\local\bank\column_action_move;
|
||||
use qbank_columnsortorder\local\bank\column_action_remove;
|
||||
use qbank_columnsortorder\local\bank\column_action_resize;
|
||||
use qbank_columnsortorder\local\bank\preview_view;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
@@ -33,40 +39,130 @@ use moodle_url;
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_manager {
|
||||
class column_manager extends column_manager_base {
|
||||
/**
|
||||
* @var array|bool Column order as set in config_plugins 'class' => 'position', ie: question_type_column => 3.
|
||||
* @var array Column order as set in config_plugins 'class' => 'position', ie: question_type_column => 3.
|
||||
*/
|
||||
public $columnorder;
|
||||
|
||||
/**
|
||||
* @var array|bool Disabled columns in config_plugins table.
|
||||
* @var array hidden columns.
|
||||
*/
|
||||
public $hiddencolumns;
|
||||
|
||||
/**
|
||||
* @var array columns with size.
|
||||
*/
|
||||
public $colsize;
|
||||
|
||||
/**
|
||||
* @var array Disabled columns in config_plugins table.
|
||||
*/
|
||||
public $disabledcolumns;
|
||||
|
||||
/**
|
||||
* Constructor for column_manager class.
|
||||
*
|
||||
* @param bool $globalsettings Only use the global default settings, ignoring user preferences?
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->columnorder = get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$this->disabledcolumns = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
public function __construct(bool $globalsettings = false) {
|
||||
$this->columnorder = $this->setup_property('enabledcol', $globalsettings);
|
||||
if (empty($this->columnorder)) {
|
||||
$this->columnorder = [
|
||||
'core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column',
|
||||
'qbank_viewquestiontype\question_type_column' . column_base::ID_SEPARATOR . 'question_type_column',
|
||||
'qbank_viewquestionname\question_name_idnumber_tags_column' . column_base::ID_SEPARATOR .
|
||||
'question_name_idnumber_tags_column',
|
||||
'core_question\local\bank\edit_menu_column' . column_base::ID_SEPARATOR . 'edit_menu_column',
|
||||
'qbank_editquestion\question_status_column' . column_base::ID_SEPARATOR . 'question_status_column',
|
||||
'qbank_history\version_number_column' . column_base::ID_SEPARATOR . 'version_number_column',
|
||||
'qbank_viewcreator\creator_name_column' . column_base::ID_SEPARATOR . 'creator_name_column',
|
||||
'qbank_comment\comment_count_column' . column_base::ID_SEPARATOR . 'comment_count_column',
|
||||
];
|
||||
}
|
||||
$this->hiddencolumns = $this->setup_property('hiddencols', $globalsettings);
|
||||
$this->colsize = $this->setup_property('colsize', $globalsettings, 'json');
|
||||
$this->disabledcolumns = $this->setup_property('disabledcol', true); // No user preference for disabledcol.
|
||||
|
||||
if ($this->columnorder) {
|
||||
$this->columnorder = array_flip(explode(',', $this->columnorder));
|
||||
$this->columnorder = array_flip($this->columnorder);
|
||||
}
|
||||
if ($this->disabledcolumns) {
|
||||
$this->disabledcolumns = array_flip(explode(',', $this->disabledcolumns));
|
||||
$this->disabledcolumns = array_flip($this->disabledcolumns);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for the given property, based the saved user preference or config setting.
|
||||
*
|
||||
* If no value is currently stored, returns an empty array.
|
||||
*
|
||||
* @param string $setting The identifier used for the saved config and user preference settings.
|
||||
* @param bool $global Only get the global default, ignoring the user preference?
|
||||
* @param string $encoding The encoding used to store the property - csv or json
|
||||
* @return array
|
||||
*/
|
||||
private function setup_property(string $setting, bool $global = false, $encoding = 'csv'): array {
|
||||
$value = get_config('qbank_columnsortorder', $setting);
|
||||
if (!$global) {
|
||||
$value = get_user_preferences("qbank_columnsortorder_{$setting}", $value);
|
||||
}
|
||||
if (empty($value)) {
|
||||
return [];
|
||||
}
|
||||
return $encoding == 'csv' ? explode(',', $value) : json_decode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets column order in the qbank_columnsortorder plugin config.
|
||||
*
|
||||
* @param array $columns Column order to set.
|
||||
* @param ?array $columns Column order to set. Null value clears the setting.
|
||||
* @param bool $global save this as a global default, rather than a user preference?
|
||||
*/
|
||||
public static function set_column_order(array $columns) : void {
|
||||
$columns = implode(',', $columns);
|
||||
set_config('enabledcol', $columns, 'qbank_columnsortorder');
|
||||
public static function set_column_order(?array $columns, bool $global = false) : void {
|
||||
if (!is_null($columns)) {
|
||||
$columns = implode(',', $columns);
|
||||
}
|
||||
self::save_preference('enabledcol', $columns, $global);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden Columns.
|
||||
*
|
||||
* @param ?array $columns List of hidden columns. Null value clears the setting.
|
||||
* @param bool $global save this as a global default, rather than a user preference?
|
||||
*/
|
||||
public static function set_hidden_columns(?array $columns, bool $global = false) : void {
|
||||
if (!is_null($columns)) {
|
||||
$columns = implode(',', $columns);
|
||||
}
|
||||
self::save_preference('hiddencols', $columns, $global);
|
||||
}
|
||||
|
||||
/**
|
||||
* Column size.
|
||||
*
|
||||
* @param ?string $sizes columns with width. Null value clears the setting.
|
||||
* @param bool $global save this as a global default, rather than a user preference?
|
||||
*/
|
||||
public static function set_column_size(?string $sizes, bool $global = false) : void {
|
||||
self::save_preference('colsize', $sizes, $global);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Preferences.
|
||||
*
|
||||
* @param string $name name of a configuration
|
||||
* @param ?string $value value of a configuration. Null value clears the setting.
|
||||
* @param bool $global save this as a global default, rather than a user preference?
|
||||
*/
|
||||
private static function save_preference(string $name, ?string $value, bool $global = false): void {
|
||||
if ($global) {
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
set_config($name, $value, 'qbank_columnsortorder');
|
||||
} else {
|
||||
set_user_preference("qbank_columnsortorder_{$name}", $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,12 +170,20 @@ class column_manager {
|
||||
*
|
||||
* @return view
|
||||
*/
|
||||
protected function get_questionbank(): view {
|
||||
public function get_questionbank(): view {
|
||||
$course = (object) ['id' => 0];
|
||||
$context = context_system::instance();
|
||||
$contexts = new question_edit_contexts($context);
|
||||
$category = question_make_default_categories($contexts->all());
|
||||
$params = ['cat' => $category->id . ',' . $context->id];
|
||||
// Dummy call to get the objects without error.
|
||||
$questionbank = new view($contexts, new moodle_url('/question/dummyurl.php'), $course, null);
|
||||
$questionbank = new preview_view(
|
||||
$contexts,
|
||||
new moodle_url('/question/bank/columnsortorder/sortcolumns.php'),
|
||||
$course,
|
||||
null,
|
||||
$params
|
||||
);
|
||||
return $questionbank;
|
||||
}
|
||||
|
||||
@@ -94,11 +198,11 @@ class column_manager {
|
||||
if ($column->get_name() === 'checkbox') {
|
||||
continue;
|
||||
}
|
||||
$classelements = explode('\\', $key);
|
||||
$columns[] = (object) [
|
||||
'class' => get_class($column),
|
||||
'name' => $column->get_title(),
|
||||
'colname' => end($classelements),
|
||||
'colname' => $column->get_column_name(),
|
||||
'id' => $column->get_column_id(),
|
||||
];
|
||||
}
|
||||
return $columns;
|
||||
@@ -112,20 +216,12 @@ class column_manager {
|
||||
public function get_disabled_columns(): array {
|
||||
$disabled = [];
|
||||
if ($this->disabledcolumns) {
|
||||
foreach ($this->disabledcolumns as $class => $value) {
|
||||
if (strpos($class, 'qbank_customfields\custom_field_column') !== false) {
|
||||
$class = explode('\\', $class);
|
||||
$disabledname = array_pop($class);
|
||||
$class = implode('\\', $class);
|
||||
$disabled[] = (object) [
|
||||
'disabledname' => $disabledname,
|
||||
];
|
||||
} else {
|
||||
$columnobject = new $class($this->get_questionbank());
|
||||
$disabled[] = (object) [
|
||||
'disabledname' => $columnobject->get_title(),
|
||||
];
|
||||
}
|
||||
foreach (array_keys($this->disabledcolumns) as $column) {
|
||||
[$classname, $columnname] = explode(column_base::ID_SEPARATOR, $column, 2);
|
||||
$columnobject = $classname::from_column_name($this->get_questionbank(), $columnname);
|
||||
$disabled[$column] = (object) [
|
||||
'disabledname' => $columnobject->get_title(),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $disabled;
|
||||
@@ -192,17 +288,10 @@ class column_manager {
|
||||
}
|
||||
|
||||
foreach ($allcolumns as $column) {
|
||||
if (strpos($column->class, $plugin) !== false) {
|
||||
if ($column->class === 'qbank_customfields\custom_field_column') {
|
||||
$disabledcolumns[$column->class . '\\' . $column->colname] = $column->class . '\\' . $column->colname;
|
||||
if (isset($enabledcolumns[$column->class . '\\' . $column->colname])) {
|
||||
unset($enabledcolumns[$column->class. '\\' . $column->colname]);
|
||||
}
|
||||
} else {
|
||||
$disabledcolumns[$column->class] = $column->class;
|
||||
if (isset($enabledcolumns[$column->class])) {
|
||||
unset($enabledcolumns[$column->class]);
|
||||
}
|
||||
if (str_contains($column->class, $plugin)) {
|
||||
$disabledcolumns[$column->id] = $column->id;
|
||||
if (isset($enabledcolumns[$column->id])) {
|
||||
unset($enabledcolumns[$column->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,7 +301,7 @@ class column_manager {
|
||||
/**
|
||||
* Orders columns in the question bank view according to config_plugins table 'qbank_columnsortorder' config.
|
||||
*
|
||||
* @param array $ordertosort Unordered array of columns
|
||||
* @param array $ordertosort Unordered array of columns, [columnname => class]
|
||||
* @return array $properorder|$ordertosort Returns array ordered if 'qbank_columnsortorder' config exists.
|
||||
*/
|
||||
public function get_sorted_columns($ordertosort): array {
|
||||
@@ -222,32 +311,84 @@ class column_manager {
|
||||
$columnsortorder = $this->columnorder;
|
||||
asort($columnsortorder);
|
||||
$columnorder = [];
|
||||
foreach ($columnsortorder as $classname => $colposition) {
|
||||
$colname = explode('\\', $classname);
|
||||
if (strpos($classname, 'qbank_customfields\custom_field_column') !== false) {
|
||||
unset($colname[0]);
|
||||
$classname = implode('\\', $colname);
|
||||
// Checks if custom column still exists.
|
||||
if (array_key_exists($classname, $ordertosort)) {
|
||||
$columnorder[$classname] = $colposition;
|
||||
} else {
|
||||
$configtounset = str_replace('\\', '\\\\', $classname);
|
||||
// Cleans config db.
|
||||
unset_config($configtounset, 'column_sortorder');
|
||||
}
|
||||
} else {
|
||||
$columnorder[end($colname)] = $colposition;
|
||||
foreach ($columnsortorder as $columnid => $colposition) {
|
||||
if (array_key_exists($columnid, $ordertosort)) {
|
||||
$columnorder[$columnid] = $colposition;
|
||||
}
|
||||
}
|
||||
$properorder = array_merge($columnorder, $ordertosort);
|
||||
// Always have the checkbox at first column position.
|
||||
if (isset($properorder['checkbox_column'])) {
|
||||
$checkboxfirstelement = $properorder['checkbox_column'];
|
||||
unset($properorder['checkbox_column']);
|
||||
$properorder = array_merge(['checkbox_column' => $checkboxfirstelement], $properorder);
|
||||
$checkboxid = 'core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column';
|
||||
if (isset($properorder[$checkboxid])) {
|
||||
$checkboxfirstelement = $properorder[$checkboxid];
|
||||
unset($properorder[$checkboxid]);
|
||||
$properorder = array_merge([
|
||||
$checkboxid => $checkboxfirstelement
|
||||
], $properorder);
|
||||
}
|
||||
return $properorder;
|
||||
}
|
||||
return $ordertosort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of columns, set the isvisible attribute according to $this->hiddencolumns and $this->disabledcolumns.
|
||||
*
|
||||
* @param column_base[] $columns
|
||||
* @return array
|
||||
*/
|
||||
public function set_columns_visibility(array $columns): array {
|
||||
foreach ($columns as $column) {
|
||||
if (!is_object($column)) {
|
||||
continue;
|
||||
}
|
||||
$columnid = $column->get_column_id();
|
||||
|
||||
$column->isvisible = !in_array($columnid, $this->hiddencolumns) && !array_key_exists($columnid, $this->disabledcolumns);
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $this->colsize mapped as an array of column name => width, excluding empty sizes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_colsize_map(): array {
|
||||
$sizes = array_reduce($this->colsize, function($result, $colsize) {
|
||||
$result[$colsize->column] = $colsize->width;
|
||||
return $result;
|
||||
}, []);
|
||||
return array_filter($sizes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of hidden columns as an array of class => column name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_hidden_columns(): array {
|
||||
return array_reduce($this->hiddencolumns, function($result, $hiddencolumn) {
|
||||
[$columnclass, $columnname] = explode(column_base::ID_SEPARATOR, $hiddencolumn, 2);
|
||||
$result[$hiddencolumn] = $columnclass::from_column_name($this->get_questionbank(), $columnname)->get_title();
|
||||
return $result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
public function get_column_width(column_base $column): string {
|
||||
$colsizemap = $this->get_colsize_map();
|
||||
$columnid = $column->get_column_id();
|
||||
if (array_key_exists($columnid, $colsizemap)) {
|
||||
return $colsizemap[$columnid] . 'px';
|
||||
}
|
||||
return parent::get_column_width($column);
|
||||
}
|
||||
|
||||
public function get_column_actions(view $qbank): array {
|
||||
return [
|
||||
new column_action_move($qbank),
|
||||
new column_action_remove($qbank),
|
||||
new column_action_resize($qbank),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\external;
|
||||
|
||||
use context_system;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_value;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
/**
|
||||
* External function for saving column sizes.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_column_size extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'sizes' => new external_value(
|
||||
PARAM_TEXT,
|
||||
'Size for each column, as a JSON string representing [column => size]',
|
||||
VALUE_DEFAULT,
|
||||
null,
|
||||
),
|
||||
'global' => new external_value(
|
||||
PARAM_BOOL,
|
||||
'Set global config setting, rather than user preference',
|
||||
VALUE_DEFAULT,
|
||||
false
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value.
|
||||
*/
|
||||
public static function execute_returns(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sizes for columns
|
||||
* Save against user preference if component is specified
|
||||
*
|
||||
* @param ?string $sizes json string representing [column => size]. Null value clears the setting.
|
||||
* @param bool $global Set global config setting, rather than user preference
|
||||
*/
|
||||
public static function execute(?string $sizes, bool $global = false): void {
|
||||
[
|
||||
'sizes' => $sizes,
|
||||
'global' => $global,
|
||||
] = self::validate_parameters(
|
||||
self::execute_parameters(),
|
||||
[
|
||||
'sizes' => $sizes,
|
||||
'global' => $global,
|
||||
]
|
||||
);
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
if ($global) {
|
||||
require_capability('moodle/site:config', $context);
|
||||
}
|
||||
|
||||
column_manager::set_column_size($sizes, $global);
|
||||
}
|
||||
}
|
||||
@@ -41,8 +41,14 @@ class set_columnbank_order extends external_api {
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'columns' => new external_multiple_structure(
|
||||
new external_value(PARAM_TEXT, 'Plugin name for the column', VALUE_REQUIRED)
|
||||
)
|
||||
new external_value(PARAM_TEXT, 'Plugin name for the column', VALUE_REQUIRED),
|
||||
'List of column in the desired order',
|
||||
VALUE_DEFAULT,
|
||||
null,
|
||||
NULL_ALLOWED,
|
||||
),
|
||||
'global' => new external_value(PARAM_BOOL, 'Set global config setting, rather than user preference',
|
||||
VALUE_DEFAULT, false),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -54,16 +60,26 @@ class set_columnbank_order extends external_api {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the columns plugin order.
|
||||
* Set columns order.
|
||||
*
|
||||
* @param array $columns json string representing new column order.
|
||||
* @param ?array $columns List of column names in the desired order. Null value clears the setting.
|
||||
* @param bool $global Set global config setting, rather than user preference
|
||||
*/
|
||||
public static function execute(array $columns): void {
|
||||
['columns' => $columns] = self::validate_parameters(self::execute_parameters(), ['columns' => $columns]);
|
||||
public static function execute(?array $columns, bool $global = false): void {
|
||||
[
|
||||
'columns' => $columns,
|
||||
'global' => $global,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'columns' => $columns,
|
||||
'global' => $global,
|
||||
]);
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/category:manage', $context);
|
||||
if ($global) {
|
||||
require_capability('moodle/site:config', $context);
|
||||
}
|
||||
|
||||
column_manager::set_column_order($columns);
|
||||
column_manager::set_column_order($columns, $global);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\external;
|
||||
|
||||
use context_system;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_multiple_structure;
|
||||
use core_external\external_value;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
/**
|
||||
* External function for saving the list of hidden columns.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_hidden_columns extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'columns' => new external_multiple_structure(
|
||||
new external_value(PARAM_TEXT, 'Plugin name for the hidden column', VALUE_REQUIRED),
|
||||
'List of hidden columns',
|
||||
VALUE_DEFAULT,
|
||||
null,
|
||||
NULL_ALLOWED,
|
||||
),
|
||||
'global' => new external_value(
|
||||
PARAM_BOOL,
|
||||
'Set global config setting, rather than user preference',
|
||||
VALUE_DEFAULT,
|
||||
false
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value.
|
||||
*
|
||||
*/
|
||||
public static function execute_returns(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hidden columns
|
||||
* Save against user preference if specified
|
||||
*
|
||||
* @param ?array $columns List of hidden columns. Null value clears the setting.
|
||||
* @param bool $global Set global config setting, rather than user preference
|
||||
*/
|
||||
public static function execute(?array $columns, bool $global = false): void {
|
||||
[
|
||||
'columns' => $columns,
|
||||
'global' => $global,
|
||||
] = self::validate_parameters(
|
||||
self::execute_parameters(),
|
||||
[
|
||||
'columns' => $columns,
|
||||
'global' => $global,
|
||||
]
|
||||
);
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
if ($global) {
|
||||
require_capability('moodle/site:config', $context);
|
||||
}
|
||||
|
||||
column_manager::set_hidden_columns($columns, $global);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\local\bank;
|
||||
|
||||
use core_question\local\bank\column_action_base;
|
||||
use core_question\local\bank\column_base;
|
||||
|
||||
/**
|
||||
* Move a column
|
||||
*
|
||||
* This will add an action menu item which will be enhanced by javascript in user_actions.js to show the move column modal for the
|
||||
* current column when clicked.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_action_move extends column_action_base {
|
||||
/** @var string Label for the Move action. */
|
||||
protected string $move;
|
||||
|
||||
protected function init(): void {
|
||||
$this->move = get_string('move');
|
||||
}
|
||||
|
||||
public function get_action_menu_link(column_base $column): ?\action_menu_link {
|
||||
return new \action_menu_link_secondary(
|
||||
new \moodle_url('/question/edit.php'),
|
||||
null,
|
||||
$this->move,
|
||||
[
|
||||
'title' => get_string('movecolumn', 'qbank_columnsortorder', $column->get_title()),
|
||||
'data-action' => 'move',
|
||||
'data-column' => get_class($column),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\local\bank;
|
||||
|
||||
use core_question\local\bank\column_action_base;
|
||||
use core_question\local\bank\column_base;
|
||||
|
||||
/**
|
||||
* Remove a column
|
||||
*
|
||||
* This action will display a link that will set the current column as hidden, then redirect back the current page.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_action_remove extends column_action_base {
|
||||
/** @var bool True if we are changing global config, false for user preferences. */
|
||||
protected bool $global;
|
||||
|
||||
/** @var string Label for the Remove action. */
|
||||
protected string $remove;
|
||||
|
||||
protected function init(): void {
|
||||
$this->global = false;
|
||||
$this->remove = get_string('remove');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the $global property to indicate whether we are changing global config.
|
||||
*
|
||||
* This action is used on both the user and admin screens, so requires this additional method.
|
||||
*
|
||||
* @param bool $global
|
||||
* @return void
|
||||
*/
|
||||
public function set_global(bool $global): void {
|
||||
$this->global = $global;
|
||||
}
|
||||
|
||||
public function get_action_menu_link(column_base $column): ?\action_menu_link {
|
||||
$actionurl = new \moodle_url('/question/bank/columnsortorder/actions.php', [
|
||||
'column' => $column->get_column_id(),
|
||||
'action' => 'remove',
|
||||
'sesskey' => sesskey(),
|
||||
'returnurl' => new \moodle_url($this->qbank->returnurl),
|
||||
]);
|
||||
if ($this->global) {
|
||||
$actionurl->param('global', $this->global);
|
||||
}
|
||||
return new \action_menu_link_secondary(
|
||||
$actionurl,
|
||||
null,
|
||||
$this->remove,
|
||||
[
|
||||
'class' => 'action-link',
|
||||
'title' => get_string('removecolumn', 'qbank_columnsortorder', $column->get_title()),
|
||||
'data-action' => 'remove',
|
||||
'data-column' => $column->get_column_id(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\local\bank;
|
||||
|
||||
use core_question\local\bank\column_action_base;
|
||||
use core_question\local\bank\column_base;
|
||||
|
||||
/**
|
||||
* Resize a column
|
||||
*
|
||||
* This will add an action menu item which will be enhanced by javascript in user_actions.js to show the resize column modal for the
|
||||
* current column when clicked.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_action_resize extends column_action_base {
|
||||
/** @var string Label for the resize action. */
|
||||
protected string $resize;
|
||||
|
||||
protected function init(): void {
|
||||
$this->resize = get_string('resize', 'qbank_columnsortorder');
|
||||
}
|
||||
|
||||
public function get_action_menu_link(column_base $column): ?\action_menu_link {
|
||||
return new \action_menu_link_secondary(
|
||||
new \moodle_url('/question/edit.php'),
|
||||
null,
|
||||
$this->resize,
|
||||
[
|
||||
'title' => get_string('resizecolumn', 'qbank_columnsortorder', $column->get_title()),
|
||||
'data-action' => 'resize',
|
||||
'data-column' => get_class($column),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\local\bank;
|
||||
|
||||
use core_question\local\bank\view;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
/**
|
||||
* Custom view for displaying a preview of the question bank
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class preview_view extends view {
|
||||
/**
|
||||
* Use global settings for the column manager.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init_column_manager(): void {
|
||||
$this->columnmanager = new column_manager(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the table row with the preview data for each column.
|
||||
*
|
||||
* @param \stdClass $question
|
||||
* @param int $rowcount
|
||||
*/
|
||||
public function print_table_row($question, $rowcount): void {
|
||||
$rowclasses = implode(' ', $this->get_row_classes($question, $rowcount));
|
||||
$attributes = [];
|
||||
if ($rowclasses) {
|
||||
$attributes['class'] = $rowclasses;
|
||||
}
|
||||
echo \html_writer::start_tag('tr', $attributes);
|
||||
foreach ($this->visiblecolumns as $column) {
|
||||
$column->display_preview($question, $rowclasses);
|
||||
}
|
||||
echo \html_writer::end_tag('tr');
|
||||
foreach ($this->extrarows as $row) {
|
||||
$row->display_preview($question, $rowclasses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dummy question containing valid data for the default question fields.
|
||||
*
|
||||
* @return \stdClass
|
||||
*/
|
||||
protected function get_dummy_question(): \stdClass {
|
||||
return (object)[
|
||||
'id' => 1,
|
||||
'qtype' => 'truefalse',
|
||||
'createdby' => 2,
|
||||
'categoryid' => 1,
|
||||
'contextid' => 1,
|
||||
'status' => 'ready',
|
||||
'version' => 1,
|
||||
'versionid' => 1,
|
||||
'questionbankentryid' => 1,
|
||||
'name' => 'Lorem ipsum',
|
||||
'idnumber' => 123,
|
||||
'creatorfirstname' => 'Admin',
|
||||
'creatorlastname' => 'User',
|
||||
'timecreated' => 1691157311,
|
||||
'modifierfirstname' => 'Admin',
|
||||
'modifierlastname' => 'User',
|
||||
'timemodified' => 1691157311,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a preview of the question bank table with a single dummy question.
|
||||
*
|
||||
* @return string An HTML table containing the column headings and a single question row.
|
||||
*/
|
||||
public function get_preview(): string {
|
||||
ob_start();
|
||||
$this->display_questions([$this->get_dummy_question()]);
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
use core_reportbuilder\local\models\column;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
use moodle_url;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Renderable for the "add column" dropdown list
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class add_column implements \renderable, \templatable {
|
||||
/** @var column_manager The column manager for getting the list of hidden columns. */
|
||||
protected column_manager $columnmanager;
|
||||
|
||||
/** @var moodle_url The current page URL to redirect back to. */
|
||||
protected moodle_url $returnurl;
|
||||
|
||||
/** @var bool True if we are changing global config, false for user preferences. */
|
||||
protected bool $global;
|
||||
|
||||
/**
|
||||
* Store arguments for generating template context.
|
||||
*
|
||||
* @param column_manager $columnmanager
|
||||
* @param moodle_url $returnurl
|
||||
* @param bool $global
|
||||
*/
|
||||
public function __construct(column_manager $columnmanager, moodle_url $returnurl, bool $global = false) {
|
||||
$this->columnmanager = $columnmanager;
|
||||
$this->returnurl = $returnurl;
|
||||
$this->global = $global;
|
||||
}
|
||||
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
$hiddencolumns = [];
|
||||
foreach ($this->columnmanager->get_hidden_columns() as $class => $name) {
|
||||
$addurl = new moodle_url('/question/bank/columnsortorder/actions.php', [
|
||||
'action' => 'add',
|
||||
'global' => $this->global,
|
||||
'column' => $class,
|
||||
'sesskey' => sesskey(),
|
||||
'returnurl' => $this->returnurl,
|
||||
]);
|
||||
$hiddencolumns[] = [
|
||||
'name' => $name,
|
||||
'addurl' => $addurl->out(false),
|
||||
'column' => $class,
|
||||
'addtext' => get_string('addcolumn', 'qbank_columnsortorder', $name),
|
||||
];
|
||||
}
|
||||
return [
|
||||
'hashiddencolumns' => !empty($hiddencolumns),
|
||||
'hiddencolumns' => $hiddencolumns,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
use moodle_url;
|
||||
use templatable;
|
||||
use renderable;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
/**
|
||||
* Renderable for the question bank preview.
|
||||
*
|
||||
* This takes the HTML for a question bank preview, and displays in a page with a link to return to the admin screen.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_sort_preview implements renderable, templatable {
|
||||
/** @var string Rendered preview HTML. */
|
||||
protected string $preview;
|
||||
|
||||
/**
|
||||
* Store rendered preview for template context.
|
||||
*
|
||||
* @param string $preview
|
||||
*/
|
||||
public function __construct(string $preview) {
|
||||
$this->preview = $preview;
|
||||
}
|
||||
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
$context = [
|
||||
'backurl' => new moodle_url('/question/bank/columnsortorder/sortcolumns.php'),
|
||||
'preview' => $this->preview,
|
||||
];
|
||||
return $context;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
use core_question\local\bank\column_base;
|
||||
use qbank_columnsortorder\local\bank\column_action_remove;
|
||||
use moodle_url;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
use renderable;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Renderable for the column sort admin UI.
|
||||
*
|
||||
* Displays a list of the currently enabled columns and allows them to be sorted, hidden, and resized.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class column_sort_ui implements renderable, templatable {
|
||||
/**
|
||||
* @var int The minimum custom width for a column.
|
||||
*/
|
||||
const MIN_COLUMN_WIDTH = 10;
|
||||
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
$columnmanager = new column_manager(true);
|
||||
$enabledcolumns = $columnmanager->get_columns();
|
||||
$disabledcolumns = $columnmanager->get_disabled_columns();
|
||||
$columnsizes = $columnmanager->get_colsize_map();
|
||||
$qbank = $columnmanager->get_questionbank();
|
||||
$returnurl = new moodle_url('/question/bank/columnsortorder/sortcolumns.php');
|
||||
$params = [];
|
||||
$params['formaction'] = new moodle_url('/question/bank/columnsortorder/actions.php');
|
||||
$params['sesskey'] = sesskey();
|
||||
$params['disabled'] = $disabledcolumns;
|
||||
$params['contextid'] = \context_system::instance()->id;
|
||||
$params['minwidth'] = self::MIN_COLUMN_WIDTH;
|
||||
foreach ($enabledcolumns as $column) {
|
||||
if (in_array($column->id, $columnmanager->hiddencolumns) || array_key_exists($column->id, $disabledcolumns)) {
|
||||
continue;
|
||||
}
|
||||
$name = $column->name;
|
||||
$colname = get_string('qbankcolumnname', 'qbank_columnsortorder', $column->colname);
|
||||
|
||||
$removeaction = new column_action_remove($qbank);
|
||||
$removeaction->set_global(true);
|
||||
$actionmenu = new \action_menu([
|
||||
$removeaction->get_action_menu_link($column->class::from_column_name($qbank, $column->colname)),
|
||||
]);
|
||||
$params['names'][] = [
|
||||
'name' => $name,
|
||||
'colname' => $colname,
|
||||
'class' => $column->class,
|
||||
'width' => $columnsizes[$column->id] ?? null,
|
||||
'widthlabel' => get_string('width', 'qbank_columnsortorder', $name),
|
||||
'actionmenu' => $actionmenu->export_for_template($output),
|
||||
'columnid' => $column->id,
|
||||
'escapedid' => str_replace('\\', '__', $column->id),
|
||||
];
|
||||
}
|
||||
|
||||
$params['disabled'] = array_values($disabledcolumns);
|
||||
$params['columnsdisabled'] = !empty($params['disabled']);
|
||||
$addcolumn = new add_column($columnmanager, $returnurl);
|
||||
$params['addcolumn'] = $addcolumn->export_for_template($output);
|
||||
$resetcolums = new reset_columns($returnurl);
|
||||
$params['resetcolumns'] = $resetcolums->export_for_template($output);
|
||||
$params['extraclasses'] = 'pr-1';
|
||||
$urltoredirect = new moodle_url('/admin/settings.php', ['section' => 'manageqbanks']);
|
||||
|
||||
$params['urltomanageqbanks'] = get_string('qbankgotomanageqbanks', 'qbank_columnsortorder', $urltoredirect->out());
|
||||
$params['previewurl'] = new moodle_url('/question/bank/columnsortorder/sortcolumns.php', [
|
||||
'preview' => true,
|
||||
]);
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
/**
|
||||
* Output fragments for the column sort order interface
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class fragment {
|
||||
/**
|
||||
* Render the column sort UI with the current global config.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function column_sort_ui(): string {
|
||||
global $OUTPUT;
|
||||
return $OUTPUT->render(new \qbank_columnsortorder\output\column_sort_ui());
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
use moodle_url;
|
||||
use plugin_renderer_base;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
/**
|
||||
* Class renderer.
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Render list of question bank plugin columns.
|
||||
*
|
||||
* @return string The rendered HTML.
|
||||
*/
|
||||
public function render_column_sort_ui() {
|
||||
$columnsortorder = new column_manager();
|
||||
$enabledcolumns = $columnsortorder->get_columns();
|
||||
$disabledcolumns = $columnsortorder->get_disabled_columns();
|
||||
$params = [];
|
||||
foreach ($enabledcolumns as $columnname) {
|
||||
$name = $columnname->name;
|
||||
$colname = get_string('qbankcolumnname', 'qbank_columnsortorder', $columnname->colname);
|
||||
if ($columnname->class === 'qbank_customfields\custom_field_column') {
|
||||
$columnname->class .= "\\$columnname->colname";
|
||||
}
|
||||
$params['names'][] = ['name' => $name, 'colname' => $colname, 'class' => $columnname->class];
|
||||
}
|
||||
$params['disabled'] = $disabledcolumns;
|
||||
$params['columnsdisabled'] = (!empty($params['disabled'])) ? true : false;
|
||||
$urltoredirect = new moodle_url('/admin/settings.php', ['section' => 'manageqbanks']);
|
||||
|
||||
$params['urltomanageqbanks'] = get_string('qbankgotomanageqbanks', 'qbank_columnsortorder', $urltoredirect->out());
|
||||
|
||||
return $this->render_from_template('qbank_columnsortorder/columnsortorder', $params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\output;
|
||||
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Renderable for resetting customised column settings.
|
||||
*
|
||||
* This will display a link that resets all customised column settings and redirects back to the current page.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class reset_columns implements \renderable, \templatable {
|
||||
/** @var \moodle_url The current page URL to redirect back to. */
|
||||
protected \moodle_url $returnurl;
|
||||
|
||||
/** @var bool True if we are changing global config, false for user preferences. */
|
||||
protected bool $global;
|
||||
|
||||
/**
|
||||
* Store data for generating the template context.
|
||||
*
|
||||
* @param \moodle_url $returnurl
|
||||
* @param bool $global
|
||||
*/
|
||||
public function __construct(\moodle_url $returnurl, bool $global = false) {
|
||||
$this->returnurl = $returnurl;
|
||||
$this->global = $global;
|
||||
}
|
||||
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
$reseturl = new \moodle_url('/question/bank/columnsortorder/actions.php', [
|
||||
'action' => 'reset',
|
||||
'global' => $this->global,
|
||||
'sesskey' => sesskey(),
|
||||
'returnurl' => $this->returnurl->out(),
|
||||
]);
|
||||
return [
|
||||
'reseturl' => $reseturl->out(false),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder;
|
||||
|
||||
use core\context;
|
||||
use core_question\local\bank\column_manager_base;
|
||||
use core_question\local\bank\plugin_features_base;
|
||||
use core_question\local\bank\view;
|
||||
use qbank_columnsortorder\output\add_column;
|
||||
use qbank_columnsortorder\output\reset_columns;
|
||||
|
||||
/**
|
||||
* Plugin features for qbank_columnsortorder
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class plugin_feature extends plugin_features_base {
|
||||
/**
|
||||
* Override the default column manager.
|
||||
*
|
||||
* This will set the column order, size and visibility based on the global settings defined on the admin screen, or on the
|
||||
* current user's preference if they have set one.
|
||||
*
|
||||
* @return ?column_manager_base
|
||||
*/
|
||||
public function get_column_manager(): ?column_manager_base {
|
||||
return new column_manager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return add and reset column controls.
|
||||
*
|
||||
* @param view $qbank The question bank view.
|
||||
* @param context $context The current context, for permission checks.
|
||||
* @param int $categoryid The current question category ID.
|
||||
* @return \renderable[]
|
||||
*/
|
||||
public function get_question_bank_controls(view $qbank, context $context, int $categoryid): array {
|
||||
global $PAGE;
|
||||
$PAGE->requires->js_call_amd('qbank_columnsortorder/user_actions', 'init');
|
||||
$returnurl = new \moodle_url($qbank->returnurl);
|
||||
return [
|
||||
200 => new add_column(new column_manager(), $returnurl),
|
||||
300 => new reset_columns($returnurl),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
namespace qbank_columnsortorder\privacy;
|
||||
|
||||
use \core_privacy\local\metadata\null_provider;
|
||||
use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\writer;
|
||||
|
||||
/**
|
||||
* Privacy provider for columnsortorder.
|
||||
@@ -26,14 +27,32 @@ use \core_privacy\local\metadata\null_provider;
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements null_provider {
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason() : string {
|
||||
return 'privacy:metadata';
|
||||
class provider implements
|
||||
// The forms subsystem does not store any data itself, it has no database tables.
|
||||
\core_privacy\local\metadata\provider,
|
||||
|
||||
// The forms subsystem has user preferences.
|
||||
\core_privacy\local\request\user_preference_provider {
|
||||
|
||||
public static function get_metadata(collection $collection): collection {
|
||||
$collection->add_user_preference('enabledcol', 'privacy:metadata:preference:enabledcol');
|
||||
$collection->add_user_preference('hiddencols', 'privacy:metadata:preference:hiddencols');
|
||||
$collection->add_user_preference('colsize', 'privacy:metadata:preference:colsize');
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public static function export_user_preferences(int $userid) {
|
||||
$components = ['core_question', "qbank_history"];
|
||||
foreach ($components as $component) {
|
||||
$prefnames = ['enabledcol', 'hiddencols', 'colsize'];
|
||||
foreach ($prefnames as $name) {
|
||||
$preference = get_user_preferences("{$component}_{$name}", null, $userid);
|
||||
if ($preference !== null) {
|
||||
$desc = get_string('enabledcol', 'privacy:metadata:preference:enabledcol');
|
||||
writer::export_user_preference('qbank_columnsortorder', "{$component}_{$name}", $preference, $desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Class defining resuable tests methods for external functions
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace qbank_columnsortorder\tests;
|
||||
|
||||
/**
|
||||
* Class defining resuable tests methods for external functions
|
||||
*/
|
||||
abstract class external_function_testcase extends \advanced_testcase {
|
||||
/**
|
||||
* @var string Fully-qualified external function class to test.
|
||||
*/
|
||||
protected $testclass;
|
||||
|
||||
/**
|
||||
* @var string The name of the setting used to store the data.
|
||||
*/
|
||||
protected $setting;
|
||||
|
||||
/**
|
||||
* @var bool Whether the data is stored as a comma-separated list.
|
||||
*/
|
||||
protected $csv = true;
|
||||
|
||||
/**
|
||||
* A function that returns the data to be passed to the external function.
|
||||
*
|
||||
* The data returned will depend on the testclass.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function generate_test_data(): mixed;
|
||||
|
||||
/**
|
||||
* Test that execute() method sets the correct config setting.
|
||||
*/
|
||||
public function test_execute(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$testdata = $this->generate_test_data();
|
||||
$this->testclass::execute($testdata, true);
|
||||
|
||||
$currentconfig = get_config('qbank_columnsortorder', $this->setting);
|
||||
if ($this->csv) {
|
||||
$currentconfig = explode(',', $currentconfig);
|
||||
}
|
||||
|
||||
$this->assertEqualsCanonicalizing($testdata, $currentconfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that execute() method sets user preference when a component is passed.
|
||||
*/
|
||||
public function test_execute_user(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
$testdata = $this->generate_test_data();
|
||||
$this->testclass::execute($testdata);
|
||||
|
||||
$userpreference = get_user_preferences('qbank_columnsortorder_' . $this->setting);
|
||||
if ($this->csv) {
|
||||
$userpreference = explode(',', $userpreference);
|
||||
}
|
||||
|
||||
$this->assertEqualsCanonicalizing($testdata, $userpreference);
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
/**
|
||||
* qbank_columnsortorder external functions and service definitions.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @category webservice
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
@@ -28,9 +28,21 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'qbank_columnsortorder_set_columnbank_order' => [
|
||||
'classname' => 'qbank_columnsortorder\external\set_columnbank_order',
|
||||
'classname' => 'qbank_columnsortorder\external\set_columnbank_order',
|
||||
'description' => 'Sets question columns order in database',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
'qbank_columnsortorder_set_hidden_columns' => [
|
||||
'classname' => 'qbank_columnsortorder\external\set_hidden_columns',
|
||||
'description' => 'Hidden Columns',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
'qbank_columnsortorder_set_column_size' => [
|
||||
'classname' => 'qbank_columnsortorder\external\set_column_size',
|
||||
'description' => 'Column size',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -23,11 +23,25 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['addcolumn'] = 'Add column \'{$a}\'';
|
||||
$string['addcolumns'] = 'Add columns';
|
||||
$string['auto'] = 'Auto';
|
||||
$string['columnwidth'] = 'Column width (pixels)';
|
||||
$string['invalidwidth'] = 'Width must be at least 10.';
|
||||
$string['movecolumn'] = 'Move column \'{$a}\'';
|
||||
$string['pluginname'] = 'Column sort order';
|
||||
$string['privacy:metadata'] = 'The Column sort order question bank plugin does not store any personal data.';
|
||||
$string['privacy:metadata:preference:enabledcol'] = 'The plugin saves user preference of column orders.';
|
||||
$string['privacy:metadata:preference:hiddencols'] = 'The plugin saves user preference of hidden columns.';
|
||||
$string['privacy:metadata:preference:colsize'] = 'The plugin saves user preference of column sizes.';
|
||||
$string['qbankcolumnsortorder'] = 'Column sort order';
|
||||
$string['qbankgotocolumnsort'] = 'You can change the order of the columns in the question bank on the page {$a}.';
|
||||
$string['qbankcolumnsdisabled'] = 'Currently disabled question bank plugins:';
|
||||
$string['qbankgotomanageqbanks'] = 'You can remove a column by disabling the plugin in <a href=\'{$a}\'>Manage question bank plugins</a>.';
|
||||
$string['qbankcolumnname'] = '({$a})';
|
||||
$string['qbankcolumnname'] = '{$a}';
|
||||
$string['qbanksortdescription'] = 'The order in which plugins are listed below determines the order of the columns in the question bank.';
|
||||
$string['resetcolumns'] = 'Reset columns';
|
||||
$string['resize'] = 'Resize';
|
||||
$string['resizecolumn'] = 'Resize column {$a}';
|
||||
$string['removecolumn'] = 'Remove column \'{$a}\'';
|
||||
$string['showhidecolumn'] = 'Show/Hide column';
|
||||
$string['width'] = 'Width of \'{$a}\' in pixels';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Standard callback functions for qbank_columnsortorder
|
||||
*
|
||||
* This file only exists for defining fragment callbacks. Do not include any other functions here.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Render the column sort UI. {@see \qbank_columnsortorder\output\fragment::column_sort_ui()}
|
||||
*
|
||||
* @param array $args
|
||||
* @return string
|
||||
*/
|
||||
function qbank_columnsortorder_output_fragment_column_sort_ui(array $args): string {
|
||||
return \qbank_columnsortorder\output\fragment::column_sort_ui();
|
||||
}
|
||||
@@ -29,9 +29,16 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
admin_externalpage_setup('qbank_columnsortorder', '', ['section' => 'columnsortorder'],
|
||||
'/question/bank/columnsortorder/sortcolumns.php');
|
||||
|
||||
$renderer = $PAGE->get_renderer('qbank_columnsortorder');
|
||||
$preview = optional_param('preview', false, PARAM_BOOL);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(new lang_string('qbankcolumnsortorder', 'qbank_columnsortorder'));
|
||||
echo $renderer->render_column_sort_ui();
|
||||
if ($preview) {
|
||||
$columnmanager = new \qbank_columnsortorder\column_manager(true);
|
||||
$preview = $columnmanager->get_questionbank()->get_preview();
|
||||
echo $OUTPUT->render(new \qbank_columnsortorder\output\column_sort_preview($preview));
|
||||
|
||||
} else {
|
||||
echo $OUTPUT->render(new \qbank_columnsortorder\output\column_sort_ui());
|
||||
}
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#page-admin-question-bank-columnsortorder-sortcolumns .addcolumn {
|
||||
display: inline-block;
|
||||
}
|
||||
.qbank-sortable-column {
|
||||
background-color: white;
|
||||
position: relative;
|
||||
}
|
||||
.jsenabled .qbank-column-list button.savewidths {
|
||||
display: none;
|
||||
}
|
||||
.qbank-sortable-column .qbank_columnsortorder-action-handle {
|
||||
display: none;
|
||||
}
|
||||
.qbank-sortable-column.show-handles .qbank_columnsortorder-action-handle {
|
||||
display: block;
|
||||
}
|
||||
.qbank-sortable-column .handle-container {
|
||||
pointer-events: none; /* Prevent the handle container blocking clicks to elements in the header */
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
z-index: 1;
|
||||
}
|
||||
.qbank_columnsortorder-action-handle {
|
||||
pointer-events: auto; /* Ensure the handles themselves receive clicks */
|
||||
}
|
||||
.qbank_columnsortorder-action-handle.move {
|
||||
margin-left: -21px;
|
||||
width: 16px;
|
||||
}
|
||||
.qbank_columnsortorder-action-handle.resize {
|
||||
cursor: col-resize;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
.qbank_columnsortorder-action-handle.resize img {
|
||||
/* Prevent the resize handle icon being dragged across the page */
|
||||
pointer-events: none;
|
||||
}
|
||||
.qbank_columnsortorder-action-handle .icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/action_handle
|
||||
|
||||
Render a single action handle for customising a column.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"action": "move",
|
||||
"target": "",
|
||||
"title": "Move column A",
|
||||
"pixicon": "i/dragdrop",
|
||||
"pixcomponent": "core",
|
||||
"popup": true
|
||||
}
|
||||
}}
|
||||
<span class="qbank_columnsortorder-action-handle {{action}}" tabindex="0" role="button"{{#popup}} aria-haspopup="true"{{/popup}}
|
||||
data-action="{{action}}"
|
||||
data-target="{{target}}"
|
||||
{{#dragtype}}data-drag-type="{{dragtype}}" {{/dragtype}}
|
||||
title="{{title}}">
|
||||
{{#pixicon}}
|
||||
{{#pix}}{{pixicon}}, {{pixcomponent}}{{/pix}}
|
||||
{{/pixicon}}
|
||||
{{#icon}}
|
||||
<i class="fa fa-{{{icon}}} mr-1" aria-hidden="true"></i>
|
||||
{{/icon}}
|
||||
{{#text}}
|
||||
{{text}}
|
||||
{{/text}}
|
||||
</span>
|
||||
@@ -0,0 +1,57 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/add_column
|
||||
|
||||
Add column widget
|
||||
|
||||
Displays a list of currently hidden columns, with links to add them back to the question bank.
|
||||
|
||||
Context variables required for this template:
|
||||
* hiddencolumns - list of currently hidden columns
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"hashiddencolumns": true,
|
||||
"hiddencolumns": [
|
||||
{
|
||||
"name": "Column A",
|
||||
"class": "class_name_A",
|
||||
"addurl": "/question/bank/columnsortorder/actions.php?action=add&column=class_name_A"
|
||||
},
|
||||
{
|
||||
"name": "Column B",
|
||||
"class": "class_name_B",
|
||||
"addurl": "/question/bank/columnsortorder/actions.php?action=add&column=class_name_B"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{#hashiddencolumns}}
|
||||
<div class="dropdown addcolumn">
|
||||
<button class="btn btn-outline-dark dropdown-toggle ml-1" data-toggle="dropdown" id="addcolumndropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{#str}}addcolumns, qbank_columnsortorder{{/str}}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="addcolumndropdown">
|
||||
{{#hiddencolumns}}
|
||||
<a class="dropdown-item action-link" href="{{addurl}}" title="{{addtext}}" data-action="add" data-column="{{column}}">
|
||||
{{name}}
|
||||
</a>
|
||||
{{/hiddencolumns}}
|
||||
</div>
|
||||
</div>
|
||||
{{/hashiddencolumns}}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/column_sort_preview
|
||||
|
||||
Display a preview of the question bank, with a button to return to the customisation UI.
|
||||
|
||||
Context variables required for this template:
|
||||
* backurl - URL of customisation UI page.
|
||||
* preview - Rendered HTML for a question bank table with the current settings.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"backurl": "https://example.com/question/bank/columnsortorder/sortcolumns.php",
|
||||
"preview": "<table></table>"
|
||||
}
|
||||
}}
|
||||
<div id="qbank_columnsortorder-{{uniqid}}" class="container">
|
||||
|
||||
<a class="btn btn-primary" href="{{backurl}}">Back</a>
|
||||
|
||||
{{{preview}}}
|
||||
</div>
|
||||
@@ -0,0 +1,181 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/column_sort_ui
|
||||
|
||||
Display a list of enable columns with customisation controls, and a list of columns from disabled plugins, with a link to the
|
||||
question bank plugin management screen.
|
||||
|
||||
Context variables required for this template:
|
||||
* contextid - Current context id.
|
||||
* formaction - The URL of the actions controller to submit the form to.
|
||||
* sesskey - The current sesskey.
|
||||
* previewurl - The URL of the question bank preview page.
|
||||
* addcolumn - The context for the qbank_columnsortorder/add_column template.
|
||||
* resetcolumns - The context for the qbank_columnsortorder/reset_columns template.
|
||||
* names - A list of the currently active columns
|
||||
* name - The display name of the column
|
||||
* tiptitle - The tooltip text for the move handle.
|
||||
* colname - The unique class name for the column from the plugin.
|
||||
* escapedclass - The class name with \ replaced by __.
|
||||
* widthlabel - The label text of for this column's width field.
|
||||
* minwidth - The minimum value for the width field.
|
||||
* width - The current value for the width field.
|
||||
* actionmenu - The context for core/action_menu, a list of actions for the column.
|
||||
* columnsdisabled - Are the any columns defined by disabled plugins?
|
||||
* disabled - A list of disabled column names.
|
||||
* disabledname - The disabled column's name.
|
||||
* urltomanageqbanks - Link to the page for managing qbank plugins.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"contextid": 1,
|
||||
"formaction": "https://example.com/question/bank/columnsortorder/actions.php",
|
||||
"sesskey": "12345abcde",
|
||||
"previewurl": "https://example.com/question/bank/columnsortorder/sortcolumns.php?preview=1",
|
||||
"addcolumn": {
|
||||
"hashiddencolumns": true,
|
||||
"hiddencolumns": [
|
||||
{
|
||||
"name": "Column A",
|
||||
"class": "class_name_A",
|
||||
"addurl": "/question/bank/columnsortorder/actions.php?action=add&column=class_name_A"
|
||||
},
|
||||
{
|
||||
"name": "Column B",
|
||||
"class": "class_name_B",
|
||||
"addurl": "/question/bank/columnsortorder/actions.php?action=add&column=class_name_B"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resetcolumns": {
|
||||
"reseturl": "https://example.com/question/bank/columnsortorder/actions.php?action=reset"
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"name": "Column A",
|
||||
"tiptitle": "Move Column A",
|
||||
"columnid": "qbank_example\\col_name_A-col_name_A",
|
||||
"escapedid": "qbank_example__col_name_A-col_name_A",
|
||||
"widthlabel": "Width of Column A",
|
||||
"minwidth": "10",
|
||||
"width": ""
|
||||
},
|
||||
{
|
||||
"name": "Column B",
|
||||
"tiptitle": "Move Column B",
|
||||
"columnid": "qbank_example\\col_name_B-col_name_B",
|
||||
"escapedid": "qbank_example__col_name_B-col_name_B",
|
||||
"minwidth": "10",
|
||||
"width": "200"
|
||||
}
|
||||
],
|
||||
"columnsdisabled": true,
|
||||
"disabled": [
|
||||
{
|
||||
"disabledname": "disabled_1"
|
||||
},
|
||||
{
|
||||
"disabledname": "disabled_2"
|
||||
}
|
||||
],
|
||||
"urltomanageqbanks": "<a href=\"https://example.com/admin/manageqbankplugins.php\">Manage qbank plugins</a>"
|
||||
}
|
||||
}}
|
||||
<div id="qbank_columnsortorder-{{uniqid}}" {{!
|
||||
}}class="container" {{!
|
||||
}}data-component="qbank_columnsortorder" {{!
|
||||
}}data-callback="column_sort_ui" {{!
|
||||
}}data-contextid="{{contextid}}">
|
||||
<p>
|
||||
{{#str}}qbanksortdescription, qbank_columnsortorder{{/str}}
|
||||
</p>
|
||||
<form class="has-validation" action="{{formaction}}" method="post">
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}">{{!
|
||||
}}<div class="d-grid gap-2 d-md-flex justify-content-between mb-2">
|
||||
<div>
|
||||
<a class="btn btn-primary" href="{{previewurl}}">
|
||||
{{#str}}preview{{/str}}
|
||||
</a>
|
||||
{{#addcolumn}}
|
||||
{{>qbank_columnsortorder/add_column}}
|
||||
{{/addcolumn}}
|
||||
</div>
|
||||
{{#resetcolumns}}
|
||||
{{>qbank_columnsortorder/reset_columns}}
|
||||
{{/resetcolumns}}
|
||||
</div>
|
||||
<table class="generaltable table table-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">{{#str}}name{{/str}}</th>
|
||||
<th scope="col">{{#str}}plugin{{/str}}</th>
|
||||
<th scope="col" class="w-25">{{#str}}columnwidth, qbank_columnsortorder{{/str}}</th>
|
||||
<th scope="col">{{#str}}action{{/str}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="qbank-column-list">
|
||||
{{#names}}
|
||||
<tr class="qbank-sortable-column" data-pluginname="{{class}}" data-name="{{name}}" data-columnid="{{columnid}}">
|
||||
<td>{{>core/drag_handle}}</td>
|
||||
<td>{{name}}</td>
|
||||
<td>{{colname}}</td>
|
||||
<td>
|
||||
<div class="input-group">
|
||||
<label class="sr-only" for="width_{{escapedid}}">{{widthlabel}}</label>
|
||||
<input id="width_{{escapedid}}" {{!
|
||||
}}class="form-control width-input" {{!
|
||||
}}type="number" {{!
|
||||
}}min="{{minwidth}}" {{!
|
||||
}}name="width[{{escapedid}}]" {{!
|
||||
}}placeholder="{{#str}}auto, qbank_columnsortorder{{/str}}" {{!
|
||||
}}value="{{width}}">
|
||||
<button class="btn btn-sm btn-outline-dark savewidths" type="submit" name="action" value="savewidths">
|
||||
{{#str}}save{{/str}}
|
||||
</button>
|
||||
<div class="invalid-feedback">
|
||||
{{#str}}invalidwidth, qbank_columnsortorder{{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{#actionmenu}}{{>core/action_menu}}{{/actionmenu}}</td>
|
||||
</tr>
|
||||
{{/names}}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
<div>
|
||||
{{#columnsdisabled}}
|
||||
{{#str}}qbankcolumnsdisabled, qbank_columnsortorder{{/str}}
|
||||
<br>
|
||||
{{/columnsdisabled}}
|
||||
{{#disabled}}
|
||||
<div class="list-group-item disabled">
|
||||
{{disabledname}}
|
||||
</div>
|
||||
{{/disabled}}
|
||||
</div>
|
||||
<div>
|
||||
{{{urltomanageqbanks}}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['qbank_columnsortorder/admin_actions'], function(AdminTable) {
|
||||
AdminTable.init("qbank_columnsortorder-{{uniqid}}");
|
||||
});
|
||||
{{/js}}
|
||||
</div>
|
||||
@@ -1,65 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/columnsortorder.mustache
|
||||
|
||||
Admin question bank setting template.
|
||||
|
||||
Context variables required for this template:
|
||||
* name - plugin name
|
||||
* hiddenname - class/columname
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "Creatorname (creator_name_column)",
|
||||
"hiddenname": "creator_name_column"
|
||||
}
|
||||
}}
|
||||
|
||||
<div>
|
||||
{{#str}}qbanksortdescription, qbank_columnsortorder{{/str}}
|
||||
</div>
|
||||
<br>
|
||||
<div class="list list-group" id="qbank_columnsortorder-{{uniqid}}">
|
||||
{{#names}}
|
||||
<div class="column item list-group-item list-group-item-action" data-pluginname={{class}}>
|
||||
{{>core/drag_handle}}
|
||||
{{name}} {{colname}}
|
||||
</div>
|
||||
{{/names}}
|
||||
</div>
|
||||
<br>
|
||||
<div>
|
||||
{{#columnsdisabled}}
|
||||
{{#str}}qbankcolumnsdisabled, qbank_columnsortorder{{/str}}
|
||||
<br>
|
||||
{{/columnsdisabled}}
|
||||
{{#disabled}}
|
||||
<div class="list-group-item disabled">
|
||||
{{disabledname}}
|
||||
</div>
|
||||
{{/disabled}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['qbank_columnsortorder/sort_columns'], function(SortColumns) {
|
||||
SortColumns.init("qbank_columnsortorder-{{uniqid}}");
|
||||
});
|
||||
{{/js}}
|
||||
<br>
|
||||
<div>
|
||||
{{{urltomanageqbanks}}}
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/handle_container
|
||||
|
||||
Container for move/resize handles.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div class="handle-container">
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/reset_columns
|
||||
|
||||
Button to reset question bank column settings to defaults.
|
||||
|
||||
Context variables required for this template:
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"reseturl": "https://example.com/question/bank/columnsortorder/actions.php?action=reset"
|
||||
}
|
||||
}}
|
||||
<span>
|
||||
<a href="{{reseturl}}" class="btn btn-outline-dark action-link ml-1" data-action="reset">
|
||||
{{#str}}resetcolumns, qbank_columnsortorder{{/str}}
|
||||
</a>
|
||||
</span>
|
||||
@@ -0,0 +1,29 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_columnsortorder/resize_modal
|
||||
|
||||
This template renders the content of the resize modal, a number input to set the column width in pixels.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<label>
|
||||
{{#str}}columnwidth, qbank_columnsortorder{{/str}}
|
||||
<input name="columnwidth" type="number" value="">
|
||||
</label>
|
||||
@@ -0,0 +1,118 @@
|
||||
@qbank @qbank_columnsortorder @javascript
|
||||
Feature: Set default question bank column order and size
|
||||
In order to set sensible defaults for the question bank interface
|
||||
As an admin
|
||||
I want to hide, reorder, and resize columns
|
||||
|
||||
Scenario: Admin can reorder question bank columns
|
||||
Given I change the window size to "large"
|
||||
And I log in as "admin"
|
||||
When I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And I drag "Created by" "qbank_columnsortorder > column move handle" and I drop it in "T" "qbank_columnsortorder > column move handle"
|
||||
Then "Created by" "table_row" should appear before "T" "table_row"
|
||||
And I reload the page
|
||||
And "Created by" "table_row" should appear before "T" "table_row"
|
||||
And I follow "Preview"
|
||||
And "Created by" "qbank_columnsortorder > column header" should appear before "T" "qbank_columnsortorder > column header"
|
||||
|
||||
Scenario: Disabling a question bank plugin removes its columns
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And I should see "Created by"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Disable" "link" in the "View creator" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then "Currently disabled question bank plugins:" "text" should appear before "Created by" "text"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Enable" "link" in the "View creator" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then I should not see "Currently disabled question bank plugins:"
|
||||
And I should see "Created by"
|
||||
|
||||
Scenario: Admin can hide a column in site administration page
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And "Created by" "table_row" should exist
|
||||
When I click on "Actions menu" "link" in the "Created by" "table_row"
|
||||
And I choose "Remove" in the open action menu
|
||||
Then "Created by" "table_row" should not exist
|
||||
And I reload the page
|
||||
And "Created by" "table_row" should not exist
|
||||
And I follow "Preview"
|
||||
And "Created by" "qbank_columnsortorder > column header" should not exist
|
||||
|
||||
Scenario: Admin can show a column in site administration page
|
||||
Given the following config values are set as admin:
|
||||
| config | value | plugin |
|
||||
| hiddencols | qbank_viewcreator\creator_name_column-creator_name_column | qbank_columnsortorder |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And "Created by" "table_row" should not exist
|
||||
When I press "Add columns"
|
||||
And I follow "Created by"
|
||||
Then "Created by" "table_row" should exist
|
||||
And I reload the page
|
||||
And "Created by" "table_row" should exist
|
||||
And I follow "Preview"
|
||||
And "Created by" "qbank_columnsortorder > column header" should exist
|
||||
|
||||
Scenario: Admin can resize a column in site administration page
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And the field "Width of 'Question' in pixels" matches value ""
|
||||
When I set the field "Width of 'Question' in pixels" to "400"
|
||||
And I reload the page
|
||||
Then the field "Width of 'Question' in pixels" matches value "400"
|
||||
And I follow "Preview"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 400px"
|
||||
|
||||
Scenario: Custom fields can be reordered, resized, hidden and shown
|
||||
Given I change the window size to "large"
|
||||
And I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration
|
||||
And I press "Add a new category"
|
||||
And I click on "Add a new custom field" "link"
|
||||
And I follow "Checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Name | checkboxcustomcolumn |
|
||||
| Short name | chckcust |
|
||||
And I press "Save changes"
|
||||
And I should see "checkboxcustomcolumn"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And "checkboxcustomcolumn" "table_row" should appear after "Comments" "table_row"
|
||||
When I drag "checkboxcustomcolumn" "qbank_columnsortorder > column move handle" and I drop it in "Comments" "qbank_columnsortorder > column move handle"
|
||||
And I set the field "Width of 'checkboxcustomcolumn' in pixels" to "200"
|
||||
And I follow "Preview"
|
||||
And "checkboxcustomcolumn" "qbank_columnsortorder > column header" should appear before "Comments" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "checkboxcustomcolumn" "qbank_columnsortorder > column header" should contain "width: 200px"
|
||||
And I follow "Back"
|
||||
And "checkboxcustomcolumn" "table_row" should appear before "Comments" "table_row"
|
||||
And the field "Width of 'checkboxcustomcolumn' in pixels" matches value "200"
|
||||
And I click on "Actions menu" "link" in the "checkboxcustomcolumn" "table_row"
|
||||
And I choose "Remove" in the open action menu
|
||||
And "checkboxcustomcolumn" "table_row" should not exist
|
||||
And I follow "Preview"
|
||||
And "checkboxcustomcolumn" "qbank_columnsortorder > column header" should not exist
|
||||
And I follow "Back"
|
||||
And I press "Add columns"
|
||||
And I follow "checkboxcustomcolumn"
|
||||
And "checkboxcustomcolumn" "table_row" should exist
|
||||
And I follow "Preview"
|
||||
And "checkboxcustomcolumn" "qbank_columnsortorder > column header" should exist
|
||||
|
||||
Scenario: Resetting columns on the admin page clears global settings
|
||||
Given the following config values are set as admin:
|
||||
| config | value | plugin |
|
||||
| hiddencols | qbank_usage\question_last_used_column-question_last_used_column | qbank_columnsortorder |
|
||||
| enabledcol | qbank_comment\comment_count_column-comment_count_column,qbank_viewquestionname\question_name_idnumber_tags_column-question_name_idnumber_tags_column,core_question\local\bank\edit_menu_column-edit_menu_column,qbank_editquestion\question_status_column-question_status_column,qbank_history\version_number_column-version_number_column,qbank_statistics\columns\discrimination_index:discrimination_index,qbank_statistics\columns\facility_index:facility_index,qbank_statistics\columns\discriminative_efficiency:discriminative_efficiency,qbank_usage\question_usage_column-question_usage_column,qbank_usage\question_last_used_column-question_last_used_column,qbank_viewcreator\creator_name_column-creator_name_column,qbank_viewcreator\modifier_name_column-modifier_name_column,qbank_viewquestiontype\question_type_column-question_type_column | qbank_columnsortorder |
|
||||
| colsize | [{"column":"qbank_comment\\comment_count_column-comment_count_column","width":"20"},{"column":"qbank_viewquestionname\\question_name_idnumber_tags_column-question_name_idnumber_tags_column","width":"300"},{"column":"qbank_editquestion\\question_status_column-question_status_column","width":"20"},{"column":"qbank_history\\version_number_column-version_number_column","width":"20"},{"column":"qbank_statistics\\columns\\discrimination_index:discrimination_index","width":"20"},{"column":"qbank_statistics\\columns\\facility_index:facility_index","width":"20"},{"column":"qbank_statistics\\columns\\discriminative_efficiency:discriminative_efficiency","width":"20"},{"column":"qbank_usage\\question_usage_column-question_usage_column","width":"20"},{"column":"qbank_viewcreator\\creator_name_column-creator_name_column","width":"200"},{"column":"qbank_viewcreator\\modifier_name_column-modifier_name_column","width":"200"},{"column":"qbank_viewquestiontype\\question_type_column-question_type_column","width":"20"},{"column":"core_question\\local\\bank\\edit_menu_column-edit_menu_column","width":"50"}] | qbank_columnsortorder |
|
||||
And I change the window size to "large"
|
||||
And I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And "Last used" "table_row" should not exist
|
||||
And "Comments" "table_row" should appear before "Question" "table_row"
|
||||
And the field "Width of 'Question' in pixels" matches value "300"
|
||||
When I follow "Reset columns"
|
||||
Then "Last used" "table_row" should exist
|
||||
And "Question" "table_row" should appear before "Comments" "table_row"
|
||||
And the field "Width of 'Question' in pixels" matches value ""
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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/>.
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Steps definitions related with the drag and drop header.
|
||||
* @package qbank_columnsortorder
|
||||
* @category test
|
||||
* @copyright 2022 Catalyst IT Australia Pty Ltd
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_qbank_columnsortorder extends behat_base {
|
||||
public static function get_exact_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector('column header', [
|
||||
"//th[contains(@data-name, %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('column move handle', [
|
||||
"//*[self::th or self::tr][contains(@data-name, %locator%)]//span[contains(@data-drag-type, 'move')]",
|
||||
]),
|
||||
new behat_component_named_selector('column resize handle', [
|
||||
"//th[contains(@data-name, %locator%)]//span[contains(@data-action, 'resize')]",
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
@qbank @qbank_columnsortorder @javascript
|
||||
Feature: An plugin column can be reordered and displayed in the question bank view.
|
||||
In order to reorganise the question bank view columns
|
||||
As an admin
|
||||
I need to be able to reorder them
|
||||
|
||||
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 |
|
||||
And the following "activity" exists:
|
||||
| activity | quiz |
|
||||
| course | C1 |
|
||||
| name | Test quiz Q001 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "question category" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | Test quiz Q001 | Question category 1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext | idnumber |
|
||||
| Question category 1 | essay | Test question to be seen | teacher1 | Write about whatever you want | idnumber1 |
|
||||
|
||||
Scenario: Teacher can see proper view
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
When I apply question bank filter "Category" with value "Question category 1"
|
||||
And I should see "Test question to be seen"
|
||||
Then I should see "Teacher 1"
|
||||
|
||||
Scenario: Reordering question bank columns
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And I drag "Created by (creator_name_column)" "text" and I drop it in "T (question_type_column)" "text"
|
||||
And I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
Then ".creatorname" "css_element" should appear before ".qtype" "css_element"
|
||||
|
||||
Scenario: Disabling and enabling column display is proper
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And I should see "Created by (creator_name_column)"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Disable" "link" in the "View creator" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then "Currently disabled question bank plugins:" "text" should appear before "Created by" "text"
|
||||
And I should not see "Created by (creator_name_column)"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Enable" "link" in the "View creator" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then I should not see "Currently disabled question bank plugins:"
|
||||
And I should see "Created by (creator_name_column)"
|
||||
|
||||
Scenario: Custom fields are reorderable
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration
|
||||
And I press "Add a new category"
|
||||
And I click on "Add a new custom field" "link"
|
||||
And I follow "Checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Name | checkboxcustomcolumn |
|
||||
| Short name | chckcust |
|
||||
And I press "Save changes"
|
||||
Then I should see "checkboxcustomcolumn"
|
||||
And I navigate to "Plugins > Question bank plugins > Column sort order" in site administration
|
||||
And I should see "checkboxcustomcolumn"
|
||||
And I change the window size to "large"
|
||||
And I drag "checkboxcustomcolumn" "text" and I drop it in "T (question_type_column)" "text"
|
||||
Then "checkboxcustomcolumn" "text" should appear before "T (question_type_column)" "text"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Disable" "link" in the "Question custom fields" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then "Currently disabled question bank plugins:" "text" should appear before "chckcust" "text"
|
||||
And I click on "Manage question bank plugins" "link"
|
||||
And I click on "Enable" "link" in the "Question custom fields" "table_row"
|
||||
And I click on "Column sort order" "link"
|
||||
Then I should not see "Currently disabled question bank plugins:"
|
||||
And I should see "checkboxcustomcolumn"
|
||||
|
||||
Scenario: Reordering with disabled columns
|
||||
When I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
|
||||
And I click on "Disable" "link" in the "Question statistics" "table_row"
|
||||
And I click on "Enable" "link" in the "Question statistics" "table_row"
|
||||
And I click on "Disable" "link" in the "Question statistics" "table_row"
|
||||
And I am on the "Course 1" "core_question > course question bank" page
|
||||
Then I should see "Question bank"
|
||||
And "Create a new question" "button" should exist
|
||||
# Really, we are just checking the question bank displayed without errors.
|
||||
@@ -0,0 +1,143 @@
|
||||
@qbank @qbank_columnsortorder @javascript
|
||||
Feature: Set question bank column order and size
|
||||
In order customise my view of the question bank
|
||||
As a teacher
|
||||
I want to hide, reorder, and resize columns
|
||||
|
||||
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 |
|
||||
And the following "activity" exists:
|
||||
| activity | quiz |
|
||||
| course | C1 |
|
||||
| name | Test quiz Q001 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "question category" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Activity module | Test quiz Q001 | Question category 1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | user | questiontext | idnumber |
|
||||
| Question category 1 | essay | Test question to be seen | teacher1 | Write about whatever you want | idnumber1 |
|
||||
And the following config values are set as admin:
|
||||
| config | value | plugin |
|
||||
| hiddencols | qbank_usage\question_last_used_column-question_last_used_column | qbank_columnsortorder |
|
||||
| enabledcol | qbank_comment\comment_count_column-comment_count_column,qbank_viewquestionname\question_name_idnumber_tags_column-question_name_idnumber_tags_column,core_question\local\bank\edit_menu_column-edit_menu_column,qbank_editquestion\question_status_column-question_status_column,qbank_history\version_number_column-version_number_column,qbank_statistics\columns\discrimination_index:discrimination_index,qbank_statistics\columns\facility_index:facility_index,qbank_statistics\columns\discriminative_efficiency:discriminative_efficiency,qbank_usage\question_usage_column-question_usage_column,qbank_usage\question_last_used_column-question_last_used_column,qbank_viewcreator\creator_name_column-creator_name_column,qbank_viewcreator\modifier_name_column-modifier_name_column,qbank_viewquestiontype\question_type_column-question_type_column | qbank_columnsortorder |
|
||||
| colsize | [{"column":"qbank_comment\\comment_count_column-comment_count_column","width":"20"},{"column":"qbank_viewquestionname\\question_name_idnumber_tags_column-question_name_idnumber_tags_column","width":"300"},{"column":"qbank_editquestion\\question_status_column-question_status_column","width":"20"},{"column":"qbank_history\\version_number_column-version_number_column","width":"20"},{"column":"qbank_statistics\\columns\\discrimination_index:discrimination_index","width":"20"},{"column":"qbank_statistics\\columns\\facility_index:facility_index","width":"20"},{"column":"qbank_statistics\\columns\\discriminative_efficiency:discriminative_efficiency","width":"20"},{"column":"qbank_usage\\question_usage_column-question_usage_column","width":"20"},{"column":"qbank_viewcreator\\creator_name_column-creator_name_column","width":"200"},{"column":"qbank_viewcreator\\modifier_name_column-modifier_name_column","width":"200"},{"column":"qbank_viewquestiontype\\question_type_column-question_type_column","width":"20"},{"column":"core_question\\local\\bank\\edit_menu_column-edit_menu_column","width":"50"}] | qbank_columnsortorder |
|
||||
|
||||
Scenario: The teacher sees the question bank with global settings initially
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
When I apply question bank filter "Category" with value "Question category 1"
|
||||
Then I should see "Test question to be seen"
|
||||
And "Last used" "qbank_columnsortorder > column header" should not exist
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear before "Question" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 300px;"
|
||||
|
||||
Scenario: User preference takes precedence over global defaults
|
||||
Given the following "user preferences" exist:
|
||||
| user | preference | value |
|
||||
| teacher1 | qbank_columnsortorder_hiddencols | qbank_comment\comment_count_column-comment_count_column |
|
||||
| teacher1 | qbank_columnsortorder_enabledcol | qbank_viewquestionname\question_name_idnumber_tags_column-question_name_idnumber_tags_column,qbank_usage\question_last_used_column-question_last_used_column,core_question\local\bank\edit_menu_column-edit_menu_column,qbank_editquestion\question_status_column-question_status_column,qbank_history\version_number_column-version_number_column,qbank_statistics\columns\discrimination_index:discrimination_index,qbank_statistics\columns\facility_index:facility_index,qbank_statistics\columns\discriminative_efficiency:discriminative_efficiency,qbank_usage\question_usage_column-question_usage_column,qbank_usage\question_last_used_column-question_last_used_column,qbank_viewcreator\creator_name_column-creator_name_column,qbank_viewcreator\modifier_name_column-modifier_name_column,qbank_viewquestiontype\question_type_column-question_type_column |
|
||||
| teacher1 | qbank_columnsortorder_colsize | [{"column":"qbank_comment\\comment_count_column-comment_count_column","width":"20"},{"column":"qbank_viewquestionname\\question_name_idnumber_tags_column-question_name_idnumber_tags_column","width":"400"},{"column":"qbank_editquestion\\question_status_column-question_status_column","width":"20"},{"column":"qbank_history\\version_number_column-version_number_column","width":"20"},{"column":"qbank_statistics\\columns\\discrimination_index:discrimination_index","width":"20"},{"column":"qbank_statistics\\columns\\facility_index:facility_index","width":"20"},{"column":"qbank_statistics\\columns\\discriminative_efficiency:discriminative_efficiency","width":"20"},{"column":"qbank_usage\\question_usage_column-question_usage_column","width":"20"},{"column":"qbank_viewcreator\\creator_name_column-creator_name_column","width":"200"},{"column":"qbank_viewcreator\\modifier_name_column-modifier_name_column","width":"200"},{"column":"qbank_viewquestiontype\\question_type_column-question_type_column","width":"20"},{"column":"core_question\\local\\bank\\edit_menu_column-edit_menu_column","width":"50"}] |
|
||||
And I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
When I apply question bank filter "Category" with value "Question category 1"
|
||||
Then "Comments" "qbank_columnsortorder > column header" should not exist
|
||||
And "Question" "qbank_columnsortorder > column header" should appear before "Last used" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 400px;"
|
||||
|
||||
Scenario: Resetting user view goes back to global defaults
|
||||
Given the following "user preferences" exist:
|
||||
| user | preference | value |
|
||||
| teacher1 | qbank_columnsortorder_hiddencols | |
|
||||
| teacher1 | qbank_columnsortorder_enabledcol | qbank_viewquestionname\question_name_idnumber_tags_column-question_name_idnumber_tags_column,qbank_usage\question_last_used_column-question_last_used_column,core_question\local\bank\edit_menu_column-edit_menu_column,qbank_editquestion\question_status_column-question_status_column,qbank_history\version_number_column-version_number_column,qbank_statistics\columns\discrimination_index:discrimination_index,qbank_statistics\columns\facility_index:facility_index,qbank_statistics\columns\discriminative_efficiency:discriminative_efficiency,qbank_usage\question_usage_column-question_usage_column,qbank_usage\question_last_used_column-question_last_used_column,qbank_viewcreator\creator_name_column-creator_name_column,qbank_viewcreator\modifier_name_column-modifier_name_column,qbank_viewquestiontype\question_type_column-question_type_column |
|
||||
| teacher1 | qbank_columnsortorder_colsize | [{"column":"qbank_comment\\comment_count_column-comment_count_column","width":"20"},{"column":"qbank_viewquestionname\\question_name_idnumber_tags_column-question_name_idnumber_tags_column","width":"400"},{"column":"qbank_editquestion\\question_status_column-question_status_column","width":"20"},{"column":"qbank_history\\version_number_column-version_number_column","width":"20"},{"column":"qbank_statistics\\columns\\discrimination_index:discrimination_index","width":"20"},{"column":"qbank_statistics\\columns\\facility_index:facility_index","width":"20"},{"column":"qbank_statistics\\columns\\discriminative_efficiency:discriminative_efficiency","width":"20"},{"column":"qbank_usage\\question_usage_column-question_usage_column","width":"20"},{"column":"qbank_viewcreator\\creator_name_column-creator_name_column","width":"200"},{"column":"qbank_viewcreator\\modifier_name_column-modifier_name_column","width":"200"},{"column":"qbank_viewquestiontype\\question_type_column-question_type_column","width":"20"},{"column":"core_question\\local\\bank\\edit_menu_column-edit_menu_column","width":"50"}] |
|
||||
And I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And "Last used" "qbank_columnsortorder > column header" should exist
|
||||
And "Question" "qbank_columnsortorder > column header" should appear before "Last used" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 400px;"
|
||||
When I follow "Reset columns"
|
||||
Then "Last used" "qbank_columnsortorder > column header" should not exist
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear before "Question" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 300px;"
|
||||
|
||||
Scenario: User can remove a column in the question bank
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And "Comments" "qbank_columnsortorder > column header" should exist
|
||||
And I click on "Actions menu" "link" in the "Comments" "qbank_columnsortorder > column header"
|
||||
And I choose "Remove" in the open action menu
|
||||
Then "Comments" "qbank_columnsortorder > column header" should not exist
|
||||
And I reload the page
|
||||
And "Comments" "qbank_columnsortorder > column header" should not exist
|
||||
|
||||
Scenario: User can add a column in the question bank
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And "Last used" "qbank_columnsortorder > column header" should not exist
|
||||
When I press "Add columns"
|
||||
And I follow "Last used"
|
||||
Then "Last used" "qbank_columnsortorder > column header" should exist
|
||||
And I reload the page
|
||||
And "Last used" "qbank_columnsortorder > column header" should exist
|
||||
|
||||
Scenario: User can resize a column in the question bank using modal dialog
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 300px"
|
||||
When I click on "Actions menu" "link" in the "Question" "qbank_columnsortorder > column header"
|
||||
And I choose "Resize" in the open action menu
|
||||
And I set the field "Column width (pixels)" to "400"
|
||||
And I press "Save changes"
|
||||
Then the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 400px"
|
||||
And I reload the page
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 400px"
|
||||
|
||||
Scenario: User can resize a column in the question bank by dragging
|
||||
Given I change the window size to "large"
|
||||
And I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should contain "width: 300px"
|
||||
When I hover "Question" "qbank_columnsortorder > column header"
|
||||
And I drag "Question" "qbank_columnsortorder > column resize handle" and I drop it in "Status" "qbank_columnsortorder > column header"
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should not contain "width: 300px"
|
||||
And I reload the page
|
||||
And the "style" attribute of "Question" "qbank_columnsortorder > column header" should not contain "width: 300px"
|
||||
|
||||
Scenario: User can move a column in the question bank using modal dialog
|
||||
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear before "Question" "qbank_columnsortorder > column header"
|
||||
When I click on "Actions menu" "link" in the "Comments" "qbank_columnsortorder > column header"
|
||||
And I choose "Move" in the open action menu
|
||||
And I follow "After \"Question\""
|
||||
Then "Comments" "qbank_columnsortorder > column header" should appear after "Question" "qbank_columnsortorder > column header"
|
||||
And I reload the page
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear after "Question" "qbank_columnsortorder > column header"
|
||||
|
||||
Scenario: User can move a column in the question bank by dragging
|
||||
Given I change the window size to "large"
|
||||
And I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "teacher1"
|
||||
And I apply question bank filter "Category" with value "Question category 1"
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear before "Question" "qbank_columnsortorder > column header"
|
||||
When I hover "Comments" "qbank_columnsortorder > column header"
|
||||
And I drag "Comments" "qbank_columnsortorder > column move handle" and I drop it in "Status" "qbank_columnsortorder > column header"
|
||||
Then "Comments" "qbank_columnsortorder > column header" should appear after "Question" "qbank_columnsortorder > column header"
|
||||
And I reload the page
|
||||
And "Comments" "qbank_columnsortorder > column header" should appear after "Question" "qbank_columnsortorder > column header"
|
||||
|
||||
Scenario: Reordering with disabled columns
|
||||
When I log in as "admin"
|
||||
And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
|
||||
And I click on "Disable" "link" in the "Question statistics" "table_row"
|
||||
And I click on "Enable" "link" in the "Question statistics" "table_row"
|
||||
And I click on "Disable" "link" in the "Question statistics" "table_row"
|
||||
And I am on the "Course 1" "core_question > course question bank" page
|
||||
Then I should see "Question bank"
|
||||
And "Create a new question" "button" should exist
|
||||
# Really, we are just checking the question bank displayed without errors.
|
||||
@@ -20,10 +20,10 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use advanced_testcase;
|
||||
use context_course;
|
||||
use core_question\local\bank\column_base;
|
||||
use core_question\local\bank\question_edit_contexts;
|
||||
use core_question\local\bank\view;
|
||||
use moodle_url;
|
||||
use qbank_columnsortorder\external\set_columnbank_order;
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/tests/fixtures/testable_core_question_column.php');
|
||||
@@ -36,43 +36,147 @@ require_once($CFG->dirroot . '/question/classes/external.php');
|
||||
* @copyright 2021 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \qbank_columnsortorder\column_manager
|
||||
* @covers \qbank_columnsortorder\column_manager
|
||||
*/
|
||||
class column_manager_test extends advanced_testcase {
|
||||
|
||||
|
||||
/** @var \stdClass course record. */
|
||||
protected $course;
|
||||
|
||||
/** @var \core_question\local\bank\view */
|
||||
protected $questionbank;
|
||||
|
||||
/** @var array */
|
||||
protected $columns;
|
||||
|
||||
/** @var \qbank_columnsortorder\column_manager */
|
||||
protected $columnmanager;
|
||||
/**
|
||||
* Generate a course and return a question bank view for the course context.
|
||||
*
|
||||
* @return view
|
||||
*/
|
||||
protected static function get_question_bank(): view {
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$questionbank = new view(
|
||||
new question_edit_contexts(context_course::instance($course->id)),
|
||||
new moodle_url('/'),
|
||||
$course
|
||||
);
|
||||
return $questionbank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup testcase.
|
||||
* Return an array of visible columns for the question bank.
|
||||
*
|
||||
* @param view $questionbank
|
||||
* @return array
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$this->course = $this->getDataGenerator()->create_course();
|
||||
// Creates question bank view.
|
||||
$this->questionbank = new view(
|
||||
new question_edit_contexts(context_course::instance($this->course->id)),
|
||||
new moodle_url('/'),
|
||||
$this->course
|
||||
);
|
||||
|
||||
// Get current view columns.
|
||||
$this->columns = [];
|
||||
foreach ($this->questionbank->get_visiblecolumns() as $columnn) {
|
||||
$this->columns[] = get_class($columnn);
|
||||
protected static function get_columns(view $questionbank): array {
|
||||
$columns = [];
|
||||
foreach ($questionbank->get_visiblecolumns() as $column) {
|
||||
$columns[] = $column->get_column_id();
|
||||
}
|
||||
$this->columnmanager = new column_manager();
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide examples for testing each column setting function, with test data and data format.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public static function settings_provider(): array {
|
||||
$questionbank = self::get_question_bank();
|
||||
return [
|
||||
'Test set_column_order' => [
|
||||
'setting' => 'enabledcol',
|
||||
'function' => 'set_column_order',
|
||||
'data' => self::get_columns($questionbank),
|
||||
'csv' => true,
|
||||
],
|
||||
'Test set_hidden_columns' => [
|
||||
'setting' => 'hiddencols',
|
||||
'function' => 'set_hidden_columns',
|
||||
'data' => self::get_columns($questionbank),
|
||||
'csv' => true,
|
||||
],
|
||||
'Test set_column_size' => [
|
||||
'setting' => 'colsize',
|
||||
'function' => 'set_column_size',
|
||||
'data' => random_string(),
|
||||
'csv' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting config settings
|
||||
*
|
||||
* @dataProvider settings_provider
|
||||
* @param string $setting The name of the setting being saved
|
||||
* @param string $function The name of the function being called
|
||||
* @param mixed $data The property of the test class to pass to the function.
|
||||
* @param bool $csv True of the data is stored as a comma-separated list.
|
||||
* @return void
|
||||
*/
|
||||
public function test_settings(string $setting, string $function, mixed $data, bool $csv): void {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest(true);
|
||||
$this->assertFalse(get_config('qbank_columnsortorder', $setting));
|
||||
$this->assertEmpty(get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
column_manager::{$function}($data, true);
|
||||
$expected = $csv ? implode(',', $data) : $data;
|
||||
$this->assertEquals($expected, get_config('qbank_columnsortorder', $setting));
|
||||
$this->assertEmpty(get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test passing null clears the corresponding config setting.
|
||||
*
|
||||
* @dataProvider settings_provider
|
||||
* @param string $setting The name of the setting being saved
|
||||
* @param string $function The name of the function being called
|
||||
* @param mixed $data The property of the test class to pass to the function.
|
||||
* @param bool $csv True of the data is stored as a comma-separated list.
|
||||
* @return void
|
||||
*/
|
||||
public function test_reset_settings(string $setting, string $function, mixed $data, bool $csv): void {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest(true);
|
||||
$initial = $csv ? implode(',', $data) : $data;
|
||||
set_config($setting, $initial, 'qbank_columnsortorder');
|
||||
$this->assertEquals($initial, get_config('qbank_columnsortorder', $setting));
|
||||
column_manager::{$function}(null, true);
|
||||
$this->assertFalse(get_config('qbank_columnsortorder', $setting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting user preferences
|
||||
*
|
||||
* @dataProvider settings_provider
|
||||
* @param string $setting The name of the setting being saved
|
||||
* @param string $function The name of the function being called
|
||||
* @param mixed $data The data to pass to the function.
|
||||
* @param bool $csv True of the data is stored as a comma-separated list.
|
||||
* @return void
|
||||
*/
|
||||
public function test_settings_user(string $setting, string $function, mixed $data, bool $csv): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->assertFalse(get_config('qbank_columnsortorder', $setting));
|
||||
$this->assertEmpty(get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
column_manager::{$function}($data);
|
||||
$expected = $csv ? implode(',', $data) : $data;
|
||||
$this->assertFalse(get_config('qbank_columnsortorder', $setting));
|
||||
$this->assertEquals($expected, get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test passing null clears the corresponding user preference.
|
||||
*
|
||||
* @dataProvider settings_provider
|
||||
* @param string $setting The name of the setting being saved
|
||||
* @param string $function The name of the function being called
|
||||
* @param mixed $data The property of the test class to pass to the function.
|
||||
* @param bool $csv True of the data is stored as a comma-separated list.
|
||||
* @return void
|
||||
*/
|
||||
public function test_reset_user_settings(string $setting, string $function, mixed $data, bool $csv): void {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest(true);
|
||||
$initial = $csv ? implode(',', $data) : $data;
|
||||
set_user_preference('qbank_columnsortorder_' . $setting, $initial);
|
||||
$this->assertEquals($initial, get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
column_manager::{$function}(null);
|
||||
$this->assertEmpty(get_user_preferences('qbank_columnsortorder_' . $setting));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +185,10 @@ class column_manager_test extends advanced_testcase {
|
||||
* @covers ::get_columns
|
||||
*/
|
||||
public function test_getcolumns_function(): void {
|
||||
$questionlistcolumns = $this->columnmanager->get_columns();
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$columnmanager = new column_manager(true);
|
||||
$questionlistcolumns = $columnmanager->get_columns();
|
||||
$this->assertIsArray($questionlistcolumns);
|
||||
foreach ($questionlistcolumns as $columnnobject) {
|
||||
$this->assertObjectHasAttribute('class', $columnnobject);
|
||||
@@ -91,45 +198,67 @@ class column_manager_test extends advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function sort columns method.
|
||||
* The get_sorted_columns method should return the provided columns sorted according to enabledcol setting.
|
||||
*
|
||||
* @covers ::get_sorted_columns
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_sorted_columns(): void {
|
||||
$neworder = $this->columnmanager->get_sorted_columns($this->columns);
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
$neworder = $columns;
|
||||
shuffle($neworder);
|
||||
set_columnbank_order::execute($neworder);
|
||||
$currentconfig = get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$currentconfig = explode(',', $currentconfig);
|
||||
ksort($currentconfig);
|
||||
$this->assertSame($neworder, $currentconfig);
|
||||
set_config('enabledcol', implode(',', $neworder), 'qbank_columnsortorder');
|
||||
|
||||
$columnmanager = new column_manager(true);
|
||||
$columnstosort = [];
|
||||
foreach ($columns as $column) {
|
||||
$columnstosort[$column] = $column;
|
||||
}
|
||||
|
||||
$sortedcolumns = $columnmanager->get_sorted_columns($columnstosort);
|
||||
|
||||
$expectedorder = ['core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column' => 0];
|
||||
foreach ($neworder as $columnid) {
|
||||
$expectedorder[$columnid] = $columnid;
|
||||
}
|
||||
$this->assertSame($expectedorder, $sortedcolumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function enabing and disablingcolumns.
|
||||
* Test disabled columns are removed from enabledcol setting and added to disabledcol setting.
|
||||
*
|
||||
* @covers ::enable_columns
|
||||
* @covers ::disable_columns
|
||||
* @return void
|
||||
*/
|
||||
public function test_enable_disable_columns(): void {
|
||||
$neworder = $this->columnmanager->get_sorted_columns($this->columns);
|
||||
shuffle($neworder);
|
||||
set_columnbank_order::execute($neworder);
|
||||
$currentconfig = get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$currentconfig = explode(',', $currentconfig);
|
||||
$class = $currentconfig[array_rand($currentconfig, 1)];
|
||||
$randomplugintodisable = explode('\\', $class)[0];
|
||||
$olddisabledconfig = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
$this->columnmanager->disable_columns($randomplugintodisable);
|
||||
$newdisabledconfig = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
$this->assertNotEquals($olddisabledconfig, $newdisabledconfig);
|
||||
$this->columnmanager->enable_columns($randomplugintodisable);
|
||||
$newdisabledconfig = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
$this->assertEmpty($newdisabledconfig);
|
||||
$enabledconfig = get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$contains = strpos($enabledconfig, $randomplugintodisable);
|
||||
$this->assertNotFalse($contains);
|
||||
$this->assertIsInt($contains);
|
||||
public function test_disable_columns(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
// Set up enabledcol with all plugins.
|
||||
set_config('enabledcol', implode(',', $columns), 'qbank_columnsortorder');
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
$columnmanager = new column_manager(true);
|
||||
$this->assertFalse(get_config('qbank_columnsortorder', 'disabledcol'));
|
||||
|
||||
// Disable a random plugin.
|
||||
$plugincolumns = array_filter($columns, fn($column) => str_starts_with($column, 'qbank_'));
|
||||
$randomcolumn = $plugincolumns[array_rand($plugincolumns, 1)];
|
||||
$randomplugin = explode('\\', $randomcolumn)[0];
|
||||
$columnmanager->disable_columns($randomplugin);
|
||||
|
||||
// The enabledcol setting should now contain all columns except the disabled plugin.
|
||||
$expectedconfig = array_filter($columns, fn($column) => !str_starts_with($column, $randomplugin));
|
||||
sort($expectedconfig);
|
||||
$newconfig = explode(',', get_config('qbank_columnsortorder', 'enabledcol'));
|
||||
sort($newconfig);
|
||||
$this->assertEquals($expectedconfig, $newconfig);
|
||||
$this->assertNotContains($randomcolumn, $newconfig);
|
||||
// The disabledcol setting should only contain columns from the disabled plugin.
|
||||
$disabledconfig = explode(',', get_config('qbank_columnsortorder', 'disabledcol'));
|
||||
array_walk($disabledconfig, fn($column) => $this->assertStringStartsWith($randomplugin, $column));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,15 +267,21 @@ class column_manager_test extends advanced_testcase {
|
||||
* @covers \qbank_columnsortorder\event\plugin_observer
|
||||
*/
|
||||
public function test_plugin_enabled_disabled_observers(): void {
|
||||
$neworder = $this->columnmanager->get_sorted_columns($this->columns);
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
$columnmanager = new column_manager(true);
|
||||
$neworder = $columnmanager->get_sorted_columns($columns);
|
||||
shuffle($neworder);
|
||||
set_columnbank_order::execute($neworder);
|
||||
$columnmanager::set_column_order($neworder, true);
|
||||
// Get the list of enabled columns, excluding core columns (we can't disable those).
|
||||
$currentconfig = get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$currentconfig = array_filter(explode(',', $currentconfig), fn($class) => !str_starts_with($class, 'core'));
|
||||
// Pick a column at random and get its plugin name.
|
||||
$class = $currentconfig[array_rand($currentconfig, 1)];
|
||||
$randomplugintodisable = explode('\\', $class)[0];
|
||||
$randomcolumnid = $currentconfig[array_rand($currentconfig, 1)];
|
||||
[$randomcolumnclass] = explode(column_base::ID_SEPARATOR, $randomcolumnid, 2);
|
||||
[$randomplugintodisable] = explode('\\', $randomcolumnclass);
|
||||
$olddisabledconfig = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
\core\event\qbank_plugin_disabled::create_for_plugin($randomplugintodisable)->trigger();
|
||||
$newdisabledconfig = get_config('qbank_columnsortorder', 'disabledcol');
|
||||
@@ -159,4 +294,79 @@ class column_manager_test extends advanced_testcase {
|
||||
$this->assertNotFalse($contains);
|
||||
$this->assertIsInt($contains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test enabled columns are removed from disabledcol setting and added to enabledcol setting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_enable_columns() {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
// Set up disablecol with columns from 2 random plugins, and enabledcol with all other columns.
|
||||
$plugincolumns = array_filter($columns, fn($column) => str_starts_with($column, 'qbank_'));
|
||||
$plugins = array_unique(array_map(fn($column) => explode('\\', $column)[0], $plugincolumns));
|
||||
$randomplugins = array_rand($plugins, 2);
|
||||
$randomplugin1 = $plugins[$randomplugins[0]];
|
||||
$randomplugin2 = $plugins[$randomplugins[1]];
|
||||
|
||||
$disabledcols = array_filter(
|
||||
$columns,
|
||||
fn($column) => str_starts_with($column, $randomplugin1) || str_starts_with($column, $randomplugin2)
|
||||
);
|
||||
$enabledcols = array_diff($columns, $disabledcols);
|
||||
|
||||
set_config('enabledcol', implode(',', $enabledcols), 'qbank_columnsortorder');
|
||||
set_config('disabledcol', implode(',', $disabledcols), 'qbank_columnsortorder');
|
||||
|
||||
// Enable one of the disabled plugins.
|
||||
$columnmanager = new column_manager(true);
|
||||
$columnmanager->enable_columns($randomplugin1);
|
||||
// The enabledcol setting should now contain all columns except the remaining disabled plugin.
|
||||
$expectedenabled = array_filter($columns, fn($column) => !str_starts_with($column, $randomplugin2));
|
||||
$expecteddisabled = array_filter($disabledcols, fn($column) => str_starts_with($column, $randomplugin2));
|
||||
sort($expectedenabled);
|
||||
sort($expecteddisabled);
|
||||
$newenabled = explode(',', get_config('qbank_columnsortorder', 'enabledcol'));
|
||||
sort($newenabled);
|
||||
$this->assertEquals($expectedenabled, $newenabled);
|
||||
$this->assertNotContains(reset($expecteddisabled), $newenabled);
|
||||
// The disabledcol setting should only contain columns from the remaining disabled plugin.
|
||||
$newdisabled = explode(',', get_config('qbank_columnsortorder', 'disabledcol'));
|
||||
array_walk($newdisabled, fn($column) => $this->assertStringStartsWith($randomplugin2, $column));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_disabled_columns returns names of all the columns in the disabledcol setting
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_disabled_columns(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$questionbank = $this->get_question_bank();
|
||||
$columns = $this->get_columns($questionbank);
|
||||
// Set up disablecol with columns from 2 random plugins, and enabledcol with all other columns.
|
||||
$plugincolumns = array_filter($columns, fn($column) => str_starts_with($column, 'qbank_'));
|
||||
$randomcolumn = $plugincolumns[array_rand($plugincolumns, 1)];
|
||||
$randomplugin = explode('\\', $randomcolumn)[0];
|
||||
|
||||
$disabledcols = array_filter($columns, fn($column) => str_starts_with($column, $randomplugin));
|
||||
|
||||
set_config('disabledcol', implode(',', $disabledcols), 'qbank_columnsortorder');
|
||||
|
||||
$columnmanager = new column_manager(true);
|
||||
$expecteddisablednames = [];
|
||||
foreach ($disabledcols as $disabledcolid) {
|
||||
[$columnclass, $columnname] = explode(column_base::ID_SEPARATOR, $disabledcolid, 2);
|
||||
$columnobject = $columnclass::from_column_name($questionbank, $columnname);
|
||||
$expecteddisablednames[$disabledcolid] = (object) [
|
||||
'disabledname' => $columnobject->get_title(),
|
||||
];
|
||||
}
|
||||
$disablednames = $columnmanager->get_disabled_columns();
|
||||
$this->assertEquals($expecteddisablednames, $disablednames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\external;
|
||||
|
||||
use qbank_columnsortorder\column_manager;
|
||||
use qbank_columnsortorder\tests\external_function_testcase;
|
||||
|
||||
// phpcs:disable moodle.PHPUnit.TestCaseNames.Missing
|
||||
// This class inherits its test methods from the parent class.
|
||||
|
||||
/**
|
||||
* Unit tests for qbank_columnsortorder external API.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \qbank_columnsortorder\external\set_column_size
|
||||
*/
|
||||
class set_column_size_test extends external_function_testcase {
|
||||
/**
|
||||
* @var string Fully-qualified external function class to test.
|
||||
*/
|
||||
protected $testclass = '\qbank_columnsortorder\external\set_column_size';
|
||||
|
||||
/**
|
||||
* @var string The name of the setting used to store the data.
|
||||
*/
|
||||
protected $setting = 'colsize';
|
||||
|
||||
/**
|
||||
* @var bool Whether the data is stored as a comma-separated list.
|
||||
*/
|
||||
protected $csv = false;
|
||||
|
||||
/**
|
||||
* Generate a list of random column sizes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function generate_test_data(): string {
|
||||
$columnsortorder = new column_manager();
|
||||
$questionlistcolumns = $columnsortorder->get_columns();
|
||||
$columnsizes = [];
|
||||
foreach ($questionlistcolumns as $columnnobject) {
|
||||
$columnsizes[] = (object)[
|
||||
'column' => $columnnobject->name,
|
||||
'width' => rand(1, 100) . 'px',
|
||||
];
|
||||
}
|
||||
return json_encode($columnsizes);
|
||||
}
|
||||
}
|
||||
+24
-23
@@ -14,35 +14,41 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder;
|
||||
namespace qbank_columnsortorder\external;
|
||||
|
||||
use advanced_testcase;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
use qbank_columnsortorder\external\set_columnbank_order;
|
||||
use qbank_columnsortorder\tests\external_function_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/question/classes/external.php');
|
||||
// phpcs:disable moodle.PHPUnit.TestCaseNames.Missing
|
||||
// This class inherits its test methods from the parent class.
|
||||
|
||||
/**
|
||||
* Unit tests for qbank_columnsortorder external API.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @author 2021, Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \qbank_columnsortorder\external\set_columnbank_order
|
||||
*/
|
||||
class columnsortorder_external_test extends advanced_testcase {
|
||||
class set_columnbank_order_test extends external_function_testcase {
|
||||
|
||||
/**
|
||||
* Test that external call core_question_external::set_columnbank_order($oldorder) sets proper
|
||||
* data in config_plugins table.
|
||||
* @var string Fully-qualified external function class to test.
|
||||
*/
|
||||
public function test_columnorder_external(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
protected $testclass = '\qbank_columnsortorder\external\set_columnbank_order';
|
||||
|
||||
/**
|
||||
* @var string The name of the setting used to store the data.
|
||||
*/
|
||||
protected $setting = 'enabledcol';
|
||||
|
||||
/**
|
||||
* Return a randomly-ordered list of columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function generate_test_data(): array {
|
||||
$columnsortorder = new column_manager();
|
||||
$questionlistcolumns = $columnsortorder->get_columns();
|
||||
$columnclasses = [];
|
||||
@@ -50,11 +56,6 @@ class columnsortorder_external_test extends advanced_testcase {
|
||||
$columnclasses[] = $columnnobject->class;
|
||||
}
|
||||
shuffle($columnclasses);
|
||||
set_columnbank_order::execute($columnclasses);
|
||||
|
||||
$currentconfig = (array)get_config('qbank_columnsortorder', 'enabledcol');
|
||||
$currentconfig = explode(',', $currentconfig[0]);
|
||||
|
||||
$this->assertSame($columnclasses, $currentconfig);
|
||||
return $columnclasses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_columnsortorder\external;
|
||||
|
||||
use qbank_columnsortorder\column_manager;
|
||||
use qbank_columnsortorder\tests\external_function_testcase;
|
||||
|
||||
// phpcs:disable moodle.PHPUnit.TestCaseNames.Missing
|
||||
// This class inherits its test methods from the parent class.
|
||||
|
||||
/**
|
||||
* Unit tests for qbank_columnsortorder external API.
|
||||
*
|
||||
* @package qbank_columnsortorder
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \qbank_columnsortorder\external\set_hidden_columns
|
||||
*/
|
||||
class set_hidden_columns_test extends external_function_testcase {
|
||||
/**
|
||||
* @var string Fully-qualified external function class to test.
|
||||
*/
|
||||
protected $testclass = '\qbank_columnsortorder\external\set_hidden_columns';
|
||||
|
||||
/**
|
||||
* @var string The name of the setting used to store the data.
|
||||
*/
|
||||
protected $setting = 'hiddencols';
|
||||
|
||||
/**
|
||||
* Return a random list of hidden column names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function generate_test_data(): array {
|
||||
$columnsortorder = new column_manager();
|
||||
$questionlistcolumns = $columnsortorder->get_columns();
|
||||
$hiddencolumns = array_slice($questionlistcolumns, rand(0, count($questionlistcolumns) - 1));
|
||||
return array_map(fn($column) => $column->name, $hiddencolumns);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'qbank_columnsortorder';
|
||||
$plugin->version = 2023042401;
|
||||
$plugin->version = 2023052201;
|
||||
$plugin->requires = 2023041800;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
|
||||
@@ -110,4 +110,7 @@ class comment_count_column extends column_base {
|
||||
return ['pr-3'];
|
||||
}
|
||||
|
||||
public function get_default_width(): int {
|
||||
return 150;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
namespace qbank_customfields;
|
||||
|
||||
use core_question\local\bank\column_base;
|
||||
use core_question\local\bank\view;
|
||||
use qbank_customfields\customfield\question_handler;
|
||||
|
||||
/**
|
||||
* A column type for the name of the question creator.
|
||||
@@ -42,6 +44,16 @@ class custom_field_column extends column_base {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
public static function from_column_name(view $view, string $columnname): custom_field_column {
|
||||
$handler = question_handler::create();
|
||||
foreach ($handler->get_fields() as $field) {
|
||||
if ($field->get('shortname') == $columnname) {
|
||||
return new static($view, $field);
|
||||
}
|
||||
}
|
||||
throw new \coding_exception('Custom field ' . $columnname . ' does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal name for this column. Used as a CSS class name,
|
||||
* and to store information about the current sort. Must match PARAM_ALPHA.
|
||||
@@ -60,7 +72,7 @@ class custom_field_column extends column_base {
|
||||
* @return string The unique name;
|
||||
*/
|
||||
public function get_column_name(): string {
|
||||
return 'custom_field_column\\' . $this->field->get('shortname');
|
||||
return $this->field->get('shortname');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,20 +40,21 @@ Feature: A teacher can edit question with custom fields
|
||||
And I am on the "Test quiz name" "mod_quiz > question bank" page
|
||||
|
||||
Scenario: Edit a previously created question and see the custom field in the overview table and in the question preview.
|
||||
When I choose "Edit question" action for "First question" in the question bank
|
||||
And I should see "Category for test"
|
||||
And I click on "Expand all" "link" in the "region-main" "region"
|
||||
When I am on the "First question" "core_question > edit" page
|
||||
Then I should see "Category for test"
|
||||
And I expand all fieldsets
|
||||
And I should see "Field 1"
|
||||
And I set the following fields to these values:
|
||||
| Field 1 | custom field text |
|
||||
| Question name | First question edited |
|
||||
| Field 1 | custom field text |
|
||||
And I press "id_submitbutton"
|
||||
And I should see "First question"
|
||||
And I should see "custom field text"
|
||||
And I choose "Preview" action for "First question" in the question bank
|
||||
And I am on the "First question edited" "core_question > preview" page
|
||||
And I should see "Field 1"
|
||||
Then I should see "custom field text"
|
||||
And I should see "custom field text"
|
||||
|
||||
Scenario: Preview a previously created question with custom fields set with empty values
|
||||
When I choose "Preview" action for "First question" in the question bank
|
||||
And I should see "Field 1"
|
||||
Then I should not see "custom field text"
|
||||
When I am on the "First question" "core_question > preview" page
|
||||
Then I should see "Field 1"
|
||||
And I should not see "custom field text"
|
||||
|
||||
@@ -37,13 +37,12 @@ Feature: The visibility of question custom fields control where they are display
|
||||
| Correct answer | False |
|
||||
| Feedback for the response 'True'. | So you think it is true |
|
||||
| Feedback for the response 'False'. | So you think it is false |
|
||||
And I am on the "Test quiz name" "mod_quiz > question bank" page
|
||||
|
||||
@javascript
|
||||
Scenario: Display custom question fields to teachers based on their visibility.
|
||||
When I choose "Edit question" action for "First question" in the question bank
|
||||
And I should see "Category for test"
|
||||
And I click on "Expand all" "link" in the "region-main" "region"
|
||||
When I am on the "First question" "core_question > edit" page
|
||||
Then I should see "Category for test"
|
||||
And I expand all fieldsets
|
||||
And I should see "Field 1"
|
||||
And I should see "Field 2"
|
||||
And I should see "Field 3"
|
||||
@@ -63,4 +62,4 @@ Feature: The visibility of question custom fields control where they are display
|
||||
And I should see "Field 2"
|
||||
And I should see "custom field text two"
|
||||
And I should see "Field 3"
|
||||
Then I should see "secret"
|
||||
And I should see "secret"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
namespace qbank_editquestion;
|
||||
|
||||
use core_question\local\bank\question_version_status;
|
||||
use qbank_editquestion\output\add_new_question;
|
||||
|
||||
/**
|
||||
* Class editquestion_helper for methods related to add/edit/copy
|
||||
@@ -69,25 +70,13 @@ class editquestion_helper {
|
||||
* @param bool $canadd the text to display on the button.
|
||||
* @param string $tooltip a tooltip to add to the button (optional).
|
||||
* @param bool $disabled if true, the button will be disabled.
|
||||
* @deprecated since Moodle 4.3. Use {@see add_new_question} renderable instead
|
||||
* @todo Final deprecation in Moodle 4.7
|
||||
*/
|
||||
public static function create_new_question_button($categoryid, $params, $canadd, $tooltip = '', $disabled = false) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$addquestiondisplay = array();
|
||||
$addquestiondisplay['canadd'] = $canadd;
|
||||
if ($canadd) {
|
||||
$params['category'] = $categoryid;
|
||||
$url = new \moodle_url('/question/bank/editquestion/addquestion.php', $params);
|
||||
$buttonparams = ['disabled' => $disabled];
|
||||
if (!empty($tooltip)) {
|
||||
$buttonparams['title'] = $tooltip;
|
||||
}
|
||||
$addquestiondisplay['buttonhtml'] = $OUTPUT->single_button($url,
|
||||
get_string('createnewquestion', 'question'),
|
||||
'get', $buttonparams);
|
||||
$addquestiondisplay['qtypeform'] = self::print_choose_qtype_to_add_form(array());
|
||||
}
|
||||
return $PAGE->get_renderer('qbank_editquestion')->render_create_new_question_button($addquestiondisplay);
|
||||
global $OUTPUT;
|
||||
debugging('create_new_question_button() is deprecated. Use the add_new_question renderable instead.');
|
||||
return $OUTPUT->render(new add_new_question($categoryid, $params, $canadd));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_editquestion\output;
|
||||
|
||||
use qbank_editquestion\editquestion_helper;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Create new question button
|
||||
*
|
||||
* @package qbank_editquestion
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class add_new_question implements \renderable, \templatable {
|
||||
/** @var int $categoryid The ID of the category the quesiton will be added to. */
|
||||
protected int $categoryid;
|
||||
|
||||
/** @var array $params URL parameters to pass to the add question form. */
|
||||
protected array $params;
|
||||
|
||||
/** @var bool $canadd True if the add question button should be displayed. If false, a placeholder will be shown.*/
|
||||
protected bool $canadd;
|
||||
|
||||
/**
|
||||
* Store data for building the template context.
|
||||
*
|
||||
* @param int $categoryid
|
||||
* @param array $params
|
||||
* @param bool $canadd
|
||||
*/
|
||||
public function __construct(int $categoryid, array $params, bool $canadd) {
|
||||
$this->categoryid = $categoryid;
|
||||
$this->params = $params;
|
||||
$this->canadd = $canadd;
|
||||
}
|
||||
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
$addquestiondisplay = [];
|
||||
$addquestiondisplay['canadd'] = $this->canadd;
|
||||
if ($this->canadd) {
|
||||
$this->params['category'] = $this->categoryid;
|
||||
$url = new \moodle_url('/question/bank/editquestion/addquestion.php', $this->params);
|
||||
$addquestiondisplay['buttonhtml'] = $output->single_button(
|
||||
$url,
|
||||
get_string('createnewquestion', 'question'),
|
||||
'get'
|
||||
);
|
||||
$addquestiondisplay['qtypeform'] = editquestion_helper::print_choose_qtype_to_add_form([]);
|
||||
}
|
||||
return $addquestiondisplay;
|
||||
}
|
||||
}
|
||||
@@ -52,8 +52,12 @@ class renderer extends \plugin_renderer_base {
|
||||
*
|
||||
* @param array $addquestiondata
|
||||
* @return bool|string
|
||||
* @deprecated since Moodle 4.3. Use {@see add_new_question} renderable instead
|
||||
* @todo Final deprecation in Moodle 4.7
|
||||
*/
|
||||
public function render_create_new_question_button ($addquestiondata) {
|
||||
debugging('render_create_new_question_button() is deprecated. '
|
||||
. 'Pass the add_new_question renderable to render() instead.');
|
||||
return $this->render_from_template('qbank_editquestion/add_new_question', $addquestiondata);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
namespace qbank_editquestion;
|
||||
|
||||
use core\context;
|
||||
use core_question\local\bank\view;
|
||||
use qbank_editquestion\output\add_new_question;
|
||||
|
||||
/**
|
||||
* Class columns is the entrypoint for the columns.
|
||||
@@ -35,7 +37,7 @@ use core_question\local\bank\view;
|
||||
* @author Safat Shahin <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class plugin_feature extends \core_question\local\bank\plugin_features_base{
|
||||
class plugin_feature extends \core_question\local\bank\plugin_features_base {
|
||||
|
||||
public function get_question_columns($qbank): array {
|
||||
return [
|
||||
@@ -50,4 +52,23 @@ class plugin_feature extends \core_question\local\bank\plugin_features_base{
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return "Add new question" control.
|
||||
*
|
||||
* @param view $qbank The question bank view.
|
||||
* @param context $context The current context, for permission checks.
|
||||
* @param int $categoryid The current question category ID.
|
||||
* @return \renderable[]
|
||||
*/
|
||||
public function get_question_bank_controls(view $qbank, context $context, int $categoryid): array {
|
||||
if (!$qbank->allow_add_questions()) {
|
||||
return [];
|
||||
}
|
||||
$canadd = has_capability('moodle/question:add', $context);
|
||||
$urlparams = (new edit_action($qbank))->editquestionurl->params();
|
||||
return [
|
||||
100 => new add_new_question($categoryid, $urlparams, $canadd),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,8 +92,9 @@ class question_history_view extends view {
|
||||
}
|
||||
}
|
||||
|
||||
protected function create_new_question_form($category, $canadd): void {
|
||||
public function allow_add_questions(): bool {
|
||||
// As we dont want to create questions in this page.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,6 +53,14 @@ class discrimination_index extends column_base {
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_discrimination_index($discriminationindex);
|
||||
}
|
||||
|
||||
public function display_preview(\stdClass $question, string $rowclasses): void {
|
||||
global $PAGE;
|
||||
|
||||
$this->display_start($question, $rowclasses);
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_discrimination_index(50.00);
|
||||
$this->display_end($question, $rowclasses);;
|
||||
}
|
||||
|
||||
public function get_extra_classes(): array {
|
||||
return ['pr-3'];
|
||||
}
|
||||
|
||||
@@ -51,6 +51,14 @@ class discriminative_efficiency extends column_base {
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_discriminative_efficiency($discriminativeefficiency);
|
||||
}
|
||||
|
||||
public function display_preview(\stdClass $question, string $rowclasses): void {
|
||||
global $PAGE;
|
||||
|
||||
$this->display_start($question, $rowclasses);
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_discriminative_efficiency(25);
|
||||
$this->display_end($question, $rowclasses);;
|
||||
}
|
||||
|
||||
public function get_extra_classes(): array {
|
||||
return ['pr-3'];
|
||||
}
|
||||
|
||||
@@ -52,6 +52,14 @@ class facility_index extends column_base {
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_facility_index($facility);
|
||||
}
|
||||
|
||||
public function display_preview(\stdClass $question, string $rowclasses): void {
|
||||
global $PAGE;
|
||||
|
||||
$this->display_start($question, $rowclasses);
|
||||
echo $PAGE->get_renderer('qbank_statistics')->render_facility_index(0.75);
|
||||
$this->display_end($question, $rowclasses);;
|
||||
}
|
||||
|
||||
public function get_extra_classes(): array {
|
||||
return ['pr-3'];
|
||||
}
|
||||
|
||||
@@ -210,10 +210,8 @@ Feature: Show statistics in question bank
|
||||
And I run the scheduled task "\quiz_statistics\task\recalculate"
|
||||
# Confirm the "Needs checking?" column matches the expected values based on students' answers
|
||||
When I am on the "Quiz 3" "mod_quiz > question bank" page logged in as "admin"
|
||||
Then the following should exist in the "categoryquestions" table:
|
||||
| Question | Needs checking? |
|
||||
| MCA | Likely |
|
||||
| MCB | Very likely |
|
||||
| MCC | Unlikely |
|
||||
| MCD | Likely |
|
||||
| MCE | Very likely |
|
||||
Then "Likely" "text" should exist in the "MCA" "table_row"
|
||||
And "Very likely" "text" should exist in the "MCB" "table_row"
|
||||
And "Unlikely" "text" should exist in the "MCC" "table_row"
|
||||
And "Likely" "text" should exist in the "MCD" "table_row"
|
||||
And "Very likely" "text" should exist in the "MCE" "table_row"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#categoryquestions td.questionlastused span.date {
|
||||
.question-bank-table td.questionlastused span.date {
|
||||
font-weight: 400;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ class question_name_idnumber_tags_column extends viewquestionname_column_helper
|
||||
// The non-breaking space ' ' is used in html to fix MDL-75051 (browser issues caused by chrome and Edge).
|
||||
if ($question->idnumber !== null && $question->idnumber !== '') {
|
||||
echo ' ' . \html_writer::span(
|
||||
\html_writer::span(get_string('idnumber', 'question'), 'accesshide')
|
||||
. ' ' . \html_writer::span(s($question->idnumber), 'badge badge-primary'), 'ml-1');
|
||||
\html_writer::span(get_string('idnumber', 'question') . ' ', 'accesshide')
|
||||
. \html_writer::span(s($question->idnumber), 'badge badge-primary'), 'ml-1');
|
||||
}
|
||||
|
||||
// Question tags.
|
||||
|
||||
@@ -72,4 +72,7 @@ class viewquestionname_column_helper extends column_base {
|
||||
return 'q.name';
|
||||
}
|
||||
|
||||
public function get_default_width(): int {
|
||||
return 250;
|
||||
}
|
||||
}
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
define("qbank_viewquestiontext/datafilter/filtertypes/showtext",["exports","core/datafilter/filtertype"],(function(_exports,_filtertype){var obj;
|
||||
/**
|
||||
* Filter managing question text display.
|
||||
*
|
||||
* @module qbank_viewquestiontext/datafilter/filtertypes/showtext
|
||||
* @author 2022 Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
|
||||
* @copyright 2022 Catalyst IT Australia Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_filtertype=(obj=_filtertype)&&obj.__esModule?obj:{default:obj};class _default extends _filtertype.default{}return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=showtext.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"showtext.min.js","sources":["../../../src/datafilter/filtertypes/showtext.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Filter managing question text display.\n *\n * @module qbank_viewquestiontext/datafilter/filtertypes/showtext\n * @author 2022 Ghaly Marc-Alexandre <[email protected]>\n * @copyright 2022 Catalyst IT Australia Pty Ltd\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport GenericFilter from 'core/datafilter/filtertype';\n\nexport default class extends GenericFilter {\n}\n"],"names":["GenericFilter"],"mappings":";;;;;;;;4KA0B6BA"}
|
||||
@@ -0,0 +1,11 @@
|
||||
define("qbank_viewquestiontext/question_text_format",["exports","qbank_viewquestiontext/repository","core_question/refresh_ui","core/notification"],(function(_exports,repository,_refresh_ui,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}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)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,repository=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}
|
||||
/**
|
||||
* Javascript for question_text_format question bank control.
|
||||
*
|
||||
* @module qbank_viewquestiontext/question_text_format
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/(repository),_refresh_ui=_interopRequireDefault(_refresh_ui),_notification=_interopRequireDefault(_notification);const SELECTORS_formatSelectId="question-text-format",SELECTORS_returnUrl="[name=returnurl]";let uiRoot;const handleFormatChange=async e=>{const value=e.target.value;try{await repository.setQuestionTextFormat(value);const returnUrlInput=e.target.closest("form").querySelector(SELECTORS_returnUrl),returnUrl=new URL(returnUrlInput.value);await _refresh_ui.default.refresh(uiRoot,returnUrl)}catch(ex){_notification.default.exception(ex)}};_exports.init=uiRootId=>{uiRoot=document.getElementById(uiRootId);document.getElementById(SELECTORS_formatSelectId).addEventListener("change",handleFormatChange)}}));
|
||||
|
||||
//# sourceMappingURL=question_text_format.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"question_text_format.min.js","sources":["../src/question_text_format.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript for question_text_format question bank control.\n *\n * @module qbank_viewquestiontext/question_text_format\n * @copyright 2023 Catalyst IT Europe Ltd.\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as repository from 'qbank_viewquestiontext/repository';\nimport RefreshUi from 'core_question/refresh_ui';\nimport Notification from 'core/notification';\n\nconst SELECTORS = {\n formatSelectId: 'question-text-format',\n returnUrl: '[name=returnurl]',\n};\n\nlet uiRoot;\n\n/**\n * Save the selected format via a web service call, and refresh the UI.\n *\n * @param {Event} e Select field change event.\n * @return {Promise<void>}\n */\nconst handleFormatChange = async(e) => {\n const value = e.target.value;\n try {\n await repository.setQuestionTextFormat(value);\n const returnUrlInput = e.target.closest('form').querySelector(SELECTORS.returnUrl);\n const returnUrl = new URL(returnUrlInput.value);\n await RefreshUi.refresh(uiRoot, returnUrl);\n } catch (ex) {\n Notification.exception(ex);\n }\n};\n\n/**\n * Initialise question text format widget.\n *\n * Find the uiRoot element and attach a change listener to the question text format selector.\n *\n * @param {String} uiRootId\n */\nexport const init = (uiRootId) => {\n uiRoot = document.getElementById(uiRootId);\n const select = document.getElementById(SELECTORS.formatSelectId);\n select.addEventListener('change', handleFormatChange);\n};\n"],"names":["SELECTORS","uiRoot","handleFormatChange","async","value","e","target","repository","setQuestionTextFormat","returnUrlInput","closest","querySelector","returnUrl","URL","RefreshUi","refresh","ex","exception","uiRootId","document","getElementById","addEventListener"],"mappings":";;;;;;;;4HA4BMA,yBACc,uBADdA,oBAES,uBAGXC,aAQEC,mBAAqBC,MAAAA,UACjBC,MAAQC,EAAEC,OAAOF,gBAEbG,WAAWC,sBAAsBJ,aACjCK,eAAiBJ,EAAEC,OAAOI,QAAQ,QAAQC,cAAcX,qBACxDY,UAAY,IAAIC,IAAIJ,eAAeL,aACnCU,oBAAUC,QAAQd,OAAQW,WAClC,MAAOI,0BACQC,UAAUD,oBAWVE,WACjBjB,OAASkB,SAASC,eAAeF,UAClBC,SAASC,eAAepB,0BAChCqB,iBAAiB,SAAUnB"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("qbank_viewquestiontext/repository",["exports","core/ajax"],(function(_exports,_ajax){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setQuestionTextFormat=void 0;_exports.setQuestionTextFormat=format=>(0,_ajax.call)([{methodname:"qbank_viewquestiontext_set_question_text_format",args:{format:format}}])[0]}));
|
||||
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"repository.min.js","sources":["../src/repository.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * External function calls for qbank_columnsortorder\n *\n * @module qbank_viewquestiontext/repository\n * @copyright 2023 Catalyst IT Europe Ltd.\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Set the question text format.\n *\n * @param {Number} format The question text format.\n * @return {Promise}\n */\nexport const setQuestionTextFormat = (format) => fetchMany([{\n methodname: 'qbank_viewquestiontext_set_question_text_format',\n args: {\n format,\n },\n}])[0];\n"],"names":["format","methodname","args"],"mappings":"0NAgCsCA,SAAW,cAAU,CAAC,CACxDC,WAAY,kDACZC,KAAM,CACFF,OAAAA,WAEJ"}
|
||||
@@ -0,0 +1,65 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Javascript for question_text_format question bank control.
|
||||
*
|
||||
* @module qbank_viewquestiontext/question_text_format
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import * as repository from 'qbank_viewquestiontext/repository';
|
||||
import RefreshUi from 'core_question/refresh_ui';
|
||||
import Notification from 'core/notification';
|
||||
|
||||
const SELECTORS = {
|
||||
formatSelectId: 'question-text-format',
|
||||
returnUrl: '[name=returnurl]',
|
||||
};
|
||||
|
||||
let uiRoot;
|
||||
|
||||
/**
|
||||
* Save the selected format via a web service call, and refresh the UI.
|
||||
*
|
||||
* @param {Event} e Select field change event.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
const handleFormatChange = async(e) => {
|
||||
const value = e.target.value;
|
||||
try {
|
||||
await repository.setQuestionTextFormat(value);
|
||||
const returnUrlInput = e.target.closest('form').querySelector(SELECTORS.returnUrl);
|
||||
const returnUrl = new URL(returnUrlInput.value);
|
||||
await RefreshUi.refresh(uiRoot, returnUrl);
|
||||
} catch (ex) {
|
||||
Notification.exception(ex);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise question text format widget.
|
||||
*
|
||||
* Find the uiRoot element and attach a change listener to the question text format selector.
|
||||
*
|
||||
* @param {String} uiRootId
|
||||
*/
|
||||
export const init = (uiRootId) => {
|
||||
uiRoot = document.getElementById(uiRootId);
|
||||
const select = document.getElementById(SELECTORS.formatSelectId);
|
||||
select.addEventListener('change', handleFormatChange);
|
||||
};
|
||||
+17
-7
@@ -14,15 +14,25 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Filter managing question text display.
|
||||
* External function calls for qbank_columnsortorder
|
||||
*
|
||||
* @module qbank_viewquestiontext/datafilter/filtertypes/showtext
|
||||
* @author 2022 Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
|
||||
* @copyright 2022 Catalyst IT Australia Pty Ltd
|
||||
* @module qbank_viewquestiontext/repository
|
||||
* @copyright 2023 Catalyst IT Europe Ltd.
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import GenericFilter from 'core/datafilter/filtertype';
|
||||
import {call as fetchMany} from 'core/ajax';
|
||||
|
||||
export default class extends GenericFilter {
|
||||
}
|
||||
/**
|
||||
* Set the question text format.
|
||||
*
|
||||
* @param {Number} format The question text format.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const setQuestionTextFormat = (format) => fetchMany([{
|
||||
methodname: 'qbank_viewquestiontext_set_question_text_format',
|
||||
args: {
|
||||
format,
|
||||
},
|
||||
}])[0];
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_viewquestiontext\external;
|
||||
|
||||
use context_system;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_value;
|
||||
use qbank_viewquestiontext\output\question_text_format;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
|
||||
/**
|
||||
* External function for setting the question text format.
|
||||
*
|
||||
* @package qbank_viewquestiontext
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_question_text_format extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'format' => new external_value(PARAM_INT, 'Format for the question text', VALUE_REQUIRED),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value.
|
||||
*/
|
||||
public static function execute_returns(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the question text format preference for the current user.
|
||||
*
|
||||
* @param int $format Format for the question text.
|
||||
*/
|
||||
public static function execute(int $format): void {
|
||||
[
|
||||
'format' => $format,
|
||||
] = self::validate_parameters(
|
||||
self::execute_parameters(),
|
||||
[
|
||||
'format' => $format,
|
||||
]
|
||||
);
|
||||
|
||||
if (!in_array($format, [question_text_format::OFF, question_text_format::PLAIN, question_text_format::FULL])) {
|
||||
throw new \invalid_parameter_exception('$format must be one of question_text_format::OFF, ::PLAIN or ::FULL.');
|
||||
}
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
\question_set_or_get_user_preference('qbshowtext', $format, 0, new \moodle_url('/'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_viewquestiontext\output;
|
||||
|
||||
use core_question\local\bank\view;
|
||||
use qbank_viewquestiontext\question_text_row;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Question text format selector.
|
||||
*
|
||||
* @package qbank_viewquestiontext
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_text_format implements \renderable, \templatable {
|
||||
/**
|
||||
* @var int Question text is off.
|
||||
*/
|
||||
const OFF = 0;
|
||||
|
||||
/**
|
||||
* @var int Question text is displayed in plain text mode.
|
||||
*/
|
||||
const PLAIN = 1;
|
||||
|
||||
/**
|
||||
* @var int Question text is displayed fully rendered.
|
||||
*/
|
||||
const FULL = 2;
|
||||
|
||||
/** @var int|mixed The current display preference value. */
|
||||
protected int $preference;
|
||||
|
||||
/**
|
||||
* @var \moodle_url The return URL for redirecting back to the current question bank page.
|
||||
*/
|
||||
protected \moodle_url $returnurl;
|
||||
|
||||
/**
|
||||
* Store the returnurl and the current preference value.
|
||||
*
|
||||
* @param view $qbank
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function __construct(view $qbank) {
|
||||
$row = new question_text_row($qbank);
|
||||
$this->returnurl = new \moodle_url($qbank->returnurl);
|
||||
$this->preference = question_get_display_preference($row->get_preference_key(), 0, PARAM_INT, new \moodle_url(''));
|
||||
}
|
||||
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
return [
|
||||
'formaction' => new \moodle_url('/question/bank/viewquestiontext/save.php'),
|
||||
'sesskey' => sesskey(),
|
||||
'returnurl' => $this->returnurl->out(false),
|
||||
'options' => [
|
||||
(object)[
|
||||
'label' => get_string('showquestiontext_off', 'question'),
|
||||
'value' => self::OFF,
|
||||
'selected' => $this->preference === self::OFF,
|
||||
],
|
||||
(object)[
|
||||
'label' => get_string('showquestiontext_plain', 'question'),
|
||||
'value' => self::PLAIN,
|
||||
'selected' => $this->preference === self::PLAIN,
|
||||
],
|
||||
(object)[
|
||||
'label' => get_string('showquestiontext_full', 'question'),
|
||||
'value' => self::FULL,
|
||||
'selected' => $this->preference === self::FULL,
|
||||
],
|
||||
],
|
||||
'label' => get_string('showquestiontext', 'core_question'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
namespace qbank_viewquestiontext;
|
||||
|
||||
use core\context;
|
||||
use core_question\local\bank\plugin_features_base;
|
||||
use core_question\local\bank\view;
|
||||
use qbank_viewquestiontext\output\question_text_format;
|
||||
|
||||
/**
|
||||
* Class columns is the entrypoint for the columns.
|
||||
@@ -29,15 +31,27 @@ use core_question\local\bank\view;
|
||||
*/
|
||||
class plugin_feature extends plugin_features_base {
|
||||
|
||||
public function get_question_columns($qbank): array {
|
||||
return [
|
||||
new question_text_row($qbank)
|
||||
];
|
||||
/**
|
||||
* Return an additional row for displaying the question text, if user has a preference set to display it.
|
||||
*
|
||||
* @param view $qbank
|
||||
* @return array
|
||||
*/
|
||||
public function get_question_columns(view $qbank): array {
|
||||
$row = new question_text_row($qbank);
|
||||
$preference = (int)question_get_display_preference($row->get_preference_key(), '0', PARAM_INT, new \moodle_url('/'));
|
||||
if ($preference != question_text_format::OFF) {
|
||||
return [
|
||||
$row,
|
||||
];
|
||||
}
|
||||
return [];
|
||||
|
||||
}
|
||||
|
||||
public function get_question_filters(view $qbank = null): array {
|
||||
public function get_question_bank_controls(view $qbank, context $context, int $categoryid): array {
|
||||
return [
|
||||
new questiontext_condition($qbank),
|
||||
400 => new question_text_format($qbank),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
namespace qbank_viewquestiontext;
|
||||
|
||||
use core_question\local\bank\row_base;
|
||||
use qbank_viewquestiontext\output\question_text_format;
|
||||
use question_utils;
|
||||
|
||||
/**
|
||||
@@ -29,8 +30,8 @@ use question_utils;
|
||||
*/
|
||||
class question_text_row extends row_base {
|
||||
|
||||
/** @var bool if true, we will show the question text reduced to plain text, else it is fully rendered. */
|
||||
protected $plain;
|
||||
/** @var int if true, we will show the question text reduced to plain text, else it is fully rendered. */
|
||||
protected $preference;
|
||||
|
||||
/** @var \stdClass $formatoptions options used when displaying the question text as HTML. */
|
||||
protected $formatoptions;
|
||||
@@ -38,8 +39,7 @@ class question_text_row extends row_base {
|
||||
protected function init(): void {
|
||||
|
||||
// Cannot use $this->get_preference because of PHP type hints.
|
||||
$preference = question_get_display_preference($this->get_preference_key(), 0, PARAM_INT, new \moodle_url(''));
|
||||
$this->plain = 1 === (int) $preference;
|
||||
$this->preference = (int)question_get_display_preference($this->get_preference_key(), 0, PARAM_INT, new \moodle_url(''));
|
||||
$this->formatoptions = new \stdClass();
|
||||
$this->formatoptions->noclean = true;
|
||||
$this->formatoptions->para = false;
|
||||
@@ -55,14 +55,12 @@ class question_text_row extends row_base {
|
||||
|
||||
protected function display_content($question, $rowclasses): void {
|
||||
// Access 'showtext' filter from pagevars.
|
||||
$display = $this->qbank->get_pagevars('filter')['showtext'] ?? null;
|
||||
if ($display) {
|
||||
$showtext = (int)$display['values'][0];
|
||||
if ($this->preference !== question_text_format::OFF) {
|
||||
$text = '';
|
||||
if ($showtext === questiontext_condition::PLAIN) {
|
||||
if ($this->preference === question_text_format::PLAIN) {
|
||||
$text = question_utils::to_plain_text($question->questiontext,
|
||||
$question->questiontextformat, ['noclean' => true, 'para' => false, 'filter' => false]);
|
||||
} else if ($showtext === questiontext_condition::FULL) {
|
||||
} else if ($this->preference === question_text_format::FULL) {
|
||||
$text = question_rewrite_question_preview_urls($question->questiontext, $question->id,
|
||||
$question->contextid, 'question', 'questiontext', $question->id,
|
||||
$question->contextid, 'core_question');
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace qbank_viewquestiontext;
|
||||
|
||||
use core\output\datafilter;
|
||||
use core_question\local\bank\condition;
|
||||
use core_question\local\bank\view;
|
||||
|
||||
/**
|
||||
* This class controls from which category questions are listed.
|
||||
*
|
||||
* @package qbank_viewquestiontext
|
||||
* @copyright 2022 Catalyst IT Australia Pty Ltd
|
||||
* @author Ghaly Marc-Alexandre <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class questiontext_condition extends condition {
|
||||
|
||||
/**
|
||||
* @var int Question text is off.
|
||||
*/
|
||||
const OFF = 0;
|
||||
|
||||
/**
|
||||
* @var int Question text is displayed in plain text mode.
|
||||
*/
|
||||
const PLAIN = 1;
|
||||
|
||||
/**
|
||||
* @var int Question text is displayed fully rendered.
|
||||
*/
|
||||
const FULL = 2;
|
||||
|
||||
/**
|
||||
* @var ?int $showtext Initial value of the filter, for determining the pre-selected option.
|
||||
*/
|
||||
protected ?int $showtext = null;
|
||||
|
||||
public function __construct(view $qbank = null) {
|
||||
if (is_null($qbank)) {
|
||||
return;
|
||||
}
|
||||
$filter = $qbank->get_pagevars('filter');
|
||||
if (isset($filter['showtext'])) {
|
||||
$this->showtext = (int)$filter['showtext']['values'][0];
|
||||
}
|
||||
}
|
||||
|
||||
public function allow_custom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function allow_multiple() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_condition_key() {
|
||||
return 'showtext';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return get_string('showquestiontext', 'core_question');
|
||||
}
|
||||
|
||||
public function get_join_list(): array {
|
||||
return [
|
||||
datafilter::JOINTYPE_ANY,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_filter_class() {
|
||||
return 'qbank_viewquestiontext/datafilter/filtertypes/showtext';
|
||||
}
|
||||
|
||||
public function get_initial_values() {
|
||||
return [
|
||||
[
|
||||
'value' => self::OFF,
|
||||
'title' => get_string('showquestiontext_off', 'question'),
|
||||
'selected' => $this->showtext === self::OFF,
|
||||
],
|
||||
[
|
||||
'value' => self::PLAIN,
|
||||
'title' => get_string('showquestiontext_plain', 'question'),
|
||||
'selected' => $this->showtext === self::PLAIN,
|
||||
],
|
||||
[
|
||||
'value' => self::FULL,
|
||||
'title' => get_string('showquestiontext_full', 'question'),
|
||||
'selected' => $this->showtext === self::FULL,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* qbank_viewquestiontext external functions and service definitions.
|
||||
*
|
||||
* @package qbank_viewquestiontext
|
||||
* @category webservice
|
||||
* @copyright 2023 Catalyst IT Europe Ltd
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'qbank_viewquestiontext_set_question_text_format' => [
|
||||
'classname' => 'qbank_viewquestiontext\external\set_question_text_format',
|
||||
'description' => 'Sets the preference for displaying and formatting the question text',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Synchronously save the question text display preference, and redirect back to the previous page.
|
||||
*
|
||||
* This is progressively enhanced by question_text_format.js, but this remains as a fallback.
|
||||
*
|
||||
* @package qbank_viewquestiontext
|
||||
* @copyright 2023 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../../config.php');
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
|
||||
$format = required_param('format', PARAM_INT);
|
||||
$returnurl = required_param('returnurl', PARAM_LOCALURL);
|
||||
|
||||
require_login();
|
||||
require_sesskey();
|
||||
|
||||
$validformats = [
|
||||
\qbank_viewquestiontext\output\question_text_format::OFF,
|
||||
\qbank_viewquestiontext\output\question_text_format::PLAIN,
|
||||
\qbank_viewquestiontext\output\question_text_format::FULL,
|
||||
];
|
||||
if (!in_array($format, $validformats)) {
|
||||
throw new \invalid_parameter_exception('$format must be one of question_text_format::OFF, ::PLAIN or ::FULL.');
|
||||
}
|
||||
|
||||
question_set_or_get_user_preference('qbshowtext', $format, 0, new \moodle_url('/'));
|
||||
|
||||
redirect(new moodle_url($returnurl));
|
||||
@@ -0,0 +1,3 @@
|
||||
.jsenabled .question-text-format .input-group-append {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template qbank_viewquestiontext/question_text_format
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"label": "Question text format",
|
||||
"options": [
|
||||
{
|
||||
"value": 1,
|
||||
"label": "Plain text",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"label": "Fully rendered",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<form class="question-text-format ml-1" action="{{formaction}}">
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}">
|
||||
<input type="hidden" name="returnurl" value="{{returnurl}}">
|
||||
<div class="input-group">
|
||||
<label class="input-group-prepend" for="question-text-format">
|
||||
<span class="input-group-text">{{label}}</span>
|
||||
</label>
|
||||
<select class="form-control" name="format" id="question-text-format">
|
||||
{{#options}}
|
||||
<option value="{{value}}"{{#selected}} selected{{/selected}}>{{label}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-dark mb-2">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{#js}}
|
||||
require(['qbank_viewquestiontext/question_text_format'], QuestionTextFormat => {
|
||||
QuestionTextFormat.init('questionscontainer');
|
||||
});
|
||||
{{/js}}
|
||||
@@ -19,19 +19,19 @@ Feature: Use the qbank plugin manager page for viewquestiontext
|
||||
@javascript
|
||||
Scenario: Display of plain question text can be turned on and off
|
||||
When I am on the "Test quiz" "mod_quiz > question bank" page logged in as admin
|
||||
And I apply question bank filter "Show question text in the question list?" with value "text only"
|
||||
And I set the field "Show question text in the question list?" to "text only"
|
||||
Then I should see "Answer the first question"
|
||||
And ".totestforhtml" "css_element" should not exist in the "Answer the first question" "table_row"
|
||||
And I apply question bank filter "Show question text in the question list?" with value "No"
|
||||
And I set the field "Show question text in the question list?" to "No"
|
||||
And I should not see "Answer the first question"
|
||||
|
||||
@javascript
|
||||
Scenario: Display of full question text can be turned on and off
|
||||
When I am on the "Test quiz" "mod_quiz > question bank" page logged in as admin
|
||||
And I apply question bank filter "Show question text in the question list?" with value "with images"
|
||||
And I set the field "Show question text in the question list?" to "with images"
|
||||
Then I should see "Answer the first question"
|
||||
And ".totestforhtml" "css_element" should exist in the "Answer the first question" "table_row"
|
||||
And I apply question bank filter "Show question text in the question list?" with value "No"
|
||||
And I set the field "Show question text in the question list?" to "No"
|
||||
And I should not see "Answer the first question"
|
||||
|
||||
@javascript
|
||||
@@ -53,5 +53,5 @@ Feature: Use the qbank plugin manager page for viewquestiontext
|
||||
And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
|
||||
And I click on "Enable" "link" in the "View question text" "table_row"
|
||||
And I am on the "Test quiz" "mod_quiz > question bank" page
|
||||
When I apply question bank filter "Show question text in the question list?" with value "text only"
|
||||
When I set the field "Show question text in the question list?" to "text only"
|
||||
And I should see "Answer the first question"
|
||||
|
||||
@@ -26,6 +26,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'qbank_viewquestiontext';
|
||||
$plugin->version = 2023042400;
|
||||
$plugin->version = 2023042401;
|
||||
$plugin->requires = 2023041800;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
|
||||
@@ -52,4 +52,7 @@ class question_type_column extends column_base {
|
||||
return 'q.qtype';
|
||||
}
|
||||
|
||||
public function get_default_width(): int {
|
||||
return 45;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user