From feef716c91e86642ddbb7033ab0e7d52f7ffcea0 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Mon, 4 Sep 2023 13:32:05 +0100 Subject: [PATCH] MDL-74054 core_question: Re-apply filters when performing a qbank action This changes the root element used by the fragment when applying filters, so that the whole of display_question_list() is reloaded. This ensures that the returnurl will be updated correctly on the question actions and bulk actions without manipulating then further in Javascript. --- question/amd/build/filter.min.js | 2 +- question/amd/build/filter.min.js.map | 2 +- question/amd/src/filter.js | 10 ---------- question/classes/local/bank/view.php | 16 +++++++++++----- question/lib.php | 9 ++++++--- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/question/amd/build/filter.min.js b/question/amd/build/filter.min.js index a1e2bdf3a57..113eed8c1db 100644 --- a/question/amd/build/filter.min.js +++ b/question/amd/build/filter.min.js @@ -5,6 +5,6 @@ define("core_question/filter",["exports","core/datafilter","core/notification"," * @module core_question/filter * @copyright 2021 Tomo Tsuyuki * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_datafilter=_interopRequireDefault(_datafilter),_notification=_interopRequireDefault(_notification),_selectors=_interopRequireDefault(_selectors),_templates=_interopRequireDefault(_templates),_fragment=_interopRequireDefault(_fragment);_exports.init=(filterRegionId,defaultcourseid,defaultcategoryid,perpage,contextId,component,callback,view,cmid,pagevars,extraparams)=>{var _document$querySelect,_document$querySelect2;const SELECTORS_QUESTION_CONTAINER_ID="#questionscontainer",SELECTORS_QUESTION_TABLE="#questionscontainer table",SELECTORS_SORT_LINK="#questionscontainer div.sorters a",SELECTORS_PAGINATION_LINK="#questionscontainer a[href].page-link",SELECTORS_LASTCHANGED_FIELD="#questionsubmit input[name=lastchanged]",SELECTORS_BULK_ACTIONS="#bulkactionsui-container input",SELECTORS_EDIT_SWITCH=".editmode-switch-form input[name=setmode]",SELECTORS_EDIT_SWITCH_URL=".editmode-switch-form input[name=pageurl]",filterSet=document.querySelector("#".concat(filterRegionId)),filterCondition={cat:defaultcategoryid,courseid:defaultcourseid,filter:{},jointype:0,qpage:0,qperpage:perpage,sortdata:{},tabname:"questions"},defaultSort=null===(_document$querySelect=document.querySelector(SELECTORS_QUESTION_TABLE))||void 0===_document$querySelect||null===(_document$querySelect2=_document$querySelect.dataset)||void 0===_document$querySelect2?void 0:_document$querySelect2.defaultsort;defaultSort&&(filterCondition.sortData=JSON.parse(defaultSort));const coreFilter=new _datafilter.default(filterSet,((filterdata,pendingPromise)=>{var _document$querySelect3,_document$querySelect4;filterdata&&(filterCondition.jointype=parseInt(filterSet.dataset.filterverb,10),delete filterdata.jointype,filterCondition.filter=filterdata,0!==Object.keys(filterdata).length&&(isNaN(filterCondition.jointype)||(filterdata.jointype=filterCondition.jointype),updateUrlParams(filterdata)));const viewData={view:view,cmid:cmid,filtercondition:JSON.stringify(filterCondition),extraparams:extraparams,filterquery:"",lastchanged:null!==(_document$querySelect3=null===(_document$querySelect4=document.querySelector(SELECTORS_LASTCHANGED_FIELD))||void 0===_document$querySelect4?void 0:_document$querySelect4.value)&&void 0!==_document$querySelect3?_document$querySelect3:null};_fragment.default.loadFragment(component,callback,contextId,viewData).then(((questionhtml,jsfooter)=>{const questionscontainer=document.querySelector(SELECTORS_QUESTION_CONTAINER_ID);return void 0===questionhtml&&(questionhtml=""),void 0===jsfooter&&(jsfooter=""),_templates.default.replaceNodeContents(questionscontainer,questionhtml,jsfooter),pendingPromise&&pendingPromise.resolve(),{questionhtml:questionhtml,jsfooter:jsfooter}})).catch(_notification.default.exception)}));coreFilter.activeFilters={},coreFilter.init();const updateUrlParams=filters=>{const url=new URL(location.href),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),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),editSwitchUrl=new URL(editSwitchUrlInput.value);editSwitchUrl.searchParams.set("filter",filterQuery),editSwitchUrlInput.value=editSwitchUrl,editSwitch.dataset.pageurl=editSwitchUrl}};let initialFilters;document.addEventListener("click",(e=>{const sortableLink=e.target.closest(SELECTORS_SORT_LINK),paginationLink=e.target.closest(SELECTORS_PAGINATION_LINK),clearLink=e.target.closest(_selectors.default.filterset.actions.resetFilters);if(sortableLink){e.preventDefault();const oldSort=filterCondition.sortdata;filterCondition.sortdata={},filterCondition.sortdata[sortableLink.dataset.sortname]=sortableLink.dataset.sortorder;for(const sortname in oldSort)sortname!==sortableLink.dataset.sortname&&(filterCondition.sortdata[sortname]=oldSort[sortname]);filterCondition.qpage=0,coreFilter.updateTableFromFilter()}if(paginationLink){e.preventDefault();const paginationURL=new URL(paginationLink.getAttribute("href")),qpage=paginationURL.searchParams.get("qpage");null!==paginationURL.search&&(filterCondition.qpage=qpage,coreFilter.updateTableFromFilter())}clearLink&&(()=>{const queryString=location.search,urlParams=new URLSearchParams(queryString);if(urlParams.has("cmid")){const cleanedUrl=new URL(location.href.replace(location.search,""));cleanedUrl.searchParams.set("cmid",urlParams.get("cmid")),history.pushState({},"",cleanedUrl)}if(urlParams.has("courseid")){const cleanedUrl=new URL(location.href.replace(location.search,""));cleanedUrl.searchParams.set("courseid",urlParams.get("courseid")),history.pushState({},"",cleanedUrl)}})()}));let jointype=null;if((pagevars=JSON.parse(pagevars)).filter&&(initialFilters=pagevars.filter,pagevars.jointype&&(jointype=pagevars.jointype)),0!==Object.entries(initialFilters).length){const emptyFilterRow=filterSet.querySelector(_selectors.default.filterset.regions.emptyFilterRow);emptyFilterRow&&emptyFilterRow.remove();let rowcount=0;for(const urlFilter in initialFilters){if("jointype"===urlFilter){jointype=initialFilters[urlFilter];continue}rowcount+=1;const filterdata={filtertype:urlFilter,values:initialFilters[urlFilter].values,jointype:initialFilters[urlFilter].jointype,filteroptions:initialFilters[urlFilter].filteroptions,rownum:rowcount};coreFilter.addFilterRow(filterdata)}coreFilter.filterSet.dataset.filterverb=jointype;const join=coreFilter.filterSet.querySelector(_selectors.default.filterset.fields.join);join.querySelectorAll('option:not([value="'.concat(jointype,'"])')).forEach((option=>option.remove())),join.disabled=!0}}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_datafilter=_interopRequireDefault(_datafilter),_notification=_interopRequireDefault(_notification),_selectors=_interopRequireDefault(_selectors),_templates=_interopRequireDefault(_templates),_fragment=_interopRequireDefault(_fragment);_exports.init=(filterRegionId,defaultcourseid,defaultcategoryid,perpage,contextId,component,callback,view,cmid,pagevars,extraparams)=>{var _document$querySelect,_document$querySelect2;const SELECTORS_QUESTION_CONTAINER_ID="#questionscontainer",SELECTORS_QUESTION_TABLE="#questionscontainer table",SELECTORS_SORT_LINK="#questionscontainer div.sorters a",SELECTORS_PAGINATION_LINK="#questionscontainer a[href].page-link",SELECTORS_LASTCHANGED_FIELD="#questionsubmit input[name=lastchanged]",SELECTORS_EDIT_SWITCH=".editmode-switch-form input[name=setmode]",SELECTORS_EDIT_SWITCH_URL=".editmode-switch-form input[name=pageurl]",filterSet=document.querySelector("#".concat(filterRegionId)),filterCondition={cat:defaultcategoryid,courseid:defaultcourseid,filter:{},jointype:0,qpage:0,qperpage:perpage,sortdata:{},tabname:"questions"},defaultSort=null===(_document$querySelect=document.querySelector(SELECTORS_QUESTION_TABLE))||void 0===_document$querySelect||null===(_document$querySelect2=_document$querySelect.dataset)||void 0===_document$querySelect2?void 0:_document$querySelect2.defaultsort;defaultSort&&(filterCondition.sortData=JSON.parse(defaultSort));const coreFilter=new _datafilter.default(filterSet,((filterdata,pendingPromise)=>{var _document$querySelect3,_document$querySelect4;filterdata&&(filterCondition.jointype=parseInt(filterSet.dataset.filterverb,10),delete filterdata.jointype,filterCondition.filter=filterdata,0!==Object.keys(filterdata).length&&(isNaN(filterCondition.jointype)||(filterdata.jointype=filterCondition.jointype),updateUrlParams(filterdata)));const viewData={view:view,cmid:cmid,filtercondition:JSON.stringify(filterCondition),extraparams:extraparams,lastchanged:null!==(_document$querySelect3=null===(_document$querySelect4=document.querySelector(SELECTORS_LASTCHANGED_FIELD))||void 0===_document$querySelect4?void 0:_document$querySelect4.value)&&void 0!==_document$querySelect3?_document$querySelect3:null};_fragment.default.loadFragment(component,callback,contextId,viewData).then(((questionhtml,jsfooter)=>{const questionscontainer=document.querySelector(SELECTORS_QUESTION_CONTAINER_ID);return void 0===questionhtml&&(questionhtml=""),void 0===jsfooter&&(jsfooter=""),_templates.default.replaceNodeContents(questionscontainer,questionhtml,jsfooter),pendingPromise&&pendingPromise.resolve(),{questionhtml:questionhtml,jsfooter:jsfooter}})).catch(_notification.default.exception)}));coreFilter.activeFilters={},coreFilter.init();const updateUrlParams=filters=>{const url=new URL(location.href),filterQuery=JSON.stringify(filters);url.searchParams.set("filter",filterQuery),history.pushState(filters,"",url);const editSwitch=document.querySelector(SELECTORS_EDIT_SWITCH);if(editSwitch){const editSwitchUrlInput=document.querySelector(SELECTORS_EDIT_SWITCH_URL),editSwitchUrl=new URL(editSwitchUrlInput.value);editSwitchUrl.searchParams.set("filter",filterQuery),editSwitchUrlInput.value=editSwitchUrl,editSwitch.dataset.pageurl=editSwitchUrl}};let initialFilters;document.addEventListener("click",(e=>{const sortableLink=e.target.closest(SELECTORS_SORT_LINK),paginationLink=e.target.closest(SELECTORS_PAGINATION_LINK),clearLink=e.target.closest(_selectors.default.filterset.actions.resetFilters);if(sortableLink){e.preventDefault();const oldSort=filterCondition.sortdata;filterCondition.sortdata={},filterCondition.sortdata[sortableLink.dataset.sortname]=sortableLink.dataset.sortorder;for(const sortname in oldSort)sortname!==sortableLink.dataset.sortname&&(filterCondition.sortdata[sortname]=oldSort[sortname]);filterCondition.qpage=0,coreFilter.updateTableFromFilter()}if(paginationLink){e.preventDefault();const paginationURL=new URL(paginationLink.getAttribute("href")),qpage=paginationURL.searchParams.get("qpage");null!==paginationURL.search&&(filterCondition.qpage=qpage,coreFilter.updateTableFromFilter())}clearLink&&(()=>{const queryString=location.search,urlParams=new URLSearchParams(queryString);if(urlParams.has("cmid")){const cleanedUrl=new URL(location.href.replace(location.search,""));cleanedUrl.searchParams.set("cmid",urlParams.get("cmid")),history.pushState({},"",cleanedUrl)}if(urlParams.has("courseid")){const cleanedUrl=new URL(location.href.replace(location.search,""));cleanedUrl.searchParams.set("courseid",urlParams.get("courseid")),history.pushState({},"",cleanedUrl)}})()}));let jointype=null;if((pagevars=JSON.parse(pagevars)).filter&&(initialFilters=pagevars.filter,pagevars.jointype&&(jointype=pagevars.jointype)),0!==Object.entries(initialFilters).length){const emptyFilterRow=filterSet.querySelector(_selectors.default.filterset.regions.emptyFilterRow);emptyFilterRow&&emptyFilterRow.remove();let rowcount=0;for(const urlFilter in initialFilters){if("jointype"===urlFilter){jointype=initialFilters[urlFilter];continue}rowcount+=1;const filterdata={filtertype:urlFilter,values:initialFilters[urlFilter].values,jointype:initialFilters[urlFilter].jointype,filteroptions:initialFilters[urlFilter].filteroptions,rownum:rowcount};coreFilter.addFilterRow(filterdata)}coreFilter.filterSet.dataset.filterverb=jointype;const join=coreFilter.filterSet.querySelector(_selectors.default.filterset.fields.join);join.querySelectorAll('option:not([value="'.concat(jointype,'"])')).forEach((option=>option.remove())),join.disabled=!0}}})); //# sourceMappingURL=filter.min.js.map \ No newline at end of file diff --git a/question/amd/build/filter.min.js.map b/question/amd/build/filter.min.js.map index 3570de23359..58994b35155 100644 --- a/question/amd/build/filter.min.js.map +++ b/question/amd/build/filter.min.js.map @@ -1 +1 @@ -{"version":3,"file":"filter.min.js","sources":["../src/filter.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 filter management.\n *\n * @module core_question/filter\n * @copyright 2021 Tomo Tsuyuki \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CoreFilter from 'core/datafilter';\nimport Notification from 'core/notification';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport Fragment from 'core/fragment';\n\n/**\n * Initialise the question bank filter on the element with the given id.\n *\n * @param {String} filterRegionId ID of the HTML element containing the filters.\n * @param {String} defaultcourseid Course ID for the default course to pass back to the view.\n * @param {String} defaultcategoryid Question bank category ID for the default course to pass back to the view.\n * @param {Number} perpage The number of questions to display per page.\n * @param {Number} contextId Context ID of the question bank view.\n * @param {string} component Frankenstyle name of the component for the fragment API callback (e.g. core_question)\n * @param {string} callback Name of the callback for the fragment API (e.g question_data)\n * @param {string} view The class name of the question bank view class used for this page.\n * @param {Number} cmid If we are in an activitiy, the course module ID.\n * @param {string} pagevars JSON-encoded parameters from passed from the view, including filters and jointype.\n * @param {string} extraparams JSON-encoded additional parameters specific to this view class, used for re-rendering the view.\n */\nexport const init = (\n filterRegionId,\n defaultcourseid,\n defaultcategoryid,\n perpage,\n contextId,\n component,\n callback,\n view,\n cmid,\n pagevars,\n extraparams\n) => {\n\n const SELECTORS = {\n QUESTION_CONTAINER_ID: '#questionscontainer',\n QUESTION_TABLE: '#questionscontainer table',\n SORT_LINK: '#questionscontainer div.sorters a',\n PAGINATION_LINK: '#questionscontainer a[href].page-link',\n LASTCHANGED_FIELD: '#questionsubmit input[name=lastchanged]',\n BULK_ACTIONS: '#bulkactionsui-container input',\n MENU_ACTIONS: '.menu-action',\n EDIT_SWITCH: '.editmode-switch-form input[name=setmode]',\n EDIT_SWITCH_URL: '.editmode-switch-form input[name=pageurl]',\n };\n\n const filterSet = document.querySelector(`#${filterRegionId}`);\n\n const filterCondition = {\n cat: defaultcategoryid,\n courseid: defaultcourseid,\n filter: {},\n jointype: 0,\n qpage: 0,\n qperpage: perpage,\n sortdata: {},\n tabname: 'questions',\n };\n\n const defaultSort = document.querySelector(SELECTORS.QUESTION_TABLE)?.dataset?.defaultsort;\n if (defaultSort) {\n filterCondition.sortData = JSON.parse(defaultSort);\n }\n\n let filterQuery = '';\n\n /**\n * Retrieve table data.\n *\n * @param {Object} filterdata data\n * @param {Promise} pendingPromise pending promise\n */\n const applyFilter = (filterdata, pendingPromise) => {\n // Reload the questions based on the specified filters. If no filters are provided,\n // use the default category filter condition.\n if (filterdata) {\n // Main join types.\n filterCondition.jointype = parseInt(filterSet.dataset.filterverb, 10);\n delete filterdata.jointype;\n // Retrieve filter info.\n filterCondition.filter = filterdata;\n if (Object.keys(filterdata).length !== 0) {\n if (!isNaN(filterCondition.jointype)) {\n filterdata.jointype = filterCondition.jointype;\n }\n updateUrlParams(filterdata);\n }\n }\n // Load questions for first page.\n const viewData = {\n view: view,\n cmid: cmid,\n filtercondition: JSON.stringify(filterCondition),\n extraparams: extraparams,\n filterquery: filterQuery,\n lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null\n };\n Fragment.loadFragment(component, callback, contextId, viewData)\n // Render questions for first page and pagination.\n .then((questionhtml, jsfooter) => {\n const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);\n if (questionhtml === undefined) {\n questionhtml = '';\n }\n if (jsfooter === undefined) {\n jsfooter = '';\n }\n Templates.replaceNodeContents(questionscontainer, questionhtml, jsfooter);\n // Resolve filter promise.\n if (pendingPromise) {\n pendingPromise.resolve();\n }\n return {questionhtml, jsfooter};\n })\n .catch(Notification.exception);\n };\n\n // Init core filter processor with apply callback.\n const coreFilter = new CoreFilter(filterSet, applyFilter);\n coreFilter.activeFilters = {}; // Unset useless courseid filter.\n coreFilter.init();\n\n /**\n * Update URL Param based upon the current filter.\n *\n * @param {Object} filters Active filters.\n */\n const updateUrlParams = (filters) => {\n const url = new URL(location.href);\n const filterQuery = JSON.stringify(filters);\n url.searchParams.set('filter', filterQuery);\n history.pushState(filters, '', url);\n document.querySelectorAll(SELECTORS.BULK_ACTIONS).forEach(bulkAction => {\n const actionUrl = new URL(bulkAction.formAction);\n const returnUrl = new URL(actionUrl.searchParams.get('returnurl'));\n returnUrl.searchParams.set('filter', filterQuery);\n actionUrl.searchParams.set('returnurl', returnUrl);\n bulkAction.formAction = actionUrl;\n });\n const editSwitch = document.querySelector(SELECTORS.EDIT_SWITCH);\n if (editSwitch) {\n const editSwitchUrlInput = document.querySelector(SELECTORS.EDIT_SWITCH_URL);\n const editSwitchUrl = new URL(editSwitchUrlInput.value);\n editSwitchUrl.searchParams.set('filter', filterQuery);\n editSwitchUrlInput.value = editSwitchUrl;\n editSwitch.dataset.pageurl = editSwitchUrl;\n }\n };\n\n /**\n * Cleans URL parameters.\n */\n const cleanUrlParams = () => {\n const queryString = location.search;\n const urlParams = new URLSearchParams(queryString);\n if (urlParams.has('cmid')) {\n const cleanedUrl = new URL(location.href.replace(location.search, ''));\n cleanedUrl.searchParams.set('cmid', urlParams.get('cmid'));\n history.pushState({}, '', cleanedUrl);\n }\n\n if (urlParams.has('courseid')) {\n const cleanedUrl = new URL(location.href.replace(location.search, ''));\n cleanedUrl.searchParams.set('courseid', urlParams.get('courseid'));\n history.pushState({}, '', cleanedUrl);\n }\n };\n\n // Add listeners for the sorting, paging and clear actions.\n document.addEventListener('click', e => {\n const sortableLink = e.target.closest(SELECTORS.SORT_LINK);\n const paginationLink = e.target.closest(SELECTORS.PAGINATION_LINK);\n const clearLink = e.target.closest(Selectors.filterset.actions.resetFilters);\n if (sortableLink) {\n e.preventDefault();\n const oldSort = filterCondition.sortdata;\n filterCondition.sortdata = {};\n filterCondition.sortdata[sortableLink.dataset.sortname] = sortableLink.dataset.sortorder;\n for (const sortname in oldSort) {\n if (sortname !== sortableLink.dataset.sortname) {\n filterCondition.sortdata[sortname] = oldSort[sortname];\n }\n }\n filterCondition.qpage = 0;\n coreFilter.updateTableFromFilter();\n }\n if (paginationLink) {\n e.preventDefault();\n const paginationURL = new URL(paginationLink.getAttribute(\"href\"));\n const qpage = paginationURL.searchParams.get('qpage');\n if (paginationURL.search !== null) {\n filterCondition.qpage = qpage;\n coreFilter.updateTableFromFilter();\n }\n }\n if (clearLink) {\n cleanUrlParams();\n }\n });\n\n // Run apply filter at page load.\n pagevars = JSON.parse(pagevars);\n let initialFilters;\n let jointype = null;\n if (pagevars.filter) {\n // Load initial filter based on page vars.\n initialFilters = pagevars.filter;\n if (pagevars.jointype) {\n jointype = pagevars.jointype;\n }\n }\n\n if (Object.entries(initialFilters).length !== 0) {\n // Remove the default empty filter row.\n const emptyFilterRow = filterSet.querySelector(Selectors.filterset.regions.emptyFilterRow);\n if (emptyFilterRow) {\n emptyFilterRow.remove();\n }\n\n // Add filters.\n let rowcount = 0;\n for (const urlFilter in initialFilters) {\n if (urlFilter === 'jointype') {\n jointype = initialFilters[urlFilter];\n continue;\n }\n // Add each filter row.\n rowcount += 1;\n const filterdata = {\n filtertype: urlFilter,\n values: initialFilters[urlFilter].values,\n jointype: initialFilters[urlFilter].jointype,\n filteroptions: initialFilters[urlFilter].filteroptions,\n rownum: rowcount\n };\n coreFilter.addFilterRow(filterdata);\n }\n coreFilter.filterSet.dataset.filterverb = jointype;\n\n // Since we must filter by category, it does not make sense to allow the top-level \"match any\" or \"match none\" conditions,\n // as this would exclude the category. Remove those options and disable the select.\n const join = coreFilter.filterSet.querySelector(Selectors.filterset.fields.join);\n join.querySelectorAll(`option:not([value=\"${jointype}\"])`).forEach((option) => option.remove());\n join.disabled = true;\n }\n};\n"],"names":["filterRegionId","defaultcourseid","defaultcategoryid","perpage","contextId","component","callback","view","cmid","pagevars","extraparams","SELECTORS","filterSet","document","querySelector","filterCondition","cat","courseid","filter","jointype","qpage","qperpage","sortdata","tabname","defaultSort","_document$querySelect","dataset","_document$querySelect2","defaultsort","sortData","JSON","parse","coreFilter","CoreFilter","filterdata","pendingPromise","parseInt","filterverb","Object","keys","length","isNaN","updateUrlParams","viewData","filtercondition","stringify","filterquery","lastchanged","_document$querySelect4","value","loadFragment","then","questionhtml","jsfooter","questionscontainer","undefined","replaceNodeContents","resolve","catch","Notification","exception","activeFilters","init","filters","url","URL","location","href","filterQuery","searchParams","set","history","pushState","querySelectorAll","forEach","bulkAction","actionUrl","formAction","returnUrl","get","editSwitch","editSwitchUrlInput","editSwitchUrl","pageurl","initialFilters","addEventListener","e","sortableLink","target","closest","paginationLink","clearLink","Selectors","filterset","actions","resetFilters","preventDefault","oldSort","sortname","sortorder","updateTableFromFilter","paginationURL","getAttribute","search","queryString","urlParams","URLSearchParams","has","cleanedUrl","replace","cleanUrlParams","entries","emptyFilterRow","regions","remove","rowcount","urlFilter","filtertype","values","filteroptions","rownum","addFilterRow","join","fields","option","disabled"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"filter.min.js","sources":["../src/filter.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 filter management.\n *\n * @module core_question/filter\n * @copyright 2021 Tomo Tsuyuki \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CoreFilter from 'core/datafilter';\nimport Notification from 'core/notification';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport Fragment from 'core/fragment';\n\n/**\n * Initialise the question bank filter on the element with the given id.\n *\n * @param {String} filterRegionId ID of the HTML element containing the filters.\n * @param {String} defaultcourseid Course ID for the default course to pass back to the view.\n * @param {String} defaultcategoryid Question bank category ID for the default course to pass back to the view.\n * @param {Number} perpage The number of questions to display per page.\n * @param {Number} contextId Context ID of the question bank view.\n * @param {string} component Frankenstyle name of the component for the fragment API callback (e.g. core_question)\n * @param {string} callback Name of the callback for the fragment API (e.g question_data)\n * @param {string} view The class name of the question bank view class used for this page.\n * @param {Number} cmid If we are in an activitiy, the course module ID.\n * @param {string} pagevars JSON-encoded parameters from passed from the view, including filters and jointype.\n * @param {string} extraparams JSON-encoded additional parameters specific to this view class, used for re-rendering the view.\n */\nexport const init = (\n filterRegionId,\n defaultcourseid,\n defaultcategoryid,\n perpage,\n contextId,\n component,\n callback,\n view,\n cmid,\n pagevars,\n extraparams\n) => {\n\n const SELECTORS = {\n QUESTION_CONTAINER_ID: '#questionscontainer',\n QUESTION_TABLE: '#questionscontainer table',\n SORT_LINK: '#questionscontainer div.sorters a',\n PAGINATION_LINK: '#questionscontainer a[href].page-link',\n LASTCHANGED_FIELD: '#questionsubmit input[name=lastchanged]',\n BULK_ACTIONS: '#bulkactionsui-container input',\n MENU_ACTIONS: '.menu-action',\n EDIT_SWITCH: '.editmode-switch-form input[name=setmode]',\n EDIT_SWITCH_URL: '.editmode-switch-form input[name=pageurl]',\n };\n\n const filterSet = document.querySelector(`#${filterRegionId}`);\n\n const filterCondition = {\n cat: defaultcategoryid,\n courseid: defaultcourseid,\n filter: {},\n jointype: 0,\n qpage: 0,\n qperpage: perpage,\n sortdata: {},\n tabname: 'questions',\n };\n\n const defaultSort = document.querySelector(SELECTORS.QUESTION_TABLE)?.dataset?.defaultsort;\n if (defaultSort) {\n filterCondition.sortData = JSON.parse(defaultSort);\n }\n\n /**\n * Retrieve table data.\n *\n * @param {Object} filterdata data\n * @param {Promise} pendingPromise pending promise\n */\n const applyFilter = (filterdata, pendingPromise) => {\n // Reload the questions based on the specified filters. If no filters are provided,\n // use the default category filter condition.\n if (filterdata) {\n // Main join types.\n filterCondition.jointype = parseInt(filterSet.dataset.filterverb, 10);\n delete filterdata.jointype;\n // Retrieve filter info.\n filterCondition.filter = filterdata;\n if (Object.keys(filterdata).length !== 0) {\n if (!isNaN(filterCondition.jointype)) {\n filterdata.jointype = filterCondition.jointype;\n }\n updateUrlParams(filterdata);\n }\n }\n // Load questions for first page.\n const viewData = {\n view: view,\n cmid: cmid,\n filtercondition: JSON.stringify(filterCondition),\n extraparams: extraparams,\n lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null\n };\n Fragment.loadFragment(component, callback, contextId, viewData)\n // Render questions for first page and pagination.\n .then((questionhtml, jsfooter) => {\n const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);\n if (questionhtml === undefined) {\n questionhtml = '';\n }\n if (jsfooter === undefined) {\n jsfooter = '';\n }\n Templates.replaceNodeContents(questionscontainer, questionhtml, jsfooter);\n // Resolve filter promise.\n if (pendingPromise) {\n pendingPromise.resolve();\n }\n return {questionhtml, jsfooter};\n })\n .catch(Notification.exception);\n };\n\n // Init core filter processor with apply callback.\n const coreFilter = new CoreFilter(filterSet, applyFilter);\n coreFilter.activeFilters = {}; // Unset useless courseid filter.\n coreFilter.init();\n\n /**\n * Update URL Param based upon the current filter.\n *\n * @param {Object} filters Active filters.\n */\n const updateUrlParams = (filters) => {\n const url = new URL(location.href);\n const filterQuery = JSON.stringify(filters);\n url.searchParams.set('filter', filterQuery);\n history.pushState(filters, '', url);\n const editSwitch = document.querySelector(SELECTORS.EDIT_SWITCH);\n if (editSwitch) {\n const editSwitchUrlInput = document.querySelector(SELECTORS.EDIT_SWITCH_URL);\n const editSwitchUrl = new URL(editSwitchUrlInput.value);\n editSwitchUrl.searchParams.set('filter', filterQuery);\n editSwitchUrlInput.value = editSwitchUrl;\n editSwitch.dataset.pageurl = editSwitchUrl;\n }\n };\n\n /**\n * Cleans URL parameters.\n */\n const cleanUrlParams = () => {\n const queryString = location.search;\n const urlParams = new URLSearchParams(queryString);\n if (urlParams.has('cmid')) {\n const cleanedUrl = new URL(location.href.replace(location.search, ''));\n cleanedUrl.searchParams.set('cmid', urlParams.get('cmid'));\n history.pushState({}, '', cleanedUrl);\n }\n\n if (urlParams.has('courseid')) {\n const cleanedUrl = new URL(location.href.replace(location.search, ''));\n cleanedUrl.searchParams.set('courseid', urlParams.get('courseid'));\n history.pushState({}, '', cleanedUrl);\n }\n };\n\n // Add listeners for the sorting, paging and clear actions.\n document.addEventListener('click', e => {\n const sortableLink = e.target.closest(SELECTORS.SORT_LINK);\n const paginationLink = e.target.closest(SELECTORS.PAGINATION_LINK);\n const clearLink = e.target.closest(Selectors.filterset.actions.resetFilters);\n if (sortableLink) {\n e.preventDefault();\n const oldSort = filterCondition.sortdata;\n filterCondition.sortdata = {};\n filterCondition.sortdata[sortableLink.dataset.sortname] = sortableLink.dataset.sortorder;\n for (const sortname in oldSort) {\n if (sortname !== sortableLink.dataset.sortname) {\n filterCondition.sortdata[sortname] = oldSort[sortname];\n }\n }\n filterCondition.qpage = 0;\n coreFilter.updateTableFromFilter();\n }\n if (paginationLink) {\n e.preventDefault();\n const paginationURL = new URL(paginationLink.getAttribute(\"href\"));\n const qpage = paginationURL.searchParams.get('qpage');\n if (paginationURL.search !== null) {\n filterCondition.qpage = qpage;\n coreFilter.updateTableFromFilter();\n }\n }\n if (clearLink) {\n cleanUrlParams();\n }\n });\n\n // Run apply filter at page load.\n pagevars = JSON.parse(pagevars);\n let initialFilters;\n let jointype = null;\n if (pagevars.filter) {\n // Load initial filter based on page vars.\n initialFilters = pagevars.filter;\n if (pagevars.jointype) {\n jointype = pagevars.jointype;\n }\n }\n\n if (Object.entries(initialFilters).length !== 0) {\n // Remove the default empty filter row.\n const emptyFilterRow = filterSet.querySelector(Selectors.filterset.regions.emptyFilterRow);\n if (emptyFilterRow) {\n emptyFilterRow.remove();\n }\n\n // Add filters.\n let rowcount = 0;\n for (const urlFilter in initialFilters) {\n if (urlFilter === 'jointype') {\n jointype = initialFilters[urlFilter];\n continue;\n }\n // Add each filter row.\n rowcount += 1;\n const filterdata = {\n filtertype: urlFilter,\n values: initialFilters[urlFilter].values,\n jointype: initialFilters[urlFilter].jointype,\n filteroptions: initialFilters[urlFilter].filteroptions,\n rownum: rowcount\n };\n coreFilter.addFilterRow(filterdata);\n }\n coreFilter.filterSet.dataset.filterverb = jointype;\n\n // Since we must filter by category, it does not make sense to allow the top-level \"match any\" or \"match none\" conditions,\n // as this would exclude the category. Remove those options and disable the select.\n const join = coreFilter.filterSet.querySelector(Selectors.filterset.fields.join);\n join.querySelectorAll(`option:not([value=\"${jointype}\"])`).forEach((option) => option.remove());\n join.disabled = true;\n }\n};\n"],"names":["filterRegionId","defaultcourseid","defaultcategoryid","perpage","contextId","component","callback","view","cmid","pagevars","extraparams","SELECTORS","filterSet","document","querySelector","filterCondition","cat","courseid","filter","jointype","qpage","qperpage","sortdata","tabname","defaultSort","_document$querySelect","dataset","_document$querySelect2","defaultsort","sortData","JSON","parse","coreFilter","CoreFilter","filterdata","pendingPromise","parseInt","filterverb","Object","keys","length","isNaN","updateUrlParams","viewData","filtercondition","stringify","lastchanged","_document$querySelect4","value","loadFragment","then","questionhtml","jsfooter","questionscontainer","undefined","replaceNodeContents","resolve","catch","Notification","exception","activeFilters","init","filters","url","URL","location","href","filterQuery","searchParams","set","history","pushState","editSwitch","editSwitchUrlInput","editSwitchUrl","pageurl","initialFilters","addEventListener","e","sortableLink","target","closest","paginationLink","clearLink","Selectors","filterset","actions","resetFilters","preventDefault","oldSort","sortname","sortorder","updateTableFromFilter","paginationURL","getAttribute","get","search","queryString","urlParams","URLSearchParams","has","cleanedUrl","replace","cleanUrlParams","entries","emptyFilterRow","regions","remove","rowcount","urlFilter","filtertype","values","filteroptions","rownum","addFilterRow","join","fields","querySelectorAll","forEach","option","disabled"],"mappings":"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"} \ No newline at end of file diff --git a/question/amd/src/filter.js b/question/amd/src/filter.js index 5cdcb841929..d89a0190218 100644 --- a/question/amd/src/filter.js +++ b/question/amd/src/filter.js @@ -86,8 +86,6 @@ export const init = ( filterCondition.sortData = JSON.parse(defaultSort); } - let filterQuery = ''; - /** * Retrieve table data. * @@ -116,7 +114,6 @@ export const init = ( cmid: cmid, filtercondition: JSON.stringify(filterCondition), extraparams: extraparams, - filterquery: filterQuery, lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null }; Fragment.loadFragment(component, callback, contextId, viewData) @@ -154,13 +151,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); diff --git a/question/classes/local/bank/view.php b/question/classes/local/bank/view.php index f072c225455..f3cdf59c172 100644 --- a/question/classes/local/bank/view.php +++ b/question/classes/local/bank/view.php @@ -1111,10 +1111,15 @@ class view { [$categoryid, $contextid] = category_condition::validate_category_param($this->pagevars['cat']); $catcontext = \context::instance_by_id($contextid); - $canadd = has_capability('moodle/question:add', $catcontext); - - $category = category_condition::get_category_record($categoryid, $contextid); - $this->create_new_question_form($category, $canadd); + echo \html_writer::start_tag( + 'div', + [ + 'id' => 'questionscontainer', + 'data-component' => $this->component, + 'data-callback' => $this->callback, + 'data-contextid' => $this->get_most_specific_context()->id, + ] + ); $this->build_query(); $questionsrs = $this->load_page_questions(); @@ -1134,7 +1139,7 @@ class view { echo \html_writer::input_hidden_params($this->baseurl); echo \html_writer::start_tag('div', - ['class' => 'categoryquestionscontainer', 'id' => 'questionscontainer']); + ['class' => 'categoryquestionscontainer']); if ($totalquestions > 0) { // Bulk load any required statistics. $this->load_required_statistics($questions); @@ -1151,6 +1156,7 @@ class view { echo \html_writer::end_tag('fieldset'); echo \html_writer::end_tag('form'); + echo \html_writer::end_tag('div'); } /** diff --git a/question/lib.php b/question/lib.php index b10c10f48ed..50fc3f953e2 100644 --- a/question/lib.php +++ b/question/lib.php @@ -138,8 +138,8 @@ function core_question_output_fragment_question_data(array $args): string { } else { $thispageurl->param('courseid', $params['courseid']); } - if (!empty($args['filterquery'])) { - $thispageurl->param('filter', $args['filterquery']); + if (!empty($args['filtercondition'])) { + $thispageurl->param('filter', $args['filtercondition']); } if (!empty($args['lastchanged'])) { $thispageurl->param('lastchanged', $args['lastchanged']); @@ -150,5 +150,8 @@ function core_question_output_fragment_question_data(array $args): string { } } $questionbank = new $viewclass($contexts, $thispageurl, $course, $cm, $params, $extraparams); - return $questionbank->display_questions_table(); + $questionbank->add_standard_search_conditions(); + ob_start(); + $questionbank->display_question_list(); + return ob_get_clean(); }