From 33e52fe4ed115f6e1488206e28c0c9bb7b586159 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Tue, 5 Sep 2023 16:25:59 +0100 Subject: [PATCH] MDL-74054 qbank_viewquestiontext: Convert from filter to question bank control This replaces the "Show question text in the question list?" filter, which was never really a filter, with a new widget displayed alongside other question bank controls like "Create a new question" and "Reset columns". It also refactors the logic of displaying the question text field or not, so that it is all handled within the qbank_viewquestiontext plugin rather than relying on code in the view. --- question/amd/build/refresh_ui.min.js | 10 ++ question/amd/build/refresh_ui.min.js.map | 1 + question/amd/src/refresh_ui.js | 65 +++++++++++ .../columnsortorder/amd/build/actions.min.js | 4 +- .../amd/build/actions.min.js.map | 2 +- .../bank/columnsortorder/amd/src/actions.js | 27 +---- .../datafilter/filtertypes/showtext.min.js | 11 -- .../filtertypes/showtext.min.js.map | 1 - .../amd/build/question_text_format.min.js | 11 ++ .../amd/build/question_text_format.min.js.map | 1 + .../amd/build/repository.min.js | 3 + .../amd/build/repository.min.js.map | 1 + .../amd/src/question_text_format.js | 65 +++++++++++ .../viewquestiontext/amd/src/repository.js | 41 +++++++ .../external/set_question_text_format.php | 78 +++++++++++++ .../classes/output/question_text_format.php | 93 +++++++++++++++ .../classes/plugin_feature.php | 26 ++++- .../classes/question_text_row.php | 16 ++- .../classes/questiontext_condition.php | 108 ------------------ .../showtext.js => db/services.php} | 22 ++-- question/bank/viewquestiontext/save.php | 48 ++++++++ question/bank/viewquestiontext/styles.css | 3 + .../templates/question_text_format.mustache | 58 ++++++++++ .../behat/view_question_text_column.feature | 10 +- question/bank/viewquestiontext/version.php | 2 +- question/classes/local/bank/view.php | 5 - question/tests/behat/sort_questions.feature | 2 +- 27 files changed, 532 insertions(+), 182 deletions(-) create mode 100644 question/amd/build/refresh_ui.min.js create mode 100644 question/amd/build/refresh_ui.min.js.map create mode 100644 question/amd/src/refresh_ui.js delete mode 100644 question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js delete mode 100644 question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js.map create mode 100644 question/bank/viewquestiontext/amd/build/question_text_format.min.js create mode 100644 question/bank/viewquestiontext/amd/build/question_text_format.min.js.map create mode 100644 question/bank/viewquestiontext/amd/build/repository.min.js create mode 100644 question/bank/viewquestiontext/amd/build/repository.min.js.map create mode 100644 question/bank/viewquestiontext/amd/src/question_text_format.js create mode 100644 question/bank/viewquestiontext/amd/src/repository.js create mode 100644 question/bank/viewquestiontext/classes/external/set_question_text_format.php create mode 100644 question/bank/viewquestiontext/classes/output/question_text_format.php delete mode 100644 question/bank/viewquestiontext/classes/questiontext_condition.php rename question/bank/viewquestiontext/{amd/src/datafilter/filtertypes/showtext.js => db/services.php} (56%) create mode 100644 question/bank/viewquestiontext/save.php create mode 100644 question/bank/viewquestiontext/styles.css create mode 100644 question/bank/viewquestiontext/templates/question_text_format.mustache diff --git a/question/amd/build/refresh_ui.min.js b/question/amd/build/refresh_ui.min.js new file mode 100644 index 00000000000..14fe30fe992 --- /dev/null +++ b/question/amd/build/refresh_ui.min.js @@ -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 \ No newline at end of file diff --git a/question/amd/build/refresh_ui.min.js.map b/question/amd/build/refresh_ui.min.js.map new file mode 100644 index 00000000000..3a5f92fddae --- /dev/null +++ b/question/amd/build/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 .\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"} \ No newline at end of file diff --git a/question/amd/src/refresh_ui.js b/question/amd/src/refresh_ui.js new file mode 100644 index 00000000000..1b0708802e4 --- /dev/null +++ b/question/amd/src/refresh_ui.js @@ -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 . + +/** + * 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); + }); + } +}; diff --git a/question/bank/columnsortorder/amd/build/actions.min.js b/question/bank/columnsortorder/amd/build/actions.min.js index 08142abbd66..29d3392df3f 100644 --- a/question/bank/columnsortorder/amd/build/actions.min.js +++ b/question/bank/columnsortorder/amd/build/actions.min.js @@ -1,4 +1,4 @@ -define("qbank_columnsortorder/actions",["exports","core/sortable_list","jquery","qbank_columnsortorder/repository","core/notification","core/fragment","core/templates"],(function(_exports,_sortable_list,_jquery,repository,_notification,_fragment,_templates){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}} +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. * @@ -6,6 +6,6 @@ define("qbank_columnsortorder/actions",["exports","core/sortable_list","jquery", * @copyright 2023 onwards Catalyst IT Europe Ltd * @author Mark Johnson * @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),_fragment=_interopRequireDefault(_fragment),_templates=_interopRequireDefault(_templates);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 Promise.all([repository.setColumnbankOrder([],global),repository.setHiddenColumns([],global),repository.setColumnSize("",global)]);const fragmentData=uiRoot.dataset,actionUrl=new URL(actionLink.href),returnUrl=new URL(actionUrl.searchParams.get("returnurl").replaceAll("&","&")),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))).catch(_notification.default.exception)}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})); + */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 Promise.all([repository.setColumnbankOrder([],global),repository.setHiddenColumns([],global),repository.setColumnSize("",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 \ No newline at end of file diff --git a/question/bank/columnsortorder/amd/build/actions.min.js.map b/question/bank/columnsortorder/amd/build/actions.min.js.map index 9c61b52c8de..e5c28ba497c 100644 --- a/question/bank/columnsortorder/amd/build/actions.min.js.map +++ b/question/bank/columnsortorder/amd/build/actions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"actions.min.js","sources":["../src/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 .\n\n/**\n * Common javascript for handling actions on the admin page and the user's view of the question bank.\n *\n * @module qbank_columnsortorder/actions\n * @copyright 2023 onwards Catalyst IT Europe Ltd\n * @author Mark Johnson \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport SortableList from 'core/sortable_list';\nimport $ from 'jquery';\nimport * as repository from 'qbank_columnsortorder/repository';\nimport Notification from \"core/notification\";\nimport Fragment from \"core/fragment\";\nimport Templates from \"core/templates\";\n\nexport const SELECTORS = {\n columnList: '.qbank-column-list',\n sortableColumn: '.qbank-sortable-column',\n removeLink: '[data-action=remove]',\n moveHandler: '[data-drag-type=move]',\n addColumn: '.addcolumn',\n addLink: '[data-action=add]',\n actionLink: '.action-link',\n};\n\n/**\n * Sets up sortable list in the column sort order page.\n *\n * @param {Element} listRoot Element containing the sortable list.\n * @param {Boolean} vertical Is the list in vertical orientation, rather than horizonal?\n * @param {Boolean} global Should changes be saved to global config, rather than user preferences?\n * @return {jQuery} sortable column elements, for attaching additional event listeners.\n */\nexport const setupSortableLists = (listRoot, vertical = false, global = false) => {\n const sortableList = new SortableList(listRoot, {\n moveHandlerSelector: SELECTORS.moveHandler,\n isHorizontal: !vertical,\n });\n sortableList.getElementName = element => Promise.resolve(element.data('name'));\n\n const sortableColumns = $(SELECTORS.sortableColumn);\n\n sortableColumns.on(SortableList.EVENTS.DROP, () => {\n repository.setColumnbankOrder(getColumnOrder(listRoot), global).catch(Notification.exception);\n listRoot.querySelectorAll(SELECTORS.sortableColumn).forEach(item => item.classList.remove('active'));\n });\n\n sortableColumns.on(SortableList.EVENTS.DRAGSTART, (event) => {\n event.currentTarget.classList.add('active');\n });\n\n return sortableColumns;\n};\n\n/**\n * Set up event handlers for action buttons.\n *\n * For each action, call the web service to update the appropriate setting or user preference, then call the fragment to\n * refresh the view.\n *\n * @param {Element} uiRoot The root of the question bank UI.\n * @param {Boolean} global Should changes be saved to global config, rather than user preferences?\n */\nexport const setupActionButtons = (uiRoot, global = false) => {\n uiRoot.addEventListener('click', async(e) => {\n const actionLink = e.target.closest(SELECTORS.actionLink);\n if (!actionLink) {\n return;\n }\n try {\n e.preventDefault();\n const action = actionLink.dataset.action;\n if (action === 'add' || action === 'remove') {\n const hiddenColumns = [];\n const addColumnList = document.querySelector(SELECTORS.addColumn);\n if (addColumnList) {\n addColumnList.querySelectorAll(SELECTORS.addLink).forEach(item => {\n if (action === 'add' && item === actionLink) {\n return;\n }\n hiddenColumns.push(item.dataset.column);\n });\n }\n if (action === 'remove') {\n hiddenColumns.push(actionLink.dataset.column);\n }\n await repository.setHiddenColumns(hiddenColumns, global);\n } else if (action === 'reset') {\n await Promise.all([\n repository.setColumnbankOrder([], global),\n repository.setHiddenColumns([], global),\n repository.setColumnSize('', global),\n ]);\n }\n const fragmentData = uiRoot.dataset;\n const actionUrl = new URL(actionLink.href);\n const returnUrl = new URL(actionUrl.searchParams.get('returnurl').replaceAll('&', '&'));\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 return Templates.replaceNode(uiRoot, html, js);\n })\n .catch(Notification.exception);\n } catch (ex) {\n await Notification.exception(ex);\n }\n });\n};\n\n/**\n * Gets the newly reordered columns to display in the question bank view.\n * @param {Element} listRoot\n * @returns {Array}\n */\nexport const getColumnOrder = listRoot => {\n const columns = Array.from(listRoot.querySelectorAll('[data-columnid]'))\n .map(column => column.dataset.columnid);\n\n return columns.filter((value, index) => columns.indexOf(value) === index);\n};\n"],"names":["SELECTORS","columnList","sortableColumn","removeLink","moveHandler","addColumn","addLink","actionLink","listRoot","vertical","global","sortableList","SortableList","moveHandlerSelector","isHorizontal","getElementName","element","Promise","resolve","data","sortableColumns","on","EVENTS","DROP","repository","setColumnbankOrder","getColumnOrder","catch","Notification","exception","querySelectorAll","forEach","item","classList","remove","DRAGSTART","event","currentTarget","add","uiRoot","addEventListener","async","e","target","closest","preventDefault","action","dataset","hiddenColumns","addColumnList","document","querySelector","push","column","setHiddenColumns","all","setColumnSize","fragmentData","actionUrl","URL","href","returnUrl","searchParams","get","replaceAll","viewData","sortData","value","key","sortItem","match","pop","sortdata","JSON","stringify","loadFragment","component","callback","contextid","then","html","js","Templates","replaceNode","ex","columns","Array","from","map","columnid","filter","index","indexOf"],"mappings":";;;;;;;;6jCA+BaA,UAAY,CACrBC,WAAY,qBACZC,eAAgB,yBAChBC,WAAY,uBACZC,YAAa,wBACbC,UAAW,aACXC,QAAS,oBACTC,WAAY,yEAWkB,SAACC,cAAUC,iEAAkBC,qEACrDC,aAAe,IAAIC,uBAAaJ,SAAU,CAC5CK,oBAAqBb,UAAUI,YAC/BU,cAAeL,WAEnBE,aAAaI,eAAiBC,SAAWC,QAAQC,QAAQF,QAAQG,KAAK,eAEhEC,iBAAkB,mBAAEpB,UAAUE,uBAEpCkB,gBAAgBC,GAAGT,uBAAaU,OAAOC,MAAM,KACzCC,WAAWC,mBAAmBC,eAAelB,UAAWE,QAAQiB,MAAMC,sBAAaC,WACnFrB,SAASsB,iBAAiB9B,UAAUE,gBAAgB6B,SAAQC,MAAQA,KAAKC,UAAUC,OAAO,eAG9Fd,gBAAgBC,GAAGT,uBAAaU,OAAOa,WAAYC,QAC/CA,MAAMC,cAAcJ,UAAUK,IAAI,aAG/BlB,6CAYuB,SAACmB,YAAQ7B,+DACvC6B,OAAOC,iBAAiB,SAASC,MAAAA,UACvBlC,WAAamC,EAAEC,OAAOC,QAAQ5C,UAAUO,eACzCA,eAIDmC,EAAEG,uBACIC,OAASvC,WAAWwC,QAAQD,UACnB,QAAXA,QAA+B,WAAXA,OAAqB,OACnCE,cAAgB,GAChBC,cAAgBC,SAASC,cAAcnD,UAAUK,WACnD4C,eACAA,cAAcnB,iBAAiB9B,UAAUM,SAASyB,SAAQC,OACvC,QAAXc,QAAoBd,OAASzB,YAGjCyC,cAAcI,KAAKpB,KAAKe,QAAQM,WAGzB,WAAXP,QACAE,cAAcI,KAAK7C,WAAWwC,QAAQM,cAEpC7B,WAAW8B,iBAAiBN,cAAetC,YAC/B,UAAXoC,cACD7B,QAAQsC,IAAI,CACd/B,WAAWC,mBAAmB,GAAIf,QAClCc,WAAW8B,iBAAiB,GAAI5C,QAChCc,WAAWgC,cAAc,GAAI9C,gBAG/B+C,aAAelB,OAAOQ,QACtBW,UAAY,IAAIC,IAAIpD,WAAWqD,MAC/BC,UAAY,IAAIF,IAAID,UAAUI,aAAaC,IAAI,aAAaC,WAAW,QAAS,MAChFC,SAAW,GACXC,SAAW,GACbL,WACAA,UAAUC,aAAa/B,SAAQ,CAACoC,MAAOC,aAG7BC,SAAWD,IAAIE,MAAM,wBACvBD,SAEAH,SAASG,SAASE,OAASJ,MAE3BF,SAASG,KAAOD,SAI5BF,SAASO,SAAWC,KAAKC,UAAUR,4BAE1BS,aAAalB,aAAamB,UAAWnB,aAAaoB,SAAUpB,aAAaqB,UAAWb,UACxFc,MAAK,CAACC,KAAMC,KACFC,mBAAUC,YAAY5C,OAAQyC,KAAMC,MAE9CtD,MAAMC,sBAAaC,WAC1B,MAAOuD,UACCxD,sBAAaC,UAAUuD,eAU5B1D,eAAiBlB,iBACpB6E,QAAUC,MAAMC,KAAK/E,SAASsB,iBAAiB,oBAChD0D,KAAInC,QAAUA,OAAON,QAAQ0C,kBAE3BJ,QAAQK,QAAO,CAACvB,MAAOwB,QAAUN,QAAQO,QAAQzB,SAAWwB"} \ No newline at end of file +{"version":3,"file":"actions.min.js","sources":["../src/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 .\n\n/**\n * Common javascript for handling actions on the admin page and the user's view of the question bank.\n *\n * @module qbank_columnsortorder/actions\n * @copyright 2023 onwards Catalyst IT Europe Ltd\n * @author Mark Johnson \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport SortableList from 'core/sortable_list';\nimport $ from 'jquery';\nimport * as repository from 'qbank_columnsortorder/repository';\nimport Notification from \"core/notification\";\nimport RefreshUi from 'core_question/refresh_ui';\n\nexport const SELECTORS = {\n columnList: '.qbank-column-list',\n sortableColumn: '.qbank-sortable-column',\n removeLink: '[data-action=remove]',\n moveHandler: '[data-drag-type=move]',\n addColumn: '.addcolumn',\n addLink: '[data-action=add]',\n actionLink: '.action-link',\n};\n\n/**\n * Sets up sortable list in the column sort order page.\n *\n * @param {Element} listRoot Element containing the sortable list.\n * @param {Boolean} vertical Is the list in vertical orientation, rather than horizonal?\n * @param {Boolean} global Should changes be saved to global config, rather than user preferences?\n * @return {jQuery} sortable column elements, for attaching additional event listeners.\n */\nexport const setupSortableLists = (listRoot, vertical = false, global = false) => {\n const sortableList = new SortableList(listRoot, {\n moveHandlerSelector: SELECTORS.moveHandler,\n isHorizontal: !vertical,\n });\n sortableList.getElementName = element => Promise.resolve(element.data('name'));\n\n const sortableColumns = $(SELECTORS.sortableColumn);\n\n sortableColumns.on(SortableList.EVENTS.DROP, () => {\n repository.setColumnbankOrder(getColumnOrder(listRoot), global).catch(Notification.exception);\n listRoot.querySelectorAll(SELECTORS.sortableColumn).forEach(item => item.classList.remove('active'));\n });\n\n sortableColumns.on(SortableList.EVENTS.DRAGSTART, (event) => {\n event.currentTarget.classList.add('active');\n });\n\n return sortableColumns;\n};\n\n/**\n * Set up event handlers for action buttons.\n *\n * For each action, call the web service to update the appropriate setting or user preference, then call the fragment to\n * refresh the view.\n *\n * @param {Element} uiRoot The root of the question bank UI.\n * @param {Boolean} global Should changes be saved to global config, rather than user preferences?\n */\nexport const setupActionButtons = (uiRoot, global = false) => {\n uiRoot.addEventListener('click', async(e) => {\n const actionLink = e.target.closest(SELECTORS.actionLink);\n if (!actionLink) {\n return;\n }\n try {\n e.preventDefault();\n const action = actionLink.dataset.action;\n if (action === 'add' || action === 'remove') {\n const hiddenColumns = [];\n const addColumnList = document.querySelector(SELECTORS.addColumn);\n if (addColumnList) {\n addColumnList.querySelectorAll(SELECTORS.addLink).forEach(item => {\n if (action === 'add' && item === actionLink) {\n return;\n }\n hiddenColumns.push(item.dataset.column);\n });\n }\n if (action === 'remove') {\n hiddenColumns.push(actionLink.dataset.column);\n }\n await repository.setHiddenColumns(hiddenColumns, global);\n } else if (action === 'reset') {\n await Promise.all([\n repository.setColumnbankOrder([], global),\n repository.setHiddenColumns([], global),\n repository.setColumnSize('', global),\n ]);\n }\n const actionUrl = new URL(actionLink.href);\n const returnUrl = new URL(actionUrl.searchParams.get('returnurl').replaceAll('&', '&'));\n await RefreshUi.refresh(uiRoot, returnUrl);\n } catch (ex) {\n await Notification.exception(ex);\n }\n });\n};\n\n/**\n * Gets the newly reordered columns to display in the question bank view.\n * @param {Element} listRoot\n * @returns {Array}\n */\nexport const getColumnOrder = listRoot => {\n const columns = Array.from(listRoot.querySelectorAll('[data-columnid]'))\n .map(column => column.dataset.columnid);\n\n return columns.filter((value, index) => columns.indexOf(value) === index);\n};\n"],"names":["SELECTORS","columnList","sortableColumn","removeLink","moveHandler","addColumn","addLink","actionLink","listRoot","vertical","global","sortableList","SortableList","moveHandlerSelector","isHorizontal","getElementName","element","Promise","resolve","data","sortableColumns","on","EVENTS","DROP","repository","setColumnbankOrder","getColumnOrder","catch","Notification","exception","querySelectorAll","forEach","item","classList","remove","DRAGSTART","event","currentTarget","add","uiRoot","addEventListener","async","e","target","closest","preventDefault","action","dataset","hiddenColumns","addColumnList","document","querySelector","push","column","setHiddenColumns","all","setColumnSize","actionUrl","URL","href","returnUrl","searchParams","get","replaceAll","RefreshUi","refresh","ex","columns","Array","from","map","columnid","filter","value","index","indexOf"],"mappings":";;;;;;;;mhCA8BaA,UAAY,CACrBC,WAAY,qBACZC,eAAgB,yBAChBC,WAAY,uBACZC,YAAa,wBACbC,UAAW,aACXC,QAAS,oBACTC,WAAY,yEAWkB,SAACC,cAAUC,iEAAkBC,qEACrDC,aAAe,IAAIC,uBAAaJ,SAAU,CAC5CK,oBAAqBb,UAAUI,YAC/BU,cAAeL,WAEnBE,aAAaI,eAAiBC,SAAWC,QAAQC,QAAQF,QAAQG,KAAK,eAEhEC,iBAAkB,mBAAEpB,UAAUE,uBAEpCkB,gBAAgBC,GAAGT,uBAAaU,OAAOC,MAAM,KACzCC,WAAWC,mBAAmBC,eAAelB,UAAWE,QAAQiB,MAAMC,sBAAaC,WACnFrB,SAASsB,iBAAiB9B,UAAUE,gBAAgB6B,SAAQC,MAAQA,KAAKC,UAAUC,OAAO,eAG9Fd,gBAAgBC,GAAGT,uBAAaU,OAAOa,WAAYC,QAC/CA,MAAMC,cAAcJ,UAAUK,IAAI,aAG/BlB,6CAYuB,SAACmB,YAAQ7B,+DACvC6B,OAAOC,iBAAiB,SAASC,MAAAA,UACvBlC,WAAamC,EAAEC,OAAOC,QAAQ5C,UAAUO,eACzCA,eAIDmC,EAAEG,uBACIC,OAASvC,WAAWwC,QAAQD,UACnB,QAAXA,QAA+B,WAAXA,OAAqB,OACnCE,cAAgB,GAChBC,cAAgBC,SAASC,cAAcnD,UAAUK,WACnD4C,eACAA,cAAcnB,iBAAiB9B,UAAUM,SAASyB,SAAQC,OACvC,QAAXc,QAAoBd,OAASzB,YAGjCyC,cAAcI,KAAKpB,KAAKe,QAAQM,WAGzB,WAAXP,QACAE,cAAcI,KAAK7C,WAAWwC,QAAQM,cAEpC7B,WAAW8B,iBAAiBN,cAAetC,YAC/B,UAAXoC,cACD7B,QAAQsC,IAAI,CACd/B,WAAWC,mBAAmB,GAAIf,QAClCc,WAAW8B,iBAAiB,GAAI5C,QAChCc,WAAWgC,cAAc,GAAI9C,gBAG/B+C,UAAY,IAAIC,IAAInD,WAAWoD,MAC/BC,UAAY,IAAIF,IAAID,UAAUI,aAAaC,IAAI,aAAaC,WAAW,QAAS,YAChFC,oBAAUC,QAAQ1B,OAAQqB,WAClC,MAAOM,UACCtC,sBAAaC,UAAUqC,eAU5BxC,eAAiBlB,iBACpB2D,QAAUC,MAAMC,KAAK7D,SAASsB,iBAAiB,oBAChDwC,KAAIjB,QAAUA,OAAON,QAAQwB,kBAE3BJ,QAAQK,QAAO,CAACC,MAAOC,QAAUP,QAAQQ,QAAQF,SAAWC"} \ No newline at end of file diff --git a/question/bank/columnsortorder/amd/src/actions.js b/question/bank/columnsortorder/amd/src/actions.js index 24f30f5ed42..f96487bec7d 100644 --- a/question/bank/columnsortorder/amd/src/actions.js +++ b/question/bank/columnsortorder/amd/src/actions.js @@ -26,8 +26,7 @@ import SortableList from 'core/sortable_list'; import $ from 'jquery'; import * as repository from 'qbank_columnsortorder/repository'; import Notification from "core/notification"; -import Fragment from "core/fragment"; -import Templates from "core/templates"; +import RefreshUi from 'core_question/refresh_ui'; export const SELECTORS = { columnList: '.qbank-column-list', @@ -108,31 +107,9 @@ export const setupActionButtons = (uiRoot, global = false) => { repository.setColumnSize('', global), ]); } - const fragmentData = uiRoot.dataset; const actionUrl = new URL(actionLink.href); const returnUrl = new URL(actionUrl.searchParams.get('returnurl').replaceAll('&', '&')); - 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) => { - return Templates.replaceNode(uiRoot, html, js); - }) - .catch(Notification.exception); + await RefreshUi.refresh(uiRoot, returnUrl); } catch (ex) { await Notification.exception(ex); } diff --git a/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js b/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js deleted file mode 100644 index 538127539f6..00000000000 --- a/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js +++ /dev/null @@ -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 - * @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 \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js.map b/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js.map deleted file mode 100644 index 719c279276c..00000000000 --- a/question/bank/viewquestiontext/amd/build/datafilter/filtertypes/showtext.min.js.map +++ /dev/null @@ -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 .\n\n/**\n * Filter managing question text display.\n *\n * @module qbank_viewquestiontext/datafilter/filtertypes/showtext\n * @author 2022 Ghaly Marc-Alexandre \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"} \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/build/question_text_format.min.js b/question/bank/viewquestiontext/amd/build/question_text_format.min.js new file mode 100644 index 00000000000..b06dd1c6616 --- /dev/null +++ b/question/bank/viewquestiontext/amd/build/question_text_format.min.js @@ -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 + * @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 \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/build/question_text_format.min.js.map b/question/bank/viewquestiontext/amd/build/question_text_format.min.js.map new file mode 100644 index 00000000000..a80fb9b47f7 --- /dev/null +++ b/question/bank/viewquestiontext/amd/build/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 .\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 \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}\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"} \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/build/repository.min.js b/question/bank/viewquestiontext/amd/build/repository.min.js new file mode 100644 index 00000000000..bc5abaabdf3 --- /dev/null +++ b/question/bank/viewquestiontext/amd/build/repository.min.js @@ -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 \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/build/repository.min.js.map b/question/bank/viewquestiontext/amd/build/repository.min.js.map new file mode 100644 index 00000000000..8024dc6239e --- /dev/null +++ b/question/bank/viewquestiontext/amd/build/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 .\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 \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) => {\n const responses = fetchMany([{\n methodname: 'qbank_viewquestiontext_set_question_text_format',\n args: {\n format\n },\n }]);\n return responses[0];\n};\n"],"names":["format","methodname","args"],"mappings":"0NAgCsCA,SAChB,cAAU,CAAC,CACzBC,WAAY,kDACZC,KAAM,CACFF,OAAAA,WAGS"} \ No newline at end of file diff --git a/question/bank/viewquestiontext/amd/src/question_text_format.js b/question/bank/viewquestiontext/amd/src/question_text_format.js new file mode 100644 index 00000000000..2186d9d69f8 --- /dev/null +++ b/question/bank/viewquestiontext/amd/src/question_text_format.js @@ -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 . + +/** + * Javascript for question_text_format question bank control. + * + * @module qbank_viewquestiontext/question_text_format + * @copyright 2023 Catalyst IT Europe Ltd. + * @author Mark Johnson + * @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} + */ +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); +}; diff --git a/question/bank/viewquestiontext/amd/src/repository.js b/question/bank/viewquestiontext/amd/src/repository.js new file mode 100644 index 00000000000..efc2c4ea72f --- /dev/null +++ b/question/bank/viewquestiontext/amd/src/repository.js @@ -0,0 +1,41 @@ +// 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 . + +/** + * External function calls for qbank_columnsortorder + * + * @module qbank_viewquestiontext/repository + * @copyright 2023 Catalyst IT Europe Ltd. + * @author Mark Johnson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {call as fetchMany} from 'core/ajax'; + +/** + * Set the question text format. + * + * @param {Number} format The question text format. + * @return {Promise} + */ +export const setQuestionTextFormat = (format) => { + const responses = fetchMany([{ + methodname: 'qbank_viewquestiontext_set_question_text_format', + args: { + format + }, + }]); + return responses[0]; +}; diff --git a/question/bank/viewquestiontext/classes/external/set_question_text_format.php b/question/bank/viewquestiontext/classes/external/set_question_text_format.php new file mode 100644 index 00000000000..41c385aae01 --- /dev/null +++ b/question/bank/viewquestiontext/classes/external/set_question_text_format.php @@ -0,0 +1,78 @@ +. + +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 + * @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('/')); + } +} diff --git a/question/bank/viewquestiontext/classes/output/question_text_format.php b/question/bank/viewquestiontext/classes/output/question_text_format.php new file mode 100644 index 00000000000..2a6c168a7ae --- /dev/null +++ b/question/bank/viewquestiontext/classes/output/question_text_format.php @@ -0,0 +1,93 @@ +. + +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 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_text_format implements \templatable, \renderable { + + /** + * @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'), + ]; + } +} diff --git a/question/bank/viewquestiontext/classes/plugin_feature.php b/question/bank/viewquestiontext/classes/plugin_feature.php index 2b7ac9c87f2..ca78b018ba9 100644 --- a/question/bank/viewquestiontext/classes/plugin_feature.php +++ b/question/bank/viewquestiontext/classes/plugin_feature.php @@ -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), ]; } } diff --git a/question/bank/viewquestiontext/classes/question_text_row.php b/question/bank/viewquestiontext/classes/question_text_row.php index 98dbc9e2ee4..998c777f275 100644 --- a/question/bank/viewquestiontext/classes/question_text_row.php +++ b/question/bank/viewquestiontext/classes/question_text_row.php @@ -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'); diff --git a/question/bank/viewquestiontext/classes/questiontext_condition.php b/question/bank/viewquestiontext/classes/questiontext_condition.php deleted file mode 100644 index 6d1d0df111e..00000000000 --- a/question/bank/viewquestiontext/classes/questiontext_condition.php +++ /dev/null @@ -1,108 +0,0 @@ -. - -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 - * @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, - ] - ]; - } -} diff --git a/question/bank/viewquestiontext/amd/src/datafilter/filtertypes/showtext.js b/question/bank/viewquestiontext/db/services.php similarity index 56% rename from question/bank/viewquestiontext/amd/src/datafilter/filtertypes/showtext.js rename to question/bank/viewquestiontext/db/services.php index 5a88b46cabd..224d0bc6546 100644 --- a/question/bank/viewquestiontext/amd/src/datafilter/filtertypes/showtext.js +++ b/question/bank/viewquestiontext/db/services.php @@ -1,3 +1,4 @@ +. /** - * Filter managing question text display. + * qbank_viewquestiontext external functions and service definitions. * - * @module qbank_viewquestiontext/datafilter/filtertypes/showtext - * @author 2022 Ghaly Marc-Alexandre - * @copyright 2022 Catalyst IT Australia Pty Ltd + * @package qbank_viewquestiontext + * @category webservice + * @copyright 2023 Catalyst IT Europe Ltd + * @author Mark Johnson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -import GenericFilter from 'core/datafilter/filtertype'; +defined('MOODLE_INTERNAL') || die(); -export default class extends GenericFilter { -} +$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, + ], +]; diff --git a/question/bank/viewquestiontext/save.php b/question/bank/viewquestiontext/save.php new file mode 100644 index 00000000000..ff18bc364c2 --- /dev/null +++ b/question/bank/viewquestiontext/save.php @@ -0,0 +1,48 @@ +. + +/** + * 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 + * @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)); diff --git a/question/bank/viewquestiontext/styles.css b/question/bank/viewquestiontext/styles.css new file mode 100644 index 00000000000..d35b2f11df0 --- /dev/null +++ b/question/bank/viewquestiontext/styles.css @@ -0,0 +1,3 @@ +.jsenabled .question-text-format .input-group-append { + display: none; +} diff --git a/question/bank/viewquestiontext/templates/question_text_format.mustache b/question/bank/viewquestiontext/templates/question_text_format.mustache new file mode 100644 index 00000000000..c240bffb12b --- /dev/null +++ b/question/bank/viewquestiontext/templates/question_text_format.mustache @@ -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 . +}} +{{! + @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 + } + ] + } +}} +
+ + +
+ + +
+ +
+
+
+{{#js}} + require(['qbank_viewquestiontext/question_text_format'], QuestionTextFormat => { + QuestionTextFormat.init('questionscontainer'); + }); +{{/js}} \ No newline at end of file diff --git a/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature b/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature index a2829f2adec..995598f78bf 100644 --- a/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature +++ b/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature @@ -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" diff --git a/question/bank/viewquestiontext/version.php b/question/bank/viewquestiontext/version.php index b9a8245fae2..a4771b5e428 100644 --- a/question/bank/viewquestiontext/version.php +++ b/question/bank/viewquestiontext/version.php @@ -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; diff --git a/question/classes/local/bank/view.php b/question/classes/local/bank/view.php index 4fa1a4c8607..f01b43c0d7e 100644 --- a/question/classes/local/bank/view.php +++ b/question/classes/local/bank/view.php @@ -391,11 +391,6 @@ class view { 'core_question\local\bank\edit_menu_column' . column_base::ID_SEPARATOR . 'edit_menu_column', ]; - if (question_get_display_preference('qbshowtext', 0, PARAM_INT, new \moodle_url(''))) { - $corequestionbankcolumns[] = 'qbank_viewquestiontext\question_text_row' . column_base::ID_SEPARATOR . - 'question_text_row'; - } - foreach ($corequestionbankcolumns as $columnid) { [$columnclass, $columnname] = explode(column_base::ID_SEPARATOR, $columnid, 2); if (class_exists($columnclass)) { diff --git a/question/tests/behat/sort_questions.feature b/question/tests/behat/sort_questions.feature index 70f9a62744d..bab2f0ce6ca 100644 --- a/question/tests/behat/sort_questions.feature +++ b/question/tests/behat/sort_questions.feature @@ -61,7 +61,7 @@ Feature: The questions in the question bank can be sorted in various ways @javascript Scenario: The question text can be shown in the list of questions - When I apply question bank filter "Show question text in the question list?" with value "Yes" + When I set the field "Show question text in the question list?" to "Yes" Then I should see "Question 1 text" And I should see "Question 2 text" And I should see "Question 3 text"