From e99d22692ff5d48de04f1f40f83f031b1c9bb189 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Tue, 17 Jun 2025 16:32:02 +0100 Subject: [PATCH] MDL-84487 mod_quiz: Use modal form for editing random questions Creating and editing random questions were using 2 different forms - one dynamic form in a modal, and the other a regular form on a standalone page. The "Switch bank" UI only works in a modal, so while it was displayed on the edit page, it didn't function. This combines the editing functionality with the existing modal form, so the same UI can be used for both operations, and the "Switch bank" functionality works. --- .../build/modal_add_random_question.min.js | 2 +- .../modal_add_random_question.min.js.map | 2 +- mod/quiz/amd/src/modal_add_random_question.js | 124 ++++++++++++-- mod/quiz/classes/form/randomquestion_form.php | 100 ----------- mod/quiz/classes/output/edit_renderer.php | 16 +- mod/quiz/editrandom.php | 162 ------------------ mod/quiz/lib.php | 26 ++- .../add_random_question_form.mustache | 16 +- .../tests/behat/editing_add_random.feature | 1 + .../tests/behat/editing_edit_random.feature | 37 +++- 10 files changed, 199 insertions(+), 287 deletions(-) delete mode 100644 mod/quiz/classes/form/randomquestion_form.php delete mode 100644 mod/quiz/editrandom.php diff --git a/mod/quiz/amd/build/modal_add_random_question.min.js b/mod/quiz/amd/build/modal_add_random_question.min.js index 0d5a1a20077..8186390a1fc 100644 --- a/mod/quiz/amd/build/modal_add_random_question.min.js +++ b/mod/quiz/amd/build/modal_add_random_question.min.js @@ -1,3 +1,3 @@ -define("mod_quiz/modal_add_random_question",["exports","jquery","./add_question_modal","core/notification","core/fragment","core/templates","core_form/changechecker","core/ajax","core/pending"],(function(_exports,_jquery,_add_question_modal,Notification,Fragment,Templates,FormChangeChecker,_ajax,_pending){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),_add_question_modal=_interopRequireDefault(_add_question_modal),Notification=_interopRequireWildcard(Notification),Fragment=_interopRequireWildcard(Fragment),Templates=_interopRequireWildcard(Templates),FormChangeChecker=_interopRequireWildcard(FormChangeChecker),_pending=_interopRequireDefault(_pending);const SELECTORS={ANCHOR:"a[href]",EXISTING_CATEGORY_CONTAINER:'[data-region="existing-category-container"]',EXISTING_CATEGORY_TAB:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:'[data-region="new-category-container"]',NEW_CATEGORY_TAB:"#id_newcategoryheader",TAB_CONTENT:'[data-region="tab-content"]',ADD_ON_PAGE_FORM_ELEMENT:'[name="addonpage"]',ADD_RANDOM_BUTTON:'input[type="submit"][name="addrandom"]',ADD_NEW_CATEGORY_BUTTON:'input[type="submit"][name="newcategory"]',SUBMIT_BUTTON_ELEMENT:'input[type="submit"][name="addrandom"], input[type="submit"][name="newcategory"]',FORM_HEADER:"legend",SELECT_NUMBER_TO_ADD:"#menurandomcount",NEW_CATEGORY_ELEMENT:"#categoryname",PARENT_CATEGORY_ELEMENT:"#parentcategory",FILTER_CONDITION_ELEMENT:"[data-filtercondition]",FORM_ELEMENT:"#add_random_question_form",MESSAGE_INPUT:'[name="message"]',SWITCH_TO_OTHER_BANK:'button[data-action="switch-question-bank"]',NEW_BANKMOD_ID:"data-newmodid",BANK_SEARCH:"#searchbanks",GO_BACK_BUTTON:'button[data-action="go-back"]'};class ModalAddRandomQuestion extends _add_question_modal.default{static init(contextId,bankCmId,category,returnUrl,quizCmId){let showNewCategory=!(arguments.length>5&&void 0!==arguments[5])||arguments[5];document.addEventListener("click",(e=>{const trigger=e.target.closest('.menu [data-action="addarandomquestion"]');trigger&&(e.preventDefault(),ModalAddRandomQuestion.create({contextId:contextId,bankCmId:bankCmId,category:category,returnUrl:returnUrl,quizCmId:quizCmId,showNewCategory:showNewCategory,title:trigger.dataset.header,addOnPage:trigger.dataset.addonpage,templateContext:{hidden:showNewCategory}}))}))}constructor(root){super(root),this.category=null,this.returnUrl=null,this.quizCmId=null,this.loadedForm=!1}configure(modalConfig){modalConfig.removeOnClose=!0,this.setCategory(modalConfig.category),this.setReturnUrl(modalConfig.returnUrl),this.showNewCategory=modalConfig.showNewCategory,super.configure(modalConfig)}setAddOnPageId(id){super.setAddOnPageId(id),this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id)}setCategory(category){this.category=category}getCategory(){return this.category}setReturnUrl(url){this.returnUrl=url}getReturnUrl(){return this.returnUrl}moveContentIntoTab(tabContent,tabElement){tabContent.find(SELECTORS.FORM_HEADER).addClass("hidden"),tabContent.wrap(tabElement)}moveTabsIntoTabContent(form){const tabContent=this.getBody().find(SELECTORS.TAB_CONTENT).empty();form.find('[role="tabpanel"]').wrapAll(tabContent)}moveCancelButtonToTabs(form){const cancelButton=form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass("ms-1"),tabFooters=form.find('[data-region="footer"]');cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove(),cancelButton.clone().appendTo(tabFooters)}loadForm(){const addonpage=this.getAddOnPageId(),returnurl=this.getReturnUrl(),quizcmid=this.quizCmId,bankcmid=this.bankCmId;return Fragment.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:addonpage,returnurl:returnurl,quizcmid:quizcmid,bankcmid:bankcmid}).then(((html,js)=>{const form=(0,_jquery.default)(html),existingCategoryTabContent=form.find(SELECTORS.EXISTING_CATEGORY_TAB),existingCategoryTab=this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER),newCategoryTabContent=form.find(SELECTORS.NEW_CATEGORY_TAB),newCategoryTab=this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);this.moveContentIntoTab(existingCategoryTabContent,existingCategoryTab),this.moveContentIntoTab(newCategoryTabContent,newCategoryTab),this.moveTabsIntoTabContent(form),Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT),form,js)})).then((()=>{FormChangeChecker.disableAllChecks(),this.getBody()[0].addEventListener("click",(e=>{if(!e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT))return;e.preventDefault(),document.querySelector('#questionscontainer input[name="cmid"]').setAttribute("name",this.quizCmId);if(e.target.closest(SELECTORS.ADD_RANDOM_BUTTON)){var _document$querySelect;const randomcount=document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value,filtercondition=null===(_document$querySelect=document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset)||void 0===_document$querySelect?void 0:_document$querySelect.filtercondition;return void this.addQuestions(quizcmid,addonpage,randomcount,filtercondition,"","")}e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON)&&this.addQuestions(quizcmid,addonpage,1,"",document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value)})),this.getModal().on("click",SELECTORS.SWITCH_TO_OTHER_BANK,(()=>{this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH).then((function(ModalQuizQuestionBank){var _$;return null===(_$=(0,_jquery.default)(SELECTORS.BANK_SEARCH))||void 0===_$||_$.on("change",(e=>{const bankCmId=(0,_jquery.default)(e.currentTarget).val();bankCmId>0&&ModalAddRandomQuestion.create({contextId:ModalQuizQuestionBank.getContextId(),bankCmId:bankCmId,category:ModalQuizQuestionBank.getCategory(),returnUrl:ModalQuizQuestionBank.getReturnUrl(),quizCmId:ModalQuizQuestionBank.quizCmId,title:ModalQuizQuestionBank.originalTitle,addOnPage:ModalQuizQuestionBank.getAddOnPageId(),templateContext:{hidden:ModalQuizQuestionBank.showNewCategory},showNewCategory:ModalQuizQuestionBank.showNewCategory}).then(ModalQuizQuestionBank.destroy()).catch(Notification.exception)})),ModalQuizQuestionBank}))})),this.getModal().on("click",SELECTORS.GO_BACK_BUTTON,(e=>{const anchorElement=(0,_jquery.default)(e.currentTarget);ModalAddRandomQuestion.create({contextId:this.getContextId(),bankCmId:anchorElement.attr("value"),category:this.getCategory(),returnUrl:this.getReturnUrl(),quizCmId:this.quizCmId,title:this.originalTitle,addOnPage:this.getAddOnPageId(),templateContext:{hidden:this.showNewCategory},showNewCategory:this.showNewCategory}).then(this.destroy()).catch(Notification.exception)})),this.getModal().on("click",SELECTORS.ANCHOR,(e=>{const anchorElement=(0,_jquery.default)(e.currentTarget);anchorElement.closest("a["+SELECTORS.NEW_BANKMOD_ID+"]").length&&ModalAddRandomQuestion.create({contextId:this.getContextId(),bankCmId:anchorElement.attr(SELECTORS.NEW_BANKMOD_ID),category:this.getCategory(),returnUrl:this.getReturnUrl(),quizCmId:this.quizCmId,title:this.originalTitle,addOnPage:this.getAddOnPageId(),templateContext:{hidden:this.showNewCategory},showNewCategory:this.showNewCategory}).then(this.destroy()).catch(Notification.exception)}))})).catch(Notification.exception)}async addQuestions(quizcmid,addonpage,randomcount,filtercondition,newcategory,parentcategory){new _pending.default("mod-quiz/modal_add_random_questions");const call={methodname:"mod_quiz_add_random_questions",args:{cmid:quizcmid,addonpage:addonpage,randomcount:randomcount,filtercondition:filtercondition,newcategory:newcategory,parentcategory:parentcategory}};try{const response=await(0,_ajax.call)([call])[0],form=document.querySelector(SELECTORS.FORM_ELEMENT);form.querySelector(SELECTORS.MESSAGE_INPUT).value=response.message,form.submit()}catch(e){Notification.exception(e)}}show(){super.show(this),this.loadedForm||(this.tabHtml=this.getBody(),this.loadForm(window.location.search),this.loadedForm=!0)}}return _exports.default=ModalAddRandomQuestion,_defineProperty(ModalAddRandomQuestion,"TYPE","mod_quiz-quiz-add-random-question"),_defineProperty(ModalAddRandomQuestion,"TEMPLATE","mod_quiz/modal_add_random_question"),ModalAddRandomQuestion.registerModalType(),_exports.default})); +define("mod_quiz/modal_add_random_question",["exports","jquery","./add_question_modal","core/notification","core/fragment","core/templates","core_form/changechecker","core/ajax","core/pending"],(function(_exports,_jquery,_add_question_modal,Notification,Fragment,Templates,FormChangeChecker,_ajax,_pending){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),_add_question_modal=_interopRequireDefault(_add_question_modal),Notification=_interopRequireWildcard(Notification),Fragment=_interopRequireWildcard(Fragment),Templates=_interopRequireWildcard(Templates),FormChangeChecker=_interopRequireWildcard(FormChangeChecker),_pending=_interopRequireDefault(_pending);const SELECTORS={ANCHOR:"a[href]",EXISTING_CATEGORY_CONTAINER:'[data-region="existing-category-container"]',EXISTING_CATEGORY_TAB:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:'[data-region="new-category-container"]',NEW_CATEGORY_TAB:"#id_newcategoryheader",TAB_CONTENT:'[data-region="tab-content"]',ADD_ON_PAGE_FORM_ELEMENT:'[name="addonpage"]',ADD_RANDOM_BUTTON:'input[type="submit"][name="addrandom"]',ADD_NEW_CATEGORY_BUTTON:'input[type="submit"][name="newcategory"]',SUBMIT_BUTTON_ELEMENT:'input[type="submit"][name="addrandom"], input[type="submit"][name="newcategory"], input[type="submit"][name="update"]',FORM_HEADER:"legend",SELECT_NUMBER_TO_ADD:"#menurandomcount",NEW_CATEGORY_ELEMENT:"#categoryname",PARENT_CATEGORY_ELEMENT:"#parentcategory",FILTER_CONDITION_ELEMENT:"[data-filtercondition]",FORM_ELEMENT:"#add_random_question_form",MESSAGE_INPUT:'[name="message"]',SWITCH_TO_OTHER_BANK:'button[data-action="switch-question-bank"]',NEW_BANKMOD_ID:"data-newmodid",BANK_SEARCH:"#searchbanks",GO_BACK_BUTTON:'button[data-action="go-back"]',UPDATE_FILTER_BUTTON:'input[type="submit"][name="update"]'};class ModalAddRandomQuestion extends _add_question_modal.default{static init(contextId,bankCmId,category,returnUrl,quizCmId){let showNewCategory=!(arguments.length>5&&void 0!==arguments[5])||arguments[5];document.addEventListener("click",(e=>{const trigger=e.target.closest('.menu [data-action="addarandomquestion"], [data-action="editrandomquestion"]');trigger&&(e.preventDefault(),trigger.dataset.slotid&&(showNewCategory=!1),ModalAddRandomQuestion.create({contextId:contextId,bankCmId:bankCmId,category:category,returnUrl:returnUrl,quizCmId:quizCmId,showNewCategory:showNewCategory,title:trigger.dataset.header,addOnPage:trigger.dataset.addonpage,slotId:trigger.dataset.slotid,templateContext:{hidden:showNewCategory}}))}))}constructor(root){super(root),this.category=null,this.returnUrl=null,this.quizCmId=null,this.loadedForm=!1,this.slotId=0,this.savedFilterCondition=null}configure(modalConfig){var _modalConfig$slotId,_modalConfig$savedFil;modalConfig.removeOnClose=!0,this.setCategory(modalConfig.category),this.setReturnUrl(modalConfig.returnUrl),this.showNewCategory=modalConfig.showNewCategory,this.setSlotId(null!==(_modalConfig$slotId=modalConfig.slotId)&&void 0!==_modalConfig$slotId?_modalConfig$slotId:0),this.setSavedFilterCondition(null!==(_modalConfig$savedFil=modalConfig.savedFilterCondition)&&void 0!==_modalConfig$savedFil?_modalConfig$savedFil:null),super.configure(modalConfig)}setAddOnPageId(id){super.setAddOnPageId(id),this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id)}setCategory(category){this.category=category}getCategory(){return this.category}setReturnUrl(url){this.returnUrl=url}getReturnUrl(){return this.returnUrl}setSlotId(slotId){this.slotId=slotId}getSlotId(){return this.slotId}setSavedFilterCondition(filterCondition){this.savedFilterCondition=filterCondition}getSavedFilterCondition(){return this.savedFilterCondition}moveContentIntoTab(tabContent,tabElement){tabContent.find(SELECTORS.FORM_HEADER).addClass("hidden"),tabContent.wrap(tabElement)}moveTabsIntoTabContent(form){const tabContent=this.getBody().find(SELECTORS.TAB_CONTENT).empty();form.find('[role="tabpanel"]').wrapAll(tabContent)}moveCancelButtonToTabs(form){const cancelButton=form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass("ms-1"),tabFooters=form.find('[data-region="footer"]');cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove(),cancelButton.clone().appendTo(tabFooters)}loadForm(){const addonpage=this.getAddOnPageId(),returnurl=this.getReturnUrl(),quizcmid=this.quizCmId,bankcmid=this.bankCmId,savedfiltercondition=this.getSavedFilterCondition();return this.setSavedFilterCondition(null),Fragment.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:null!=addonpage?addonpage:null,returnurl:returnurl,quizcmid:quizcmid,bankcmid:bankcmid,slotid:this.getSlotId(),savedfiltercondition:savedfiltercondition}).then(((html,js)=>{const form=(0,_jquery.default)(html);if(!this.getSlotId()){const existingCategoryTabContent=form.find(SELECTORS.EXISTING_CATEGORY_TAB),existingCategoryTab=this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER),newCategoryTabContent=form.find(SELECTORS.NEW_CATEGORY_TAB),newCategoryTab=this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);this.moveContentIntoTab(existingCategoryTabContent,existingCategoryTab),this.moveContentIntoTab(newCategoryTabContent,newCategoryTab),this.moveTabsIntoTabContent(form)}Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT),form,js)})).then((()=>{FormChangeChecker.disableAllChecks(),this.getBody()[0].addEventListener("click",(e=>{if(!e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT))return;e.preventDefault(),document.querySelector('#questionscontainer input[name="cmid"]').setAttribute("name",this.quizCmId);if(e.target.closest(SELECTORS.ADD_RANDOM_BUTTON)){var _document$querySelect;const randomcount=document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value,filtercondition=null===(_document$querySelect=document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset)||void 0===_document$querySelect?void 0:_document$querySelect.filtercondition;return void this.addQuestions(quizcmid,addonpage,randomcount,filtercondition,"","")}if(e.target.closest(SELECTORS.UPDATE_FILTER_BUTTON)){var _document$querySelect2;const filtercondition=null===(_document$querySelect2=document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset)||void 0===_document$querySelect2?void 0:_document$querySelect2.filtercondition;return void this.updateFilterCondition(quizcmid,this.getSlotId(),filtercondition)}e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON)&&this.addQuestions(quizcmid,addonpage,1,"",document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value)})),this.getModal().on("click",SELECTORS.SWITCH_TO_OTHER_BANK,(()=>{var _document$querySelect3;this.setSavedFilterCondition(null===(_document$querySelect3=document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset)||void 0===_document$querySelect3?void 0:_document$querySelect3.filtercondition),this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH).then((function(ModalQuizQuestionBank){var _$;return null===(_$=(0,_jquery.default)(SELECTORS.BANK_SEARCH))||void 0===_$||_$.on("change",(e=>{const bankCmId=(0,_jquery.default)(e.currentTarget).val();bankCmId>0&&ModalAddRandomQuestion.create({contextId:ModalQuizQuestionBank.getContextId(),bankCmId:bankCmId,category:ModalQuizQuestionBank.getCategory(),returnUrl:ModalQuizQuestionBank.getReturnUrl(),quizCmId:ModalQuizQuestionBank.quizCmId,title:ModalQuizQuestionBank.originalTitle,addOnPage:ModalQuizQuestionBank.getAddOnPageId(),templateContext:{hidden:ModalQuizQuestionBank.showNewCategory},showNewCategory:ModalQuizQuestionBank.showNewCategory,slotId:ModalQuizQuestionBank.getSlotId()}).then(ModalQuizQuestionBank.destroy()).catch(Notification.exception)})),ModalQuizQuestionBank}))})),this.getModal().on("click",SELECTORS.GO_BACK_BUTTON,(e=>{const anchorElement=(0,_jquery.default)(e.currentTarget);ModalAddRandomQuestion.create({contextId:this.getContextId(),bankCmId:anchorElement.attr("value"),category:this.getCategory(),returnUrl:this.getReturnUrl(),quizCmId:this.quizCmId,title:this.originalTitle,addOnPage:this.getAddOnPageId(),templateContext:{hidden:this.showNewCategory},showNewCategory:this.showNewCategory,savedFilterCondition:this.getSavedFilterCondition(),slotId:this.getSlotId()}).then(this.destroy()).catch(Notification.exception)})),this.getModal().on("click",SELECTORS.ANCHOR,(e=>{const anchorElement=(0,_jquery.default)(e.currentTarget);anchorElement.closest("a["+SELECTORS.NEW_BANKMOD_ID+"]").length&&ModalAddRandomQuestion.create({contextId:this.getContextId(),bankCmId:anchorElement.attr(SELECTORS.NEW_BANKMOD_ID),category:this.getCategory(),returnUrl:this.getReturnUrl(),quizCmId:this.quizCmId,title:this.originalTitle,addOnPage:this.getAddOnPageId(),templateContext:{hidden:this.showNewCategory},showNewCategory:this.showNewCategory,slotId:this.getSlotId()}).then(this.destroy()).catch(Notification.exception)}))})).catch(Notification.exception)}async addQuestions(quizcmid,addonpage,randomcount,filtercondition,newcategory,parentcategory){new _pending.default("mod-quiz/modal_add_random_questions");const call={methodname:"mod_quiz_add_random_questions",args:{cmid:quizcmid,addonpage:addonpage,randomcount:randomcount,filtercondition:filtercondition,newcategory:newcategory,parentcategory:parentcategory}};try{const response=await(0,_ajax.call)([call])[0],form=document.querySelector(SELECTORS.FORM_ELEMENT);form.querySelector(SELECTORS.MESSAGE_INPUT).value=response.message,form.submit()}catch(e){Notification.exception(e)}}async updateFilterCondition(quizcmid,slotid,filtercondition){new _pending.default("mod-quiz/modal_add_random_questions");const call={methodname:"mod_quiz_update_filter_condition",args:{cmid:quizcmid,slotid:slotid,filtercondition:filtercondition}};try{const response=await(0,_ajax.call)([call])[0],form=document.querySelector(SELECTORS.FORM_ELEMENT);form.querySelector(SELECTORS.MESSAGE_INPUT).value=response.message,form.submit()}catch(e){Notification.exception(e)}}show(){super.show(this),this.loadedForm||(this.tabHtml=this.getBody(),this.loadForm(window.location.search),this.loadedForm=!0)}}return _exports.default=ModalAddRandomQuestion,_defineProperty(ModalAddRandomQuestion,"TYPE","mod_quiz-quiz-add-random-question"),_defineProperty(ModalAddRandomQuestion,"TEMPLATE","mod_quiz/modal_add_random_question"),ModalAddRandomQuestion.registerModalType(),_exports.default})); //# sourceMappingURL=modal_add_random_question.min.js.map \ No newline at end of file diff --git a/mod/quiz/amd/build/modal_add_random_question.min.js.map b/mod/quiz/amd/build/modal_add_random_question.min.js.map index 8997a6c8490..cc6cab4e700 100644 --- a/mod/quiz/amd/build/modal_add_random_question.min.js.map +++ b/mod/quiz/amd/build/modal_add_random_question.min.js.map @@ -1 +1 @@ -{"version":3,"file":"modal_add_random_question.min.js","sources":["../src/modal_add_random_question.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 * Contain the logic for the add random question modal.\n *\n * @module mod_quiz/modal_add_random_question\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Modal from './add_question_modal';\nimport * as Notification from 'core/notification';\nimport * as Fragment from 'core/fragment';\nimport * as Templates from 'core/templates';\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport {call as fetchMany} from 'core/ajax';\nimport Pending from 'core/pending';\n\nconst SELECTORS = {\n ANCHOR: 'a[href]',\n EXISTING_CATEGORY_CONTAINER: '[data-region=\"existing-category-container\"]',\n EXISTING_CATEGORY_TAB: '#id_existingcategoryheader',\n NEW_CATEGORY_CONTAINER: '[data-region=\"new-category-container\"]',\n NEW_CATEGORY_TAB: '#id_newcategoryheader',\n TAB_CONTENT: '[data-region=\"tab-content\"]',\n ADD_ON_PAGE_FORM_ELEMENT: '[name=\"addonpage\"]',\n ADD_RANDOM_BUTTON: 'input[type=\"submit\"][name=\"addrandom\"]',\n ADD_NEW_CATEGORY_BUTTON: 'input[type=\"submit\"][name=\"newcategory\"]',\n SUBMIT_BUTTON_ELEMENT: 'input[type=\"submit\"][name=\"addrandom\"], input[type=\"submit\"][name=\"newcategory\"]',\n FORM_HEADER: 'legend',\n SELECT_NUMBER_TO_ADD: '#menurandomcount',\n NEW_CATEGORY_ELEMENT: '#categoryname',\n PARENT_CATEGORY_ELEMENT: '#parentcategory',\n FILTER_CONDITION_ELEMENT: '[data-filtercondition]',\n FORM_ELEMENT: '#add_random_question_form',\n MESSAGE_INPUT: '[name=\"message\"]',\n SWITCH_TO_OTHER_BANK: 'button[data-action=\"switch-question-bank\"]',\n NEW_BANKMOD_ID: 'data-newmodid',\n BANK_SEARCH: '#searchbanks',\n GO_BACK_BUTTON: 'button[data-action=\"go-back\"]',\n};\n\nexport default class ModalAddRandomQuestion extends Modal {\n static TYPE = 'mod_quiz-quiz-add-random-question';\n static TEMPLATE = 'mod_quiz/modal_add_random_question';\n\n /**\n * Create the add random question modal.\n *\n * @param {Number} contextId Current context id.\n * @param {Number} bankCmId Current question bank course module id.\n * @param {string} category Category id and category context id comma separated.\n * @param {string} returnUrl URL to return to after form submission.\n * @param {Number} quizCmId Current quiz course module id.\n * @param {boolean} showNewCategory Display the New category tab when selecting random questions.\n */\n static init(\n contextId,\n bankCmId,\n category,\n returnUrl,\n quizCmId,\n showNewCategory = true\n ) {\n const selector = '.menu [data-action=\"addarandomquestion\"]';\n document.addEventListener('click', (e) => {\n const trigger = e.target.closest(selector);\n if (!trigger) {\n return;\n }\n e.preventDefault();\n\n ModalAddRandomQuestion.create({\n contextId,\n bankCmId,\n category,\n returnUrl,\n quizCmId,\n showNewCategory,\n title: trigger.dataset.header,\n addOnPage: trigger.dataset.addonpage,\n\n templateContext: {\n hidden: showNewCategory,\n },\n });\n });\n }\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n constructor(root) {\n super(root);\n this.category = null;\n this.returnUrl = null;\n this.quizCmId = null;\n this.loadedForm = false;\n }\n\n configure(modalConfig) {\n modalConfig.removeOnClose = true;\n\n this.setCategory(modalConfig.category);\n this.setReturnUrl(modalConfig.returnUrl);\n this.showNewCategory = modalConfig.showNewCategory;\n\n super.configure(modalConfig);\n }\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n setAddOnPageId(id) {\n super.setAddOnPageId(id);\n this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id);\n }\n\n /**\n * Set the category for this form. The category is a comma separated\n * category id and category context id.\n *\n * @method setCategory\n * @param {string} category\n */\n setCategory(category) {\n this.category = category;\n }\n\n /**\n * Returns the saved category.\n *\n * @method getCategory\n * @return {string}\n */\n getCategory() {\n return this.category;\n }\n\n /**\n * Set the return URL for the form.\n *\n * @method setReturnUrl\n * @param {string} url\n */\n setReturnUrl(url) {\n this.returnUrl = url;\n }\n\n /**\n * Returns the return URL for the form.\n *\n * @method getReturnUrl\n * @return {string}\n */\n getReturnUrl() {\n return this.returnUrl;\n }\n\n /**\n * Moves a given form element inside (a child of) a given tab element.\n *\n * Hides the 'legend' (e.g. header) element of the form element because the\n * tab has the name.\n *\n * Moves the submit button into a footer element at the bottom of the form\n * element for styling purposes.\n *\n * @method moveContentIntoTab\n * @param {jquery} tabContent The form element to move into the tab.\n * @param {jquey} tabElement The tab element for the form element to move into.\n */\n moveContentIntoTab(tabContent, tabElement) {\n // Hide the header because the tabs show us which part of the form we're\n // looking at.\n tabContent.find(SELECTORS.FORM_HEADER).addClass('hidden');\n // Move the element inside a tab.\n tabContent.wrap(tabElement);\n }\n\n /**\n * Empty the tab content container and move all tabs from the form into the\n * tab container element.\n *\n * @method moveTabsIntoTabContent\n * @param {jquery} form The form element.\n */\n moveTabsIntoTabContent(form) {\n // Empty it to remove the loading icon.\n const tabContent = this.getBody().find(SELECTORS.TAB_CONTENT).empty();\n // Make sure all tabs are inside the tab content element.\n form.find('[role=\"tabpanel\"]').wrapAll(tabContent);\n }\n\n /**\n * Make sure all of the tabs have a cancel button in their fotter to sit along\n * side the submit button.\n *\n * @method moveCancelButtonToTabs\n * @param {jquey} form The form element.\n */\n moveCancelButtonToTabs(form) {\n const cancelButton = form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass('ms-1');\n const tabFooters = form.find('[data-region=\"footer\"]');\n // Remove the buttons container element.\n cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove();\n cancelButton.clone().appendTo(tabFooters);\n }\n\n /**\n * Load the add random question form in a fragement and perform some transformation\n * on the HTML to convert it into tabs for rendering in the modal.\n *\n * @method loadForm\n * @return {promise} Resolved with form HTML and JS.\n */\n loadForm() {\n const addonpage = this.getAddOnPageId();\n const returnurl = this.getReturnUrl();\n const quizcmid = this.quizCmId;\n const bankcmid = this.bankCmId;\n\n return Fragment.loadFragment(\n 'mod_quiz',\n 'add_random_question_form',\n this.getContextId(),\n {\n addonpage,\n returnurl,\n quizcmid,\n bankcmid,\n }\n )\n .then((html, js) => {\n const form = $(html);\n const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB);\n const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);\n const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB);\n const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);\n\n // Transform the form into tabs for better rendering in the modal.\n this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab);\n this.moveContentIntoTab(newCategoryTabContent, newCategoryTab);\n this.moveTabsIntoTabContent(form);\n\n Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);\n return;\n })\n .then(() => {\n // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the\n // page once the modal is hidden.\n FormChangeChecker.disableAllChecks();\n\n // Add question to quiz.\n this.getBody()[0].addEventListener('click', (e) => {\n const button = e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT);\n if (!button) {\n return;\n }\n e.preventDefault();\n\n // Intercept the submission to adjust the POST params so that the quiz mod id is set and not the bank module id.\n document.querySelector('#questionscontainer input[name=\"cmid\"]').setAttribute('name', this.quizCmId);\n\n // Add Random questions if the add random button was clicked.\n const addRandomButton = e.target.closest(SELECTORS.ADD_RANDOM_BUTTON);\n if (addRandomButton) {\n const randomcount = document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value;\n const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition;\n\n this.addQuestions(quizcmid, addonpage, randomcount, filtercondition, '', '');\n return;\n }\n // Add new category if the add category button was clicked.\n const addCategoryButton = e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON);\n if (addCategoryButton) {\n this.addQuestions(\n quizcmid,\n addonpage,\n 1,\n '',\n document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,\n document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value\n );\n return;\n }\n });\n\n this.getModal().on('click', SELECTORS.SWITCH_TO_OTHER_BANK, () => {\n this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH)\n .then(function(ModalQuizQuestionBank) {\n $(SELECTORS.BANK_SEARCH)?.on('change', (e) => {\n const bankCmId = $(e.currentTarget).val();\n // Have to recreate the modal as we have already used the body for the switch bank content.\n if (bankCmId > 0) {\n ModalAddRandomQuestion.create({\n 'contextId': ModalQuizQuestionBank.getContextId(),\n 'bankCmId': bankCmId,\n 'category': ModalQuizQuestionBank.getCategory(),\n 'returnUrl': ModalQuizQuestionBank.getReturnUrl(),\n 'quizCmId': ModalQuizQuestionBank.quizCmId,\n 'title': ModalQuizQuestionBank.originalTitle,\n 'addOnPage': ModalQuizQuestionBank.getAddOnPageId(),\n 'templateContext': {hidden: ModalQuizQuestionBank.showNewCategory},\n 'showNewCategory': ModalQuizQuestionBank.showNewCategory,\n })\n .then(ModalQuizQuestionBank.destroy())\n .catch(Notification.exception);\n }\n });\n return ModalQuizQuestionBank;\n });\n });\n\n this.getModal().on('click', SELECTORS.GO_BACK_BUTTON, (e) => {\n const anchorElement = $(e.currentTarget);\n // Have to recreate the modal as we have already used the body for the switch bank content.\n ModalAddRandomQuestion.create({\n 'contextId': this.getContextId(),\n 'bankCmId': anchorElement.attr('value'),\n 'category': this.getCategory(),\n 'returnUrl': this.getReturnUrl(),\n 'quizCmId': this.quizCmId,\n 'title': this.originalTitle,\n 'addOnPage': this.getAddOnPageId(),\n 'templateContext': {hidden: this.showNewCategory},\n 'showNewCategory': this.showNewCategory,\n }).then(this.destroy()).catch(Notification.exception);\n });\n\n this.getModal().on('click', SELECTORS.ANCHOR, (e) => {\n const anchorElement = $(e.currentTarget);\n // Have to recreate the modal as we have already used the body for the switch bank content.\n if (anchorElement.closest('a[' + SELECTORS.NEW_BANKMOD_ID + ']').length) {\n ModalAddRandomQuestion.create({\n 'contextId': this.getContextId(),\n 'bankCmId': anchorElement.attr(SELECTORS.NEW_BANKMOD_ID),\n 'category': this.getCategory(),\n 'returnUrl': this.getReturnUrl(),\n 'quizCmId': this.quizCmId,\n 'title': this.originalTitle,\n 'addOnPage': this.getAddOnPageId(),\n 'templateContext': {hidden: this.showNewCategory},\n 'showNewCategory': this.showNewCategory,\n }).then(this.destroy()).catch(Notification.exception);\n }\n });\n })\n .catch(Notification.exception);\n }\n\n /**\n * Call web service function to add random questions\n *\n * @param {number} quizcmid the course module id of the quiz to add questions to.\n * @param {number} addonpage the page where random questions will be added to\n * @param {number} randomcount Number of random questions\n * @param {string} filtercondition Filter condition\n * @param {string} newcategory add new category\n * @param {string} parentcategory parent category of new category\n */\n async addQuestions(\n quizcmid,\n addonpage,\n randomcount,\n filtercondition,\n newcategory,\n parentcategory\n ) {\n // We do not need to resolve this Pending because the form submission will result in a page redirect.\n new Pending('mod-quiz/modal_add_random_questions');\n const call = {\n methodname: 'mod_quiz_add_random_questions',\n args: {\n cmid: quizcmid,\n addonpage,\n randomcount,\n filtercondition,\n newcategory,\n parentcategory,\n }\n };\n try {\n const response = await fetchMany([call])[0];\n const form = document.querySelector(SELECTORS.FORM_ELEMENT);\n const messageInput = form.querySelector(SELECTORS.MESSAGE_INPUT);\n messageInput.value = response.message;\n form.submit();\n } catch (e) {\n Notification.exception(e);\n }\n }\n\n /**\n * Override the modal show function to load the form when this modal is first\n * shown.\n *\n * @method show\n */\n show() {\n super.show(this);\n\n if (!this.loadedForm) {\n this.tabHtml = this.getBody();\n this.loadForm(window.location.search);\n this.loadedForm = true;\n }\n }\n}\n\nModalAddRandomQuestion.registerModalType();\n"],"names":["SELECTORS","ANCHOR","EXISTING_CATEGORY_CONTAINER","EXISTING_CATEGORY_TAB","NEW_CATEGORY_CONTAINER","NEW_CATEGORY_TAB","TAB_CONTENT","ADD_ON_PAGE_FORM_ELEMENT","ADD_RANDOM_BUTTON","ADD_NEW_CATEGORY_BUTTON","SUBMIT_BUTTON_ELEMENT","FORM_HEADER","SELECT_NUMBER_TO_ADD","NEW_CATEGORY_ELEMENT","PARENT_CATEGORY_ELEMENT","FILTER_CONDITION_ELEMENT","FORM_ELEMENT","MESSAGE_INPUT","SWITCH_TO_OTHER_BANK","NEW_BANKMOD_ID","BANK_SEARCH","GO_BACK_BUTTON","ModalAddRandomQuestion","Modal","contextId","bankCmId","category","returnUrl","quizCmId","showNewCategory","document","addEventListener","e","trigger","target","closest","preventDefault","create","title","dataset","header","addOnPage","addonpage","templateContext","hidden","constructor","root","loadedForm","configure","modalConfig","removeOnClose","setCategory","setReturnUrl","setAddOnPageId","id","getBody","find","val","getCategory","this","url","getReturnUrl","moveContentIntoTab","tabContent","tabElement","addClass","wrap","moveTabsIntoTabContent","form","empty","wrapAll","moveCancelButtonToTabs","cancelButton","CANCEL_BUTTON_ELEMENT","tabFooters","BUTTON_CONTAINER","remove","clone","appendTo","loadForm","getAddOnPageId","returnurl","quizcmid","bankcmid","Fragment","loadFragment","getContextId","then","html","js","existingCategoryTabContent","existingCategoryTab","newCategoryTabContent","newCategoryTab","Templates","replaceNode","FormChangeChecker","disableAllChecks","querySelector","setAttribute","randomcount","value","filtercondition","_document$querySelect","addQuestions","getModal","on","handleSwitchBankContentReload","ModalQuizQuestionBank","currentTarget","originalTitle","destroy","catch","Notification","exception","anchorElement","attr","length","newcategory","parentcategory","Pending","call","methodname","args","cmid","response","message","submit","show","tabHtml","window","location","search","registerModalType"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"modal_add_random_question.min.js","sources":["../src/modal_add_random_question.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 * Contain the logic for the add random question modal.\n *\n * @module mod_quiz/modal_add_random_question\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Modal from './add_question_modal';\nimport * as Notification from 'core/notification';\nimport * as Fragment from 'core/fragment';\nimport * as Templates from 'core/templates';\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport {call as fetchMany} from 'core/ajax';\nimport Pending from 'core/pending';\n\nconst SELECTORS = {\n ANCHOR: 'a[href]',\n EXISTING_CATEGORY_CONTAINER: '[data-region=\"existing-category-container\"]',\n EXISTING_CATEGORY_TAB: '#id_existingcategoryheader',\n NEW_CATEGORY_CONTAINER: '[data-region=\"new-category-container\"]',\n NEW_CATEGORY_TAB: '#id_newcategoryheader',\n TAB_CONTENT: '[data-region=\"tab-content\"]',\n ADD_ON_PAGE_FORM_ELEMENT: '[name=\"addonpage\"]',\n ADD_RANDOM_BUTTON: 'input[type=\"submit\"][name=\"addrandom\"]',\n ADD_NEW_CATEGORY_BUTTON: 'input[type=\"submit\"][name=\"newcategory\"]',\n SUBMIT_BUTTON_ELEMENT: 'input[type=\"submit\"][name=\"addrandom\"], '\n + 'input[type=\"submit\"][name=\"newcategory\"], '\n + 'input[type=\"submit\"][name=\"update\"]',\n FORM_HEADER: 'legend',\n SELECT_NUMBER_TO_ADD: '#menurandomcount',\n NEW_CATEGORY_ELEMENT: '#categoryname',\n PARENT_CATEGORY_ELEMENT: '#parentcategory',\n FILTER_CONDITION_ELEMENT: '[data-filtercondition]',\n FORM_ELEMENT: '#add_random_question_form',\n MESSAGE_INPUT: '[name=\"message\"]',\n SWITCH_TO_OTHER_BANK: 'button[data-action=\"switch-question-bank\"]',\n NEW_BANKMOD_ID: 'data-newmodid',\n BANK_SEARCH: '#searchbanks',\n GO_BACK_BUTTON: 'button[data-action=\"go-back\"]',\n UPDATE_FILTER_BUTTON: 'input[type=\"submit\"][name=\"update\"]',\n};\n\nexport default class ModalAddRandomQuestion extends Modal {\n static TYPE = 'mod_quiz-quiz-add-random-question';\n static TEMPLATE = 'mod_quiz/modal_add_random_question';\n\n /**\n * Create the add random question modal.\n *\n * @param {Number} contextId Current context id.\n * @param {Number} bankCmId Current question bank course module id.\n * @param {string} category Category id and category context id comma separated.\n * @param {string} returnUrl URL to return to after form submission.\n * @param {Number} quizCmId Current quiz course module id.\n * @param {boolean} showNewCategory Display the New category tab when selecting random questions.\n */\n static init(\n contextId,\n bankCmId,\n category,\n returnUrl,\n quizCmId,\n showNewCategory = true\n ) {\n const selector = '.menu [data-action=\"addarandomquestion\"], [data-action=\"editrandomquestion\"]';\n document.addEventListener('click', (e) => {\n const trigger = e.target.closest(selector);\n if (!trigger) {\n return;\n }\n e.preventDefault();\n\n if (trigger.dataset.slotid) {\n showNewCategory = false;\n }\n\n ModalAddRandomQuestion.create({\n contextId,\n bankCmId,\n category,\n returnUrl,\n quizCmId,\n showNewCategory,\n title: trigger.dataset.header,\n addOnPage: trigger.dataset.addonpage,\n slotId: trigger.dataset.slotid,\n templateContext: {\n hidden: showNewCategory,\n },\n });\n });\n }\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n constructor(root) {\n super(root);\n this.category = null;\n this.returnUrl = null;\n this.quizCmId = null;\n this.loadedForm = false;\n this.slotId = 0;\n this.savedFilterCondition = null;\n }\n\n configure(modalConfig) {\n modalConfig.removeOnClose = true;\n\n this.setCategory(modalConfig.category);\n this.setReturnUrl(modalConfig.returnUrl);\n this.showNewCategory = modalConfig.showNewCategory;\n this.setSlotId(modalConfig.slotId ?? 0);\n this.setSavedFilterCondition(modalConfig.savedFilterCondition ?? null);\n\n super.configure(modalConfig);\n }\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n setAddOnPageId(id) {\n super.setAddOnPageId(id);\n this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id);\n }\n\n /**\n * Set the category for this form. The category is a comma separated\n * category id and category context id.\n *\n * @method setCategory\n * @param {string} category\n */\n setCategory(category) {\n this.category = category;\n }\n\n /**\n * Returns the saved category.\n *\n * @method getCategory\n * @return {string}\n */\n getCategory() {\n return this.category;\n }\n\n /**\n * Set the return URL for the form.\n *\n * @method setReturnUrl\n * @param {string} url\n */\n setReturnUrl(url) {\n this.returnUrl = url;\n }\n\n /**\n * Returns the return URL for the form.\n *\n * @method getReturnUrl\n * @return {string}\n */\n getReturnUrl() {\n return this.returnUrl;\n }\n\n /**\n * Set the ID of the quiz slot, if we are editing an existing random question.\n *\n * @param {Number} slotId\n */\n setSlotId(slotId) {\n this.slotId = slotId;\n }\n\n /**\n * Get the current slot ID.\n *\n * @return {Number}\n */\n getSlotId() {\n return this.slotId;\n }\n\n /**\n * Store the current filterCondition JSON string.\n *\n * @param {String} filterCondition\n */\n setSavedFilterCondition(filterCondition) {\n this.savedFilterCondition = filterCondition;\n }\n\n /**\n * Return the saved filterCondition JSON string.\n *\n * @return {String}\n */\n getSavedFilterCondition() {\n return this.savedFilterCondition;\n }\n\n /**\n * Moves a given form element inside (a child of) a given tab element.\n *\n * Hides the 'legend' (e.g. header) element of the form element because the\n * tab has the name.\n *\n * Moves the submit button into a footer element at the bottom of the form\n * element for styling purposes.\n *\n * @method moveContentIntoTab\n * @param {jquery} tabContent The form element to move into the tab.\n * @param {jquey} tabElement The tab element for the form element to move into.\n */\n moveContentIntoTab(tabContent, tabElement) {\n // Hide the header because the tabs show us which part of the form we're\n // looking at.\n tabContent.find(SELECTORS.FORM_HEADER).addClass('hidden');\n // Move the element inside a tab.\n tabContent.wrap(tabElement);\n }\n\n /**\n * Empty the tab content container and move all tabs from the form into the\n * tab container element.\n *\n * @method moveTabsIntoTabContent\n * @param {jquery} form The form element.\n */\n moveTabsIntoTabContent(form) {\n // Empty it to remove the loading icon.\n const tabContent = this.getBody().find(SELECTORS.TAB_CONTENT).empty();\n // Make sure all tabs are inside the tab content element.\n form.find('[role=\"tabpanel\"]').wrapAll(tabContent);\n }\n\n /**\n * Make sure all of the tabs have a cancel button in their fotter to sit along\n * side the submit button.\n *\n * @method moveCancelButtonToTabs\n * @param {jquey} form The form element.\n */\n moveCancelButtonToTabs(form) {\n const cancelButton = form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass('ms-1');\n const tabFooters = form.find('[data-region=\"footer\"]');\n // Remove the buttons container element.\n cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove();\n cancelButton.clone().appendTo(tabFooters);\n }\n\n /**\n * Load the add random question form in a fragement and perform some transformation\n * on the HTML to convert it into tabs for rendering in the modal.\n *\n * @method loadForm\n * @return {promise} Resolved with form HTML and JS.\n */\n loadForm() {\n const addonpage = this.getAddOnPageId();\n const returnurl = this.getReturnUrl();\n const quizcmid = this.quizCmId;\n const bankcmid = this.bankCmId;\n const savedfiltercondition = this.getSavedFilterCondition();\n this.setSavedFilterCondition(null);\n\n return Fragment.loadFragment(\n 'mod_quiz',\n 'add_random_question_form',\n this.getContextId(),\n {\n addonpage: addonpage ?? null,\n returnurl,\n quizcmid,\n bankcmid,\n slotid: this.getSlotId(),\n savedfiltercondition,\n }\n )\n .then((html, js) => {\n const form = $(html);\n if (!this.getSlotId()) {\n const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB);\n const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);\n const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB);\n const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);\n\n // Transform the form into tabs for better rendering in the modal.\n this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab);\n this.moveContentIntoTab(newCategoryTabContent, newCategoryTab);\n this.moveTabsIntoTabContent(form);\n }\n\n Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);\n return;\n })\n .then(() => {\n // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the\n // page once the modal is hidden.\n FormChangeChecker.disableAllChecks();\n\n // Add question to quiz.\n this.getBody()[0].addEventListener('click', (e) => {\n const button = e.target.closest(SELECTORS.SUBMIT_BUTTON_ELEMENT);\n if (!button) {\n return;\n }\n e.preventDefault();\n\n // Intercept the submission to adjust the POST params so that the quiz mod id is set and not the bank module id.\n document.querySelector('#questionscontainer input[name=\"cmid\"]').setAttribute('name', this.quizCmId);\n\n // Add Random questions if the add random button was clicked.\n const addRandomButton = e.target.closest(SELECTORS.ADD_RANDOM_BUTTON);\n if (addRandomButton) {\n const randomcount = document.querySelector(SELECTORS.SELECT_NUMBER_TO_ADD).value;\n const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition;\n\n this.addQuestions(quizcmid, addonpage, randomcount, filtercondition, '', '');\n return;\n }\n // Update the filter condition for the slot if the update button was clicked.\n const updateFilterButton = e.target.closest(SELECTORS.UPDATE_FILTER_BUTTON);\n if (updateFilterButton) {\n const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition;\n this.updateFilterCondition(quizcmid, this.getSlotId(), filtercondition);\n return;\n }\n // Add new category if the add category button was clicked.\n const addCategoryButton = e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON);\n if (addCategoryButton) {\n this.addQuestions(\n quizcmid,\n addonpage,\n 1,\n '',\n document.querySelector(SELECTORS.NEW_CATEGORY_ELEMENT).value,\n document.querySelector(SELECTORS.PARENT_CATEGORY_ELEMENT).value\n );\n return;\n }\n });\n\n this.getModal().on('click', SELECTORS.SWITCH_TO_OTHER_BANK, () => {\n this.setSavedFilterCondition(\n document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition\n );\n this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH)\n .then(function(ModalQuizQuestionBank) {\n $(SELECTORS.BANK_SEARCH)?.on('change', (e) => {\n const bankCmId = $(e.currentTarget).val();\n // Have to recreate the modal as we have already used the body for the switch bank content.\n if (bankCmId > 0) {\n ModalAddRandomQuestion.create({\n 'contextId': ModalQuizQuestionBank.getContextId(),\n 'bankCmId': bankCmId,\n 'category': ModalQuizQuestionBank.getCategory(),\n 'returnUrl': ModalQuizQuestionBank.getReturnUrl(),\n 'quizCmId': ModalQuizQuestionBank.quizCmId,\n 'title': ModalQuizQuestionBank.originalTitle,\n 'addOnPage': ModalQuizQuestionBank.getAddOnPageId(),\n 'templateContext': {hidden: ModalQuizQuestionBank.showNewCategory},\n 'showNewCategory': ModalQuizQuestionBank.showNewCategory,\n 'slotId': ModalQuizQuestionBank.getSlotId(),\n })\n .then(ModalQuizQuestionBank.destroy())\n .catch(Notification.exception);\n }\n });\n return ModalQuizQuestionBank;\n });\n });\n\n this.getModal().on('click', SELECTORS.GO_BACK_BUTTON, (e) => {\n const anchorElement = $(e.currentTarget);\n // Have to recreate the modal as we have already used the body for the switch bank content.\n ModalAddRandomQuestion.create({\n 'contextId': this.getContextId(),\n 'bankCmId': anchorElement.attr('value'),\n 'category': this.getCategory(),\n 'returnUrl': this.getReturnUrl(),\n 'quizCmId': this.quizCmId,\n 'title': this.originalTitle,\n 'addOnPage': this.getAddOnPageId(),\n 'templateContext': {hidden: this.showNewCategory},\n 'showNewCategory': this.showNewCategory,\n 'savedFilterCondition': this.getSavedFilterCondition(),\n 'slotId': this.getSlotId(),\n }).then(this.destroy()).catch(Notification.exception);\n });\n\n this.getModal().on('click', SELECTORS.ANCHOR, (e) => {\n const anchorElement = $(e.currentTarget);\n // Have to recreate the modal as we have already used the body for the switch bank content.\n if (anchorElement.closest('a[' + SELECTORS.NEW_BANKMOD_ID + ']').length) {\n ModalAddRandomQuestion.create({\n 'contextId': this.getContextId(),\n 'bankCmId': anchorElement.attr(SELECTORS.NEW_BANKMOD_ID),\n 'category': this.getCategory(),\n 'returnUrl': this.getReturnUrl(),\n 'quizCmId': this.quizCmId,\n 'title': this.originalTitle,\n 'addOnPage': this.getAddOnPageId(),\n 'templateContext': {hidden: this.showNewCategory},\n 'showNewCategory': this.showNewCategory,\n 'slotId': this.getSlotId(),\n }).then(this.destroy()).catch(Notification.exception);\n }\n });\n })\n .catch(Notification.exception);\n }\n\n /**\n * Call web service function to add random questions\n *\n * @param {number} quizcmid the course module id of the quiz to add questions to.\n * @param {number} addonpage the page where random questions will be added to\n * @param {number} randomcount Number of random questions\n * @param {string} filtercondition Filter condition\n * @param {string} newcategory add new category\n * @param {string} parentcategory parent category of new category\n */\n async addQuestions(\n quizcmid,\n addonpage,\n randomcount,\n filtercondition,\n newcategory,\n parentcategory\n ) {\n // We do not need to resolve this Pending because the form submission will result in a page redirect.\n new Pending('mod-quiz/modal_add_random_questions');\n const call = {\n methodname: 'mod_quiz_add_random_questions',\n args: {\n cmid: quizcmid,\n addonpage,\n randomcount,\n filtercondition,\n newcategory,\n parentcategory,\n }\n };\n try {\n const response = await fetchMany([call])[0];\n const form = document.querySelector(SELECTORS.FORM_ELEMENT);\n const messageInput = form.querySelector(SELECTORS.MESSAGE_INPUT);\n messageInput.value = response.message;\n form.submit();\n } catch (e) {\n Notification.exception(e);\n }\n }\n\n /**\n * Call web service function to update the filter condition for an existing slot.\n *\n * @param {number} quizcmid the course module id of the quiz.\n * @param {number} slotid The slot the random question is in.\n * @param {string} filtercondition The new filter condition.\n */\n async updateFilterCondition(\n quizcmid,\n slotid,\n filtercondition,\n ) {\n // We do not need to resolve this Pending because the form submission will result in a page redirect.\n new Pending('mod-quiz/modal_add_random_questions');\n const call = {\n methodname: 'mod_quiz_update_filter_condition',\n args: {\n cmid: quizcmid,\n slotid,\n filtercondition,\n }\n };\n try {\n const response = await fetchMany([call])[0];\n const form = document.querySelector(SELECTORS.FORM_ELEMENT);\n const messageInput = form.querySelector(SELECTORS.MESSAGE_INPUT);\n messageInput.value = response.message;\n form.submit();\n } catch (e) {\n Notification.exception(e);\n }\n }\n\n /**\n * Override the modal show function to load the form when this modal is first\n * shown.\n *\n * @method show\n */\n show() {\n super.show(this);\n\n if (!this.loadedForm) {\n this.tabHtml = this.getBody();\n this.loadForm(window.location.search);\n this.loadedForm = true;\n }\n }\n}\n\nModalAddRandomQuestion.registerModalType();\n"],"names":["SELECTORS","ANCHOR","EXISTING_CATEGORY_CONTAINER","EXISTING_CATEGORY_TAB","NEW_CATEGORY_CONTAINER","NEW_CATEGORY_TAB","TAB_CONTENT","ADD_ON_PAGE_FORM_ELEMENT","ADD_RANDOM_BUTTON","ADD_NEW_CATEGORY_BUTTON","SUBMIT_BUTTON_ELEMENT","FORM_HEADER","SELECT_NUMBER_TO_ADD","NEW_CATEGORY_ELEMENT","PARENT_CATEGORY_ELEMENT","FILTER_CONDITION_ELEMENT","FORM_ELEMENT","MESSAGE_INPUT","SWITCH_TO_OTHER_BANK","NEW_BANKMOD_ID","BANK_SEARCH","GO_BACK_BUTTON","UPDATE_FILTER_BUTTON","ModalAddRandomQuestion","Modal","contextId","bankCmId","category","returnUrl","quizCmId","showNewCategory","document","addEventListener","e","trigger","target","closest","preventDefault","dataset","slotid","create","title","header","addOnPage","addonpage","slotId","templateContext","hidden","constructor","root","loadedForm","savedFilterCondition","configure","modalConfig","removeOnClose","setCategory","setReturnUrl","setSlotId","setSavedFilterCondition","setAddOnPageId","id","getBody","find","val","getCategory","this","url","getReturnUrl","getSlotId","filterCondition","getSavedFilterCondition","moveContentIntoTab","tabContent","tabElement","addClass","wrap","moveTabsIntoTabContent","form","empty","wrapAll","moveCancelButtonToTabs","cancelButton","CANCEL_BUTTON_ELEMENT","tabFooters","BUTTON_CONTAINER","remove","clone","appendTo","loadForm","getAddOnPageId","returnurl","quizcmid","bankcmid","savedfiltercondition","Fragment","loadFragment","getContextId","then","html","js","existingCategoryTabContent","existingCategoryTab","newCategoryTabContent","newCategoryTab","Templates","replaceNode","FormChangeChecker","disableAllChecks","querySelector","setAttribute","randomcount","value","filtercondition","_document$querySelect","addQuestions","_document$querySelect2","updateFilterCondition","getModal","on","_document$querySelect3","handleSwitchBankContentReload","ModalQuizQuestionBank","currentTarget","originalTitle","destroy","catch","Notification","exception","anchorElement","attr","length","newcategory","parentcategory","Pending","call","methodname","args","cmid","response","message","submit","show","tabHtml","window","location","search","registerModalType"],"mappings":"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"} \ No newline at end of file diff --git a/mod/quiz/amd/src/modal_add_random_question.js b/mod/quiz/amd/src/modal_add_random_question.js index de99f9658ec..12d05f4fc9b 100644 --- a/mod/quiz/amd/src/modal_add_random_question.js +++ b/mod/quiz/amd/src/modal_add_random_question.js @@ -40,7 +40,9 @@ const SELECTORS = { ADD_ON_PAGE_FORM_ELEMENT: '[name="addonpage"]', ADD_RANDOM_BUTTON: 'input[type="submit"][name="addrandom"]', ADD_NEW_CATEGORY_BUTTON: 'input[type="submit"][name="newcategory"]', - SUBMIT_BUTTON_ELEMENT: 'input[type="submit"][name="addrandom"], input[type="submit"][name="newcategory"]', + SUBMIT_BUTTON_ELEMENT: 'input[type="submit"][name="addrandom"], ' + + 'input[type="submit"][name="newcategory"], ' + + 'input[type="submit"][name="update"]', FORM_HEADER: 'legend', SELECT_NUMBER_TO_ADD: '#menurandomcount', NEW_CATEGORY_ELEMENT: '#categoryname', @@ -52,6 +54,7 @@ const SELECTORS = { NEW_BANKMOD_ID: 'data-newmodid', BANK_SEARCH: '#searchbanks', GO_BACK_BUTTON: 'button[data-action="go-back"]', + UPDATE_FILTER_BUTTON: 'input[type="submit"][name="update"]', }; export default class ModalAddRandomQuestion extends Modal { @@ -76,7 +79,7 @@ export default class ModalAddRandomQuestion extends Modal { quizCmId, showNewCategory = true ) { - const selector = '.menu [data-action="addarandomquestion"]'; + const selector = '.menu [data-action="addarandomquestion"], [data-action="editrandomquestion"]'; document.addEventListener('click', (e) => { const trigger = e.target.closest(selector); if (!trigger) { @@ -84,6 +87,10 @@ export default class ModalAddRandomQuestion extends Modal { } e.preventDefault(); + if (trigger.dataset.slotid) { + showNewCategory = false; + } + ModalAddRandomQuestion.create({ contextId, bankCmId, @@ -93,7 +100,7 @@ export default class ModalAddRandomQuestion extends Modal { showNewCategory, title: trigger.dataset.header, addOnPage: trigger.dataset.addonpage, - + slotId: trigger.dataset.slotid, templateContext: { hidden: showNewCategory, }, @@ -112,6 +119,8 @@ export default class ModalAddRandomQuestion extends Modal { this.returnUrl = null; this.quizCmId = null; this.loadedForm = false; + this.slotId = 0; + this.savedFilterCondition = null; } configure(modalConfig) { @@ -120,6 +129,8 @@ export default class ModalAddRandomQuestion extends Modal { this.setCategory(modalConfig.category); this.setReturnUrl(modalConfig.returnUrl); this.showNewCategory = modalConfig.showNewCategory; + this.setSlotId(modalConfig.slotId ?? 0); + this.setSavedFilterCondition(modalConfig.savedFilterCondition ?? null); super.configure(modalConfig); } @@ -177,6 +188,42 @@ export default class ModalAddRandomQuestion extends Modal { return this.returnUrl; } + /** + * Set the ID of the quiz slot, if we are editing an existing random question. + * + * @param {Number} slotId + */ + setSlotId(slotId) { + this.slotId = slotId; + } + + /** + * Get the current slot ID. + * + * @return {Number} + */ + getSlotId() { + return this.slotId; + } + + /** + * Store the current filterCondition JSON string. + * + * @param {String} filterCondition + */ + setSavedFilterCondition(filterCondition) { + this.savedFilterCondition = filterCondition; + } + + /** + * Return the saved filterCondition JSON string. + * + * @return {String} + */ + getSavedFilterCondition() { + return this.savedFilterCondition; + } + /** * Moves a given form element inside (a child of) a given tab element. * @@ -239,29 +286,35 @@ export default class ModalAddRandomQuestion extends Modal { const returnurl = this.getReturnUrl(); const quizcmid = this.quizCmId; const bankcmid = this.bankCmId; + const savedfiltercondition = this.getSavedFilterCondition(); + this.setSavedFilterCondition(null); return Fragment.loadFragment( 'mod_quiz', 'add_random_question_form', this.getContextId(), { - addonpage, + addonpage: addonpage ?? null, returnurl, quizcmid, bankcmid, + slotid: this.getSlotId(), + savedfiltercondition, } ) .then((html, js) => { const form = $(html); - const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB); - const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER); - const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB); - const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER); + if (!this.getSlotId()) { + const existingCategoryTabContent = form.find(SELECTORS.EXISTING_CATEGORY_TAB); + const existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER); + const newCategoryTabContent = form.find(SELECTORS.NEW_CATEGORY_TAB); + const newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER); - // Transform the form into tabs for better rendering in the modal. - this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab); - this.moveContentIntoTab(newCategoryTabContent, newCategoryTab); - this.moveTabsIntoTabContent(form); + // Transform the form into tabs for better rendering in the modal. + this.moveContentIntoTab(existingCategoryTabContent, existingCategoryTab); + this.moveContentIntoTab(newCategoryTabContent, newCategoryTab); + this.moveTabsIntoTabContent(form); + } Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js); return; @@ -291,6 +344,13 @@ export default class ModalAddRandomQuestion extends Modal { this.addQuestions(quizcmid, addonpage, randomcount, filtercondition, '', ''); return; } + // Update the filter condition for the slot if the update button was clicked. + const updateFilterButton = e.target.closest(SELECTORS.UPDATE_FILTER_BUTTON); + if (updateFilterButton) { + const filtercondition = document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition; + this.updateFilterCondition(quizcmid, this.getSlotId(), filtercondition); + return; + } // Add new category if the add category button was clicked. const addCategoryButton = e.target.closest(SELECTORS.ADD_NEW_CATEGORY_BUTTON); if (addCategoryButton) { @@ -307,6 +367,9 @@ export default class ModalAddRandomQuestion extends Modal { }); this.getModal().on('click', SELECTORS.SWITCH_TO_OTHER_BANK, () => { + this.setSavedFilterCondition( + document.querySelector(SELECTORS.FILTER_CONDITION_ELEMENT).dataset?.filtercondition + ); this.handleSwitchBankContentReload(SELECTORS.BANK_SEARCH) .then(function(ModalQuizQuestionBank) { $(SELECTORS.BANK_SEARCH)?.on('change', (e) => { @@ -323,6 +386,7 @@ export default class ModalAddRandomQuestion extends Modal { 'addOnPage': ModalQuizQuestionBank.getAddOnPageId(), 'templateContext': {hidden: ModalQuizQuestionBank.showNewCategory}, 'showNewCategory': ModalQuizQuestionBank.showNewCategory, + 'slotId': ModalQuizQuestionBank.getSlotId(), }) .then(ModalQuizQuestionBank.destroy()) .catch(Notification.exception); @@ -345,6 +409,8 @@ export default class ModalAddRandomQuestion extends Modal { 'addOnPage': this.getAddOnPageId(), 'templateContext': {hidden: this.showNewCategory}, 'showNewCategory': this.showNewCategory, + 'savedFilterCondition': this.getSavedFilterCondition(), + 'slotId': this.getSlotId(), }).then(this.destroy()).catch(Notification.exception); }); @@ -362,6 +428,7 @@ export default class ModalAddRandomQuestion extends Modal { 'addOnPage': this.getAddOnPageId(), 'templateContext': {hidden: this.showNewCategory}, 'showNewCategory': this.showNewCategory, + 'slotId': this.getSlotId(), }).then(this.destroy()).catch(Notification.exception); } }); @@ -411,6 +478,39 @@ export default class ModalAddRandomQuestion extends Modal { } } + /** + * Call web service function to update the filter condition for an existing slot. + * + * @param {number} quizcmid the course module id of the quiz. + * @param {number} slotid The slot the random question is in. + * @param {string} filtercondition The new filter condition. + */ + async updateFilterCondition( + quizcmid, + slotid, + filtercondition, + ) { + // We do not need to resolve this Pending because the form submission will result in a page redirect. + new Pending('mod-quiz/modal_add_random_questions'); + const call = { + methodname: 'mod_quiz_update_filter_condition', + args: { + cmid: quizcmid, + slotid, + filtercondition, + } + }; + try { + const response = await fetchMany([call])[0]; + const form = document.querySelector(SELECTORS.FORM_ELEMENT); + const messageInput = form.querySelector(SELECTORS.MESSAGE_INPUT); + messageInput.value = response.message; + form.submit(); + } catch (e) { + Notification.exception(e); + } + } + /** * Override the modal show function to load the form when this modal is first * shown. diff --git a/mod/quiz/classes/form/randomquestion_form.php b/mod/quiz/classes/form/randomquestion_form.php deleted file mode 100644 index 4636e115eb0..00000000000 --- a/mod/quiz/classes/form/randomquestion_form.php +++ /dev/null @@ -1,100 +0,0 @@ -. - -/** - * Defines the editing form for random questions. - * - * @package mod_quiz - * @copyright 2018 Shamim Rezaie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace mod_quiz\form; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot.'/lib/formslib.php'); - -/** - * Class randomquestion_form - * - * @package mod_quiz - * @copyright 2018 Shamim Rezaie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class randomquestion_form extends \moodleform { - - /** - * Form definiton. - */ - public function definition() { - $mform = $this->_form; - - $contexts = $this->_customdata['contexts']; - $usablecontexts = $contexts->having_cap('moodle/question:useall'); - - // Standard fields at the start of the form. - $mform->addElement('header', 'generalheader', get_string("general", 'form')); - - $mform->addElement('questioncategory', 'category', get_string('category', 'question'), - ['contexts' => $usablecontexts, 'top' => true]); - - $mform->addElement('advcheckbox', 'includesubcategories', get_string('recurse', 'quiz'), null, null, [0, 1]); - - $tops = question_get_top_categories_for_contexts(array_column($contexts->all(), 'id')); - $mform->hideIf('includesubcategories', 'category', 'in', $tops); - - $tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $usablecontexts); - $tagstrings = []; - foreach ($tags as $tag) { - $tagstrings["{$tag->id},{$tag->name}"] = $tag->name; - } - $options = [ - 'multiple' => true, - 'noselectionstring' => get_string('anytags', 'quiz'), - ]; - $mform->addElement('autocomplete', 'fromtags', get_string('randomquestiontags', 'mod_quiz'), $tagstrings, $options); - $mform->addHelpButton('fromtags', 'randomquestiontags', 'mod_quiz'); - - $mform->addElement('hidden', 'slotid'); - $mform->setType('slotid', PARAM_INT); - - $mform->addElement('hidden', 'returnurl'); - $mform->setType('returnurl', PARAM_LOCALURL); - - $buttonarray = []; - $buttonarray[] = $mform->createElement('submit', 'submitbutton', get_string('savechanges')); - $buttonarray[] = $mform->createElement('cancel'); - $mform->addGroup($buttonarray, 'buttonar', '', [' '], false); - $mform->closeHeaderBefore('buttonar'); - } - - public function set_data($defaultvalues) { - $mform = $this->_form; - - if ($defaultvalues->fromtags) { - $fromtagselement = $mform->getElement('fromtags'); - foreach ($defaultvalues->fromtags as $fromtag) { - if (!$fromtagselement->optionExists($fromtag)) { - $optionname = get_string('randomfromunavailabletag', 'mod_quiz', explode(',', $fromtag)[1]); - $fromtagselement->addOption($optionname, $fromtag); - } - } - } - - parent::set_data($defaultvalues); - } -} diff --git a/mod/quiz/classes/output/edit_renderer.php b/mod/quiz/classes/output/edit_renderer.php index c89493c0db1..8db71c6fd92 100644 --- a/mod/quiz/classes/output/edit_renderer.php +++ b/mod/quiz/classes/output/edit_renderer.php @@ -1104,10 +1104,7 @@ class edit_renderer extends \plugin_renderer_base { */ public function random_question(structure $structure, $slotnumber, $pageurl) { $question = $structure->get_question_in_slot($slotnumber); - $bankcontext = \context::instance_by_id($question->contextid); $slot = $structure->get_slot_by_number($slotnumber); - $editurl = new \moodle_url('/mod/quiz/editrandom.php', - ['returnurl' => $pageurl->out_as_local_url(), 'slotid' => $slot->id, 'bankcmid' => $bankcontext->instanceid]); $temp = clone($question); $temp->questiontext = ''; @@ -1138,8 +1135,17 @@ class edit_renderer extends \plugin_renderer_base { $qbanklink = ' ' . \html_writer::link($qbankurl, get_string('seequestions', 'quiz'), ['class' => 'mod_quiz_random_qbank_link']); - return html_writer::link($editurl, $icon . $editicon, ['title' => $configuretitle]) . - ' ' . $instancename . ' ' . $qbanklink; + $editlink = html_writer::link( + $pageurl->out(), + $icon . $editicon, + [ + 'title' => $configuretitle, + 'data-action' => 'editrandomquestion', + 'data-slotid' => $slot->id, + 'data-header' => get_string('randomediting', 'mod_quiz'), + ], + ); + return $editlink . ' ' . $instancename . ' ' . $qbanklink; } /** diff --git a/mod/quiz/editrandom.php b/mod/quiz/editrandom.php deleted file mode 100644 index 1d25086f517..00000000000 --- a/mod/quiz/editrandom.php +++ /dev/null @@ -1,162 +0,0 @@ -. - -/** - * Page for editing random questions. - * - * @package mod_quiz - * @copyright 2018 Shamim Rezaie - * @author 2021 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use core_question\local\bank\filter_condition_manager; -use core_question\question_reference_manager; -use mod_quiz\quiz_settings; -use mod_quiz\question\bank\random_question_view; - -require_once(__DIR__ . '/../../config.php'); -require_once($CFG->dirroot . '/mod/quiz/locallib.php'); -require_once($CFG->dirroot . '/mod/quiz/lib.php'); - -$slotid = required_param('slotid', PARAM_INT); -$bankcmid = required_param('bankcmid', PARAM_INT); -$returnurl = optional_param('returnurl', '', PARAM_LOCALURL); - -// Get the quiz slot. -$slot = $DB->get_record('quiz_slots', ['id' => $slotid], '*', MUST_EXIST); -$quizobj = quiz_settings::create($slot->quizid); -$quiz = $quizobj->get_quiz(); -$cm = $quizobj->get_cm(); -$course = $quizobj->get_course(); - -require_login($course, false, $cm); - -if ($returnurl) { - $returnurl = new moodle_url($returnurl); -} else { - $returnurl = new moodle_url('/mod/quiz/edit.php', ['cmid' => $cm->id]); -} - -$url = new moodle_url('/mod/quiz/editrandom.php', ['slotid' => $slotid]); -$PAGE->set_url($url); -$PAGE->set_pagelayout('admin'); -$PAGE->add_body_class('limitedwidth'); - -$setreference = $DB->get_record('question_set_references', - ['itemid' => $slot->id, 'component' => 'mod_quiz', 'questionarea' => 'slot']); -$filterconditions = json_decode($setreference->filtercondition, true); -$filterconditions = question_reference_manager::convert_legacy_set_reference_filter_condition($filterconditions); -$filterconditions = filter_condition_manager::filter_invalid_values($filterconditions); - -$params = $filterconditions; -$params['cmid'] = $cm->id; -$extraparams['view'] = random_question_view::class; -$extraparams['requirebankswitch'] = false; -$extraparams['quizcmid'] = $quizobj->get_cm()->id; - -// Build required parameters. -[$contexts, $thispageurl, $cm, $pagevars, $extraparams] = build_required_parameters_for_custom_view($params, $extraparams); - -$thiscontext = context_module::instance($bankcmid); -$contexts = new core_question\local\bank\question_edit_contexts($thiscontext); - -// Create the editing form. -$mform = new mod_quiz\form\randomquestion_form(new moodle_url('/mod/quiz/editrandom.php'), ['contexts' => $contexts]); - -// Set the form data. -$toform = new stdClass(); -$toform->category = $filterconditions['filter']['category']['values'][0]; -$includesubcategories = false; -if (!empty($filterconditions['filter']['category']['filteroptions']['includesubcategories'])) { - $includesubcategories = true; -} -$toform->includesubcategories = $includesubcategories; -$toform->fromtags = []; -if (isset($filterconditions['tags'])) { - $currentslottags = $filterconditions['tags']; - foreach ($currentslottags as $slottag) { - $toform->fromtags[] = $slottag; - } -} - -$toform->returnurl = $returnurl; -$toform->slotid = $slot->id; -if ($cm !== null) { - $toform->cmid = $cm->id; - $toform->courseid = $cm->course; -} else { - $toform->courseid = $COURSE->id; -} - -$mform->set_data($toform); - -if ($mform->is_cancelled()) { - redirect($returnurl); -} else if ($fromform = $mform->get_data()) { - list($newcatid, $newcontextid) = explode(',', $fromform->category); - if ($newcatid != $category->id) { - $contextid = $newcontextid; - } else { - $contextid = $category->contextid; - } - $setreference->questionscontextid = $contextid; - - // Set the filter conditions. - $filtercondition = new stdClass(); - $filtercondition->questioncategoryid = $newcatid; - $filtercondition->includingsubcategories = $fromform->includesubcategories; - - if (isset($fromform->fromtags)) { - $tags = []; - foreach ($fromform->fromtags as $tagstring) { - list($tagid, $tagname) = explode(',', $tagstring); - $tags[] = "{$tagid},{$tagname}"; - } - if (!empty($tags)) { - $filtercondition->tags = $tags; - } - } - - $setreference->filtercondition = json_encode($filtercondition); - $DB->update_record('question_set_references', $setreference); - - redirect($returnurl); -} - -$heading = get_string('randomediting', 'mod_quiz'); -$PAGE->set_title($heading); -$PAGE->set_heading($COURSE->fullname); -$PAGE->navbar->add($heading); - -// Custom View. -$questionbank = new random_question_view($contexts, $thispageurl, $course, $cm, $params, $extraparams); - -// Output. -$renderer = $PAGE->get_renderer('mod_quiz', 'edit'); -$data = new \stdClass(); -$data->questionbank = $renderer->question_bank_contents($questionbank, $params); -$data->cmid = $cm->id; -$data->slotid = $slot->id; -$data->returnurl = $returnurl; -$updateform = $OUTPUT->render_from_template('mod_quiz/update_filter_condition_form', $data); -$PAGE->requires->js_call_amd('mod_quiz/update_random_question_filter_condition', 'init'); - -// Display a heading, question editing form. -echo $OUTPUT->header(); -echo $OUTPUT->heading_with_help($heading, 'randomquestion', 'mod_quiz'); -echo $updateform; -echo $OUTPUT->footer(); diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index dcd3cd5c94c..43c78fc7575 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -2386,7 +2386,26 @@ function mod_quiz_output_fragment_switch_question_bank($args): string { * @return string The rendered mform fragment. */ function mod_quiz_output_fragment_add_random_question_form($args) { - global $PAGE, $OUTPUT; + global $PAGE, $OUTPUT, $DB; + + $slotid = clean_param($args['slotid'] ?? 0, PARAM_INT); + if (empty($slotid)) { + $params = $args; + } else { + // Load the stored filters for the current slot. + $setreference = $DB->get_record('question_set_references', + ['itemid' => $slotid, 'component' => 'mod_quiz', 'questionarea' => 'slot']); + $filterconditions = json_decode($setreference->filtercondition, true); + $filterconditions = \core_question\question_reference_manager::convert_legacy_set_reference_filter_condition( + $filterconditions, + ); + $params = \core_question\local\bank\filter_condition_manager::filter_invalid_values($filterconditions); + } + + if (!empty($args['savedfiltercondition'])) { + $filtercondition = json_decode($args['savedfiltercondition'], true); + $params['filter'] = $filtercondition['filter']; + } $extraparams = []; $extraparams['quizcmid'] = clean_param($args['quizcmid'], PARAM_INT); @@ -2394,7 +2413,7 @@ function mod_quiz_output_fragment_add_random_question_form($args) { // Build required parameters. [$contexts, $thispageurl, $cm, $pagevars, $extraparams] = - build_required_parameters_for_custom_view($args, $extraparams); + build_required_parameters_for_custom_view($params, $extraparams); // Additional param to differentiate with other question bank view. $extraparams['view'] = mod_quiz\question\bank\random_question_view::class; @@ -2432,6 +2451,9 @@ function mod_quiz_output_fragment_add_random_question_form($args) { 'randomoptions' => $randomcount, 'questioncategoryoptions' => $catoptions, ]; + if (!empty($slotid)) { + $data['slotid'] = $slotid; + } $helpicon = new \help_icon('parentcategory', 'question'); $data['questioncategoryhelp'] = $helpicon->export_for_template($renderer); diff --git a/mod/quiz/templates/add_random_question_form.mustache b/mod/quiz/templates/add_random_question_form.mustache index 02a0dbb9dc7..938763712b3 100644 --- a/mod/quiz/templates/add_random_question_form.mustache +++ b/mod/quiz/templates/add_random_question_form.mustache @@ -52,11 +52,14 @@
+ {{^slotid}} {{#str}} randomfromexistingcategory, mod_quiz {{/str}} + {{/slotid}} {{{questionbank}}} + {{^slotid}} + {{/slotid}} - +
+ {{^slotid}}
{{#str}} randomquestionusinganewcategory, mod_quiz {{/str}} @@ -114,5 +125,6 @@
+ {{/slotid}} diff --git a/mod/quiz/tests/behat/editing_add_random.feature b/mod/quiz/tests/behat/editing_add_random.feature index 6873baf8217..139fa207764 100644 --- a/mod/quiz/tests/behat/editing_add_random.feature +++ b/mod/quiz/tests/behat/editing_add_random.feature @@ -102,6 +102,7 @@ Feature: Adding random questions to a quiz based on category and tags And I should see "foo" And I should see "question 1 name" And I should see "\"listen\" & \"answer\"" + And I click on "Cancel" "button" in the "Editing a random question" "dialogue" # Include subcategories. And I navigate to "Questions" in current page administration And I open the "Page 1" add to quiz menu diff --git a/mod/quiz/tests/behat/editing_edit_random.feature b/mod/quiz/tests/behat/editing_edit_random.feature index 3bbcfa6bd38..cfe31b9ecb7 100644 --- a/mod/quiz/tests/behat/editing_edit_random.feature +++ b/mod/quiz/tests/behat/editing_edit_random.feature @@ -15,22 +15,26 @@ Feature: Editing random questions already in a quiz based on category and tags | user | course | role | | teacher1 | C1 | editingteacher | And the following "activities" exist: - | activity | name | intro | course | idnumber | - | quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 | + | activity | name | intro | course | idnumber | + | quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 | + | qbank | Qbank 1 | Qbank 1 for testing the Edit random question form | C1 | qbank1 | And the following "question categories" exist: | contextlevel | reference | name | | Activity module | quiz1 | Questions Category 1| | Activity module | quiz1 | Questions Category 2| + | Activity module | qbank1 | Questions Category 3| And the following "questions" exist: | questioncategory | qtype | name | user | questiontext | | Questions Category 1 | essay | question 1 name | admin | Question 1 text | | Questions Category 1 | essay | question 2 name | teacher1 | Question 2 text | + | Questions Category 3 | essay | question 3 name | teacher1 | Question 3 text | And the following "core_question > Tags" exist: | question | tag | | question 1 name | easy | | question 1 name | essay | | question 2 name | hard | | question 2 name | essay | + | question 3 name | essay | Scenario: Editing tags on one slot does not delete the rest Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1" @@ -52,3 +56,32 @@ Feature: Editing random questions already in a quiz based on category and tags And I should see "Random (Questions Category 1) based on filter condition with tags: hard" on quiz page "2" And I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: hard" "list_item" And "hard" "autocomplete_selection" should be visible + + Scenario: Switch banks when editing a random question + Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1" + And I open the "last" add to quiz menu + And I follow "a random question" + And I apply question bank filter "Tag" with value "essay" + And I press "Add random question" + When I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: essay" "list_item" + And I press "Switch bank" + And I click on "Qbank 1" "link" in the "Select question bank" "dialogue" + And the field "filter-value-qtagids" matches value "essay" + And I apply question bank filter "Category" with value "Questions Category 3 (1)" + And I should see "question 3 name" + And I press "Update filter conditions" + Then I should see "Random (Questions Category 3) based on filter condition with tags: essay" on quiz page "1" + + Scenario: "Go back" from bank switcher keeps existing filter values. + Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1" + And I open the "last" add to quiz menu + And I follow "a random question" + And I apply question bank filter "Tag" with value "essay" + And I press "Add random question" + When I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: essay" "list_item" + And the field "filter-value-category" matches value "   Questions Category 1 (2)" + And the field "filter-value-qtagids" matches value "essay" + And I press "Switch bank" + And I press "Go back" + Then the field "filter-value-category" matches value "   Questions Category 1 (2)" + And the field "filter-value-qtagids" matches value "essay"