diff --git a/question/bank/managecategories/amd/build/category.min.js b/question/bank/managecategories/amd/build/category.min.js index f0e27bd3b5151..dc30b8638f859 100644 --- a/question/bank/managecategories/amd/build/category.min.js +++ b/question/bank/managecategories/amd/build/category.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/category",["exports","core/reactive","qbank_managecategories/categorymanager","core/templates","core/modal","core/str"],(function(_exports,_reactive,_categorymanager,_templates,_modal,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_modal=_interopRequireDefault(_modal);class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={CATEGORY_LIST:".qbank_managecategories-categorylist",LIST_ITEM:".qbank_managecategories-item[data-categoryid]",ACTIVITY_ITEM:".activity-item",EDIT_BUTTON:'[data-action="addeditcategory"]',MOVE_BUTTON:'[role="menuitem"][data-actiontype="move"]',CONTEXT:".qbank_managecategories-categorylist[data-contextid]",MODAL_CATEGORY_ITEM:".modal_category_item[data-movingcategoryid]"}}stateReady(){this.initDragDrop(),this.addEventListener(this.getElement(this.selectors.EDIT_BUTTON),"click",_categorymanager.categorymanager.showEditModal);const moveButton=this.getElement(this.selectors.MOVE_BUTTON);moveButton&&this.addEventListener(moveButton,"click",this.showMoveModal)}destroy(){this.deInitDragDrop()}initDragDrop(){this.deInitDragDrop(),this.element.classList.contains("draghandle")&&(this.getDraggableData=this._getDraggableData),this.dragdrop=new _reactive.DragDrop(this)}deInitDragDrop(){void 0!==this.dragdrop&&(void 0!==this.getDraggableData&&(this.dragdrop.setDraggable(!1),this.getDraggableData=void 0),this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}_getDraggableData(){return{id:this.element.dataset.categoryid}}validateDropData(){return!0}showDropZone(dropData,event){const dropTarget=event.target.closest(this.selectors.LIST_ITEM);dropTarget.closest("#category-".concat(dropData.id))||dropTarget.classList.add("qbank_managecategories-category-droptarget-before")}hideDropZone(dropData,event){event.target.closest(this.selectors.LIST_ITEM).classList.remove("qbank_managecategories-category-droptarget-before")}drop(dropData,event){var _precedingSibling;const dropTarget=event.target.closest(this.selectors.LIST_ITEM);if(!dropTarget)return;if(dropTarget.closest("#category-".concat(dropData.id)))return;if(!document.getElementById("category-".concat(dropData.id)))return;const targetParentId=dropTarget.dataset.parent,parentList=dropTarget.closest(this.selectors.CATEGORY_LIST);let precedingSibling;precedingSibling=dropTarget===parentList.firstElementChild?null:dropTarget.previousElementSibling,_categorymanager.categorymanager.setCatOrder(dropData.id,targetParentId,null===(_precedingSibling=precedingSibling)||void 0===_precedingSibling?void 0:_precedingSibling.dataset.categoryid)}getWatchers(){return[{watch:"categories[".concat(this.element.dataset.categoryid,"]:updated"),handler:this.updatePosition},{watch:"categories[".concat(this.element.dataset.categoryid,"].templatecontext:created"),handler:this.rerender},{watch:"categories[".concat(this.element.dataset.categoryid,"].templatecontext:updated"),handler:this.rerender},{watch:"categories:created",handler:this.checkChildList}]}async rerender(_ref){let{element:element}=_ref;const{html:html,js:js}=await _templates.default.renderForPromise("qbank_managecategories/category",element.templatecontext);_templates.default.replaceNodeContents(this.getElement(".activity-name-area"),html,js)}async createChildList(context){const{html:html,js:js}=await _templates.default.renderForPromise("qbank_managecategories/childlist",context),parentContainer=document.querySelector("#category-".concat(context.categoryid," .activity-grid"));await _templates.default.appendNodeContents(parentContainer,html,js);const childList=document.querySelector('ul[data-categoryid="'.concat(context.categoryid,'"]'));return childList.closest(this.selectors.ACTIVITY_ITEM).classList.add("pb-0"),childList}async updatePosition(_ref2){let newParent,{element:element}=_ref2;const originParent=document.querySelector('ul[data-categoryid="'.concat(this.getElement().dataset.parent,'"]'));let previousSibling,nextSibling;var _previousSibling;(parseInt(this.getElement().dataset.parent)!==element.parent?(newParent=document.querySelector('ul[data-categoryid="'.concat(element.parent,'"]')),newParent||(newParent=await this.createChildList({categoryid:element.parent})),this.getElement().dataset.parent=element.parent):newParent=this.getElement().parentElement,0===element.sortorder&&newParent.firstElementChild)?nextSibling=newParent.firstElementChild:(previousSibling=newParent.querySelector(':scope > [data-sortorder="'.concat(element.sortorder-1,'"]')),nextSibling=null===(_previousSibling=previousSibling)||void 0===_previousSibling?void 0:_previousSibling.nextElementSibling);(newParent!==this.element.parentElement||nextSibling!==this.element)&&(nextSibling?newParent.insertBefore(this.element,nextSibling):newParent.appendChild(this.element)),originParent!==newParent&&this.reactive.stateManager.processUpdates([{name:"categoryLists",action:"put",fields:{id:originParent.dataset.categoryid,childCount:originParent.querySelectorAll(this.selectors.LIST_ITEM).length}},{name:"categoryLists",action:"put",fields:{id:newParent.dataset.categoryid,childCount:newParent.querySelectorAll(this.selectors.LIST_ITEM).length}}]),this.element.dataset.sortorder=element.sortorder;const isDraggable=this.element.classList.contains("draghandle");isDraggable&&!element.draghandle?(this.element.classList.remove("draghandle"),this.initDragDrop()):!isDraggable&&element.draghandle&&(this.element.classList.add("draghandle"),this.initDragDrop())}createMoveCategoryList(item,movingCategory){const categories=[];if(item.children){let precedingSibling=null;item.children.forEach((category=>{var _precedingSibling$dat,_precedingSibling2;if(category.dataset.categoryid===movingCategory)return;let child={categoryid:category.dataset.categoryid,movingcategoryid:movingCategory,precedingsiblingid:null!==(_precedingSibling$dat=null===(_precedingSibling2=precedingSibling)||void 0===_precedingSibling2?void 0:_precedingSibling2.dataset.categoryid)&&void 0!==_precedingSibling$dat?_precedingSibling$dat:0,parent:category.dataset.parent,categoryname:category.dataset.categoryname,categories:null,current:category.dataset.categoryid===movingCategory};const childList=category.querySelector(this.selectors.CATEGORY_LIST);child.categories=childList?this.createMoveCategoryList(childList,movingCategory):[{movingcategoryid:movingCategory,precedingsiblingid:0,parent:category.dataset.categoryid,categoryname:category.dataset.categoryname,categories:null,newchild:!0}],categories.push(child),precedingSibling=category})),precedingSibling.dataset.categoryid!==movingCategory&&categories.push({movingcategoryid:movingCategory,precedingsiblingid:precedingSibling.dataset.categoryid,parent:precedingSibling.dataset.parent,categoryname:precedingSibling.dataset.categoryname,categories:null,lastchild:!0})}return categories}async showMoveModal(e){const item=e.target;if(!item)return;if("true"===item.getAttribute("aria-disabled"))return;item.setAttribute("aria-disabled",!0);let moveList={contexts:[]};document.querySelectorAll(this.selectors.CONTEXT).forEach((context=>{const moveContext={contextname:context.dataset.contextname,categories:[],hascategories:!1};moveContext.categories=this.createMoveCategoryList(context,item.dataset.categoryid),moveContext.hascategories=moveContext.categories.length>0,moveList.contexts.push(moveContext)}));const modal=await _modal.default.create({title:(0,_str.get_string)("movecategory","qbank_managecategories",item.dataset.categoryname),body:_templates.default.render("qbank_managecategories/move_context_list",moveList),footer:"",show:!0,large:!0});modal.getBody()[0].addEventListener("click",(e=>{const target=e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);target&&(_categorymanager.categorymanager.setCatOrder(target.dataset.movingcategoryid,target.dataset.parent,target.dataset.precedingsiblingid),modal.destroy())})),item.setAttribute("aria-disabled",!1)}async checkChildList(_ref3){let{element:element}=_ref3;if(element.parent===parseInt(this.getElement().dataset.categoryid))return this.getElement(this.selectors.CATEGORY_LIST)?void 0:this.createChildList({categoryid:element.parent,children:[element.templatecontext]})}}return _exports.default=_default,_exports.default})); +define("qbank_managecategories/category",["exports","core/reactive","qbank_managecategories/categorymanager","core/templates","core/modal","core/str"],(function(_exports,_reactive,_categorymanager,_templates,_modal,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_modal=_interopRequireDefault(_modal);class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={CATEGORY_LIST:".qbank_managecategories-categorylist",LIST_ITEM:".qbank_managecategories-item[data-categoryid]",ACTIVITY_ITEM:".activity-item",EDIT_BUTTON:'[data-action="addeditcategory"]',MOVE_BUTTON:'[role="menuitem"][data-actiontype="move"]',CONTEXT:".qbank_managecategories-categorylist[data-contextid]",MODAL_CATEGORY_ITEM:".modal_category_item[data-movingcategoryid]",CONTENT_AREA:".activity-name-area",CATEGORY_ID:id=>"#category-".concat(id),CONTENT_CONTAINER:id=>"#category-".concat(id," .activity-grid"),CHILD_LIST:id=>'ul[data-categoryid="'.concat(id,'"]'),PREVIOUS_SIBLING:sortorder=>':scope > [data-sortorder="'.concat(sortorder-1,'"]')},this.classes={NO_BOTTOM_PADDING:"pb-0",DRAGHANDLE:"draghandle",DROPTARGET:"qbank_managecategories-category-droptarget-before"},this.ids={CATEGORY:id=>"#category-".concat(id)}}stateReady(){this.initDragDrop(),this.addEventListener(this.getElement(this.selectors.EDIT_BUTTON),"click",_categorymanager.categorymanager.showEditModal);const moveButton=this.getElement(this.selectors.MOVE_BUTTON);this.addEventListener(moveButton,"click",this.showMoveModal)}destroy(){this.deInitDragDrop()}initDragDrop(){this.deInitDragDrop(),this.element.classList.contains(this.classes.DRAGHANDLE)&&(this.getDraggableData=this._getDraggableData),this.dragdrop=new _reactive.DragDrop(this)}deInitDragDrop(){void 0!==this.dragdrop&&(void 0!==this.getDraggableData&&(this.dragdrop.setDraggable(!1),this.getDraggableData=void 0),this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}_getDraggableData(){return{id:this.getElement().dataset.categoryid}}validateDropData(dropData){return!event.target.closest(this.selectors.LIST_ITEM).closest(this.selectors.CATEGORY_ID(dropData.id))}showDropZone(dropData,event){event.target.closest(this.selectors.LIST_ITEM).classList.add(this.classes.DROPTARGET)}hideDropZone(dropData,event){event.target.closest(this.selectors.LIST_ITEM).classList.remove(this.classes.DROPTARGET)}drop(dropData,event){var _precedingSibling;const dropTarget=event.target.closest(this.selectors.LIST_ITEM);if(!dropTarget)return;if(dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id)))return;if(!document.getElementById(this.ids.CATEGORY(dropData.id)))return;const targetParentId=dropTarget.dataset.parent,parentList=dropTarget.closest(this.selectors.CATEGORY_LIST);let precedingSibling;precedingSibling=dropTarget===parentList.firstElementChild?null:dropTarget.previousElementSibling,_categorymanager.categorymanager.moveCategory(dropData.id,targetParentId,null===(_precedingSibling=precedingSibling)||void 0===_precedingSibling?void 0:_precedingSibling.dataset.categoryid)}getWatchers(){return[{watch:"categories[".concat(this.element.dataset.categoryid,"]:updated"),handler:this.updatePosition},{watch:"categories[".concat(this.element.dataset.categoryid,"].templatecontext:created"),handler:this.rerender},{watch:"categories[".concat(this.element.dataset.categoryid,"].templatecontext:updated"),handler:this.rerender},{watch:"categories:created",handler:this.checkChildList}]}async rerender(_ref){let{element:element}=_ref;const{html:html,js:js}=await _templates.default.renderForPromise("qbank_managecategories/category",element.templatecontext);return _templates.default.replaceNodeContents(this.getElement(this.selectors.CONTENT_AREA),html,js)}async createChildList(context){const{html:html,js:js}=await _templates.default.renderForPromise("qbank_managecategories/childlist",context),parentContainer=document.querySelector(this.selectors.CONTENT_CONTAINER(context.categoryid));await _templates.default.appendNodeContents(parentContainer,html,js);const childList=document.querySelector(this.selectors.CHILD_LIST(context.categoryid));return childList.closest(this.selectors.ACTIVITY_ITEM).classList.add(this.classes.NO_BOTTOM_PADDING),childList}async updatePosition(_ref2){let newParent,{element:element}=_ref2;const originParent=document.querySelector(this.selectors.CHILD_LIST(this.getElement().dataset.parent));let previousSibling,nextSibling;var _previousSibling;(parseInt(this.getElement().dataset.parent)!==element.parent?(newParent=document.querySelector(this.selectors.CHILD_LIST(element.parent)),newParent||(newParent=await this.createChildList({categoryid:element.parent})),this.getElement().dataset.parent=element.parent):newParent=this.getElement().parentElement,0===element.sortorder&&newParent.firstElementChild)?nextSibling=newParent.firstElementChild:(previousSibling=newParent.querySelector(this.selectors.PREVIOUS_SIBLING(element.sortorder)),nextSibling=null===(_previousSibling=previousSibling)||void 0===_previousSibling?void 0:_previousSibling.nextElementSibling);(newParent!==this.element.parentElement||nextSibling!==this.element)&&(nextSibling?newParent.insertBefore(this.element,nextSibling):newParent.appendChild(this.element)),originParent!==newParent&&this.reactive.stateManager.processUpdates([{name:"categoryLists",action:"put",fields:{id:originParent.dataset.categoryid,childCount:originParent.querySelectorAll(this.selectors.LIST_ITEM).length}},{name:"categoryLists",action:"put",fields:{id:newParent.dataset.categoryid,childCount:newParent.querySelectorAll(this.selectors.LIST_ITEM).length}}]),this.element.dataset.sortorder=element.sortorder;const isDraggable=this.element.classList.contains(this.classes.DRAGHANDLE);isDraggable&&!element.draghandle?(this.element.classList.remove(this.classes.DRAGHANDLE),this.initDragDrop()):!isDraggable&&element.draghandle&&(this.element.classList.add(this.classes.DRAGHANDLE),this.initDragDrop())}createMoveCategoryList(item,movingCategoryId){const categories=[];if(item.children){let precedingSibling=null;item.children.forEach((category=>{var _precedingSibling$dat,_precedingSibling2;const categoryId=parseInt(category.dataset.categoryid);if(categoryId===movingCategoryId)return;let child={categoryid:categoryId,movingcategoryid:movingCategoryId,precedingsiblingid:null!==(_precedingSibling$dat=null===(_precedingSibling2=precedingSibling)||void 0===_precedingSibling2?void 0:_precedingSibling2.dataset.categoryid)&&void 0!==_precedingSibling$dat?_precedingSibling$dat:0,parent:category.dataset.parent,categoryname:category.dataset.categoryname,categories:null,current:categoryId===movingCategoryId};const childList=category.querySelector(this.selectors.CATEGORY_LIST);child.categories=childList?this.createMoveCategoryList(childList,movingCategoryId):[{movingcategoryid:movingCategoryId,precedingsiblingid:0,parent:categoryId,categoryname:category.dataset.categoryname,categories:null,newchild:!0}],categories.push(child),precedingSibling=category}));const precedingId=parseInt(precedingSibling.dataset.categoryid);precedingId!==movingCategoryId&&categories.push({movingcategoryid:movingCategoryId,precedingsiblingid:precedingId,parent:precedingSibling.dataset.parent,categoryname:precedingSibling.dataset.categoryname,categories:null,lastchild:!0})}return categories}async showMoveModal(e){const item=e.target;if(!item)return;if("true"===item.getAttribute("aria-disabled"))return;item.setAttribute("aria-disabled",!0);let moveList={contexts:[]};document.querySelectorAll(this.selectors.CONTEXT).forEach((context=>{const moveContext={contextname:context.dataset.contextname,categories:[],hascategories:!1};moveContext.categories=this.createMoveCategoryList(context,parseInt(item.dataset.categoryid)),moveContext.hascategories=moveContext.categories.length>0,moveList.contexts.push(moveContext)}));const modal=await _modal.default.create({title:(0,_str.get_string)("movecategory","qbank_managecategories",item.dataset.categoryname),body:_templates.default.render("qbank_managecategories/move_context_list",moveList),footer:"",show:!0,large:!0});modal.getBody()[0].addEventListener("click",(e=>{const target=e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);target&&(_categorymanager.categorymanager.moveCategory(target.dataset.movingcategoryid,target.dataset.parent,target.dataset.precedingsiblingid),modal.destroy())})),item.setAttribute("aria-disabled",!1)}async checkChildList(_ref3){let{element:element}=_ref3;if(element.parent===parseInt(this.getElement().dataset.categoryid))return this.getElement(this.selectors.CATEGORY_LIST)?void 0:this.createChildList({categoryid:element.parent,children:[element.templatecontext]})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=category.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/category.min.js.map b/question/bank/managecategories/amd/build/category.min.js.map index 8afb3d5eaa2db..e579f62e44060 100644 --- a/question/bank/managecategories/amd/build/category.min.js.map +++ b/question/bank/managecategories/amd/build/category.min.js.map @@ -1 +1 @@ -{"version":3,"file":"category.min.js","sources":["../src/category.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 * The category component.\n *\n * @module qbank_managecategories/category\n * @class qbank_managecategories/category\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\nimport Templates from 'core/templates';\nimport Modal from \"core/modal\";\nimport {get_string as getString} from \"core/str\";\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n ACTIVITY_ITEM: '.activity-item',\n EDIT_BUTTON: '[data-action=\"addeditcategory\"]',\n MOVE_BUTTON: '[role=\"menuitem\"][data-actiontype=\"move\"]',\n CONTEXT: '.qbank_managecategories-categorylist[data-contextid]',\n MODAL_CATEGORY_ITEM: '.modal_category_item[data-movingcategoryid]',\n };\n }\n\n stateReady() {\n this.initDragDrop();\n this.addEventListener(this.getElement(this.selectors.EDIT_BUTTON), 'click', categorymanager.showEditModal);\n const moveButton = this.getElement(this.selectors.MOVE_BUTTON);\n if (moveButton) {\n this.addEventListener(moveButton, 'click', this.showMoveModal);\n }\n\n }\n\n destroy() {\n // The draggable element must be unregistered.\n this.deInitDragDrop();\n }\n\n initDragDrop() {\n this.deInitDragDrop();\n if (this.element.classList.contains('draghandle')) {\n this.getDraggableData = this._getDraggableData;\n }\n this.dragdrop = new DragDrop(this);\n }\n\n deInitDragDrop() {\n if (this.dragdrop !== undefined) {\n if (this.getDraggableData !== undefined) {\n this.dragdrop.setDraggable(false);\n this.getDraggableData = undefined;\n }\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n selectors,\n reactive: categorymanager,\n });\n }\n\n _getDraggableData() {\n return {\n id: this.element.dataset.categoryid\n };\n }\n\n validateDropData() {\n return true;\n }\n\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n if (dropTarget.closest(`#category-${dropData.id}`)) {\n // Can't drop onto your own child.\n return;\n }\n dropTarget.classList.add('qbank_managecategories-category-droptarget-before');\n }\n\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n dropTarget.classList.remove('qbank_managecategories-category-droptarget-before');\n }\n\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n\n if (!dropTarget) {\n return;\n }\n\n if (dropTarget.closest(`#category-${dropData.id}`)) {\n // Can't drop onto your own child.\n return;\n }\n\n const source = document.getElementById(`category-${dropData.id}`);\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.parent;\n const parentList = dropTarget.closest(this.selectors.CATEGORY_LIST);\n let precedingSibling;\n\n if (dropTarget === parentList.firstElementChild) {\n // Dropped at the top of the list.\n precedingSibling = null;\n } else {\n precedingSibling = dropTarget.previousElementSibling;\n }\n\n // Insert the category after the target category\n categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n getWatchers() {\n return [\n {watch: `categories[${this.element.dataset.categoryid}]:updated`, handler: this.updatePosition},\n {watch: `categories[${this.element.dataset.categoryid}].templatecontext:created`, handler: this.rerender},\n {watch: `categories[${this.element.dataset.categoryid}].templatecontext:updated`, handler: this.rerender},\n {watch: `categories:created`, handler: this.checkChildList},\n ];\n }\n\n async rerender({element}) {\n const {html, js} = await Templates.renderForPromise('qbank_managecategories/category', element.templatecontext);\n Templates.replaceNodeContents(this.getElement('.activity-name-area'), html, js);\n }\n\n /**\n * Render and append a new child list.\n *\n * @param {Object} context Template context, must include at least categoryid.\n * @return {Promise<*>}\n */\n async createChildList(context) {\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/childlist',\n context,\n );\n const parentContainer = document.querySelector(`#category-${context.categoryid} .activity-grid`);\n await Templates.appendNodeContents(parentContainer, html, js);\n const childList = document.querySelector(`ul[data-categoryid=\"${context.categoryid}\"]`);\n childList.closest(this.selectors.ACTIVITY_ITEM).classList.add('pb-0');\n return childList;\n }\n\n async updatePosition({element}) {\n // Move to a new parent category.\n let newParent;\n const originParent = document.querySelector(`ul[data-categoryid=\"${this.getElement().dataset.parent}\"]`);\n if (parseInt(this.getElement().dataset.parent) !== element.parent) {\n newParent = document.querySelector(`ul[data-categoryid=\"${element.parent}\"]`);\n if (!newParent) {\n // The target category doesn't have a child list yet. We'd better create one.\n newParent = await this.createChildList({categoryid: element.parent});\n }\n this.getElement().dataset.parent = element.parent;\n } else {\n newParent = this.getElement().parentElement;\n }\n\n // Move to a new position within the parent.\n let previousSibling;\n let nextSibling;\n if (element.sortorder === 0 && newParent.firstElementChild) {\n // Move to the top of the list.\n nextSibling = newParent.firstElementChild;\n } else {\n // Move later in the list.\n previousSibling = newParent.querySelector(`:scope > [data-sortorder=\"${element.sortorder - 1}\"]`);\n nextSibling = previousSibling?.nextElementSibling;\n }\n\n // Check if this has actually moved, or if it's just having its sortorder updated due to another element moving.\n const moved = (newParent !== this.element.parentElement || nextSibling !== this.element);\n\n if (moved) {\n if (nextSibling) {\n // Move to the specified position in the list.\n newParent.insertBefore(this.element, nextSibling);\n } else {\n // Move to the end of the list (may also be the top of the list is empty).\n newParent.appendChild(this.element);\n }\n }\n if (originParent !== newParent) {\n // Update child count of old and new parent.\n this.reactive.stateManager.processUpdates([\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: originParent.dataset.categoryid,\n childCount: originParent.querySelectorAll(this.selectors.LIST_ITEM).length\n }\n },\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: newParent.dataset.categoryid,\n childCount: newParent.querySelectorAll(this.selectors.LIST_ITEM).length\n }\n }\n ]);\n }\n\n this.element.dataset.sortorder = element.sortorder;\n\n // Enable/disable dragging.\n const isDraggable = this.element.classList.contains('draghandle');\n if (isDraggable && !element.draghandle) {\n this.element.classList.remove('draghandle');\n this.initDragDrop();\n } else if (!isDraggable && element.draghandle) {\n this.element.classList.add('draghandle');\n this.initDragDrop();\n }\n }\n\n createMoveCategoryList(item, movingCategory) {\n const categories = [];\n if (item.children) {\n let precedingSibling = null;\n item.children.forEach(category => {\n if (category.dataset.categoryid === movingCategory) {\n return;\n }\n let child = {\n categoryid: category.dataset.categoryid,\n movingcategoryid: movingCategory,\n precedingsiblingid: precedingSibling?.dataset.categoryid ?? 0,\n parent: category.dataset.parent,\n categoryname: category.dataset.categoryname,\n categories: null,\n current: category.dataset.categoryid === movingCategory,\n };\n const childList = category.querySelector(this.selectors.CATEGORY_LIST);\n if (childList) {\n child.categories = this.createMoveCategoryList(childList, movingCategory);\n } else {\n child.categories = [\n {\n movingcategoryid: movingCategory,\n precedingsiblingid: 0,\n parent: category.dataset.categoryid,\n categoryname: category.dataset.categoryname,\n categories: null,\n newchild: true,\n }\n ];\n }\n categories.push(child);\n precedingSibling = category;\n });\n if (precedingSibling.dataset.categoryid !== movingCategory) {\n categories.push({\n movingcategoryid: movingCategory,\n precedingsiblingid: precedingSibling.dataset.categoryid,\n parent: precedingSibling.dataset.parent,\n categoryname: precedingSibling.dataset.categoryname,\n categories: null,\n lastchild: true,\n });\n }\n }\n return categories;\n }\n\n /**\n * Sets events listener for move category using dragdrop icon.\n * @param {Event} e\n */\n async showMoveModal(e) {\n // Return if it is not menu item.\n const item = e.target;\n if (!item) {\n return;\n }\n // Return if it is disabled.\n if (item.getAttribute('aria-disabled') === 'true') {\n return;\n }\n\n // Prevent addition click on the item.\n item.setAttribute('aria-disabled', true);\n\n let moveList = {contexts: []};\n const contexts = document.querySelectorAll(this.selectors.CONTEXT);\n contexts.forEach(context => {\n const moveContext = {\n contextname: context.dataset.contextname,\n categories: [],\n hascategories: false,\n };\n moveContext.categories = this.createMoveCategoryList(context, item.dataset.categoryid);\n moveContext.hascategories = moveContext.categories.length > 0;\n moveList.contexts.push(moveContext);\n });\n\n const modal = await Modal.create({\n title: getString('movecategory', 'qbank_managecategories', item.dataset.categoryname),\n body: Templates.render('qbank_managecategories/move_context_list', moveList),\n footer: '',\n show: true,\n large: true,\n });\n // Show modal and add click event for list item.\n modal.getBody()[0].addEventListener('click', e => {\n const target = e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);\n if (!target) {\n return;\n }\n categorymanager.setCatOrder(target.dataset.movingcategoryid, target.dataset.parent, target.dataset.precedingsiblingid);\n modal.destroy();\n });\n item.setAttribute('aria-disabled', false);\n }\n\n /**\n * Check and add a child list if needed.\n *\n * Check whether the category that has just been added has this category as its parent. If it does,\n * check that this category has a child list, and if not, add one.\n *\n * @param {Event} event\n * @param {Element} event.element The new category.\n */\n async checkChildList({element}) {\n if (element.parent !== parseInt(this.getElement().dataset.categoryid)) {\n return; // Not for me.\n }\n let childList = this.getElement(this.selectors.CATEGORY_LIST);\n if (childList) {\n return; // List already exists, it will handle adding the new category.\n }\n // Render and add a new child list containing the new category.\n return this.createChildList({\n categoryid: element.parent,\n children: [\n element.templatecontext,\n ]\n });\n }\n}\n"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","CATEGORY_LIST","LIST_ITEM","ACTIVITY_ITEM","EDIT_BUTTON","MOVE_BUTTON","CONTEXT","MODAL_CATEGORY_ITEM","stateReady","initDragDrop","addEventListener","this","getElement","categorymanager","showEditModal","moveButton","showMoveModal","destroy","deInitDragDrop","classList","contains","getDraggableData","_getDraggableData","dragdrop","DragDrop","undefined","setDraggable","unregister","target","document","querySelector","reactive","dataset","categoryid","validateDropData","showDropZone","dropData","event","dropTarget","closest","add","hideDropZone","remove","drop","getElementById","targetParentId","parent","parentList","precedingSibling","firstElementChild","previousElementSibling","setCatOrder","_precedingSibling","getWatchers","watch","handler","updatePosition","rerender","checkChildList","html","js","Templates","renderForPromise","templatecontext","replaceNodeContents","context","parentContainer","appendNodeContents","childList","newParent","originParent","previousSibling","nextSibling","parseInt","createChildList","parentElement","sortorder","_previousSibling","nextElementSibling","insertBefore","appendChild","stateManager","processUpdates","action","fields","childCount","querySelectorAll","length","isDraggable","draghandle","createMoveCategoryList","item","movingCategory","categories","children","forEach","category","child","movingcategoryid","precedingsiblingid","_precedingSibling2","categoryname","current","newchild","push","lastchild","e","getAttribute","setAttribute","moveList","contexts","moveContext","contextname","hascategories","modal","Modal","title","body","render","footer","show","large","getBody"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"category.min.js","sources":["../src/category.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 * The category component.\n *\n * @module qbank_managecategories/category\n * @class qbank_managecategories/category\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\nimport Templates from 'core/templates';\nimport Modal from \"core/modal\";\nimport {get_string as getString} from \"core/str\";\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n ACTIVITY_ITEM: '.activity-item',\n EDIT_BUTTON: '[data-action=\"addeditcategory\"]',\n MOVE_BUTTON: '[role=\"menuitem\"][data-actiontype=\"move\"]',\n CONTEXT: '.qbank_managecategories-categorylist[data-contextid]',\n MODAL_CATEGORY_ITEM: '.modal_category_item[data-movingcategoryid]',\n CONTENT_AREA: '.activity-name-area',\n CATEGORY_ID: id => `#category-${id}`,\n CONTENT_CONTAINER: id => `#category-${id} .activity-grid`,\n CHILD_LIST: id => `ul[data-categoryid=\"${id}\"]`,\n PREVIOUS_SIBLING: sortorder => `:scope > [data-sortorder=\"${sortorder - 1}\"]`,\n };\n this.classes = {\n NO_BOTTOM_PADDING: 'pb-0',\n DRAGHANDLE: 'draghandle',\n DROPTARGET: 'qbank_managecategories-category-droptarget-before',\n };\n this.ids = {\n CATEGORY: id => `#category-${id}`,\n };\n }\n\n stateReady() {\n this.initDragDrop();\n this.addEventListener(this.getElement(this.selectors.EDIT_BUTTON), 'click', categorymanager.showEditModal);\n const moveButton = this.getElement(this.selectors.MOVE_BUTTON);\n this.addEventListener(moveButton, 'click', this.showMoveModal);\n }\n\n destroy() {\n // The draggable element must be unregistered.\n this.deInitDragDrop();\n }\n\n /**\n * Remove any existing DragDrop component, and create a new one.\n */\n initDragDrop() {\n this.deInitDragDrop();\n // If the element is currently draggable, register the getDraggableData method.\n if (this.element.classList.contains(this.classes.DRAGHANDLE)) {\n this.getDraggableData = this._getDraggableData;\n }\n this.dragdrop = new DragDrop(this);\n }\n\n /**\n * If the DragDrop component is currently registered, unregister it.\n */\n deInitDragDrop() {\n if (this.dragdrop !== undefined) {\n if (this.getDraggableData !== undefined) {\n this.dragdrop.setDraggable(false);\n this.getDraggableData = undefined;\n }\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n selectors,\n reactive: categorymanager,\n });\n }\n\n /**\n * Return the category ID from the component's element.\n *\n * This method is referenced as getDraggableData when the component can be dragged.\n *\n * @return {{id: string}}\n * @private\n */\n _getDraggableData() {\n return {\n id: this.getElement().dataset.categoryid\n };\n }\n\n /**\n * A category cannot be dropped onto its own child.\n *\n * @param {Object} dropData\n * @return {boolean}\n */\n validateDropData(dropData) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) {\n return false;\n }\n return true;\n }\n\n /**\n * Highlight the top border of the category item.\n *\n * @param {Object} dropData Not used.\n * @param {Event} event The dragEnter or dragOver event.\n */\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n dropTarget.classList.add(this.classes.DROPTARGET);\n }\n\n /**\n * Remove highlighting.\n *\n * @param {Object} dropData Not used.\n * @param {Event} event The dragLeave event.\n */\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n dropTarget.classList.remove(this.classes.DROPTARGET);\n }\n\n /**\n * Find the new position of the dropped category, and trigger the move.\n *\n * @param {Object} dropData The category being moved.\n * @param {Event} event The drop event.\n */\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.LIST_ITEM);\n\n if (!dropTarget) {\n return;\n }\n\n if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) {\n // Can't drop onto your own child.\n return;\n }\n\n const source = document.getElementById(this.ids.CATEGORY(dropData.id));\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.parent;\n const parentList = dropTarget.closest(this.selectors.CATEGORY_LIST);\n let precedingSibling;\n\n if (dropTarget === parentList.firstElementChild) {\n // Dropped at the top of the list.\n precedingSibling = null;\n } else {\n precedingSibling = dropTarget.previousElementSibling;\n }\n\n // Insert the category after the target category\n categorymanager.moveCategory(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n getWatchers() {\n return [\n // After any update to this category, move it to the new position.\n {watch: `categories[${this.element.dataset.categoryid}]:updated`, handler: this.updatePosition},\n // When the template context is added or updated, re-render the content.\n {watch: `categories[${this.element.dataset.categoryid}].templatecontext:created`, handler: this.rerender},\n {watch: `categories[${this.element.dataset.categoryid}].templatecontext:updated`, handler: this.rerender},\n // When a new category is created, check whether we need to add a child list to this category.\n {watch: `categories:created`, handler: this.checkChildList},\n ];\n }\n\n /**\n * Re-render the category content.\n *\n * @param {Object} event\n * @param {Object} event.element\n * @return {Promise}\n */\n async rerender({element}) {\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/category',\n element.templatecontext\n );\n return Templates.replaceNodeContents(this.getElement(this.selectors.CONTENT_AREA), html, js);\n }\n\n /**\n * Render and append a new child list.\n *\n * @param {Object} context Template context, must include at least categoryid.\n * @return {Promise}\n */\n async createChildList(context) {\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/childlist',\n context,\n );\n const parentContainer = document.querySelector(this.selectors.CONTENT_CONTAINER(context.categoryid));\n await Templates.appendNodeContents(parentContainer, html, js);\n const childList = document.querySelector(this.selectors.CHILD_LIST(context.categoryid));\n childList.closest(this.selectors.ACTIVITY_ITEM).classList.add(this.classes.NO_BOTTOM_PADDING);\n return childList;\n }\n\n /**\n * Move a category to its new position.\n *\n * A category may change its parent, sortorder and draghandle independently or at the same time. This method will resolve those\n * changes and move the element to the new position. If the parent doesn't already have a child list, one will be created.\n *\n * If the parent has changed, this will also update the state with the new child count of the old and new parents.\n *\n * @param {Event} event\n * @param {Element} event.element\n * @return {Promise}\n */\n async updatePosition({element}) {\n // Move to a new parent category.\n let newParent;\n const originParent = document.querySelector(this.selectors.CHILD_LIST(this.getElement().dataset.parent));\n if (parseInt(this.getElement().dataset.parent) !== element.parent) {\n newParent = document.querySelector(this.selectors.CHILD_LIST(element.parent));\n if (!newParent) {\n // The target category doesn't have a child list yet. We'd better create one.\n newParent = await this.createChildList({categoryid: element.parent});\n }\n this.getElement().dataset.parent = element.parent;\n } else {\n newParent = this.getElement().parentElement;\n }\n\n // Move to a new position within the parent.\n let previousSibling;\n let nextSibling;\n if (element.sortorder === 0 && newParent.firstElementChild) {\n // Move to the top of the list.\n nextSibling = newParent.firstElementChild;\n } else {\n // Move later in the list.\n previousSibling = newParent.querySelector(this.selectors.PREVIOUS_SIBLING(element.sortorder));\n nextSibling = previousSibling?.nextElementSibling;\n }\n\n // Check if this has actually moved, or if it's just having its sortorder updated due to another element moving.\n const moved = (newParent !== this.element.parentElement || nextSibling !== this.element);\n\n if (moved) {\n if (nextSibling) {\n // Move to the specified position in the list.\n newParent.insertBefore(this.element, nextSibling);\n } else {\n // Move to the end of the list (may also be the top of the list is empty).\n newParent.appendChild(this.element);\n }\n }\n if (originParent !== newParent) {\n // Update child count of old and new parent.\n this.reactive.stateManager.processUpdates([\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: originParent.dataset.categoryid,\n childCount: originParent.querySelectorAll(this.selectors.LIST_ITEM).length\n }\n },\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: newParent.dataset.categoryid,\n childCount: newParent.querySelectorAll(this.selectors.LIST_ITEM).length\n }\n }\n ]);\n }\n\n this.element.dataset.sortorder = element.sortorder;\n\n // Enable/disable dragging.\n const isDraggable = this.element.classList.contains(this.classes.DRAGHANDLE);\n if (isDraggable && !element.draghandle) {\n this.element.classList.remove(this.classes.DRAGHANDLE);\n this.initDragDrop();\n } else if (!isDraggable && element.draghandle) {\n this.element.classList.add(this.classes.DRAGHANDLE);\n this.initDragDrop();\n }\n }\n\n /**\n * Recursively create a list of all valid destinations for a current category within a parent category.\n *\n * @param {Element} item\n * @param {Number} movingCategoryId\n * @return {*[]}\n */\n createMoveCategoryList(item, movingCategoryId) {\n const categories = [];\n if (item.children) {\n let precedingSibling = null;\n item.children.forEach(category => {\n const categoryId = parseInt(category.dataset.categoryid);\n // Don't create a target for the category that's moving.\n if (categoryId === movingCategoryId) {\n return;\n }\n // Create a target to move before this child.\n let child = {\n categoryid: categoryId,\n movingcategoryid: movingCategoryId,\n precedingsiblingid: precedingSibling?.dataset.categoryid ?? 0,\n parent: category.dataset.parent,\n categoryname: category.dataset.categoryname,\n categories: null,\n current: categoryId === movingCategoryId,\n };\n const childList = category.querySelector(this.selectors.CATEGORY_LIST);\n if (childList) {\n // If the child has its own children, recursively make a list of those.\n child.categories = this.createMoveCategoryList(childList, movingCategoryId);\n } else {\n // Otherwise, create a target to move as a new child of this one.\n child.categories = [\n {\n movingcategoryid: movingCategoryId,\n precedingsiblingid: 0,\n parent: categoryId,\n categoryname: category.dataset.categoryname,\n categories: null,\n newchild: true,\n }\n ];\n }\n categories.push(child);\n precedingSibling = category;\n });\n const precedingId = parseInt(precedingSibling.dataset.categoryid);\n if (precedingId !== movingCategoryId) {\n // If this is the last child of its parent, also create a target to move the category after this one.\n categories.push({\n movingcategoryid: movingCategoryId,\n precedingsiblingid: precedingId,\n parent: precedingSibling.dataset.parent,\n categoryname: precedingSibling.dataset.categoryname,\n categories: null,\n lastchild: true,\n });\n }\n }\n return categories;\n }\n\n /**\n * Displays a modal containing links to move the category to a new location.\n *\n * @param {Event} e Button click event.\n */\n async showMoveModal(e) {\n // Return if it is not menu item.\n const item = e.target;\n if (!item) {\n return;\n }\n // Return if it is disabled.\n if (item.getAttribute('aria-disabled') === 'true') {\n return;\n }\n\n // Prevent addition click on the item.\n item.setAttribute('aria-disabled', true);\n\n // Build the list of move links.\n let moveList = {contexts: []};\n const contexts = document.querySelectorAll(this.selectors.CONTEXT);\n contexts.forEach(context => {\n const moveContext = {\n contextname: context.dataset.contextname,\n categories: [],\n hascategories: false,\n };\n moveContext.categories = this.createMoveCategoryList(context, parseInt(item.dataset.categoryid));\n moveContext.hascategories = moveContext.categories.length > 0;\n moveList.contexts.push(moveContext);\n });\n\n const modal = await Modal.create({\n title: getString('movecategory', 'qbank_managecategories', item.dataset.categoryname),\n body: Templates.render('qbank_managecategories/move_context_list', moveList),\n footer: '',\n show: true,\n large: true,\n });\n // Show modal and add click event for list items.\n modal.getBody()[0].addEventListener('click', e => {\n const target = e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);\n if (!target) {\n return;\n }\n categorymanager.moveCategory(target.dataset.movingcategoryid, target.dataset.parent, target.dataset.precedingsiblingid);\n modal.destroy();\n });\n item.setAttribute('aria-disabled', false);\n }\n\n /**\n * Check and add a child list if needed.\n *\n * Check whether the category that has just been added has this category as its parent. If it does,\n * check that this category has a child list, and if not, add one.\n *\n * @param {Event} event\n * @param {Element} event.element The new category.\n */\n async checkChildList({element}) {\n if (element.parent !== parseInt(this.getElement().dataset.categoryid)) {\n return; // Not for me.\n }\n let childList = this.getElement(this.selectors.CATEGORY_LIST);\n if (childList) {\n return; // List already exists, it will handle adding the new category.\n }\n // Render and add a new child list containing the new category.\n return this.createChildList({\n categoryid: element.parent,\n children: [\n element.templatecontext,\n ]\n });\n }\n}\n"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","CATEGORY_LIST","LIST_ITEM","ACTIVITY_ITEM","EDIT_BUTTON","MOVE_BUTTON","CONTEXT","MODAL_CATEGORY_ITEM","CONTENT_AREA","CATEGORY_ID","CONTENT_CONTAINER","CHILD_LIST","PREVIOUS_SIBLING","sortorder","classes","NO_BOTTOM_PADDING","DRAGHANDLE","DROPTARGET","ids","CATEGORY","stateReady","initDragDrop","addEventListener","this","getElement","categorymanager","showEditModal","moveButton","showMoveModal","destroy","deInitDragDrop","classList","contains","getDraggableData","_getDraggableData","dragdrop","DragDrop","undefined","setDraggable","unregister","target","document","querySelector","reactive","dataset","categoryid","validateDropData","dropData","event","closest","showDropZone","add","hideDropZone","remove","drop","dropTarget","getElementById","targetParentId","parent","parentList","precedingSibling","firstElementChild","previousElementSibling","moveCategory","_precedingSibling","getWatchers","watch","handler","updatePosition","rerender","checkChildList","html","js","Templates","renderForPromise","templatecontext","replaceNodeContents","context","parentContainer","appendNodeContents","childList","newParent","originParent","previousSibling","nextSibling","parseInt","createChildList","parentElement","_previousSibling","nextElementSibling","insertBefore","appendChild","stateManager","processUpdates","action","fields","childCount","querySelectorAll","length","isDraggable","draghandle","createMoveCategoryList","item","movingCategoryId","categories","children","forEach","category","categoryId","child","movingcategoryid","precedingsiblingid","_precedingSibling2","categoryname","current","newchild","push","precedingId","lastchild","e","getAttribute","setAttribute","moveList","contexts","moveContext","contextname","hascategories","modal","Modal","title","body","render","footer","show","large","getBody"],"mappings":"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"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/category_list.min.js b/question/bank/managecategories/amd/build/category_list.min.js deleted file mode 100644 index 9d6d7114a30d5..0000000000000 --- a/question/bank/managecategories/amd/build/category_list.min.js +++ /dev/null @@ -1,12 +0,0 @@ -define("qbank_managecategories/category_list",["exports","core/ajax","core/fragment","core/notification","core/pending","core/templates","core/modal","core/str"],(function(_exports,_ajax,_fragment,_notification,_pending,_templates,_modal,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} -/** - * Javascript module handling ordering of categories. - * - * @module qbank_managecategories - * @copyright 2021 Catalyst IT Australia Pty Ltd - * @author Ghaly Marc-Alexandre - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_fragment=_interopRequireDefault(_fragment),_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_templates=_interopRequireDefault(_templates),_modal=_interopRequireDefault(_modal);const SELECTORS_CATEGORY_LIST=".qbank_managecategories-categorylist",SELECTORS_MODAL_CATEGORY_ITEM=".modal_category_item[data-categoryid]",SELECTORS_CATEGORY_RENDERED="#categoriesrendered",SELECTORS_ACTIONABLE_ELEMENT='a, [role="button"], [role="menuitem"]',SELECTORS_SHOW_DESCRIPTION_CHECKBOX='[name="qbshowdescr"]',SELECTORS_MOVE_CATEGORY_MENU_ITEM='[role="menuitem"][data-actiontype="move"]',SELECTORS_LIST_ITEM=".qbank_managecategories-item[data-categoryid]",SELECTORS_CONTEXT=".qbank_managecategories-categorylist[data-contextid]",SELECTORS_NOT_DRAGGABLE="[draggable=false]",getCategoriesFragment=contextid=>{let params={url:location.href};return _fragment.default.loadFragment("qbank_managecategories","categories",contextid,params)},setCatOrder=function(originCategory,targetCategory,isBeforeTarget,pageContextId){let pendingPromise=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;const call={methodname:"qbank_managecategories_update_category_order",args:{categoryid:originCategory,targetcategoryid:targetCategory,isbeforetarget:isBeforeTarget}};_ajax.default.call([call])[0].then((()=>getCategoriesFragment(pageContextId))).catch((error=>{var _document$getElements;return _notification.default.addNotification({message:error.message,type:"error"}),null===(_document$getElements=document.getElementsByClassName("alert-danger")[0])||void 0===_document$getElements||_document$getElements.scrollIntoView(),getCategoriesFragment(pageContextId)})).then(((html,js)=>{_templates.default.replaceNode("#categoriesrendered",html,js),pendingPromise&&pendingPromise.resolve()})).catch((error=>{pendingPromise&&pendingPromise.reject(error),_notification.default.exception(error)}))},createMoveCategoryList=(item,movingCategory)=>{const categories=[];return item.children&&item.children.forEach((category=>{let child={categoryid:category.dataset.categoryid,categoryname:category.dataset.categoryname,categories:null,firstchild:category===item.children[0],current:category.dataset.categoryid===movingCategory};const childList=category.querySelector(SELECTORS_CATEGORY_LIST);childList&&(child.categories=createMoveCategoryList(childList,movingCategory)),categories.push(child)})),categories};_exports.init=pagecontextid=>{var pageContextId;pageContextId=pagecontextid,document.querySelector(SELECTORS_CATEGORY_RENDERED).addEventListener("click",(e=>{if(!e.target.closest(SELECTORS_CATEGORY_RENDERED))return;const actionIcon=e.target.closest(".action-icon");if(!actionIcon)return;e.preventDefault();const data=actionIcon.dataset;let call;const targetParent=document.querySelector("#category-".concat(data.tocategory));if(targetParent){const childList=targetParent.querySelector(SELECTORS_CATEGORY_LIST);call=childList?{methodname:"qbank_managecategories_update_category_order",args:{categoryid:data.tomove,targetcategoryid:childList.lastElementChild.dataset.categoryid,isbeforetarget:!1}}:{methodname:"qbank_managecategories_move_category_to_new_parent",args:{categoryid:data.tomove,newparentcategoryid:data.tocategory}}}else{const currentParent=actionIcon.closest(SELECTORS_CATEGORY_LIST).closest(SELECTORS_LIST_ITEM);call={methodname:"qbank_managecategories_update_category_order",args:{categoryid:data.tomove,targetcategoryid:currentParent.dataset.categoryid,isbeforetarget:!1}}}_ajax.default.call([call])[0].then((()=>getCategoriesFragment(pageContextId))).then(((html,js)=>{_templates.default.replaceNode(SELECTORS_CATEGORY_RENDERED,html,js)})).catch(_notification.default.exception)})),(pagecontextid=>{let categoryid,dragProxy,touchTimeout,touchScrollInterval;const getTouchTarget=e=>document.elementFromPoint(e.changedTouches[0].clientX,e.changedTouches[0].clientY).closest(SELECTORS_LIST_ITEM),getInsertBefore=(event,dropTarget)=>(event.changedTouches?event.changedTouches[0].clientY:event.clientY)-dropTarget.getBoundingClientRect().top{const dropTarget=document.querySelector(".qbank_managecategories-category-droptarget");dropTarget&&dropTarget.classList.remove("qbank_managecategories-category-droptarget");const dropTargetBefore=document.querySelector(".qbank_managecategories-category-droptarget-before");dropTargetBefore&&dropTargetBefore.classList.remove("qbank_managecategories-category-droptarget-before")},handleDragStart=e=>{var _target$dataset;const target=e.target.closest(SELECTORS_LIST_ITEM);target&&!e.target.closest(SELECTORS_NOT_DRAGGABLE)&&(categoryid=null===(_target$dataset=target.dataset)||void 0===_target$dataset?void 0:_target$dataset.categoryid,"touchstart"===e.type&&(touchTimeout=void 0,makeDragProxy(e,target)))},makeDragProxy=(event,element)=>{dragProxy&&(dragProxy.remove(),dragProxy=null),dragProxy=document.createElement("div"),dragProxy.id="qbank_managecategories-dragproxy",dragProxy.classList.add("editing"),dragProxy.style.width=element.getBoundingClientRect().width+"px",dragProxy.style.height=element.getBoundingClientRect().height+"px",dragProxy.style.top=Math.round(event.touches[0].clientY)+"px",dragProxy.style.left=Math.round(event.touches[0].clientX)+"px",dragProxy.innerHTML=element.innerHTML,document.body.appendChild(dragProxy)},handleDrag=e=>{let target;if("touchmove"===e.type){if("number"==typeof touchTimeout)return clearTimeout(touchTimeout),void(touchTimeout=void 0);target=getTouchTarget(e),touchMoveScroll(e),dragProxy&&(dragProxy.style.top=Math.round(e.changedTouches[0].clientY)+"px",dragProxy.style.left=Math.round(e.changedTouches[0].clientX)+"px")}else target=e.target.closest(SELECTORS_LIST_ITEM);if(!target||!categoryid)return;if(target.closest('[data-categoryid="'.concat(categoryid,'"]')))return;const insertBefore=getInsertBefore(e,target);if(clearTargetIndicators(),insertBefore&&target===target.parentElement.firstElementChild)return void target.classList.add("qbank_managecategories-category-droptarget-before");if(!insertBefore&&target===target.parentElement.lastElementChild)return void target.classList.add("qbank_managecategories-category-droptarget");const insertTarget=insertBefore?target:target.nextElementSibling;insertTarget&&insertTarget.classList.add("qbank_managecategories-category-droptarget-before")},handleDragEnd=e=>{let target;const pending=new _pending.default("qbank_managecategories/dragend");if(clearTargetIndicators(),"touchend"===e.type){if("number"==typeof touchScrollInterval&&(window.clearInterval(touchScrollInterval),touchScrollInterval=void 0),"number"==typeof touchTimeout)return window.clearTimeout(touchTimeout),void(touchTimeout=void 0);dragProxy&&(dragProxy.remove(),dragProxy=null),target=getTouchTarget(e)}else target=e.target.closest(SELECTORS_LIST_ITEM);if(!target){const listTarget=e.target.closest(SELECTORS_CATEGORY_LIST);listTarget&&(target=getInsertBefore(e,listTarget)?listTarget.firstElementChild:listTarget.lastElementChild)}if(!target||!categoryid)return;const source=document.getElementById("category-".concat(categoryid));if(!source)return;let targetCategory;e.preventDefault(),categoryid=null;const insertBefore=getInsertBefore(e,target);let before=insertBefore;if(insertBefore&&target===target.parentElement.firstElementChild)targetCategory=target.dataset.categoryid,target.closest(SELECTORS_CATEGORY_LIST).insertBefore(source,target);else if(insertBefore||target!==target.parentElement.lastElementChild){const insertTarget=insertBefore?target:target.nextElementSibling;targetCategory=insertTarget.dataset.categoryid,before=!0,target.closest(SELECTORS_CATEGORY_LIST).insertBefore(source,insertTarget)}else targetCategory=target.dataset.categoryid,target.closest(SELECTORS_CATEGORY_LIST).appendChild(source);const originCategory=source.dataset.categoryid;setCatOrder(originCategory,targetCategory,before,pagecontextid,pending)},touchMoveScroll=e=>{if(!categoryid)return;const intervalRunning=void 0!==touchScrollInterval;e.changedTouches[0].clientY<50&&!intervalRunning?touchScrollInterval=window.setInterval((()=>{window.scrollBy(0,-1)}),5):window.innerHeight-e.changedTouches[0].clientY<50&&!intervalRunning?touchScrollInterval=window.setInterval((()=>{window.scrollBy(0,1)}),5):intervalRunning&&(window.clearInterval(touchScrollInterval),touchScrollInterval=void 0)},allowDrop=e=>{e.preventDefault()},categoryRoot=document.getElementById("categoriesrendered");categoryRoot.addEventListener("dragover",allowDrop),categoryRoot.addEventListener("dragenter",allowDrop),categoryRoot.addEventListener("dragstart",handleDragStart),categoryRoot.addEventListener("dragenter",handleDrag),categoryRoot.addEventListener("dragleave",(e=>{e.target.classList.contains("qbank_managecategories-categorylist")&&clearTargetIndicators()})),categoryRoot.addEventListener("drop",handleDragEnd),categoryRoot.addEventListener("touchmove",handleDrag,!1),categoryRoot.addEventListener("touchend",handleDragEnd,!1),categoryRoot.addEventListener("touchstart",(e=>{touchTimeout=window.setTimeout((()=>handleDragStart(e)),500)}),!1),document.querySelectorAll(SELECTORS_LIST_ITEM+" "+SELECTORS_ACTIONABLE_ELEMENT).forEach((element=>{element.setAttribute("draggable",!1)}))})(pagecontextid),document.addEventListener("click",(e=>{const checkbox=e.target.closest(SELECTORS_SHOW_DESCRIPTION_CHECKBOX);checkbox&&checkbox.form.submit()})),(pagecontextid=>{document.querySelector(SELECTORS_CATEGORY_RENDERED).addEventListener("click",(async e=>{const item=e.target.closest(SELECTORS_MOVE_CATEGORY_MENU_ITEM);if(!item)return;if(item.getAttribute("aria-disabled"))return;item.setAttribute("aria-disabled",!0);let moveList={contexts:[]};document.querySelectorAll(SELECTORS_CONTEXT).forEach((context=>{const moveContext={contextname:context.dataset.contextname,categories:[],hascategories:!1};moveContext.categories=createMoveCategoryList(context,item.dataset.categoryid),moveContext.hascategories=moveContext.categories.length>0,moveList.contexts.push(moveContext)}));const modal=await _modal.default.create({title:(0,_str.get_string)("movecategory","qbank_managecategories",item.dataset.categoryname),body:_templates.default.render("qbank_managecategories/move_context_list",moveList),footer:"",show:!0,large:!0});modal.getBody()[0].addEventListener("click",(e=>{const target=e.target.closest(SELECTORS_MODAL_CATEGORY_ITEM);if(!target)return;const pending=new _pending.default("qbank_managecategories/modal");setCatOrder(item.dataset.categoryid,target.dataset.categoryid,target.dataset.before,pagecontextid,pending),modal.destroy()})),item.setAttribute("aria-disabled",!1)}))})(pagecontextid)}})); - -//# sourceMappingURL=category_list.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/category_list.min.js.map b/question/bank/managecategories/amd/build/category_list.min.js.map deleted file mode 100644 index ce93c6c94de6e..0000000000000 --- a/question/bank/managecategories/amd/build/category_list.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"category_list.min.js","sources":["../src/category_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module handling ordering of categories.\n *\n * @module qbank_managecategories\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Ghaly Marc-Alexandre \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n *\n */\n\nimport Ajax from 'core/ajax';\nimport Fragment from 'core/fragment';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Templates from 'core/templates';\nimport Modal from 'core/modal';\nimport {get_string as getString} from 'core/str';\n\nconst SELECTORS = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n MODAL_CATEGORY_ITEM: '.modal_category_item[data-categoryid]',\n CATEGORY_RENDERED: '#categoriesrendered',\n ACTIONABLE_ELEMENT: 'a, [role=\"button\"], [role=\"menuitem\"]',\n SHOW_DESCRIPTION_CHECKBOX: '[name=\"qbshowdescr\"]',\n MOVE_CATEGORY_MENU_ITEM: '[role=\"menuitem\"][data-actiontype=\"move\"]',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n CONTEXT: '.qbank_managecategories-categorylist[data-contextid]',\n NOT_DRAGGABLE: '[draggable=false]',\n};\n\n/**\n * Sets up sortable list in the column sort order page.\n * @param {number} pagecontextid Context id for fragment.\n */\nconst setupSortableLists = (pagecontextid) => {\n // Touch events do not have datatransfer property.\n // This variable is used to store id of first element that started the touch events.\n let categoryid;\n // Drag proxy element for touch events.\n let dragProxy;\n // Timeout before dragging starts on touch.\n let touchTimeout;\n // Interval for scrolling the page with touch.\n let touchScrollInterval;\n\n /**\n * Get touch target at touch point.\n * The target of all touch events is the first element that has been touched at 'touch start'.\n * So we need to infer the target from touch point for 'touch move' and 'touch end' events.\n *\n * @param {Object} e event\n * @returns {any | Element}\n */\n const getTouchTarget = (e) => {\n const target = document.elementFromPoint(\n e.changedTouches[0].clientX,\n e.changedTouches[0].clientY\n );\n // Check if the target is droppable.\n return target.closest(SELECTORS.LIST_ITEM);\n };\n\n /**\n * Decide if we are before or after the current drop target.\n *\n * Based on the current vertical position of the dragged element relative to the mid-point of the\n * current drop target, decide if dropping will place the dragged element before or after the target.\n *\n * @param {Event} event\n * @param {Element} dropTarget\n * @return {boolean}\n */\n const getInsertBefore = (event, dropTarget) => {\n\n const clientY = event.changedTouches ? event.changedTouches[0].clientY : event.clientY;\n\n // Get the current mouse position within the drop target\n const mouseY = clientY - dropTarget.getBoundingClientRect().top;\n\n // Get the height of the drop target\n const targetHeight = dropTarget.clientHeight;\n\n // Check if the mouse is over the top half of the drop target\n return mouseY < targetHeight / 2;\n };\n\n /**\n * Remove any drop target indicators currently displayed.\n */\n const clearTargetIndicators = () => {\n const dropTarget = document.querySelector('.qbank_managecategories-category-droptarget');\n if (dropTarget) {\n dropTarget.classList.remove('qbank_managecategories-category-droptarget');\n }\n const dropTargetBefore = document.querySelector('.qbank_managecategories-category-droptarget-before');\n if (dropTargetBefore) {\n dropTargetBefore.classList.remove('qbank_managecategories-category-droptarget-before');\n }\n };\n\n /**\n * Handle Drag start\n *\n * This will register the dragged element so it can be moved when dropped.\n *\n * @param {Object} e event\n */\n const handleDragStart = (e) => {\n const target = e.target.closest(SELECTORS.LIST_ITEM);\n\n // Return if target is not a draggable item.\n if (!target || e.target.closest(SELECTORS.NOT_DRAGGABLE)) {\n return;\n }\n // Save category ID of current moving item.\n // The datatransfer is not used as it is not a property of touch events.\n categoryid = target.dataset?.categoryid;\n\n if (e.type === 'touchstart') {\n touchTimeout = undefined;\n makeDragProxy(e, target);\n }\n };\n\n /**\n * Touch events don't create a drag proxy, so create one manually.\n *\n * @param {Event} event The touchstart event.\n * @param {Element} element The element being dragged, to create the proxy for.\n */\n const makeDragProxy = (event, element) => {\n if (dragProxy) {\n dragProxy.remove();\n dragProxy = null;\n }\n dragProxy = document.createElement('div');\n dragProxy.id = 'qbank_managecategories-dragproxy';\n dragProxy.classList.add('editing');\n dragProxy.style.width = element.getBoundingClientRect().width + 'px';\n dragProxy.style.height = element.getBoundingClientRect().height + 'px';\n dragProxy.style.top = Math.round(event.touches[0].clientY) + 'px';\n dragProxy.style.left = Math.round(event.touches[0].clientX) + 'px';\n dragProxy.innerHTML = element.innerHTML;\n document.body.appendChild(dragProxy);\n };\n\n /**\n * Handle Drag move\n *\n * Keep track of the current drop target, and move the drop indicator to the appropriate position.\n *\n * @param {Event} e event\n */\n const handleDrag = (e) => {\n let target;\n if (e.type === 'touchmove') {\n if (typeof touchTimeout === 'number') {\n clearTimeout(touchTimeout);\n touchTimeout = undefined;\n return;\n }\n target = getTouchTarget(e);\n touchMoveScroll(e);\n if (dragProxy) {\n dragProxy.style.top = Math.round(e.changedTouches[0].clientY) + 'px';\n dragProxy.style.left = Math.round(e.changedTouches[0].clientX) + 'px';\n }\n } else {\n target = e.target.closest(SELECTORS.LIST_ITEM);\n }\n // Return if target is not a droppable item or there is no sourceid.\n if (!target || !categoryid) {\n return;\n }\n\n // Return if target is a child of the dragged category, so we don't indicate this as a valid drop target.\n if (target.closest(`[data-categoryid=\"${categoryid}\"]`)) {\n return;\n }\n\n const insertBefore = getInsertBefore(e, target);\n\n // Remove all target indicators.\n clearTargetIndicators();\n\n if (insertBefore && target === target.parentElement.firstElementChild) {\n // Show the indicator at the top of the list.\n target.classList.add('qbank_managecategories-category-droptarget-before');\n return;\n }\n\n if (!insertBefore && target === target.parentElement.lastElementChild) {\n // Show the indicator at the bottom of the list.\n target.classList.add('qbank_managecategories-category-droptarget');\n return;\n }\n\n const insertTarget = insertBefore ? target : target.nextElementSibling;\n\n // Show the indicator at the top of the target element.\n if (insertTarget) {\n insertTarget.classList.add('qbank_managecategories-category-droptarget-before');\n }\n };\n\n /**\n * When an item is dragged out of a list, remove the current drag indicators.\n *\n * @param {Event} e\n */\n const handleDragLeaveList = (e) => {\n if (e.target.classList.contains('qbank_managecategories-categorylist')) {\n clearTargetIndicators();\n }\n };\n\n /**\n * Handle Drag end\n *\n * When an item is dropped, find the target element and re-order the categories.\n * If the item is dropped at the top or bottom of a list, it will be moved before the first or after\n * the last item, respectively. Otherwise, if it is dropped on the top half of an item, it will be moved\n * before that item, and if on the bottom half, after that item.\n *\n * @param {Event} e event\n */\n const handleDragEnd = (e) => {\n let target;\n const pending = new Pending('qbank_managecategories/dragend');\n clearTargetIndicators();\n if (e.type === 'touchend') {\n if (typeof touchScrollInterval === 'number') {\n // Stop scrolling.\n window.clearInterval(touchScrollInterval);\n touchScrollInterval = undefined;\n }\n if (typeof touchTimeout === 'number') {\n // Cancel waiting on a long touch to start dragging.\n window.clearTimeout(touchTimeout);\n touchTimeout = undefined;\n return;\n }\n if (dragProxy) {\n dragProxy.remove();\n dragProxy = null;\n }\n target = getTouchTarget(e);\n } else {\n target = e.target.closest(SELECTORS.LIST_ITEM);\n }\n\n if (!target) {\n // Check if we're at the top or bottom of the list, and target the first or last element accordingly.\n const listTarget = e.target.closest(SELECTORS.CATEGORY_LIST);\n if (listTarget) {\n if (getInsertBefore(e, listTarget)) {\n target = listTarget.firstElementChild;\n } else {\n target = listTarget.lastElementChild;\n }\n }\n }\n\n // Return if target is not a droppable item or there is no sourceid.\n if (!target || !categoryid) {\n return;\n }\n\n // Get list item whose id is the same as current moving category id.\n const source = document.getElementById(`category-${categoryid}`);\n if (!source) {\n return;\n }\n\n e.preventDefault();\n\n // Reset sourceid for touch event.\n categoryid = null;\n\n let targetCategory;\n const insertBefore = getInsertBefore(e, target);\n let before = insertBefore;\n if (insertBefore && target === target.parentElement.firstElementChild) {\n targetCategory = target.dataset.categoryid;\n // Insert the category at the top of the list.\n target.closest(SELECTORS.CATEGORY_LIST).insertBefore(source, target);\n } else if (!insertBefore && target === target.parentElement.lastElementChild) {\n targetCategory = target.dataset.categoryid;\n // Insert the category at the end of the list.\n target.closest(SELECTORS.CATEGORY_LIST).appendChild(source);\n } else {\n const insertTarget = insertBefore ? target : target.nextElementSibling;\n targetCategory = insertTarget.dataset.categoryid;\n before = true; // We always insert before the selected target.\n\n // Move the source category to its new position.\n target.closest(SELECTORS.CATEGORY_LIST).insertBefore(source, insertTarget);\n }\n\n // Moved category.\n const originCategory = source.dataset.categoryid;\n\n // Insert the category after the target category\n setCatOrder(originCategory, targetCategory, before, pagecontextid, pending);\n };\n\n /**\n * If something is dragged near the top or bottom of the screen by touch, scroll until it is moved away.\n *\n * @param {Event} e\n */\n const touchMoveScroll = (e) => {\n if (!categoryid) {\n return;\n }\n const threshold = 50;\n const timeout = 5;\n const intervalRunning = typeof touchScrollInterval !== 'undefined';\n if (e.changedTouches[0].clientY < threshold && !intervalRunning) {\n touchScrollInterval = window.setInterval(\n () => {\n window.scrollBy(0, -1);\n },\n timeout\n );\n } else if (window.innerHeight - e.changedTouches[0].clientY < threshold && !intervalRunning) {\n touchScrollInterval = window.setInterval(\n () => {\n window.scrollBy(0, 1);\n },\n timeout\n );\n } else if (intervalRunning) {\n window.clearInterval(touchScrollInterval);\n touchScrollInterval = undefined;\n }\n };\n\n /**\n * Allow drop\n *\n * This allows elements to be used as a drop target.\n *\n * @param {Object} e event\n */\n const allowDrop = (e) => {\n e.preventDefault();\n };\n\n const categoryRoot = document.getElementById('categoriesrendered');\n categoryRoot.addEventListener('dragover', allowDrop);\n categoryRoot.addEventListener('dragenter', allowDrop);\n categoryRoot.addEventListener('dragstart', handleDragStart);\n categoryRoot.addEventListener('dragenter', handleDrag);\n categoryRoot.addEventListener('dragleave', handleDragLeaveList);\n categoryRoot.addEventListener('drop', handleDragEnd);\n categoryRoot.addEventListener('touchmove', handleDrag, false);\n categoryRoot.addEventListener('touchend', handleDragEnd, false);\n categoryRoot.addEventListener('touchstart', (e) => {\n // Delay before we start dragging on touch. This avoids accidental dragging when trying to scroll.\n touchTimeout = window.setTimeout(() => handleDragStart(e), 500);\n }, false);\n\n document.querySelectorAll(SELECTORS.LIST_ITEM + ' ' + SELECTORS.ACTIONABLE_ELEMENT).forEach(element => {\n // Prevent interactive elements inside a list item from being dragged.\n element.setAttribute('draggable', false);\n });\n};\n\n/**\n * Call categories fragment.\n *\n * @param {number} contextid String containing new ordered categories.\n * @returns {Promise}\n */\nconst getCategoriesFragment = (contextid) => {\n let params = {\n url: location.href,\n };\n return Fragment.loadFragment('qbank_managecategories', 'categories', contextid, params);\n};\n\n/**\n * Call external function update_category_order - inserts the updated column in the question_categories table.\n *\n * @param {number} originCategory Category which was dragged.\n * @param {number} targetCategory Context where category was dropped.\n * @param {boolean} isBeforeTarget True if the category was moved before the target category.\n * @param {number} pageContextId Context from which the category was dragged.\n * @param {Pending} pendingPromise Optional pending promise, will be resolved once the page fragment has been re-rendered.\n */\nconst setCatOrder = (originCategory, targetCategory, isBeforeTarget, pageContextId, pendingPromise = null) => {\n const call = {\n methodname: 'qbank_managecategories_update_category_order',\n args: {\n categoryid: originCategory,\n targetcategoryid: targetCategory,\n isbeforetarget: isBeforeTarget,\n }\n };\n Ajax.call([call])[0]\n .then(() => {\n return getCategoriesFragment(pageContextId);\n })\n .catch(error => {\n Notification.addNotification({\n message: error.message,\n type: 'error',\n });\n document.getElementsByClassName('alert-danger')[0]?.scrollIntoView();\n return getCategoriesFragment(pageContextId);\n })\n .then((html, js) => {\n Templates.replaceNode('#categoriesrendered', html, js);\n if (pendingPromise) {\n pendingPromise.resolve();\n }\n return;\n })\n .catch(error => {\n if (pendingPromise) {\n pendingPromise.reject(error);\n }\n Notification.exception(error);\n });\n};\n\n\n/**\n * Method to add listener on category arrow - descendants.\n *\n * @param {number} pageContextId Context id for fragment.\n */\nconst categoryParentListener = (pageContextId) => {\n document.querySelector(SELECTORS.CATEGORY_RENDERED).addEventListener('click', e => {\n // Ignore if there is no categories containers.\n if (!e.target.closest(SELECTORS.CATEGORY_RENDERED)) {\n return;\n }\n\n // Ignore if there is no action icon.\n const actionIcon = e.target.closest('.action-icon');\n if (!actionIcon) {\n return;\n }\n\n e.preventDefault();\n\n // Retrieve data from action icon.\n const data = actionIcon.dataset;\n\n let call;\n const targetParent = document.querySelector(`#category-${data.tocategory}`);\n if (!targetParent) {\n // Moving to the top level. Move after the current parent.\n const currentParent = actionIcon.closest(SELECTORS.CATEGORY_LIST).closest(SELECTORS.LIST_ITEM);\n call = {\n methodname: 'qbank_managecategories_update_category_order',\n args: {\n categoryid: data.tomove,\n targetcategoryid: currentParent.dataset.categoryid,\n isbeforetarget: false,\n }\n };\n } else {\n const childList = targetParent.querySelector(SELECTORS.CATEGORY_LIST);\n if (childList) {\n // The new parent already has children. Move the category to the end of its list.\n call = {\n methodname: 'qbank_managecategories_update_category_order',\n args: {\n categoryid: data.tomove,\n targetcategoryid: childList.lastElementChild.dataset.categoryid,\n isbeforetarget: false,\n }\n };\n } else {\n // Move the category to the new parent.\n call = {\n methodname: 'qbank_managecategories_move_category_to_new_parent',\n args: {\n categoryid: data.tomove,\n newparentcategoryid: data.tocategory,\n }\n };\n }\n }\n\n Ajax.call([call])[0]\n .then(() => getCategoriesFragment(pageContextId))\n .then((html, js) => {\n Templates.replaceNode(SELECTORS.CATEGORY_RENDERED, html, js);\n return;\n })\n .catch(Notification.exception);\n });\n};\n\n/**\n * Sets events listener for checkbox ticking change.\n */\nconst setupShowDescriptionCheckbox = () => {\n document.addEventListener('click', e => {\n const checkbox = e.target.closest(SELECTORS.SHOW_DESCRIPTION_CHECKBOX);\n if (!checkbox) {\n return;\n }\n checkbox.form.submit();\n });\n};\n\nconst createMoveCategoryList = (item, movingCategory) => {\n const categories = [];\n if (item.children) {\n item.children.forEach(category => {\n let child = {\n categoryid: category.dataset.categoryid,\n categoryname: category.dataset.categoryname,\n categories: null,\n firstchild: category === item.children[0],\n current: category.dataset.categoryid === movingCategory,\n };\n\n const childList = category.querySelector(SELECTORS.CATEGORY_LIST);\n if (childList) {\n child.categories = createMoveCategoryList(childList, movingCategory);\n }\n categories.push(child);\n });\n }\n return categories;\n};\n\n/**\n * Sets events listener for move category using dragdrop icon.\n * @param {number} pagecontextid Context id to get all relevant categories.\n */\nconst setUpMoveMenuItem = (pagecontextid) => {\n document.querySelector(SELECTORS.CATEGORY_RENDERED).addEventListener('click', async(e) => {\n // Return if it is not menu item.\n const item = e.target.closest(SELECTORS.MOVE_CATEGORY_MENU_ITEM);\n if (!item) {\n return;\n }\n // Return if it is disabled.\n if (item.getAttribute('aria-disabled')) {\n return;\n }\n\n // Prevent addition click on the item.\n item.setAttribute('aria-disabled', true);\n\n let moveList = {contexts: []};\n const contexts = document.querySelectorAll(SELECTORS.CONTEXT);\n contexts.forEach(context => {\n const moveContext = {\n contextname: context.dataset.contextname,\n categories: [],\n hascategories: false,\n };\n moveContext.categories = createMoveCategoryList(context, item.dataset.categoryid);\n moveContext.hascategories = moveContext.categories.length > 0;\n moveList.contexts.push(moveContext);\n });\n\n const modal = await Modal.create({\n title: getString('movecategory', 'qbank_managecategories', item.dataset.categoryname),\n body: Templates.render('qbank_managecategories/move_context_list', moveList),\n footer: '',\n show: true,\n large: true,\n });\n // Show modal and add click event for list item.\n modal.getBody()[0].addEventListener('click', e => {\n const target = e.target.closest(SELECTORS.MODAL_CATEGORY_ITEM);\n if (!target) {\n return;\n }\n const pending = new Pending('qbank_managecategories/modal');\n setCatOrder(item.dataset.categoryid, target.dataset.categoryid, target.dataset.before, pagecontextid, pending);\n modal.destroy();\n });\n item.setAttribute('aria-disabled', false);\n });\n};\n\nexport const init = (pagecontextid) => {\n categoryParentListener(pagecontextid);\n setupSortableLists(pagecontextid);\n setupShowDescriptionCheckbox();\n setUpMoveMenuItem(pagecontextid);\n};\n"],"names":["SELECTORS","getCategoriesFragment","contextid","params","url","location","href","Fragment","loadFragment","setCatOrder","originCategory","targetCategory","isBeforeTarget","pageContextId","pendingPromise","call","methodname","args","categoryid","targetcategoryid","isbeforetarget","then","catch","error","addNotification","message","type","document","getElementsByClassName","scrollIntoView","html","js","replaceNode","resolve","reject","exception","createMoveCategoryList","item","movingCategory","categories","children","forEach","category","child","dataset","categoryname","firstchild","current","childList","querySelector","push","pagecontextid","addEventListener","e","target","closest","actionIcon","preventDefault","data","targetParent","tocategory","tomove","lastElementChild","newparentcategoryid","currentParent","Notification","dragProxy","touchTimeout","touchScrollInterval","getTouchTarget","elementFromPoint","changedTouches","clientX","clientY","getInsertBefore","event","dropTarget","getBoundingClientRect","top","clientHeight","clearTargetIndicators","classList","remove","dropTargetBefore","handleDragStart","_target$dataset","undefined","makeDragProxy","element","createElement","id","add","style","width","height","Math","round","touches","left","innerHTML","body","appendChild","handleDrag","clearTimeout","touchMoveScroll","insertBefore","parentElement","firstElementChild","insertTarget","nextElementSibling","handleDragEnd","pending","Pending","window","clearInterval","listTarget","source","getElementById","before","intervalRunning","setInterval","scrollBy","innerHeight","allowDrop","categoryRoot","contains","setTimeout","querySelectorAll","setAttribute","setupSortableLists","checkbox","form","submit","async","getAttribute","moveList","contexts","context","moveContext","contextname","hascategories","length","modal","Modal","create","title","Templates","render","footer","show","large","getBody","destroy","setUpMoveMenuItem"],"mappings":"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"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/categorylist.min.js b/question/bank/managecategories/amd/build/categorylist.min.js index 0159397b6a637..c3eab3c0cfeaf 100644 --- a/question/bank/managecategories/amd/build/categorylist.min.js +++ b/question/bank/managecategories/amd/build/categorylist.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/categorylist",["exports","core/reactive","qbank_managecategories/categorymanager","core/templates"],(function(_exports,_reactive,_categorymanager,_templates){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={CATEGORY_LIST:".qbank_managecategories-categorylist",LIST_ITEM:".qbank_managecategories-item[data-categoryid]",ACTIVITY_ITEM:".activity-item",ACTIVITY_NAME_AREA:".activity-name-area"}}stateReady(){this.initDragDrop()}destroy(){this.deInitDragDrop()}initDragDrop(){this.dragdrop=new _reactive.DragDrop(this)}deInitDragDrop(){void 0!==this.dragdrop&&(this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}validateDropData(){return!0}showDropZone(dropData,event){const dropTarget=event.target.closest(this.selectors.CATEGORY_LIST);dropTarget.closest("#category-".concat(dropData.id))||(this.getInsertBefore(event,dropTarget)?(dropTarget.classList.add("qbank_managecategories-category-droptarget-before"),dropTarget.classList.remove("qbank_managecategories-category-droptarget")):(dropTarget.classList.add("qbank_managecategories-category-droptarget"),dropTarget.classList.remove("qbank_managecategories-category-droptarget-before")))}hideDropZone(dropData,event){const dropTarget=event.target.closest(this.selectors.CATEGORY_LIST);dropTarget.classList.remove("qbank_managecategories-category-droptarget-before"),dropTarget.classList.remove("qbank_managecategories-category-droptarget")}getInsertBefore(event,dropTarget){return event.clientY-dropTarget.getBoundingClientRect().top"#category-".concat(id)},this.classes={DROP_TARGET_BEFORE:"qbank_managecategories-category-droptarget-before",DROP_TARGET:"qbank_managecategories-category-droptarget",NO_BOTTOM_PADDING:"pb-0",SHOWDESCRIPTIONS:"showdescriptions"},this.ids={CATEGORY:id=>"#category-".concat(id)}}stateReady(){this.dragdrop=new _reactive.DragDrop(this)}destroy(){void 0!==this.dragdrop&&(this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}validateDropData(dropData,event){return!event.target.closest(this.selectors.CATEGORY_LIST).closest(this.selectors.CATEGORY_ID(dropData.id))}showDropZone(dropData,event){const dropTarget=event.target.closest(this.selectors.CATEGORY_LIST);this.getInsertBefore(event,dropTarget)?(dropTarget.classList.add(this.classes.DROP_TARGET_BEFORE),dropTarget.classList.remove(this.classes.DROP_TARGET)):(dropTarget.classList.add(this.classes.DROP_TARGET),dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE))}hideDropZone(dropData,event){const dropTarget=event.target.closest(this.selectors.CATEGORY_LIST);dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE),dropTarget.classList.remove(this.classes.DROP_TARGET)}getInsertBefore(event,dropTarget){return event.clientY-dropTarget.getBoundingClientRect().top.\n\n/**\n * The category component.\n *\n * @module qbank_managecategories/categorylist\n * @class qbank_managecategories/categorylist\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\nimport Templates from \"core/templates\";\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n ACTIVITY_ITEM: '.activity-item',\n ACTIVITY_NAME_AREA: '.activity-name-area',\n };\n }\n\n stateReady() {\n this.initDragDrop();\n }\n\n destroy() {\n // The draggable element must be unregistered.\n this.deInitDragDrop();\n }\n\n initDragDrop() {\n this.dragdrop = new DragDrop(this);\n }\n\n deInitDragDrop() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n selectors,\n reactive: categorymanager,\n });\n }\n\n validateDropData() {\n return true;\n }\n\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n if (dropTarget.closest(`#category-${dropData.id}`)) {\n // Can't drop onto your own child.\n return;\n }\n if (this.getInsertBefore(event, dropTarget)) {\n dropTarget.classList.add('qbank_managecategories-category-droptarget-before');\n dropTarget.classList.remove('qbank_managecategories-category-droptarget');\n } else {\n dropTarget.classList.add('qbank_managecategories-category-droptarget');\n dropTarget.classList.remove('qbank_managecategories-category-droptarget-before');\n }\n\n }\n\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n dropTarget.classList.remove('qbank_managecategories-category-droptarget-before');\n dropTarget.classList.remove('qbank_managecategories-category-droptarget');\n\n }\n\n getInsertBefore(event, dropTarget) {\n // Get the current mouse position within the drop target\n const mouseY = event.clientY - dropTarget.getBoundingClientRect().top;\n\n // Get the height of the drop target\n const targetHeight = dropTarget.clientHeight;\n\n // Check if the mouse is over the top half of the drop target\n return mouseY < targetHeight / 2;\n }\n\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n\n if (!dropTarget) {\n return;\n }\n\n if (dropTarget.closest(`#category-${dropData.id}`)) {\n // Can't drop onto your own child.\n return;\n }\n\n const source = document.getElementById(`category-${dropData.id}`);\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.categoryid;\n let precedingSibling;\n\n if (this.getInsertBefore(event, dropTarget)) {\n // Dropped at the top of the list.\n precedingSibling = null;\n } else {\n precedingSibling = dropTarget.lastElementChild;\n }\n\n // Insert the category after the target category\n categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n /**\n * Watch for categories moving to a new parent.\n *\n * @return {Array} A list of watchers.\n */\n getWatchers() {\n return [\n {watch: `categoryLists[${this.element.dataset.categoryid}].childCount:updated`, handler: this.checkEmptyList},\n {watch: `categories:created`, handler: this.addCategory},\n ];\n }\n\n /**\n * If this list is now empty, remove it.\n *\n * @param {Object} args\n * @param {Object} args.element The categoryList state element.\n */\n async checkEmptyList({element}) {\n if (element.childCount === 0) {\n // Display a new child drop zone.\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/newchild',\n {\n categoryid: this.element.dataset.categoryid,\n }\n );\n const activityNameArea = this.element\n .closest(this.selectors.LIST_ITEM)\n .querySelector(this.selectors.ACTIVITY_NAME_AREA);\n await Templates.appendNodeContents(activityNameArea, html, js);\n // Reinstate padding on the parent element.\n this.element.closest(this.selectors.ACTIVITY_ITEM).classList.remove('pb-0');\n // Remove this list.\n this.remove();\n }\n }\n\n async addCategory({element}) {\n if (element.parent !== parseInt(this.getElement().dataset.categoryid)) {\n return; // Not for me.\n }\n const {html, js} = await Templates.renderForPromise('qbank_managecategories/item', element.templatecontext);\n Templates.appendNodeContents(this.getElement(), html, js);\n }\n}"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","CATEGORY_LIST","LIST_ITEM","ACTIVITY_ITEM","ACTIVITY_NAME_AREA","stateReady","initDragDrop","destroy","deInitDragDrop","dragdrop","DragDrop","this","undefined","unregister","target","document","querySelector","reactive","categorymanager","validateDropData","showDropZone","dropData","event","dropTarget","closest","getInsertBefore","classList","add","remove","hideDropZone","clientY","getBoundingClientRect","top","clientHeight","drop","getElementById","targetParentId","dataset","categoryid","precedingSibling","lastElementChild","setCatOrder","_precedingSibling","getWatchers","watch","handler","checkEmptyList","addCategory","childCount","html","js","Templates","renderForPromise","activityNameArea","appendNodeContents","parent","parseInt","getElement","templatecontext"],"mappings":"0WA0B6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,UAAY,CACbC,cAAe,uCACfC,UAAW,gDACXC,cAAe,iBACfC,mBAAoB,uBAI5BC,kBACSC,eAGTC,eAESC,iBAGTF,oBACSG,SAAW,IAAIC,mBAASC,MAGjCH,sBAC0BI,IAAlBD,KAAKF,gBACAA,SAASI,kBACTJ,cAAWG,eAWZE,OAAQd,kBACT,IAAIW,KAAK,CACZb,QAASiB,SAASC,cAAcF,QAChCd,UAAAA,UACAiB,SAAUC,mCAIlBC,0BACW,EAGXC,aAAaC,SAAUC,aACbC,WAAaD,MAAMR,OAAOU,QAAQb,KAAKX,UAAUC,eACnDsB,WAAWC,4BAAqBH,SAAStB,OAIzCY,KAAKc,gBAAgBH,MAAOC,aAC5BA,WAAWG,UAAUC,IAAI,qDACzBJ,WAAWG,UAAUE,OAAO,gDAE5BL,WAAWG,UAAUC,IAAI,8CACzBJ,WAAWG,UAAUE,OAAO,uDAKpCC,aAAaR,SAAUC,aACbC,WAAaD,MAAMR,OAAOU,QAAQb,KAAKX,UAAUC,eACvDsB,WAAWG,UAAUE,OAAO,qDAC5BL,WAAWG,UAAUE,OAAO,8CAIhCH,gBAAgBH,MAAOC,mBAEJD,MAAMQ,QAAUP,WAAWQ,wBAAwBC,IAG7CT,WAAWU,aAGD,EAGnCC,KAAKb,SAAUC,mCACLC,WAAaD,MAAMR,OAAOU,QAAQb,KAAKX,UAAUC,mBAElDsB,qBAIDA,WAAWC,4BAAqBH,SAAStB,gBAK9BgB,SAASoB,kCAA2Bd,SAAStB,kBAMtDqC,eAAiBb,WAAWc,QAAQC,eACtCC,iBAIAA,iBAFA5B,KAAKc,gBAAgBH,MAAOC,YAET,KAEAA,WAAWiB,kDAIlBC,YAAYpB,SAAStB,GAAIqC,yCAAgBG,qDAAAG,kBAAkBL,QAAQC,YAQvFK,oBACW,CACH,CAACC,8BAAwBjC,KAAKb,QAAQuC,QAAQC,mCAAkCO,QAASlC,KAAKmC,gBAC9F,CAACF,2BAA6BC,QAASlC,KAAKoC,6CAU/BjD,QAACA,iBACS,IAAvBA,QAAQkD,WAAkB,OAEpBC,KAACA,KAADC,GAAOA,UAAYC,mBAAUC,iBAC/B,kCACA,CACId,WAAY3B,KAAKb,QAAQuC,QAAQC,aAGnCe,iBAAmB1C,KAAKb,QACzB0B,QAAQb,KAAKX,UAAUE,WACvBc,cAAcL,KAAKX,UAAUI,0BAC5B+C,mBAAUG,mBAAmBD,iBAAkBJ,KAAMC,SAEtDpD,QAAQ0B,QAAQb,KAAKX,UAAUG,eAAeuB,UAAUE,OAAO,aAE/DA,uCAIK9B,QAACA,kBACXA,QAAQyD,SAAWC,SAAS7C,KAAK8C,aAAapB,QAAQC,yBAGpDW,KAACA,KAADC,GAAOA,UAAYC,mBAAUC,iBAAiB,8BAA+BtD,QAAQ4D,oCACjFJ,mBAAmB3C,KAAK8C,aAAcR,KAAMC"} \ No newline at end of file +{"version":3,"file":"categorylist.min.js","sources":["../src/categorylist.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 * The category list component.\n *\n * The category list is a drop target, so that a category may be dropped at the top or bottom of the list.\n *\n * @module qbank_managecategories/categorylist\n * @class qbank_managecategories/categorylist\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\nimport Templates from \"core/templates\";\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n ACTIVITY_ITEM: '.activity-item',\n ACTIVITY_NAME_AREA: '.activity-name-area',\n CATEGORY_ID: id => `#category-${id}`,\n };\n this.classes = {\n DROP_TARGET_BEFORE: 'qbank_managecategories-category-droptarget-before',\n DROP_TARGET: 'qbank_managecategories-category-droptarget',\n NO_BOTTOM_PADDING: 'pb-0',\n SHOWDESCRIPTIONS: 'showdescriptions',\n };\n this.ids = {\n CATEGORY: id => `#category-${id}`,\n };\n }\n\n stateReady() {\n this.dragdrop = new DragDrop(this);\n }\n\n destroy() {\n // The draggable element must be unregistered.\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n selectors,\n reactive: categorymanager,\n });\n }\n\n /**\n * You can't drop into a list that is a descendant of the dragged category.\n *\n * @param {Object} dropData\n * @param {Event} event\n * @return {boolean}\n */\n validateDropData(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) {\n return false;\n }\n return true;\n }\n\n /**\n * Highlight the border of the list where the category will be moved.\n *\n * If dropping at the top of the list, highlight the top border.\n * If dropping at the bottom, highlight the bottom border.\n *\n * @param {Object} dropData\n * @param {Event} event\n */\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n if (this.getInsertBefore(event, dropTarget)) {\n dropTarget.classList.add(this.classes.DROP_TARGET_BEFORE);\n dropTarget.classList.remove(this.classes.DROP_TARGET);\n } else {\n dropTarget.classList.add(this.classes.DROP_TARGET);\n dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE);\n }\n }\n\n /**\n * Remove highlighting.\n *\n * @param {Object} dropData\n * @param {Event} event\n */\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE);\n dropTarget.classList.remove(this.classes.DROP_TARGET);\n }\n\n /**\n * Determine whether we're dragging over the top or bottom half of the list.\n *\n * @param {Event} event\n * @param {Element} dropTarget\n * @return {boolean}\n */\n getInsertBefore(event, dropTarget) {\n // Get the current mouse position within the drop target\n const mouseY = event.clientY - dropTarget.getBoundingClientRect().top;\n\n // Get the height of the drop target\n const targetHeight = dropTarget.clientHeight;\n\n // Check if the mouse is over the top half of the drop target\n return mouseY < targetHeight / 2;\n }\n\n /**\n * Find the new position of the dropped category, and trigger the move.\n *\n * @param {Object} dropData\n * @param {Event} event\n */\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST);\n\n if (!dropTarget) {\n return;\n }\n\n if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) {\n // Can't drop onto your own child.\n return;\n }\n\n const source = document.getElementById(this.ids.CATEGORY(dropData.id));\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.categoryid;\n let precedingSibling;\n\n if (this.getInsertBefore(event, dropTarget)) {\n // Dropped at the top of the list.\n precedingSibling = null;\n } else {\n // Dropped at the bottom of the list.\n precedingSibling = dropTarget.lastElementChild;\n }\n\n // Insert the category after the target category\n categorymanager.moveCategory(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n /**\n * Watch for categories moving to a new parent.\n *\n * @return {Array} A list of watchers.\n */\n getWatchers() {\n return [\n // Watch for this category having its child count updated.\n {watch: `categoryLists[${this.element.dataset.categoryid}].childCount:updated`, handler: this.checkEmptyList},\n // Watch for any new category being created.\n {watch: `categories:created`, handler: this.addCategory},\n // Watch for descriptions being toggled.\n {watch: `page.showdescriptions:updated`, handler: this.toggleDescriptions}\n ];\n }\n\n /**\n * If this list is now empty, remove it.\n *\n * @param {Object} args\n * @param {Object} args.element The categoryList state element.\n */\n async checkEmptyList({element}) {\n if (element.childCount === 0) {\n // Display a new child drop zone.\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/newchild',\n {\n categoryid: this.element.dataset.categoryid,\n }\n );\n const activityNameArea = this.element\n .closest(this.selectors.LIST_ITEM)\n .querySelector(this.selectors.ACTIVITY_NAME_AREA);\n await Templates.appendNodeContents(activityNameArea, html, js);\n // Reinstate padding on the parent element.\n this.element.closest(this.selectors.ACTIVITY_ITEM).classList.remove(this.classes.NO_BOTTOM_PADDING);\n // Remove this list.\n this.remove();\n }\n }\n\n /**\n * If a newly-created category has this list's category as its parent, add it to this list.\n *\n * @param {Object} args\n * @param {Object} args.element\n * @return {Promise}\n */\n async addCategory({element}) {\n if (element.parent !== parseInt(this.getElement().dataset.categoryid)) {\n return; // Not for me.\n }\n const {html, js} = await Templates.renderForPromise('qbank_managecategories/item', element.templatecontext);\n Templates.appendNodeContents(this.getElement(), html, js);\n }\n\n /**\n * Show or hide descriptions when the flag in the state is changed.\n *\n * @param {Object} args\n * @param {Object} args.element The updated page state.\n */\n toggleDescriptions({element}){\n if (element.showdescriptions) {\n this.getElement().classList.add(this.classes.SHOWDESCRIPTIONS);\n } else {\n this.getElement().classList.remove(this.classes.SHOWDESCRIPTIONS);\n }\n }\n}"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","CATEGORY_LIST","LIST_ITEM","ACTIVITY_ITEM","ACTIVITY_NAME_AREA","CATEGORY_ID","classes","DROP_TARGET_BEFORE","DROP_TARGET","NO_BOTTOM_PADDING","SHOWDESCRIPTIONS","ids","CATEGORY","stateReady","dragdrop","DragDrop","this","destroy","undefined","unregister","target","document","querySelector","reactive","categorymanager","validateDropData","dropData","event","closest","showDropZone","dropTarget","getInsertBefore","classList","add","remove","hideDropZone","clientY","getBoundingClientRect","top","clientHeight","drop","getElementById","targetParentId","dataset","categoryid","precedingSibling","lastElementChild","moveCategory","_precedingSibling","getWatchers","watch","handler","checkEmptyList","addCategory","toggleDescriptions","childCount","html","js","Templates","renderForPromise","activityNameArea","appendNodeContents","parent","parseInt","getElement","templatecontext","showdescriptions"],"mappings":"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"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/categorymanager.min.js b/question/bank/managecategories/amd/build/categorymanager.min.js index 6e60921ce13c0..06f77d6e55055 100644 --- a/question/bank/managecategories/amd/build/categorymanager.min.js +++ b/question/bank/managecategories/amd/build/categorymanager.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/categorymanager",["exports","core/reactive","core/str","qbank_managecategories/mutations","qbank_managecategories/events","core/ajax","core/notification","core_form/modalform"],(function(_exports,_reactive,_str,_mutations,_events,_ajax,_notification,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.categorymanager=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_modalform=_interopRequireDefault(_modalform);const SELECTORS_CATEGORY_LIST=".qbank_managecategories-categorylist",SELECTORS_LIST_ITEM=".qbank_managecategories-item[data-categoryid]",SELECTORS_MODULE_ROOT="#categoriesrendered",SELECTORS_SHOWDESCRIPTIONS_TOGGLE="#showdescriptions-toggle",CLASSES_DRAGHANDLE="draghandle";class CategoryManager extends _reactive.Reactive{setCatOrder(categoryId,targetParentId){let precedingSiblingId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const call={methodname:"qbank_managecategories_move_category",args:{pagecontextid:this.state.page.contextid,categoryid:categoryId,targetparentid:targetParentId,precedingsiblingid:precedingSiblingId}};_ajax.default.call([call])[0].then((stateUpdates=>{this.stateManager.processUpdates(stateUpdates)})).catch((error=>{var _document$getElements;_notification.default.addNotification({message:error.message,type:"error"}),null===(_document$getElements=document.getElementsByClassName("alert-danger")[0])||void 0===_document$getElements||_document$getElements.scrollIntoView()}))}getTitle(isEdit){return(0,_str.get_string)(isEdit?"editcategory":"addcategory","question")}getSave(isEdit){return isEdit?(0,_str.get_string)("savechanges","core"):(0,_str.get_string)("addcategory","question")}showEditModal(e){const addEditButton=e.target.closest('[data-action="addeditcategory"]');if(!addEditButton)return;if(!addEditButton.dataset.actiontype)return;e.preventDefault();const title=categorymanager.getTitle("edit"===addEditButton.dataset.actiontype),save=categorymanager.getSave("edit"===addEditButton.dataset.actiontype),cmid=addEditButton.dataset.cmid,courseid=addEditButton.dataset.courseid,questioncount=addEditButton.dataset.questioncount;let contextid=addEditButton.dataset.contextid,categoryid=null,sortorder=null;const categoryItem=e.target.closest(".qbank_managecategories-item");categoryItem&&(contextid=categoryItem.dataset.contextid,categoryid=categoryItem.dataset.categoryid,sortorder=categoryItem.dataset.sortorder);const modalForm=new _modalform.default({formClass:"qbank_managecategories\\form\\question_category_edit_form",args:{cmid:cmid,courseid:courseid,questioncount:questioncount,contextid:contextid,categoryid:categoryid,sortorder:sortorder},modalConfig:{title:title,large:!0},saveButtonText:save,returnFocus:addEditButton});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(response=>{categorymanager.stateManager.processUpdates(response.detail)})),modalForm.show()}}const categorymanager=new CategoryManager({name:"qtype_managecategories_categorymanager",eventName:_events.eventTypes.qbankManagecategoriesStateUpdated,eventDispatch:_events.notifyQbankManagecategoriesStateUpdated,mutations:_mutations.mutations});_exports.categorymanager=categorymanager;_exports.init=()=>{(async reactive=>{const stateData={page:{contextid:document.querySelector(SELECTORS_MODULE_ROOT).dataset.contextid,showdescriptions:document.querySelector(SELECTORS_SHOWDESCRIPTIONS_TOGGLE).checked},categories:[],categoryLists:[]};document.querySelectorAll(SELECTORS_LIST_ITEM).forEach((item=>{stateData.categories.push({id:item.dataset.categoryid,name:item.dataset.categoryname,parent:item.dataset.parent,contextid:item.dataset.contextid,sortorder:item.dataset.sortorder,draghandle:item.classList.contains(CLASSES_DRAGHANDLE)})})),document.querySelectorAll(SELECTORS_CATEGORY_LIST).forEach((categoryList=>{stateData.categoryLists.push({id:categoryList.dataset.categoryid,childCount:categoryList.querySelectorAll(SELECTORS_LIST_ITEM).length})})),reactive.setInitialState(stateData)})(categorymanager)}})); +define("qbank_managecategories/categorymanager",["exports","core/reactive","core/str","qbank_managecategories/mutations","qbank_managecategories/events","core/ajax","core/notification","core_form/modalform"],(function(_exports,_reactive,_str,_mutations,_events,_ajax,_notification,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.categorymanager=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_modalform=_interopRequireDefault(_modalform);const SELECTORS_CATEGORY_LIST=".qbank_managecategories-categorylist",SELECTORS_LIST_ITEM=".qbank_managecategories-item[data-categoryid]",SELECTORS_CATEGORY_ROOT="#categoryroot",SELECTORS_SHOWDESCRIPTIONS_TOGGLE="#showdescriptions-toggle",CLASSES_DRAGHANDLE="draghandle";class CategoryManager extends _reactive.Reactive{moveCategory(categoryId,targetParentId){let precedingSiblingId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const call={methodname:"qbank_managecategories_move_category",args:{pagecontextid:this.state.page.contextid,categoryid:categoryId,targetparentid:targetParentId,precedingsiblingid:precedingSiblingId}};_ajax.default.call([call])[0].then((stateUpdates=>{this.stateManager.processUpdates(stateUpdates)})).catch((error=>{var _document$getElements;_notification.default.addNotification({message:error.message,type:"error"}),null===(_document$getElements=document.getElementsByClassName(this.classes.DANGER)[0])||void 0===_document$getElements||_document$getElements.scrollIntoView()}))}getTitle(isEdit){return(0,_str.get_string)(isEdit?"editcategory":"addcategory","question")}getSave(isEdit){return isEdit?(0,_str.get_string)("savechanges","core"):(0,_str.get_string)("addcategory","question")}showEditModal(e){const addEditButton=e.target.closest(this.selectors.ADD_EDIT_BUTTON);if(!addEditButton)return;if(!addEditButton.dataset.actiontype)return;e.preventDefault();const title=categorymanager.getTitle("edit"===addEditButton.dataset.actiontype),save=categorymanager.getSave("edit"===addEditButton.dataset.actiontype),cmid=addEditButton.dataset.cmid,courseid=addEditButton.dataset.courseid,questioncount=addEditButton.dataset.questioncount;let contextid=addEditButton.dataset.contextid,categoryid=null,sortorder=null;const categoryItem=e.target.closest(this.selectors.CATEGORY_ITEM);categoryItem&&(contextid=categoryItem.dataset.contextid,categoryid=categoryItem.dataset.categoryid,sortorder=categoryItem.dataset.sortorder);const modalForm=new _modalform.default({formClass:"qbank_managecategories\\form\\question_category_edit_form",args:{cmid:cmid,courseid:courseid,questioncount:questioncount,contextid:contextid,categoryid:categoryid,sortorder:sortorder},modalConfig:{title:title,large:!0},saveButtonText:save,returnFocus:addEditButton});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(response=>{categorymanager.stateManager.processUpdates(response.detail)})),modalForm.show()}}const categorymanager=new CategoryManager({name:"qtype_managecategories_categorymanager",eventName:_events.eventTypes.qbankManagecategoriesStateUpdated,eventDispatch:_events.notifyQbankManagecategoriesStateUpdated,mutations:_mutations.mutations});_exports.categorymanager=categorymanager;_exports.init=()=>{(async reactive=>{const stateData={page:{contextid:document.querySelector(SELECTORS_CATEGORY_ROOT).dataset.contextid,showdescriptions:document.querySelector(SELECTORS_SHOWDESCRIPTIONS_TOGGLE).checked},categories:[],categoryLists:[]};document.querySelectorAll(SELECTORS_LIST_ITEM).forEach((item=>{stateData.categories.push({id:item.dataset.categoryid,name:item.dataset.categoryname,parent:item.dataset.parent,contextid:item.dataset.contextid,sortorder:item.dataset.sortorder,draghandle:item.classList.contains(CLASSES_DRAGHANDLE)})})),document.querySelectorAll(SELECTORS_CATEGORY_LIST).forEach((categoryList=>{stateData.categoryLists.push({id:categoryList.dataset.categoryid,childCount:categoryList.querySelectorAll(SELECTORS_LIST_ITEM).length})})),reactive.setInitialState(stateData)})(categorymanager)}})); //# sourceMappingURL=categorymanager.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/categorymanager.min.js.map b/question/bank/managecategories/amd/build/categorymanager.min.js.map index a9ac9cc0957a6..bbd96f05ba899 100644 --- a/question/bank/managecategories/amd/build/categorymanager.min.js.map +++ b/question/bank/managecategories/amd/build/categorymanager.min.js.map @@ -1 +1 @@ -{"version":3,"file":"categorymanager.min.js","sources":["../src/categorymanager.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 * Reactive module for category manager\n *\n * @module qbank_managecategories/categorymanager\n */\n\nimport {Reactive} from 'core/reactive';\nimport {get_string as getString} from 'core/str';\nimport {mutations} from 'qbank_managecategories/mutations';\nimport {eventTypes, notifyQbankManagecategoriesStateUpdated} from 'qbank_managecategories/events';\nimport Ajax from \"core/ajax\";\nimport Notification from \"core/notification\";\nimport ModalForm from 'core_form/modalform';\n\nconst SELECTORS = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n CONTEXT: '.qbank_managecategories-categorylist[data-contextid]',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n MODULE_ROOT: '#categoriesrendered',\n SHOWDESCRIPTIONS_TOGGLE: '#showdescriptions-toggle',\n};\n\nconst CLASSES = {\n DRAGHANDLE: 'draghandle',\n};\n\nconst loadState = async (reactive) => {\n const rootElement = document.querySelector(SELECTORS.MODULE_ROOT);\n const stateData = {\n page: {\n contextid: rootElement.dataset.contextid,\n showdescriptions: document.querySelector(SELECTORS.SHOWDESCRIPTIONS_TOGGLE).checked,\n },\n categories: [],\n categoryLists: [],\n };\n const listItems = document.querySelectorAll(SELECTORS.LIST_ITEM);\n listItems.forEach(item => {\n stateData.categories.push({\n id: item.dataset.categoryid,\n name: item.dataset.categoryname,\n parent: item.dataset.parent,\n contextid: item.dataset.contextid,\n sortorder: item.dataset.sortorder,\n draghandle: item.classList.contains(CLASSES.DRAGHANDLE),\n });\n });\n const categoryLists = document.querySelectorAll(SELECTORS.CATEGORY_LIST);\n categoryLists.forEach(categoryList => {\n stateData.categoryLists.push({\n id: categoryList.dataset.categoryid,\n childCount: categoryList.querySelectorAll(SELECTORS.LIST_ITEM).length,\n });\n });\n reactive.setInitialState(stateData);\n};\n\nclass CategoryManager extends Reactive {\n setCatOrder(\n categoryId,\n targetParentId,\n precedingSiblingId = null,\n ) {\n const call = {\n methodname: 'qbank_managecategories_move_category',\n args: {\n pagecontextid: this.state.page.contextid,\n categoryid: categoryId,\n targetparentid: targetParentId,\n precedingsiblingid: precedingSiblingId,\n }\n };\n Ajax.call([call])[0]\n .then((stateUpdates) => {\n this.stateManager.processUpdates(stateUpdates);\n })\n .catch(error => {\n Notification.addNotification({\n message: error.message,\n type: 'error',\n });\n document.getElementsByClassName('alert-danger')[0]?.scrollIntoView();\n });\n }\n\n /**\n * Return modal title\n *\n * @param {boolean} isEdit is 'add' or 'edit' form\n * @returns {String} title string\n */\n getTitle(isEdit) {\n return getString(isEdit ? 'editcategory' : 'addcategory', 'question');\n }\n\n /**\n * Return modal save button label\n *\n * @param {boolean} isEdit is 'add' or 'edit' form\n * @returns {String} save string\n */\n getSave(isEdit) {\n return isEdit ? getString('savechanges', 'core') : getString('addcategory', 'question');\n }\n\n /**\n * Function handling display of moodle form.\n *\n * @param {Event} e The click event triggering the modal.\n */\n showEditModal(e) {\n const addEditButton = e.target.closest('[data-action=\"addeditcategory\"]');\n\n // Return if it is not 'addeditcategory' button.\n if (!addEditButton) {\n return;\n }\n\n // Return if the action type is not specified.\n if (!addEditButton.dataset.actiontype) {\n return;\n }\n\n e.preventDefault();\n // Data for the modal.\n const title = categorymanager.getTitle(addEditButton.dataset.actiontype === 'edit');\n const save = categorymanager.getSave(addEditButton.dataset.actiontype === 'edit');\n const cmid = addEditButton.dataset.cmid;\n const courseid = addEditButton.dataset.courseid;\n const questioncount = addEditButton.dataset.questioncount;\n let contextid = addEditButton.dataset.contextid;\n let categoryid = null;\n let sortorder = null;\n const categoryItem = e.target.closest('.qbank_managecategories-item');\n if (categoryItem) {\n contextid = categoryItem.dataset.contextid;\n categoryid = categoryItem.dataset.categoryid;\n sortorder = categoryItem.dataset.sortorder;\n }\n\n // Call the modal.\n const modalForm = new ModalForm({\n formClass: \"qbank_managecategories\\\\form\\\\question_category_edit_form\",\n args: {\n cmid,\n courseid,\n questioncount,\n contextid,\n categoryid,\n sortorder,\n },\n modalConfig: {\n title: title,\n large: true,\n },\n saveButtonText: save,\n returnFocus: addEditButton,\n });\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (response) => {\n categorymanager.stateManager.processUpdates(response.detail);\n });\n // Show the form.\n modalForm.show();\n }\n}\n\n// The reactive instance requires an event (eventNamer and eventDispatch method)\nexport const categorymanager = new CategoryManager({\n name: 'qtype_managecategories_categorymanager',\n eventName: eventTypes.qbankManagecategoriesStateUpdated,\n eventDispatch: notifyQbankManagecategoriesStateUpdated,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n loadState(categorymanager);\n};\n"],"names":["SELECTORS","CLASSES","CategoryManager","Reactive","setCatOrder","categoryId","targetParentId","precedingSiblingId","call","methodname","args","pagecontextid","this","state","page","contextid","categoryid","targetparentid","precedingsiblingid","then","stateUpdates","stateManager","processUpdates","catch","error","addNotification","message","type","document","getElementsByClassName","scrollIntoView","getTitle","isEdit","getSave","showEditModal","e","addEditButton","target","closest","dataset","actiontype","preventDefault","title","categorymanager","save","cmid","courseid","questioncount","sortorder","categoryItem","modalForm","ModalForm","formClass","modalConfig","large","saveButtonText","returnFocus","addEventListener","events","FORM_SUBMITTED","response","detail","show","name","eventName","eventTypes","qbankManagecategoriesStateUpdated","eventDispatch","notifyQbankManagecategoriesStateUpdated","mutations","async","stateData","querySelector","showdescriptions","checked","categories","categoryLists","querySelectorAll","forEach","item","push","id","categoryname","parent","draghandle","classList","contains","categoryList","childCount","length","reactive","setInitialState","loadState"],"mappings":"ymBA6BMA,wBACa,uCADbA,oBAGS,gDAHTA,sBAIW,sBAJXA,kCAKuB,2BAGvBC,mBACU,mBAkCVC,wBAAwBC,mBAC1BC,YACIC,WACAC,oBACAC,0EAAqB,WAEfC,KAAO,CACTC,WAAY,uCACZC,KAAM,CACFC,cAAeC,KAAKC,MAAMC,KAAKC,UAC/BC,WAAYX,WACZY,eAAgBX,eAChBY,mBAAoBX,mCAGvBC,KAAK,CAACA,OAAO,GACbW,MAAMC,oBACEC,aAAaC,eAAeF,iBAEpCG,OAAMC,wDACUC,gBAAgB,CACzBC,QAASF,MAAME,QACfC,KAAM,wCAEVC,SAASC,uBAAuB,gBAAgB,2DAAIC,oBAUhEC,SAASC,eACE,mBAAUA,OAAS,eAAiB,cAAe,YAS9DC,QAAQD,eACGA,QAAS,mBAAU,cAAe,SAAU,mBAAU,cAAe,YAQhFE,cAAcC,SACJC,cAAgBD,EAAEE,OAAOC,QAAQ,uCAGlCF,yBAKAA,cAAcG,QAAQC,kBAI3BL,EAAEM,uBAEIC,MAAQC,gBAAgBZ,SAA8C,SAArCK,cAAcG,QAAQC,YACvDI,KAAOD,gBAAgBV,QAA6C,SAArCG,cAAcG,QAAQC,YACrDK,KAAOT,cAAcG,QAAQM,KAC7BC,SAAWV,cAAcG,QAAQO,SACjCC,cAAgBX,cAAcG,QAAQQ,kBACxChC,UAAYqB,cAAcG,QAAQxB,UAClCC,WAAa,KACbgC,UAAY,WACVC,aAAed,EAAEE,OAAOC,QAAQ,gCAClCW,eACAlC,UAAYkC,aAAaV,QAAQxB,UACjCC,WAAaiC,aAAaV,QAAQvB,WAClCgC,UAAYC,aAAaV,QAAQS,iBAI/BE,UAAY,IAAIC,mBAAU,CAC5BC,UAAW,4DACX1C,KAAM,CACFmC,KAAAA,KACAC,SAAAA,SACAC,cAAAA,cACAhC,UAAAA,UACAC,WAAAA,WACAgC,UAAAA,WAEJK,YAAa,CACTX,MAAOA,MACPY,OAAO,GAEXC,eAAgBX,KAChBY,YAAapB,gBAEjBc,UAAUO,iBAAiBP,UAAUQ,OAAOC,gBAAiBC,WACzDjB,gBAAgBtB,aAAaC,eAAesC,SAASC,WAGzDX,UAAUY,cAKLnB,gBAAkB,IAAIzC,gBAAgB,CAC/C6D,KAAM,yCACNC,UAAWC,mBAAWC,kCACtBC,cAAeC,gDACfC,UAAAA,8EAMgB,KAvJFC,OAAAA,iBAERC,UAAY,CACdzD,KAAM,CACFC,UAHYa,SAAS4C,cAAcxE,uBAGZuC,QAAQxB,UAC/B0D,iBAAkB7C,SAAS4C,cAAcxE,mCAAmC0E,SAEhFC,WAAY,GACZC,cAAe,IAEDhD,SAASiD,iBAAiB7E,qBAClC8E,SAAQC,OACdR,UAAUI,WAAWK,KAAK,CACtBC,GAAIF,KAAKxC,QAAQvB,WACjB+C,KAAMgB,KAAKxC,QAAQ2C,aACnBC,OAAQJ,KAAKxC,QAAQ4C,OACrBpE,UAAWgE,KAAKxC,QAAQxB,UACxBiC,UAAW+B,KAAKxC,QAAQS,UACxBoC,WAAYL,KAAKM,UAAUC,SAASrF,yBAGtB2B,SAASiD,iBAAiB7E,yBAClC8E,SAAQS,eAClBhB,UAAUK,cAAcI,KAAK,CACzBC,GAAIM,aAAahD,QAAQvB,WACzBwE,WAAYD,aAAaV,iBAAiB7E,qBAAqByF,YAGvEC,SAASC,gBAAgBpB,YA4HzBqB,CAAUjD"} \ No newline at end of file +{"version":3,"file":"categorymanager.min.js","sources":["../src/categorymanager.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 * Reactive module for category manager\n *\n * @module qbank_managecategories/categorymanager\n */\n\nimport {Reactive} from 'core/reactive';\nimport {get_string as getString} from 'core/str';\nimport {mutations} from 'qbank_managecategories/mutations';\nimport {eventTypes, notifyQbankManagecategoriesStateUpdated} from 'qbank_managecategories/events';\nimport Ajax from \"core/ajax\";\nimport Notification from \"core/notification\";\nimport ModalForm from 'core_form/modalform';\n\nconst SELECTORS = {\n CATEGORY_LIST: '.qbank_managecategories-categorylist',\n CONTEXT: '.qbank_managecategories-categorylist[data-contextid]',\n LIST_ITEM: '.qbank_managecategories-item[data-categoryid]',\n CATEGORY_ROOT: '#categoryroot',\n SHOWDESCRIPTIONS_TOGGLE: '#showdescriptions-toggle',\n ADD_EDIT_BUTTON: '[data-action=\"addeditcategory\"]',\n CATEGORY_ITEM: '.qbank_managecategories-item',\n};\n\nconst CLASSES = {\n DRAGHANDLE: 'draghandle',\n DANGER: 'alert-danger',\n};\n\n/**\n * Load the initial state.\n *\n * This iterates over the initial tree of category items, and captures the data required for the state from each category.\n * It also captures a count of the number of children in each list.\n *\n * @param {Reactive} reactive\n * @return {Promise}\n */\nconst loadState = async (reactive) => {\n const rootElement = document.querySelector(SELECTORS.CATEGORY_ROOT);\n const stateData = {\n page: {\n contextid: rootElement.dataset.contextid,\n showdescriptions: document.querySelector(SELECTORS.SHOWDESCRIPTIONS_TOGGLE).checked,\n },\n categories: [],\n categoryLists: [],\n };\n const listItems = document.querySelectorAll(SELECTORS.LIST_ITEM);\n listItems.forEach(item => {\n stateData.categories.push({\n id: item.dataset.categoryid,\n name: item.dataset.categoryname,\n parent: item.dataset.parent,\n contextid: item.dataset.contextid,\n sortorder: item.dataset.sortorder,\n draghandle: item.classList.contains(CLASSES.DRAGHANDLE),\n });\n });\n const categoryLists = document.querySelectorAll(SELECTORS.CATEGORY_LIST);\n categoryLists.forEach(categoryList => {\n stateData.categoryLists.push({\n id: categoryList.dataset.categoryid,\n childCount: categoryList.querySelectorAll(SELECTORS.LIST_ITEM).length,\n });\n });\n reactive.setInitialState(stateData);\n};\n\n/**\n * Reactive instance for the category manager.\n */\nclass CategoryManager extends Reactive {\n /**\n * Move a category to a new position within the given parent.\n *\n * This will call the move_category web service function to re-order the categories, then update\n * the state with the returned updates.\n *\n * @param {Number} categoryId The ID of the category being moved.\n * @param {Number} targetParentId The ID of the destination parent category (this may not have changed).\n * @param {Number} precedingSiblingId The ID of the category to put the moved category after.\n * This may be null if moving to the top of a list.\n */\n moveCategory(\n categoryId,\n targetParentId,\n precedingSiblingId = null,\n ) {\n const call = {\n methodname: 'qbank_managecategories_move_category',\n args: {\n pagecontextid: this.state.page.contextid,\n categoryid: categoryId,\n targetparentid: targetParentId,\n precedingsiblingid: precedingSiblingId,\n }\n };\n Ajax.call([call])[0]\n .then((stateUpdates) => {\n this.stateManager.processUpdates(stateUpdates);\n })\n .catch(error => {\n Notification.addNotification({\n message: error.message,\n type: 'error',\n });\n document.getElementsByClassName(this.classes.DANGER)[0]?.scrollIntoView();\n });\n }\n\n /**\n * Return title for the add/edit modal.\n *\n * @param {boolean} isEdit is 'add' or 'edit' form\n * @returns {String} title string\n */\n getTitle(isEdit) {\n return getString(isEdit ? 'editcategory' : 'addcategory', 'question');\n }\n\n /**\n * Return save button label for the add/edit modal.\n *\n * @param {boolean} isEdit is 'add' or 'edit' form\n * @returns {String} save string\n */\n getSave(isEdit) {\n return isEdit ? getString('savechanges', 'core') : getString('addcategory', 'question');\n }\n\n /**\n * Function handling display of modal form.\n *\n * @param {Event} e The click event triggering the modal.\n */\n showEditModal(e) {\n const addEditButton = e.target.closest(this.selectors.ADD_EDIT_BUTTON);\n\n // Return if it is not 'addeditcategory' button.\n if (!addEditButton) {\n return;\n }\n\n // Return if the action type is not specified.\n if (!addEditButton.dataset.actiontype) {\n return;\n }\n\n e.preventDefault();\n // Data for the modal.\n const title = categorymanager.getTitle(addEditButton.dataset.actiontype === 'edit');\n const save = categorymanager.getSave(addEditButton.dataset.actiontype === 'edit');\n const cmid = addEditButton.dataset.cmid;\n const courseid = addEditButton.dataset.courseid;\n const questioncount = addEditButton.dataset.questioncount;\n let contextid = addEditButton.dataset.contextid;\n let categoryid = null;\n let sortorder = null;\n const categoryItem = e.target.closest(this.selectors.CATEGORY_ITEM);\n if (categoryItem) {\n contextid = categoryItem.dataset.contextid;\n categoryid = categoryItem.dataset.categoryid;\n sortorder = categoryItem.dataset.sortorder;\n }\n\n // Call the modal.\n const modalForm = new ModalForm({\n formClass: \"qbank_managecategories\\\\form\\\\question_category_edit_form\",\n args: {\n cmid,\n courseid,\n questioncount,\n contextid,\n categoryid,\n sortorder,\n },\n modalConfig: {\n title: title,\n large: true,\n },\n saveButtonText: save,\n returnFocus: addEditButton,\n });\n // Once the form has been submitted via the web service, update the state with the new or updated\n // category based on the web service response.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (response) => {\n categorymanager.stateManager.processUpdates(response.detail);\n });\n // Show the form.\n modalForm.show();\n }\n}\n\nexport const categorymanager = new CategoryManager({\n name: 'qtype_managecategories_categorymanager',\n eventName: eventTypes.qbankManagecategoriesStateUpdated,\n eventDispatch: notifyQbankManagecategoriesStateUpdated,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n loadState(categorymanager);\n};\n"],"names":["SELECTORS","CLASSES","CategoryManager","Reactive","moveCategory","categoryId","targetParentId","precedingSiblingId","call","methodname","args","pagecontextid","this","state","page","contextid","categoryid","targetparentid","precedingsiblingid","then","stateUpdates","stateManager","processUpdates","catch","error","addNotification","message","type","document","getElementsByClassName","classes","DANGER","scrollIntoView","getTitle","isEdit","getSave","showEditModal","e","addEditButton","target","closest","selectors","ADD_EDIT_BUTTON","dataset","actiontype","preventDefault","title","categorymanager","save","cmid","courseid","questioncount","sortorder","categoryItem","CATEGORY_ITEM","modalForm","ModalForm","formClass","modalConfig","large","saveButtonText","returnFocus","addEventListener","events","FORM_SUBMITTED","response","detail","show","name","eventName","eventTypes","qbankManagecategoriesStateUpdated","eventDispatch","notifyQbankManagecategoriesStateUpdated","mutations","async","stateData","querySelector","showdescriptions","checked","categories","categoryLists","querySelectorAll","forEach","item","push","id","categoryname","parent","draghandle","classList","contains","categoryList","childCount","length","reactive","setInitialState","loadState"],"mappings":"ymBA6BMA,wBACa,uCADbA,oBAGS,gDAHTA,wBAIa,gBAJbA,kCAKuB,2BAKvBC,mBACU,mBA+CVC,wBAAwBC,mBAY1BC,aACIC,WACAC,oBACAC,0EAAqB,WAEfC,KAAO,CACTC,WAAY,uCACZC,KAAM,CACFC,cAAeC,KAAKC,MAAMC,KAAKC,UAC/BC,WAAYX,WACZY,eAAgBX,eAChBY,mBAAoBX,mCAGvBC,KAAK,CAACA,OAAO,GACbW,MAAMC,oBACEC,aAAaC,eAAeF,iBAEpCG,OAAMC,wDACUC,gBAAgB,CACzBC,QAASF,MAAME,QACfC,KAAM,wCAEVC,SAASC,uBAAuBjB,KAAKkB,QAAQC,QAAQ,2DAAIC,oBAUrEC,SAASC,eACE,mBAAUA,OAAS,eAAiB,cAAe,YAS9DC,QAAQD,eACGA,QAAS,mBAAU,cAAe,SAAU,mBAAU,cAAe,YAQhFE,cAAcC,SACJC,cAAgBD,EAAEE,OAAOC,QAAQ5B,KAAK6B,UAAUC,qBAGjDJ,yBAKAA,cAAcK,QAAQC,kBAI3BP,EAAEQ,uBAEIC,MAAQC,gBAAgBd,SAA8C,SAArCK,cAAcK,QAAQC,YACvDI,KAAOD,gBAAgBZ,QAA6C,SAArCG,cAAcK,QAAQC,YACrDK,KAAOX,cAAcK,QAAQM,KAC7BC,SAAWZ,cAAcK,QAAQO,SACjCC,cAAgBb,cAAcK,QAAQQ,kBACxCpC,UAAYuB,cAAcK,QAAQ5B,UAClCC,WAAa,KACboC,UAAY,WACVC,aAAehB,EAAEE,OAAOC,QAAQ5B,KAAK6B,UAAUa,eACjDD,eACAtC,UAAYsC,aAAaV,QAAQ5B,UACjCC,WAAaqC,aAAaV,QAAQ3B,WAClCoC,UAAYC,aAAaV,QAAQS,iBAI/BG,UAAY,IAAIC,mBAAU,CAC5BC,UAAW,4DACX/C,KAAM,CACFuC,KAAAA,KACAC,SAAAA,SACAC,cAAAA,cACApC,UAAAA,UACAC,WAAAA,WACAoC,UAAAA,WAEJM,YAAa,CACTZ,MAAOA,MACPa,OAAO,GAEXC,eAAgBZ,KAChBa,YAAavB,gBAIjBiB,UAAUO,iBAAiBP,UAAUQ,OAAOC,gBAAiBC,WACzDlB,gBAAgB1B,aAAaC,eAAe2C,SAASC,WAGzDX,UAAUY,cAILpB,gBAAkB,IAAI7C,gBAAgB,CAC/CkE,KAAM,yCACNC,UAAWC,mBAAWC,kCACtBC,cAAeC,gDACfC,UAAAA,8EAMgB,KAtKFC,OAAAA,iBAERC,UAAY,CACd9D,KAAM,CACFC,UAHYa,SAASiD,cAAc7E,yBAGZ2C,QAAQ5B,UAC/B+D,iBAAkBlD,SAASiD,cAAc7E,mCAAmC+E,SAEhFC,WAAY,GACZC,cAAe,IAEDrD,SAASsD,iBAAiBlF,qBAClCmF,SAAQC,OACdR,UAAUI,WAAWK,KAAK,CACtBC,GAAIF,KAAKzC,QAAQ3B,WACjBoD,KAAMgB,KAAKzC,QAAQ4C,aACnBC,OAAQJ,KAAKzC,QAAQ6C,OACrBzE,UAAWqE,KAAKzC,QAAQ5B,UACxBqC,UAAWgC,KAAKzC,QAAQS,UACxBqC,WAAYL,KAAKM,UAAUC,SAAS1F,yBAGtB2B,SAASsD,iBAAiBlF,yBAClCmF,SAAQS,eAClBhB,UAAUK,cAAcI,KAAK,CACzBC,GAAIM,aAAajD,QAAQ3B,WACzB6E,WAAYD,aAAaV,iBAAiBlF,qBAAqB8F,YAGvEC,SAASC,gBAAgBpB,YA2IzBqB,CAAUlD"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/categoryroot.min.js b/question/bank/managecategories/amd/build/categoryroot.min.js new file mode 100644 index 0000000000000..e5813de926047 --- /dev/null +++ b/question/bank/managecategories/amd/build/categoryroot.min.js @@ -0,0 +1,3 @@ +define("qbank_managecategories/categoryroot",["exports","core/reactive","qbank_managecategories/categorymanager"],(function(_exports,_reactive,_categorymanager){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.classes={SHOWDESCRIPTIONS:"showdescriptions"}}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}getWatchers(){return[{watch:"page.showdescriptions:updated",handler:this.toggleDescriptions}]}toggleDescriptions(_ref){let{element:element}=_ref;element.showdescriptions?this.getElement().classList.add(this.classes.SHOWDESCRIPTIONS):this.getElement().classList.remove(this.classes.SHOWDESCRIPTIONS)}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=categoryroot.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/categoryroot.min.js.map b/question/bank/managecategories/amd/build/categoryroot.min.js.map new file mode 100644 index 0000000000000..0f7d6a1fc93e9 --- /dev/null +++ b/question/bank/managecategories/amd/build/categoryroot.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"categoryroot.min.js","sources":["../src/categoryroot.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 * The category root component.\n *\n * @module qbank_managecategories/categoryroot\n * @class qbank_managecategories/categoryroot\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.classes = {\n SHOWDESCRIPTIONS: 'showdescriptions',\n };\n }\n\n /**\n * Static method to create a component instance.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n selectors,\n reactive: categorymanager,\n });\n }\n\n /**\n * Watch for changes to the page state.\n *\n * @return {Array} A list of watchers.\n */\n getWatchers() {\n return [\n // Watch for descriptions being toggled.\n {watch: `page.showdescriptions:updated`, handler: this.toggleDescriptions}\n ];\n }\n\n /**\n * Show or hide descriptions when the flag in the state is changed.\n *\n * @param {Object} args\n * @param {Object} args.element The updated page state.\n */\n toggleDescriptions({element}){\n if (element.showdescriptions) {\n this.getElement().classList.add(this.classes.SHOWDESCRIPTIONS);\n } else {\n this.getElement().classList.remove(this.classes.SHOWDESCRIPTIONS);\n }\n }\n}"],"names":["BaseComponent","create","descriptor","name","element","id","classes","SHOWDESCRIPTIONS","target","selectors","this","document","querySelector","reactive","categorymanager","getWatchers","watch","handler","toggleDescriptions","showdescriptions","getElement","classList","add","remove"],"mappings":"wQAyB6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,QAAU,CACXC,iBAAkB,gCAWdC,OAAQC,kBACT,IAAIC,KAAK,CACZN,QAASO,SAASC,cAAcJ,QAChCC,UAAAA,UACAI,SAAUC,mCASlBC,oBACW,CAEH,CAACC,sCAAwCC,QAASP,KAAKQ,qBAU/DA,6BAAmBd,QAACA,cACZA,QAAQe,sBACHC,aAAaC,UAAUC,IAAIZ,KAAKJ,QAAQC,uBAExCa,aAAaC,UAAUE,OAAOb,KAAKJ,QAAQC"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/list.min.js b/question/bank/managecategories/amd/build/list.min.js deleted file mode 100644 index e0d57ed0f7a81..0000000000000 --- a/question/bank/managecategories/amd/build/list.min.js +++ /dev/null @@ -1,3 +0,0 @@ - - -//# sourceMappingURL=list.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/list.min.js.map b/question/bank/managecategories/amd/build/list.min.js.map deleted file mode 100644 index 0f141afae76f3..0000000000000 --- a/question/bank/managecategories/amd/build/list.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"list.min.js","sources":[],"sourcesContent":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/movecategory_dialogue.min.js b/question/bank/managecategories/amd/build/movecategory_dialogue.min.js deleted file mode 100644 index e1f001df8733d..0000000000000 --- a/question/bank/managecategories/amd/build/movecategory_dialogue.min.js +++ /dev/null @@ -1,13 +0,0 @@ -define("qbank_managecategories/movecategory_dialogue",["exports","core/templates","core/modal","core/str"],(function(_exports,_templates,_modal,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} -/** - * Javascript module for addition or edition of category as a modal form. - * Clicking "Add category" or "Edit > Edit settings" will trigger this modal. - * - * @module qbank_managecategories - * @copyright 2021 Catalyst IT Australia Pty Ltd - * @author Ghaly Marc-Alexandre - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_modal=_interopRequireDefault(_modal);return _exports.default=class{static createMoveCategoryList(item,movingCategory){const categories=[];return item.children&&item.children.forEach((category=>{let child={categoryid:category.dataset.categoryid,categoryname:category.dataset.categoryname,categories:null,firstchild:category===item.children[0],current:category.dataset.categoryid===movingCategory};const childList=category.querySelector(this.selectors.CATEGORY_LIST);childList&&(child.categories=this.createMoveCategoryList(childList,movingCategory)),categories.push(child)})),categories}static async setUpMoveMenuItem(e){const item=e.target;if(!item)return;if(item.getAttribute("aria-disabled"))return;item.setAttribute("aria-disabled",!0);let moveList={contexts:[]};document.querySelectorAll(this.selectors.CONTEXT).forEach((context=>{const moveContext={contextname:context.dataset.contextname,categories:[],hascategories:!1};moveContext.categories=this.createMoveCategoryList(context,item.dataset.categoryid),moveContext.hascategories=moveContext.categories.length>0,moveList.contexts.push(moveContext)}));const modal=await _modal.default.create({title:(0,_str.get_string)("movecategory","qbank_managecategories",item.dataset.categoryname),body:_templates.default.render("qbank_managecategories/move_context_list",moveList),footer:"",show:!0,large:!0});modal.getBody()[0].addEventListener("click",(e=>{const target=e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);target&&(window.console.log(target),modal.destroy())})),item.setAttribute("aria-disabled",!1)}},_exports.default})); - -//# sourceMappingURL=movecategory_dialogue.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/movecategory_dialogue.min.js.map b/question/bank/managecategories/amd/build/movecategory_dialogue.min.js.map deleted file mode 100644 index 1259ff16b9af4..0000000000000 --- a/question/bank/managecategories/amd/build/movecategory_dialogue.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"movecategory_dialogue.min.js","sources":["../src/movecategory_dialogue.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module for addition or edition of category as a modal form.\n * Clicking \"Add category\" or \"Edit > Edit settings\" will trigger this modal.\n *\n * @module qbank_managecategories\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Ghaly Marc-Alexandre \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n *\n */\n\nimport Templates from 'core/templates';\nimport Modal from 'core/modal';\nimport {get_string as getString} from 'core/str';\n\nexport default class {\n\n static createMoveCategoryList(item, movingCategory) {\n const categories = [];\n if (item.children) {\n item.children.forEach(category => {\n let child = {\n categoryid: category.dataset.categoryid,\n categoryname: category.dataset.categoryname,\n categories: null,\n firstchild: category === item.children[0],\n current: category.dataset.categoryid === movingCategory,\n };\n\n const childList = category.querySelector(this.selectors.CATEGORY_LIST);\n if (childList) {\n child.categories = this.createMoveCategoryList(childList, movingCategory);\n }\n categories.push(child);\n });\n }\n return categories;\n }\n\n /**\n * Sets events listener for move category using dragdrop icon.\n * @param {Event} e\n */\n static async setUpMoveMenuItem(e) {\n // Return if it is not menu item.\n const item = e.target;\n if (!item) {\n return;\n }\n // Return if it is disabled.\n if (item.getAttribute('aria-disabled')) {\n return;\n }\n\n // Prevent addition click on the item.\n item.setAttribute('aria-disabled', true);\n\n let moveList = {contexts: []};\n const contexts = document.querySelectorAll(this.selectors.CONTEXT);\n contexts.forEach(context => {\n const moveContext = {\n contextname: context.dataset.contextname,\n categories: [],\n hascategories: false,\n };\n moveContext.categories = this.createMoveCategoryList(context, item.dataset.categoryid);\n moveContext.hascategories = moveContext.categories.length > 0;\n moveList.contexts.push(moveContext);\n });\n\n const modal = await Modal.create({\n title: getString('movecategory', 'qbank_managecategories', item.dataset.categoryname),\n body: Templates.render('qbank_managecategories/move_context_list', moveList),\n footer: '',\n show: true,\n large: true,\n });\n // Show modal and add click event for list item.\n modal.getBody()[0].addEventListener('click', e => {\n const target = e.target.closest(this.selectors.MODAL_CATEGORY_ITEM);\n if (!target) {\n return;\n }\n window.console.log(target);\n modal.destroy();\n });\n item.setAttribute('aria-disabled', false);\n }\n}\n"],"names":["item","movingCategory","categories","children","forEach","category","child","categoryid","dataset","categoryname","firstchild","current","childList","querySelector","this","selectors","CATEGORY_LIST","createMoveCategoryList","push","e","target","getAttribute","setAttribute","moveList","contexts","document","querySelectorAll","CONTEXT","context","moveContext","contextname","hascategories","length","modal","Modal","create","title","body","Templates","render","footer","show","large","getBody","addEventListener","closest","MODAL_CATEGORY_ITEM","window","console","log","destroy"],"mappings":";;;;;;;;;;qOAgCkCA,KAAMC,sBAC1BC,WAAa,UACfF,KAAKG,UACLH,KAAKG,SAASC,SAAQC,eACdC,MAAQ,CACRC,WAAYF,SAASG,QAAQD,WAC7BE,aAAcJ,SAASG,QAAQC,aAC/BP,WAAY,KACZQ,WAAYL,WAAaL,KAAKG,SAAS,GACvCQ,QAASN,SAASG,QAAQD,aAAeN,sBAGvCW,UAAYP,SAASQ,cAAcC,KAAKC,UAAUC,eACpDJ,YACAN,MAAMJ,WAAaY,KAAKG,uBAAuBL,UAAWX,iBAE9DC,WAAWgB,KAAKZ,UAGjBJ,0CAOoBiB,SAErBnB,KAAOmB,EAAEC,WACVpB,eAIDA,KAAKqB,aAAa,wBAKtBrB,KAAKsB,aAAa,iBAAiB,OAE/BC,SAAW,CAACC,SAAU,IACTC,SAASC,iBAAiBZ,KAAKC,UAAUY,SACjDvB,SAAQwB,gBACPC,YAAc,CAChBC,YAAaF,QAAQpB,QAAQsB,YAC7B5B,WAAY,GACZ6B,eAAe,GAEnBF,YAAY3B,WAAaY,KAAKG,uBAAuBW,QAAS5B,KAAKQ,QAAQD,YAC3EsB,YAAYE,cAAgBF,YAAY3B,WAAW8B,OAAS,EAC5DT,SAASC,SAASN,KAAKW,sBAGrBI,YAAcC,eAAMC,OAAO,CAC7BC,OAAO,mBAAU,eAAgB,yBAA0BpC,KAAKQ,QAAQC,cACxE4B,KAAMC,mBAAUC,OAAO,2CAA4ChB,UACnEiB,OAAQ,GACRC,MAAM,EACNC,OAAO,IAGXT,MAAMU,UAAU,GAAGC,iBAAiB,SAASzB,UACnCC,OAASD,EAAEC,OAAOyB,QAAQ/B,KAAKC,UAAU+B,qBAC1C1B,SAGL2B,OAAOC,QAAQC,IAAI7B,QACnBa,MAAMiB,cAEVlD,KAAKsB,aAAa,iBAAiB"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/mutations.min.js b/question/bank/managecategories/amd/build/mutations.min.js index e73cd555cdf12..cd6555bd56003 100644 --- a/question/bank/managecategories/amd/build/mutations.min.js +++ b/question/bank/managecategories/amd/build/mutations.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/mutations",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.mutations=void 0;const mutations=new class{};_exports.mutations=mutations})); +define("qbank_managecategories/mutations",["exports","core_user/repository"],(function(_exports,_repository){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.mutations=void 0;const mutations=new class{async toggleDescriptions(stateManager,showDescriptions){stateManager.setReadOnly(!1),await(0,_repository.setUserPreference)("qbank_managecategories_showdescriptions",showDescriptions),stateManager.state.page.showdescriptions=showDescriptions,stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/mutations.min.js.map b/question/bank/managecategories/amd/build/mutations.min.js.map index 754722cb2bfe6..8c701e19a4d7b 100644 --- a/question/bank/managecategories/amd/build/mutations.min.js.map +++ b/question/bank/managecategories/amd/build/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../src/mutations.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 * Default mutation manager\n *\n * @module qbank_managecategories/mutations\n */\nclass Mutations {\n}\n\nexport const mutations = new Mutations();"],"names":["mutations"],"mappings":"kKAuBaA,UAAY"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../src/mutations.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\nimport {setUserPreference} from 'core_user/repository';\n\n/**\n * Default mutation manager\n *\n * @module qbank_managecategories/mutations\n */\nclass Mutations {\n async toggleDescriptions(stateManager, showDescriptions) {\n stateManager.setReadOnly(false);\n await setUserPreference('qbank_managecategories_showdescriptions', showDescriptions);\n stateManager.state.page.showdescriptions = showDescriptions;\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","stateManager","showDescriptions","setReadOnly","state","page","showdescriptions"],"mappings":"qMA+BaA,UAAY,mCARIC,aAAcC,kBACnCD,aAAaE,aAAY,SACnB,iCAAkB,0CAA2CD,kBACnED,aAAaG,MAAMC,KAAKC,iBAAmBJ,iBAC3CD,aAAaE,aAAY"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/newchild.min.js b/question/bank/managecategories/amd/build/newchild.min.js index edc25f0472316..42b4454381842 100644 --- a/question/bank/managecategories/amd/build/newchild.min.js +++ b/question/bank/managecategories/amd/build/newchild.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/newchild",["exports","core/reactive","qbank_managecategories/categorymanager"],(function(_exports,_reactive,_categorymanager){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={NEW_CHILD:".qbank_managecategories-newchild"}}stateReady(){this.initDragDrop()}destroy(){this.deInitDragDrop()}initDragDrop(){this.dragdrop=new _reactive.DragDrop(this)}deInitDragDrop(){void 0!==this.dragdrop&&(this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}validateDropData(){return!0}showDropZone(dropData,event){event.target.closest(this.selectors.NEW_CHILD).classList.add("qbank_managecategories-category-droptarget")}hideDropZone(dropData,event){event.target.closest(this.selectors.NEW_CHILD).classList.remove("qbank_managecategories-category-droptarget")}drop(dropData,event){const dropTarget=event.target.closest(this.selectors.NEW_CHILD);if(!dropTarget)return;if(!document.getElementById("category-".concat(dropData.id)))return;const targetParentId=dropTarget.dataset.parent;_categorymanager.categorymanager.setCatOrder(dropData.id,targetParentId,void 0)}getWatchers(){return[{watch:"categories.parent:updated",handler:this.checkNewChild}]}checkNewChild(_ref){let{element:element}=_ref;element.parent===parseInt(this.element.dataset.parent)&&this.remove()}}return _exports.default=_default,_exports.default})); +define("qbank_managecategories/newchild",["exports","core/reactive","qbank_managecategories/categorymanager"],(function(_exports,_reactive,_categorymanager){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={NEW_CHILD:".qbank_managecategories-newchild"}}stateReady(){this.initDragDrop()}destroy(){this.deInitDragDrop()}initDragDrop(){this.dragdrop=new _reactive.DragDrop(this)}deInitDragDrop(){void 0!==this.dragdrop&&(this.dragdrop.unregister(),this.dragdrop=void 0)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}validateDropData(){return!0}showDropZone(dropData,event){event.target.closest(this.selectors.NEW_CHILD).classList.add("qbank_managecategories-category-droptarget")}hideDropZone(dropData,event){event.target.closest(this.selectors.NEW_CHILD).classList.remove("qbank_managecategories-category-droptarget")}drop(dropData,event){const dropTarget=event.target.closest(this.selectors.NEW_CHILD);if(!dropTarget)return;if(!document.getElementById("category-".concat(dropData.id)))return;const targetParentId=dropTarget.dataset.parent;_categorymanager.categorymanager.moveCategory(dropData.id,targetParentId,void 0)}getWatchers(){return[{watch:"categories.parent:updated",handler:this.checkNewChild}]}checkNewChild(_ref){let{element:element}=_ref;element.parent===parseInt(this.element.dataset.parent)&&this.remove()}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=newchild.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/newchild.min.js.map b/question/bank/managecategories/amd/build/newchild.min.js.map index 458841218163e..00bfef72731e9 100644 --- a/question/bank/managecategories/amd/build/newchild.min.js.map +++ b/question/bank/managecategories/amd/build/newchild.min.js.map @@ -1 +1 @@ -{"version":3,"file":"newchild.min.js","sources":["../src/newchild.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 * The newchild component.\n *\n * @module qbank_managecategories/categorylist\n * @class qbank_managecategories/categorylist\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n NEW_CHILD: '.qbank_managecategories-newchild',\n };\n }\n\n stateReady() {\n this.initDragDrop();\n }\n\n destroy() {\n // The draggable element must be unregistered.\n this.deInitDragDrop();\n }\n\n initDragDrop() {\n this.dragdrop = new DragDrop(this);\n }\n\n deInitDragDrop() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n const targetElement = document.querySelector(target);\n return new this({\n element: targetElement,\n selectors,\n reactive: categorymanager,\n });\n }\n\n validateDropData() {\n return true;\n }\n\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n dropTarget.classList.add('qbank_managecategories-category-droptarget');\n }\n\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n dropTarget.classList.remove('qbank_managecategories-category-droptarget');\n }\n\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n\n if (!dropTarget) {\n return;\n }\n\n const source = document.getElementById(`category-${dropData.id}`);\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.parent;\n const precedingSibling = null;\n\n // Insert the category after the target category\n categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n /**\n * Watch for categories moving to a new parent.\n *\n * @return {Array} A list of watchers.\n */\n getWatchers() {\n return [\n {watch: `categories.parent:updated`, handler: this.checkNewChild},\n ];\n }\n\n /**\n * If an element now has this category as the parent, remove this new child target.\n *\n * @param {Object} args\n * @param {Element} args.element\n */\n checkNewChild({element}) {\n if (element.parent === parseInt(this.element.dataset.parent)) {\n this.remove();\n }\n }\n}"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","NEW_CHILD","stateReady","initDragDrop","destroy","deInitDragDrop","dragdrop","DragDrop","this","undefined","unregister","target","document","querySelector","reactive","categorymanager","validateDropData","showDropZone","dropData","event","closest","classList","add","hideDropZone","remove","drop","dropTarget","getElementById","targetParentId","dataset","parent","setCatOrder","getWatchers","watch","handler","checkNewChild","parseInt"],"mappings":"oQAyB6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,UAAY,CACbC,UAAW,oCAInBC,kBACSC,eAGTC,eAESC,iBAGTF,oBACSG,SAAW,IAAIC,mBAASC,MAGjCH,sBAC0BI,IAAlBD,KAAKF,gBACAA,SAASI,kBACTJ,cAAWG,eAWZE,OAAQX,kBAET,IAAIQ,KAAK,CACZV,QAFkBc,SAASC,cAAcF,QAGzCX,UAAAA,UACAc,SAAUC,mCAIlBC,0BACW,EAGXC,aAAaC,SAAUC,OACAA,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,WAC5CoB,UAAUC,IAAI,8CAG7BC,aAAaL,SAAUC,OACAA,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,WAC5CoB,UAAUG,OAAO,8CAGhCC,KAAKP,SAAUC,aACLO,WAAaP,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,eAElDyB,sBAIUd,SAASe,kCAA2BT,SAASnB,kBAMtD6B,eAAiBF,WAAWG,QAAQC,wCAI1BC,YAAYb,SAASnB,GAAI6B,uBAQ7CI,oBACW,CACH,CAACC,kCAAoCC,QAAS1B,KAAK2B,gBAU3DA,wBAAcrC,QAACA,cACPA,QAAQgC,SAAWM,SAAS5B,KAAKV,QAAQ+B,QAAQC,cAC5CN"} \ No newline at end of file +{"version":3,"file":"newchild.min.js","sources":["../src/newchild.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 * The newchild component.\n *\n * This is a drop target for moving a category to an as-yet-nonexistant child list under another category.\n *\n * @module qbank_managecategories/newchild\n * @class qbank_managecategories/newchild\n */\n\nimport {BaseComponent, DragDrop} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n NEW_CHILD: '.qbank_managecategories-newchild',\n };\n }\n\n stateReady() {\n this.initDragDrop();\n }\n\n destroy() {\n // The draggable element must be unregistered.\n this.deInitDragDrop();\n }\n\n initDragDrop() {\n this.dragdrop = new DragDrop(this);\n }\n\n deInitDragDrop() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n this.dragdrop = undefined;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n const targetElement = document.querySelector(target);\n return new this({\n element: targetElement,\n selectors,\n reactive: categorymanager,\n });\n }\n\n validateDropData() {\n return true;\n }\n\n showDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n dropTarget.classList.add('qbank_managecategories-category-droptarget');\n }\n\n hideDropZone(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n dropTarget.classList.remove('qbank_managecategories-category-droptarget');\n }\n\n drop(dropData, event) {\n const dropTarget = event.target.closest(this.selectors.NEW_CHILD);\n\n if (!dropTarget) {\n return;\n }\n\n const source = document.getElementById(`category-${dropData.id}`);\n\n if (!source) {\n return;\n }\n\n const targetParentId = dropTarget.dataset.parent;\n const precedingSibling = null;\n\n // Insert the category after the target category\n categorymanager.moveCategory(dropData.id, targetParentId, precedingSibling?.dataset.categoryid);\n }\n\n /**\n * Watch for categories moving to a new parent.\n *\n * @return {Array} A list of watchers.\n */\n getWatchers() {\n return [\n {watch: `categories.parent:updated`, handler: this.checkNewChild},\n ];\n }\n\n /**\n * If an element now has this category as the parent, remove this new child target.\n *\n * @param {Object} args\n * @param {Element} args.element\n */\n checkNewChild({element}) {\n if (element.parent === parseInt(this.element.dataset.parent)) {\n this.remove();\n }\n }\n}"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","NEW_CHILD","stateReady","initDragDrop","destroy","deInitDragDrop","dragdrop","DragDrop","this","undefined","unregister","target","document","querySelector","reactive","categorymanager","validateDropData","showDropZone","dropData","event","closest","classList","add","hideDropZone","remove","drop","dropTarget","getElementById","targetParentId","dataset","parent","moveCategory","getWatchers","watch","handler","checkNewChild","parseInt"],"mappings":"oQA2B6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,UAAY,CACbC,UAAW,oCAInBC,kBACSC,eAGTC,eAESC,iBAGTF,oBACSG,SAAW,IAAIC,mBAASC,MAGjCH,sBAC0BI,IAAlBD,KAAKF,gBACAA,SAASI,kBACTJ,cAAWG,eAWZE,OAAQX,kBAET,IAAIQ,KAAK,CACZV,QAFkBc,SAASC,cAAcF,QAGzCX,UAAAA,UACAc,SAAUC,mCAIlBC,0BACW,EAGXC,aAAaC,SAAUC,OACAA,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,WAC5CoB,UAAUC,IAAI,8CAG7BC,aAAaL,SAAUC,OACAA,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,WAC5CoB,UAAUG,OAAO,8CAGhCC,KAAKP,SAAUC,aACLO,WAAaP,MAAMR,OAAOS,QAAQZ,KAAKR,UAAUC,eAElDyB,sBAIUd,SAASe,kCAA2BT,SAASnB,kBAMtD6B,eAAiBF,WAAWG,QAAQC,wCAI1BC,aAAab,SAASnB,GAAI6B,uBAQ9CI,oBACW,CACH,CAACC,kCAAoCC,QAAS1B,KAAK2B,gBAU3DA,wBAAcrC,QAACA,cACPA,QAAQgC,SAAWM,SAAS5B,KAAKV,QAAQ+B,QAAQC,cAC5CN"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/showdescriptions.min.js b/question/bank/managecategories/amd/build/showdescriptions.min.js index de59f944ffbf9..1c79c7a045499 100644 --- a/question/bank/managecategories/amd/build/showdescriptions.min.js +++ b/question/bank/managecategories/amd/build/showdescriptions.min.js @@ -1,3 +1,3 @@ -define("qbank_managecategories/showdescriptions",["exports","core/reactive","qbank_managecategories/categorymanager","core_user/repository"],(function(_exports,_reactive,_categorymanager,_repository){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={TOGGLE:"#showdescriptions-toggle",CATEGORIES_ROOT:"#categoriesrendered"}}stateReady(){this.addEventListener(this.getElement(this.selectors.TOGGLE),"change",this.updateShowDescriptions)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}updateShowDescriptions(event){const checked=event.target.checked,categoriesRoot=document.querySelector(this.selectors.CATEGORIES_ROOT);checked?categoriesRoot.classList.add("showdescriptions"):categoriesRoot.classList.remove("showdescriptions"),(0,_repository.setUserPreference)("qbank_managecategories_showdescriptions",checked)}}return _exports.default=_default,_exports.default})); +define("qbank_managecategories/showdescriptions",["exports","core/reactive","qbank_managecategories/categorymanager"],(function(_exports,_reactive,_categorymanager){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;class _default extends _reactive.BaseComponent{create(descriptor){this.name=descriptor.element.id,this.selectors={TOGGLE:"#showdescriptions-toggle"}}stateReady(){this.addEventListener(this.getElement(this.selectors.TOGGLE),"change",this.updateShowDescriptions)}static init(target,selectors){return new this({element:document.querySelector(target),selectors:selectors,reactive:_categorymanager.categorymanager})}async updateShowDescriptions(event){const checked=event.target.checked;this.reactive.dispatch("toggleDescriptions",checked)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=showdescriptions.min.js.map \ No newline at end of file diff --git a/question/bank/managecategories/amd/build/showdescriptions.min.js.map b/question/bank/managecategories/amd/build/showdescriptions.min.js.map index dbfee61a78ab9..eabc750b7091b 100644 --- a/question/bank/managecategories/amd/build/showdescriptions.min.js.map +++ b/question/bank/managecategories/amd/build/showdescriptions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"showdescriptions.min.js","sources":["../src/showdescriptions.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 * The show descriptions toggle component.\n *\n * @module qbank_managecategories/showdescriptions\n * @class qbank_managecategories/showdescriptions\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\nimport {setUserPreference} from 'core_user/repository';\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n TOGGLE: '#showdescriptions-toggle',\n CATEGORIES_ROOT: '#categoriesrendered',\n };\n }\n\n stateReady() {\n this.addEventListener(this.getElement(this.selectors.TOGGLE), 'change', this.updateShowDescriptions);\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n const targetElement = document.querySelector(target);\n return new this({\n element: targetElement,\n selectors,\n reactive: categorymanager,\n });\n }\n\n updateShowDescriptions(event) {\n const checked = event.target.checked;\n const categoriesRoot = document.querySelector(this.selectors.CATEGORIES_ROOT);\n if (checked) {\n categoriesRoot.classList.add('showdescriptions');\n } else {\n categoriesRoot.classList.remove('showdescriptions');\n }\n setUserPreference('qbank_managecategories_showdescriptions', checked);\n }\n}\n"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","TOGGLE","CATEGORIES_ROOT","stateReady","addEventListener","this","getElement","updateShowDescriptions","target","document","querySelector","reactive","categorymanager","event","checked","categoriesRoot","classList","add","remove"],"mappings":"+SA0B6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,UAAY,CACbC,OAAQ,2BACRC,gBAAiB,uBAIzBC,kBACSC,iBAAiBC,KAAKC,WAAWD,KAAKL,UAAUC,QAAS,SAAUI,KAAKE,oCAUrEC,OAAQR,kBAET,IAAIK,KAAK,CACZP,QAFkBW,SAASC,cAAcF,QAGzCR,UAAAA,UACAW,SAAUC,mCAIlBL,uBAAuBM,aACbC,QAAUD,MAAML,OAAOM,QACvBC,eAAiBN,SAASC,cAAcL,KAAKL,UAAUE,iBACzDY,QACAC,eAAeC,UAAUC,IAAI,oBAE7BF,eAAeC,UAAUE,OAAO,sDAElB,0CAA2CJ"} \ No newline at end of file +{"version":3,"file":"showdescriptions.min.js","sources":["../src/showdescriptions.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 * The show descriptions toggle component.\n *\n * @module qbank_managecategories/showdescriptions\n * @class qbank_managecategories/showdescriptions\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {categorymanager} from 'qbank_managecategories/categorymanager';\n\nexport default class extends BaseComponent {\n\n create(descriptor) {\n this.name = descriptor.element.id;\n this.selectors = {\n TOGGLE: '#showdescriptions-toggle',\n };\n }\n\n stateReady() {\n this.addEventListener(this.getElement(this.selectors.TOGGLE), 'change', this.updateShowDescriptions);\n }\n\n /**\n * Static method to create a component instance.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n const targetElement = document.querySelector(target);\n return new this({\n element: targetElement,\n selectors,\n reactive: categorymanager,\n });\n }\n\n /**\n * Dispatch a mutation to toggle the showDescriptions setting.\n *\n * @param {Event} event The toggle change event.\n * @return {Promise}\n */\n async updateShowDescriptions(event) {\n const checked = event.target.checked;\n this.reactive.dispatch('toggleDescriptions', checked);\n }\n}\n"],"names":["BaseComponent","create","descriptor","name","element","id","selectors","TOGGLE","stateReady","addEventListener","this","getElement","updateShowDescriptions","target","document","querySelector","reactive","categorymanager","event","checked","dispatch"],"mappings":"4QAyB6BA,wBAEzBC,OAAOC,iBACEC,KAAOD,WAAWE,QAAQC,QAC1BC,UAAY,CACbC,OAAQ,4BAIhBC,kBACSC,iBAAiBC,KAAKC,WAAWD,KAAKJ,UAAUC,QAAS,SAAUG,KAAKE,oCAUrEC,OAAQP,kBAET,IAAII,KAAK,CACZN,QAFkBU,SAASC,cAAcF,QAGzCP,UAAAA,UACAU,SAAUC,gEAUWC,aACnBC,QAAUD,MAAML,OAAOM,aACxBH,SAASI,SAAS,qBAAsBD"} \ No newline at end of file diff --git a/question/bank/managecategories/amd/src/addcategory.js b/question/bank/managecategories/amd/src/addcategory.js index 586a8782dbb9d..207f400124ddc 100644 --- a/question/bank/managecategories/amd/src/addcategory.js +++ b/question/bank/managecategories/amd/src/addcategory.js @@ -16,6 +16,8 @@ /** * Add category button for displaying the modal form. * + * This just connects up the button to the showEditModal listener. + * * @module qbank_managecategories/addcategory * @class qbank_managecategories/addcategory */ diff --git a/question/bank/managecategories/amd/src/category.js b/question/bank/managecategories/amd/src/category.js index 363ac8a1732b6..e913697bfcb2f 100644 --- a/question/bank/managecategories/amd/src/category.js +++ b/question/bank/managecategories/amd/src/category.js @@ -38,6 +38,19 @@ export default class extends BaseComponent { MOVE_BUTTON: '[role="menuitem"][data-actiontype="move"]', CONTEXT: '.qbank_managecategories-categorylist[data-contextid]', MODAL_CATEGORY_ITEM: '.modal_category_item[data-movingcategoryid]', + CONTENT_AREA: '.activity-name-area', + CATEGORY_ID: id => `#category-${id}`, + CONTENT_CONTAINER: id => `#category-${id} .activity-grid`, + CHILD_LIST: id => `ul[data-categoryid="${id}"]`, + PREVIOUS_SIBLING: sortorder => `:scope > [data-sortorder="${sortorder - 1}"]`, + }; + this.classes = { + NO_BOTTOM_PADDING: 'pb-0', + DRAGHANDLE: 'draghandle', + DROPTARGET: 'qbank_managecategories-category-droptarget-before', + }; + this.ids = { + CATEGORY: id => `#category-${id}`, }; } @@ -45,10 +58,7 @@ export default class extends BaseComponent { this.initDragDrop(); this.addEventListener(this.getElement(this.selectors.EDIT_BUTTON), 'click', categorymanager.showEditModal); const moveButton = this.getElement(this.selectors.MOVE_BUTTON); - if (moveButton) { - this.addEventListener(moveButton, 'click', this.showMoveModal); - } - + this.addEventListener(moveButton, 'click', this.showMoveModal); } destroy() { @@ -56,14 +66,21 @@ export default class extends BaseComponent { this.deInitDragDrop(); } + /** + * Remove any existing DragDrop component, and create a new one. + */ initDragDrop() { this.deInitDragDrop(); - if (this.element.classList.contains('draghandle')) { + // If the element is currently draggable, register the getDraggableData method. + if (this.element.classList.contains(this.classes.DRAGHANDLE)) { this.getDraggableData = this._getDraggableData; } this.dragdrop = new DragDrop(this); } + /** + * If the DragDrop component is currently registered, unregister it. + */ deInitDragDrop() { if (this.dragdrop !== undefined) { if (this.getDraggableData !== undefined) { @@ -76,7 +93,7 @@ export default class extends BaseComponent { } /** - * Static method to create a component instance form the mustahce template. + * Static method to create a component instance. * * @param {string} target the DOM main element or its ID * @param {object} selectors optional css selector overrides @@ -90,30 +107,62 @@ export default class extends BaseComponent { }); } + /** + * Return the category ID from the component's element. + * + * This method is referenced as getDraggableData when the component can be dragged. + * + * @return {{id: string}} + * @private + */ _getDraggableData() { return { - id: this.element.dataset.categoryid + id: this.getElement().dataset.categoryid }; } - validateDropData() { + /** + * A category cannot be dropped onto its own child. + * + * @param {Object} dropData + * @return {boolean} + */ + validateDropData(dropData) { + const dropTarget = event.target.closest(this.selectors.LIST_ITEM); + if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) { + return false; + } return true; } + /** + * Highlight the top border of the category item. + * + * @param {Object} dropData Not used. + * @param {Event} event The dragEnter or dragOver event. + */ showDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.LIST_ITEM); - if (dropTarget.closest(`#category-${dropData.id}`)) { - // Can't drop onto your own child. - return; - } - dropTarget.classList.add('qbank_managecategories-category-droptarget-before'); + dropTarget.classList.add(this.classes.DROPTARGET); } + /** + * Remove highlighting. + * + * @param {Object} dropData Not used. + * @param {Event} event The dragLeave event. + */ hideDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.LIST_ITEM); - dropTarget.classList.remove('qbank_managecategories-category-droptarget-before'); + dropTarget.classList.remove(this.classes.DROPTARGET); } + /** + * Find the new position of the dropped category, and trigger the move. + * + * @param {Object} dropData The category being moved. + * @param {Event} event The drop event. + */ drop(dropData, event) { const dropTarget = event.target.closest(this.selectors.LIST_ITEM); @@ -121,12 +170,12 @@ export default class extends BaseComponent { return; } - if (dropTarget.closest(`#category-${dropData.id}`)) { + if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) { // Can't drop onto your own child. return; } - const source = document.getElementById(`category-${dropData.id}`); + const source = document.getElementById(this.ids.CATEGORY(dropData.id)); if (!source) { return; @@ -144,47 +193,72 @@ export default class extends BaseComponent { } // Insert the category after the target category - categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid); + categorymanager.moveCategory(dropData.id, targetParentId, precedingSibling?.dataset.categoryid); } getWatchers() { return [ + // After any update to this category, move it to the new position. {watch: `categories[${this.element.dataset.categoryid}]:updated`, handler: this.updatePosition}, + // When the template context is added or updated, re-render the content. {watch: `categories[${this.element.dataset.categoryid}].templatecontext:created`, handler: this.rerender}, {watch: `categories[${this.element.dataset.categoryid}].templatecontext:updated`, handler: this.rerender}, + // When a new category is created, check whether we need to add a child list to this category. {watch: `categories:created`, handler: this.checkChildList}, ]; } + /** + * Re-render the category content. + * + * @param {Object} args + * @param {Element} args.element + * @return {Promise} + */ async rerender({element}) { - const {html, js} = await Templates.renderForPromise('qbank_managecategories/category', element.templatecontext); - Templates.replaceNodeContents(this.getElement('.activity-name-area'), html, js); + const {html, js} = await Templates.renderForPromise( + 'qbank_managecategories/category', + element.templatecontext + ); + return Templates.replaceNodeContents(this.getElement(this.selectors.CONTENT_AREA), html, js); } /** * Render and append a new child list. * * @param {Object} context Template context, must include at least categoryid. - * @return {Promise<*>} + * @return {Promise} */ async createChildList(context) { const {html, js} = await Templates.renderForPromise( 'qbank_managecategories/childlist', context, ); - const parentContainer = document.querySelector(`#category-${context.categoryid} .activity-grid`); + const parentContainer = document.querySelector(this.selectors.CONTENT_CONTAINER(context.categoryid)); await Templates.appendNodeContents(parentContainer, html, js); - const childList = document.querySelector(`ul[data-categoryid="${context.categoryid}"]`); - childList.closest(this.selectors.ACTIVITY_ITEM).classList.add('pb-0'); + const childList = document.querySelector(this.selectors.CHILD_LIST(context.categoryid)); + childList.closest(this.selectors.ACTIVITY_ITEM).classList.add(this.classes.NO_BOTTOM_PADDING); return childList; } + /** + * Move a category to its new position. + * + * A category may change its parent, sortorder and draghandle independently or at the same time. This method will resolve those + * changes and move the element to the new position. If the parent doesn't already have a child list, one will be created. + * + * If the parent has changed, this will also update the state with the new child count of the old and new parents. + * + * @param {Object} args + * @param {Element} args.element + * @return {Promise} + */ async updatePosition({element}) { // Move to a new parent category. let newParent; - const originParent = document.querySelector(`ul[data-categoryid="${this.getElement().dataset.parent}"]`); + const originParent = document.querySelector(this.selectors.CHILD_LIST(this.getElement().dataset.parent)); if (parseInt(this.getElement().dataset.parent) !== element.parent) { - newParent = document.querySelector(`ul[data-categoryid="${element.parent}"]`); + newParent = document.querySelector(this.selectors.CHILD_LIST(element.parent)); if (!newParent) { // The target category doesn't have a child list yet. We'd better create one. newParent = await this.createChildList({categoryid: element.parent}); @@ -202,7 +276,7 @@ export default class extends BaseComponent { nextSibling = newParent.firstElementChild; } else { // Move later in the list. - previousSibling = newParent.querySelector(`:scope > [data-sortorder="${element.sortorder - 1}"]`); + previousSibling = newParent.querySelector(this.selectors.PREVIOUS_SIBLING(element.sortorder)); nextSibling = previousSibling?.nextElementSibling; } @@ -243,42 +317,54 @@ export default class extends BaseComponent { this.element.dataset.sortorder = element.sortorder; // Enable/disable dragging. - const isDraggable = this.element.classList.contains('draghandle'); + const isDraggable = this.element.classList.contains(this.classes.DRAGHANDLE); if (isDraggable && !element.draghandle) { - this.element.classList.remove('draghandle'); + this.element.classList.remove(this.classes.DRAGHANDLE); this.initDragDrop(); } else if (!isDraggable && element.draghandle) { - this.element.classList.add('draghandle'); + this.element.classList.add(this.classes.DRAGHANDLE); this.initDragDrop(); } } - createMoveCategoryList(item, movingCategory) { + /** + * Recursively create a list of all valid destinations for a current category within a parent category. + * + * @param {Element} item + * @param {Number} movingCategoryId + * @return {*[]} + */ + createMoveCategoryList(item, movingCategoryId) { const categories = []; if (item.children) { let precedingSibling = null; item.children.forEach(category => { - if (category.dataset.categoryid === movingCategory) { + const categoryId = parseInt(category.dataset.categoryid); + // Don't create a target for the category that's moving. + if (categoryId === movingCategoryId) { return; } + // Create a target to move before this child. let child = { - categoryid: category.dataset.categoryid, - movingcategoryid: movingCategory, + categoryid: categoryId, + movingcategoryid: movingCategoryId, precedingsiblingid: precedingSibling?.dataset.categoryid ?? 0, parent: category.dataset.parent, categoryname: category.dataset.categoryname, categories: null, - current: category.dataset.categoryid === movingCategory, + current: categoryId === movingCategoryId, }; const childList = category.querySelector(this.selectors.CATEGORY_LIST); if (childList) { - child.categories = this.createMoveCategoryList(childList, movingCategory); + // If the child has its own children, recursively make a list of those. + child.categories = this.createMoveCategoryList(childList, movingCategoryId); } else { + // Otherwise, create a target to move as a new child of this one. child.categories = [ { - movingcategoryid: movingCategory, + movingcategoryid: movingCategoryId, precedingsiblingid: 0, - parent: category.dataset.categoryid, + parent: categoryId, categoryname: category.dataset.categoryname, categories: null, newchild: true, @@ -288,10 +374,12 @@ export default class extends BaseComponent { categories.push(child); precedingSibling = category; }); - if (precedingSibling.dataset.categoryid !== movingCategory) { + const precedingId = parseInt(precedingSibling.dataset.categoryid); + if (precedingId !== movingCategoryId) { + // If this is the last child of its parent, also create a target to move the category after this one. categories.push({ - movingcategoryid: movingCategory, - precedingsiblingid: precedingSibling.dataset.categoryid, + movingcategoryid: movingCategoryId, + precedingsiblingid: precedingId, parent: precedingSibling.dataset.parent, categoryname: precedingSibling.dataset.categoryname, categories: null, @@ -303,8 +391,9 @@ export default class extends BaseComponent { } /** - * Sets events listener for move category using dragdrop icon. - * @param {Event} e + * Displays a modal containing links to move the category to a new location. + * + * @param {Event} e Button click event. */ async showMoveModal(e) { // Return if it is not menu item. @@ -320,6 +409,7 @@ export default class extends BaseComponent { // Prevent addition click on the item. item.setAttribute('aria-disabled', true); + // Build the list of move links. let moveList = {contexts: []}; const contexts = document.querySelectorAll(this.selectors.CONTEXT); contexts.forEach(context => { @@ -328,7 +418,7 @@ export default class extends BaseComponent { categories: [], hascategories: false, }; - moveContext.categories = this.createMoveCategoryList(context, item.dataset.categoryid); + moveContext.categories = this.createMoveCategoryList(context, parseInt(item.dataset.categoryid)); moveContext.hascategories = moveContext.categories.length > 0; moveList.contexts.push(moveContext); }); @@ -340,13 +430,13 @@ export default class extends BaseComponent { show: true, large: true, }); - // Show modal and add click event for list item. + // Show modal and add click event for list items. modal.getBody()[0].addEventListener('click', e => { const target = e.target.closest(this.selectors.MODAL_CATEGORY_ITEM); if (!target) { return; } - categorymanager.setCatOrder(target.dataset.movingcategoryid, target.dataset.parent, target.dataset.precedingsiblingid); + categorymanager.moveCategory(target.dataset.movingcategoryid, target.dataset.parent, target.dataset.precedingsiblingid); modal.destroy(); }); item.setAttribute('aria-disabled', false); @@ -358,8 +448,8 @@ export default class extends BaseComponent { * Check whether the category that has just been added has this category as its parent. If it does, * check that this category has a child list, and if not, add one. * - * @param {Event} event - * @param {Element} event.element The new category. + * @param {Object} args + * @param {Element} args.element The new category. */ async checkChildList({element}) { if (element.parent !== parseInt(this.getElement().dataset.categoryid)) { diff --git a/question/bank/managecategories/amd/src/category_list.js b/question/bank/managecategories/amd/src/category_list.js deleted file mode 100644 index 69f1fb2e3eea3..0000000000000 --- a/question/bank/managecategories/amd/src/category_list.js +++ /dev/null @@ -1,607 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * Javascript module handling ordering of categories. - * - * @module qbank_managecategories - * @copyright 2021 Catalyst IT Australia Pty Ltd - * @author Ghaly Marc-Alexandre - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * - */ - -import Ajax from 'core/ajax'; -import Fragment from 'core/fragment'; -import Notification from 'core/notification'; -import Pending from 'core/pending'; -import Templates from 'core/templates'; -import Modal from 'core/modal'; -import {get_string as getString} from 'core/str'; - -const SELECTORS = { - CATEGORY_LIST: '.qbank_managecategories-categorylist', - MODAL_CATEGORY_ITEM: '.modal_category_item[data-categoryid]', - CATEGORY_RENDERED: '#categoriesrendered', - ACTIONABLE_ELEMENT: 'a, [role="button"], [role="menuitem"]', - SHOW_DESCRIPTION_CHECKBOX: '[name="qbshowdescr"]', - MOVE_CATEGORY_MENU_ITEM: '[role="menuitem"][data-actiontype="move"]', - LIST_ITEM: '.qbank_managecategories-item[data-categoryid]', - CONTEXT: '.qbank_managecategories-categorylist[data-contextid]', - NOT_DRAGGABLE: '[draggable=false]', -}; - -/** - * Sets up sortable list in the column sort order page. - * @param {number} pagecontextid Context id for fragment. - */ -const setupSortableLists = (pagecontextid) => { - // Touch events do not have datatransfer property. - // This variable is used to store id of first element that started the touch events. - let categoryid; - // Drag proxy element for touch events. - let dragProxy; - // Timeout before dragging starts on touch. - let touchTimeout; - // Interval for scrolling the page with touch. - let touchScrollInterval; - - /** - * Get touch target at touch point. - * The target of all touch events is the first element that has been touched at 'touch start'. - * So we need to infer the target from touch point for 'touch move' and 'touch end' events. - * - * @param {Object} e event - * @returns {any | Element} - */ - const getTouchTarget = (e) => { - const target = document.elementFromPoint( - e.changedTouches[0].clientX, - e.changedTouches[0].clientY - ); - // Check if the target is droppable. - return target.closest(SELECTORS.LIST_ITEM); - }; - - /** - * Decide if we are before or after the current drop target. - * - * Based on the current vertical position of the dragged element relative to the mid-point of the - * current drop target, decide if dropping will place the dragged element before or after the target. - * - * @param {Event} event - * @param {Element} dropTarget - * @return {boolean} - */ - const getInsertBefore = (event, dropTarget) => { - - const clientY = event.changedTouches ? event.changedTouches[0].clientY : event.clientY; - - // Get the current mouse position within the drop target - const mouseY = clientY - dropTarget.getBoundingClientRect().top; - - // Get the height of the drop target - const targetHeight = dropTarget.clientHeight; - - // Check if the mouse is over the top half of the drop target - return mouseY < targetHeight / 2; - }; - - /** - * Remove any drop target indicators currently displayed. - */ - const clearTargetIndicators = () => { - const dropTarget = document.querySelector('.qbank_managecategories-category-droptarget'); - if (dropTarget) { - dropTarget.classList.remove('qbank_managecategories-category-droptarget'); - } - const dropTargetBefore = document.querySelector('.qbank_managecategories-category-droptarget-before'); - if (dropTargetBefore) { - dropTargetBefore.classList.remove('qbank_managecategories-category-droptarget-before'); - } - }; - - /** - * Handle Drag start - * - * This will register the dragged element so it can be moved when dropped. - * - * @param {Object} e event - */ - const handleDragStart = (e) => { - const target = e.target.closest(SELECTORS.LIST_ITEM); - - // Return if target is not a draggable item. - if (!target || e.target.closest(SELECTORS.NOT_DRAGGABLE)) { - return; - } - // Save category ID of current moving item. - // The datatransfer is not used as it is not a property of touch events. - categoryid = target.dataset?.categoryid; - - if (e.type === 'touchstart') { - touchTimeout = undefined; - makeDragProxy(e, target); - } - }; - - /** - * Touch events don't create a drag proxy, so create one manually. - * - * @param {Event} event The touchstart event. - * @param {Element} element The element being dragged, to create the proxy for. - */ - const makeDragProxy = (event, element) => { - if (dragProxy) { - dragProxy.remove(); - dragProxy = null; - } - dragProxy = document.createElement('div'); - dragProxy.id = 'qbank_managecategories-dragproxy'; - dragProxy.classList.add('editing'); - dragProxy.style.width = element.getBoundingClientRect().width + 'px'; - dragProxy.style.height = element.getBoundingClientRect().height + 'px'; - dragProxy.style.top = Math.round(event.touches[0].clientY) + 'px'; - dragProxy.style.left = Math.round(event.touches[0].clientX) + 'px'; - dragProxy.innerHTML = element.innerHTML; - document.body.appendChild(dragProxy); - }; - - /** - * Handle Drag move - * - * Keep track of the current drop target, and move the drop indicator to the appropriate position. - * - * @param {Event} e event - */ - const handleDrag = (e) => { - let target; - if (e.type === 'touchmove') { - if (typeof touchTimeout === 'number') { - clearTimeout(touchTimeout); - touchTimeout = undefined; - return; - } - target = getTouchTarget(e); - touchMoveScroll(e); - if (dragProxy) { - dragProxy.style.top = Math.round(e.changedTouches[0].clientY) + 'px'; - dragProxy.style.left = Math.round(e.changedTouches[0].clientX) + 'px'; - } - } else { - target = e.target.closest(SELECTORS.LIST_ITEM); - } - // Return if target is not a droppable item or there is no sourceid. - if (!target || !categoryid) { - return; - } - - // Return if target is a child of the dragged category, so we don't indicate this as a valid drop target. - if (target.closest(`[data-categoryid="${categoryid}"]`)) { - return; - } - - const insertBefore = getInsertBefore(e, target); - - // Remove all target indicators. - clearTargetIndicators(); - - if (insertBefore && target === target.parentElement.firstElementChild) { - // Show the indicator at the top of the list. - target.classList.add('qbank_managecategories-category-droptarget-before'); - return; - } - - if (!insertBefore && target === target.parentElement.lastElementChild) { - // Show the indicator at the bottom of the list. - target.classList.add('qbank_managecategories-category-droptarget'); - return; - } - - const insertTarget = insertBefore ? target : target.nextElementSibling; - - // Show the indicator at the top of the target element. - if (insertTarget) { - insertTarget.classList.add('qbank_managecategories-category-droptarget-before'); - } - }; - - /** - * When an item is dragged out of a list, remove the current drag indicators. - * - * @param {Event} e - */ - const handleDragLeaveList = (e) => { - if (e.target.classList.contains('qbank_managecategories-categorylist')) { - clearTargetIndicators(); - } - }; - - /** - * Handle Drag end - * - * When an item is dropped, find the target element and re-order the categories. - * If the item is dropped at the top or bottom of a list, it will be moved before the first or after - * the last item, respectively. Otherwise, if it is dropped on the top half of an item, it will be moved - * before that item, and if on the bottom half, after that item. - * - * @param {Event} e event - */ - const handleDragEnd = (e) => { - let target; - const pending = new Pending('qbank_managecategories/dragend'); - clearTargetIndicators(); - if (e.type === 'touchend') { - if (typeof touchScrollInterval === 'number') { - // Stop scrolling. - window.clearInterval(touchScrollInterval); - touchScrollInterval = undefined; - } - if (typeof touchTimeout === 'number') { - // Cancel waiting on a long touch to start dragging. - window.clearTimeout(touchTimeout); - touchTimeout = undefined; - return; - } - if (dragProxy) { - dragProxy.remove(); - dragProxy = null; - } - target = getTouchTarget(e); - } else { - target = e.target.closest(SELECTORS.LIST_ITEM); - } - - if (!target) { - // Check if we're at the top or bottom of the list, and target the first or last element accordingly. - const listTarget = e.target.closest(SELECTORS.CATEGORY_LIST); - if (listTarget) { - if (getInsertBefore(e, listTarget)) { - target = listTarget.firstElementChild; - } else { - target = listTarget.lastElementChild; - } - } - } - - // Return if target is not a droppable item or there is no sourceid. - if (!target || !categoryid) { - return; - } - - // Get list item whose id is the same as current moving category id. - const source = document.getElementById(`category-${categoryid}`); - if (!source) { - return; - } - - e.preventDefault(); - - // Reset sourceid for touch event. - categoryid = null; - - let targetCategory; - const insertBefore = getInsertBefore(e, target); - let before = insertBefore; - if (insertBefore && target === target.parentElement.firstElementChild) { - targetCategory = target.dataset.categoryid; - // Insert the category at the top of the list. - target.closest(SELECTORS.CATEGORY_LIST).insertBefore(source, target); - } else if (!insertBefore && target === target.parentElement.lastElementChild) { - targetCategory = target.dataset.categoryid; - // Insert the category at the end of the list. - target.closest(SELECTORS.CATEGORY_LIST).appendChild(source); - } else { - const insertTarget = insertBefore ? target : target.nextElementSibling; - targetCategory = insertTarget.dataset.categoryid; - before = true; // We always insert before the selected target. - - // Move the source category to its new position. - target.closest(SELECTORS.CATEGORY_LIST).insertBefore(source, insertTarget); - } - - // Moved category. - const originCategory = source.dataset.categoryid; - - // Insert the category after the target category - setCatOrder(originCategory, targetCategory, before, pagecontextid, pending); - }; - - /** - * If something is dragged near the top or bottom of the screen by touch, scroll until it is moved away. - * - * @param {Event} e - */ - const touchMoveScroll = (e) => { - if (!categoryid) { - return; - } - const threshold = 50; - const timeout = 5; - const intervalRunning = typeof touchScrollInterval !== 'undefined'; - if (e.changedTouches[0].clientY < threshold && !intervalRunning) { - touchScrollInterval = window.setInterval( - () => { - window.scrollBy(0, -1); - }, - timeout - ); - } else if (window.innerHeight - e.changedTouches[0].clientY < threshold && !intervalRunning) { - touchScrollInterval = window.setInterval( - () => { - window.scrollBy(0, 1); - }, - timeout - ); - } else if (intervalRunning) { - window.clearInterval(touchScrollInterval); - touchScrollInterval = undefined; - } - }; - - /** - * Allow drop - * - * This allows elements to be used as a drop target. - * - * @param {Object} e event - */ - const allowDrop = (e) => { - e.preventDefault(); - }; - - const categoryRoot = document.getElementById('categoriesrendered'); - categoryRoot.addEventListener('dragover', allowDrop); - categoryRoot.addEventListener('dragenter', allowDrop); - categoryRoot.addEventListener('dragstart', handleDragStart); - categoryRoot.addEventListener('dragenter', handleDrag); - categoryRoot.addEventListener('dragleave', handleDragLeaveList); - categoryRoot.addEventListener('drop', handleDragEnd); - categoryRoot.addEventListener('touchmove', handleDrag, false); - categoryRoot.addEventListener('touchend', handleDragEnd, false); - categoryRoot.addEventListener('touchstart', (e) => { - // Delay before we start dragging on touch. This avoids accidental dragging when trying to scroll. - touchTimeout = window.setTimeout(() => handleDragStart(e), 500); - }, false); - - document.querySelectorAll(SELECTORS.LIST_ITEM + ' ' + SELECTORS.ACTIONABLE_ELEMENT).forEach(element => { - // Prevent interactive elements inside a list item from being dragged. - element.setAttribute('draggable', false); - }); -}; - -/** - * Call categories fragment. - * - * @param {number} contextid String containing new ordered categories. - * @returns {Promise} - */ -const getCategoriesFragment = (contextid) => { - let params = { - url: location.href, - }; - return Fragment.loadFragment('qbank_managecategories', 'categories', contextid, params); -}; - -/** - * Call external function update_category_order - inserts the updated column in the question_categories table. - * - * @param {number} originCategory Category which was dragged. - * @param {number} targetCategory Context where category was dropped. - * @param {boolean} isBeforeTarget True if the category was moved before the target category. - * @param {number} pageContextId Context from which the category was dragged. - * @param {Pending} pendingPromise Optional pending promise, will be resolved once the page fragment has been re-rendered. - */ -const setCatOrder = (originCategory, targetCategory, isBeforeTarget, pageContextId, pendingPromise = null) => { - const call = { - methodname: 'qbank_managecategories_update_category_order', - args: { - categoryid: originCategory, - targetcategoryid: targetCategory, - isbeforetarget: isBeforeTarget, - } - }; - Ajax.call([call])[0] - .then(() => { - return getCategoriesFragment(pageContextId); - }) - .catch(error => { - Notification.addNotification({ - message: error.message, - type: 'error', - }); - document.getElementsByClassName('alert-danger')[0]?.scrollIntoView(); - return getCategoriesFragment(pageContextId); - }) - .then((html, js) => { - Templates.replaceNode('#categoriesrendered', html, js); - if (pendingPromise) { - pendingPromise.resolve(); - } - return; - }) - .catch(error => { - if (pendingPromise) { - pendingPromise.reject(error); - } - Notification.exception(error); - }); -}; - - -/** - * Method to add listener on category arrow - descendants. - * - * @param {number} pageContextId Context id for fragment. - */ -const categoryParentListener = (pageContextId) => { - document.querySelector(SELECTORS.CATEGORY_RENDERED).addEventListener('click', e => { - // Ignore if there is no categories containers. - if (!e.target.closest(SELECTORS.CATEGORY_RENDERED)) { - return; - } - - // Ignore if there is no action icon. - const actionIcon = e.target.closest('.action-icon'); - if (!actionIcon) { - return; - } - - e.preventDefault(); - - // Retrieve data from action icon. - const data = actionIcon.dataset; - - let call; - const targetParent = document.querySelector(`#category-${data.tocategory}`); - if (!targetParent) { - // Moving to the top level. Move after the current parent. - const currentParent = actionIcon.closest(SELECTORS.CATEGORY_LIST).closest(SELECTORS.LIST_ITEM); - call = { - methodname: 'qbank_managecategories_update_category_order', - args: { - categoryid: data.tomove, - targetcategoryid: currentParent.dataset.categoryid, - isbeforetarget: false, - } - }; - } else { - const childList = targetParent.querySelector(SELECTORS.CATEGORY_LIST); - if (childList) { - // The new parent already has children. Move the category to the end of its list. - call = { - methodname: 'qbank_managecategories_update_category_order', - args: { - categoryid: data.tomove, - targetcategoryid: childList.lastElementChild.dataset.categoryid, - isbeforetarget: false, - } - }; - } else { - // Move the category to the new parent. - call = { - methodname: 'qbank_managecategories_move_category_to_new_parent', - args: { - categoryid: data.tomove, - newparentcategoryid: data.tocategory, - } - }; - } - } - - Ajax.call([call])[0] - .then(() => getCategoriesFragment(pageContextId)) - .then((html, js) => { - Templates.replaceNode(SELECTORS.CATEGORY_RENDERED, html, js); - return; - }) - .catch(Notification.exception); - }); -}; - -/** - * Sets events listener for checkbox ticking change. - */ -const setupShowDescriptionCheckbox = () => { - document.addEventListener('click', e => { - const checkbox = e.target.closest(SELECTORS.SHOW_DESCRIPTION_CHECKBOX); - if (!checkbox) { - return; - } - checkbox.form.submit(); - }); -}; - -const createMoveCategoryList = (item, movingCategory) => { - const categories = []; - if (item.children) { - item.children.forEach(category => { - let child = { - categoryid: category.dataset.categoryid, - categoryname: category.dataset.categoryname, - categories: null, - firstchild: category === item.children[0], - current: category.dataset.categoryid === movingCategory, - }; - - const childList = category.querySelector(SELECTORS.CATEGORY_LIST); - if (childList) { - child.categories = createMoveCategoryList(childList, movingCategory); - } - categories.push(child); - }); - } - return categories; -}; - -/** - * Sets events listener for move category using dragdrop icon. - * @param {number} pagecontextid Context id to get all relevant categories. - */ -const setUpMoveMenuItem = (pagecontextid) => { - document.querySelector(SELECTORS.CATEGORY_RENDERED).addEventListener('click', async(e) => { - // Return if it is not menu item. - const item = e.target.closest(SELECTORS.MOVE_CATEGORY_MENU_ITEM); - if (!item) { - return; - } - // Return if it is disabled. - if (item.getAttribute('aria-disabled')) { - return; - } - - // Prevent addition click on the item. - item.setAttribute('aria-disabled', true); - - let moveList = {contexts: []}; - const contexts = document.querySelectorAll(SELECTORS.CONTEXT); - contexts.forEach(context => { - const moveContext = { - contextname: context.dataset.contextname, - categories: [], - hascategories: false, - }; - moveContext.categories = createMoveCategoryList(context, item.dataset.categoryid); - moveContext.hascategories = moveContext.categories.length > 0; - moveList.contexts.push(moveContext); - }); - - const modal = await Modal.create({ - title: getString('movecategory', 'qbank_managecategories', item.dataset.categoryname), - body: Templates.render('qbank_managecategories/move_context_list', moveList), - footer: '', - show: true, - large: true, - }); - // Show modal and add click event for list item. - modal.getBody()[0].addEventListener('click', e => { - const target = e.target.closest(SELECTORS.MODAL_CATEGORY_ITEM); - if (!target) { - return; - } - const pending = new Pending('qbank_managecategories/modal'); - setCatOrder(item.dataset.categoryid, target.dataset.categoryid, target.dataset.before, pagecontextid, pending); - modal.destroy(); - }); - item.setAttribute('aria-disabled', false); - }); -}; - -export const init = (pagecontextid) => { - categoryParentListener(pagecontextid); - setupSortableLists(pagecontextid); - setupShowDescriptionCheckbox(); - setUpMoveMenuItem(pagecontextid); -}; diff --git a/question/bank/managecategories/amd/src/categorylist.js b/question/bank/managecategories/amd/src/categorylist.js index 1580d0ba92926..93b27d5bfb9bf 100644 --- a/question/bank/managecategories/amd/src/categorylist.js +++ b/question/bank/managecategories/amd/src/categorylist.js @@ -14,7 +14,9 @@ // along with Moodle. If not, see . /** - * The category component. + * The category list component. + * + * The category list is a drop target, so that a category may be dropped at the top or bottom of the list. * * @module qbank_managecategories/categorylist * @class qbank_managecategories/categorylist @@ -33,23 +35,24 @@ export default class extends BaseComponent { LIST_ITEM: '.qbank_managecategories-item[data-categoryid]', ACTIVITY_ITEM: '.activity-item', ACTIVITY_NAME_AREA: '.activity-name-area', + CATEGORY_ID: id => `#category-${id}`, + }; + this.classes = { + DROP_TARGET_BEFORE: 'qbank_managecategories-category-droptarget-before', + DROP_TARGET: 'qbank_managecategories-category-droptarget', + NO_BOTTOM_PADDING: 'pb-0', + }; + this.ids = { + CATEGORY: id => `#category-${id}`, }; } stateReady() { - this.initDragDrop(); + this.dragdrop = new DragDrop(this); } destroy() { // The draggable element must be unregistered. - this.deInitDragDrop(); - } - - initDragDrop() { - this.dragdrop = new DragDrop(this); - } - - deInitDragDrop() { if (this.dragdrop !== undefined) { this.dragdrop.unregister(); this.dragdrop = undefined; @@ -57,7 +60,7 @@ export default class extends BaseComponent { } /** - * Static method to create a component instance form the mustahce template. + * Static method to create a component instance. * * @param {string} target the DOM main element or its ID * @param {object} selectors optional css selector overrides @@ -71,33 +74,60 @@ export default class extends BaseComponent { }); } - validateDropData() { + /** + * You can't drop into a list that is a descendant of the dragged category. + * + * @param {Object} dropData + * @param {Event} event + * @return {boolean} + */ + validateDropData(dropData, event) { + const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST); + if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) { + return false; + } return true; } + /** + * Highlight the border of the list where the category will be moved. + * + * If dropping at the top of the list, highlight the top border. + * If dropping at the bottom, highlight the bottom border. + * + * @param {Object} dropData + * @param {Event} event + */ showDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST); - if (dropTarget.closest(`#category-${dropData.id}`)) { - // Can't drop onto your own child. - return; - } if (this.getInsertBefore(event, dropTarget)) { - dropTarget.classList.add('qbank_managecategories-category-droptarget-before'); - dropTarget.classList.remove('qbank_managecategories-category-droptarget'); + dropTarget.classList.add(this.classes.DROP_TARGET_BEFORE); + dropTarget.classList.remove(this.classes.DROP_TARGET); } else { - dropTarget.classList.add('qbank_managecategories-category-droptarget'); - dropTarget.classList.remove('qbank_managecategories-category-droptarget-before'); + dropTarget.classList.add(this.classes.DROP_TARGET); + dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE); } - } + /** + * Remove highlighting. + * + * @param {Object} dropData + * @param {Event} event + */ hideDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST); - dropTarget.classList.remove('qbank_managecategories-category-droptarget-before'); - dropTarget.classList.remove('qbank_managecategories-category-droptarget'); - + dropTarget.classList.remove(this.classes.DROP_TARGET_BEFORE); + dropTarget.classList.remove(this.classes.DROP_TARGET); } + /** + * Determine whether we're dragging over the top or bottom half of the list. + * + * @param {Event} event + * @param {Element} dropTarget + * @return {boolean} + */ getInsertBefore(event, dropTarget) { // Get the current mouse position within the drop target const mouseY = event.clientY - dropTarget.getBoundingClientRect().top; @@ -109,6 +139,12 @@ export default class extends BaseComponent { return mouseY < targetHeight / 2; } + /** + * Find the new position of the dropped category, and trigger the move. + * + * @param {Object} dropData + * @param {Event} event + */ drop(dropData, event) { const dropTarget = event.target.closest(this.selectors.CATEGORY_LIST); @@ -116,12 +152,12 @@ export default class extends BaseComponent { return; } - if (dropTarget.closest(`#category-${dropData.id}`)) { + if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) { // Can't drop onto your own child. return; } - const source = document.getElementById(`category-${dropData.id}`); + const source = document.getElementById(this.ids.CATEGORY(dropData.id)); if (!source) { return; @@ -134,11 +170,12 @@ export default class extends BaseComponent { // Dropped at the top of the list. precedingSibling = null; } else { + // Dropped at the bottom of the list. precedingSibling = dropTarget.lastElementChild; } // Insert the category after the target category - categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid); + categorymanager.moveCategory(dropData.id, targetParentId, precedingSibling?.dataset.categoryid); } /** @@ -148,7 +185,9 @@ export default class extends BaseComponent { */ getWatchers() { return [ + // Watch for this category having its child count updated. {watch: `categoryLists[${this.element.dataset.categoryid}].childCount:updated`, handler: this.checkEmptyList}, + // Watch for any new category being created. {watch: `categories:created`, handler: this.addCategory}, ]; } @@ -173,12 +212,19 @@ export default class extends BaseComponent { .querySelector(this.selectors.ACTIVITY_NAME_AREA); await Templates.appendNodeContents(activityNameArea, html, js); // Reinstate padding on the parent element. - this.element.closest(this.selectors.ACTIVITY_ITEM).classList.remove('pb-0'); + this.element.closest(this.selectors.ACTIVITY_ITEM).classList.remove(this.classes.NO_BOTTOM_PADDING); // Remove this list. this.remove(); } } + /** + * If a newly-created category has this list's category as its parent, add it to this list. + * + * @param {Object} args + * @param {Object} args.element + * @return {Promise} + */ async addCategory({element}) { if (element.parent !== parseInt(this.getElement().dataset.categoryid)) { return; // Not for me. diff --git a/question/bank/managecategories/amd/src/categorymanager.js b/question/bank/managecategories/amd/src/categorymanager.js index 598b5a9a351d6..969d77b184bd1 100644 --- a/question/bank/managecategories/amd/src/categorymanager.js +++ b/question/bank/managecategories/amd/src/categorymanager.js @@ -31,16 +31,28 @@ const SELECTORS = { CATEGORY_LIST: '.qbank_managecategories-categorylist', CONTEXT: '.qbank_managecategories-categorylist[data-contextid]', LIST_ITEM: '.qbank_managecategories-item[data-categoryid]', - MODULE_ROOT: '#categoriesrendered', + CATEGORY_ROOT: '#categoryroot', SHOWDESCRIPTIONS_TOGGLE: '#showdescriptions-toggle', + ADD_EDIT_BUTTON: '[data-action="addeditcategory"]', + CATEGORY_ITEM: '.qbank_managecategories-item', }; const CLASSES = { DRAGHANDLE: 'draghandle', + DANGER: 'alert-danger', }; +/** + * Load the initial state. + * + * This iterates over the initial tree of category items, and captures the data required for the state from each category. + * It also captures a count of the number of children in each list. + * + * @param {Reactive} reactive + * @return {Promise} + */ const loadState = async (reactive) => { - const rootElement = document.querySelector(SELECTORS.MODULE_ROOT); + const rootElement = document.querySelector(SELECTORS.CATEGORY_ROOT); const stateData = { page: { contextid: rootElement.dataset.contextid, @@ -70,8 +82,22 @@ const loadState = async (reactive) => { reactive.setInitialState(stateData); }; +/** + * Reactive instance for the category manager. + */ class CategoryManager extends Reactive { - setCatOrder( + /** + * Move a category to a new position within the given parent. + * + * This will call the move_category web service function to re-order the categories, then update + * the state with the returned updates. + * + * @param {Number} categoryId The ID of the category being moved. + * @param {Number} targetParentId The ID of the destination parent category (this may not have changed). + * @param {Number} precedingSiblingId The ID of the category to put the moved category after. + * This may be null if moving to the top of a list. + */ + moveCategory( categoryId, targetParentId, precedingSiblingId = null, @@ -94,12 +120,12 @@ class CategoryManager extends Reactive { message: error.message, type: 'error', }); - document.getElementsByClassName('alert-danger')[0]?.scrollIntoView(); + document.getElementsByClassName(this.classes.DANGER)[0]?.scrollIntoView(); }); } /** - * Return modal title + * Return title for the add/edit modal. * * @param {boolean} isEdit is 'add' or 'edit' form * @returns {String} title string @@ -109,7 +135,7 @@ class CategoryManager extends Reactive { } /** - * Return modal save button label + * Return save button label for the add/edit modal. * * @param {boolean} isEdit is 'add' or 'edit' form * @returns {String} save string @@ -119,12 +145,12 @@ class CategoryManager extends Reactive { } /** - * Function handling display of moodle form. + * Function handling display of modal form. * * @param {Event} e The click event triggering the modal. */ showEditModal(e) { - const addEditButton = e.target.closest('[data-action="addeditcategory"]'); + const addEditButton = e.target.closest(this.selectors.ADD_EDIT_BUTTON); // Return if it is not 'addeditcategory' button. if (!addEditButton) { @@ -146,7 +172,7 @@ class CategoryManager extends Reactive { let contextid = addEditButton.dataset.contextid; let categoryid = null; let sortorder = null; - const categoryItem = e.target.closest('.qbank_managecategories-item'); + const categoryItem = e.target.closest(this.selectors.CATEGORY_ITEM); if (categoryItem) { contextid = categoryItem.dataset.contextid; categoryid = categoryItem.dataset.categoryid; @@ -171,6 +197,8 @@ class CategoryManager extends Reactive { saveButtonText: save, returnFocus: addEditButton, }); + // Once the form has been submitted via the web service, update the state with the new or updated + // category based on the web service response. modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (response) => { categorymanager.stateManager.processUpdates(response.detail); }); @@ -179,7 +207,6 @@ class CategoryManager extends Reactive { } } -// The reactive instance requires an event (eventNamer and eventDispatch method) export const categorymanager = new CategoryManager({ name: 'qtype_managecategories_categorymanager', eventName: eventTypes.qbankManagecategoriesStateUpdated, diff --git a/question/bank/managecategories/amd/src/categoryroot.js b/question/bank/managecategories/amd/src/categoryroot.js new file mode 100644 index 0000000000000..73393256b3578 --- /dev/null +++ b/question/bank/managecategories/amd/src/categoryroot.js @@ -0,0 +1,75 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * The category root component. + * + * @module qbank_managecategories/categoryroot + * @class qbank_managecategories/categoryroot + */ + +import {BaseComponent} from 'core/reactive'; +import {categorymanager} from 'qbank_managecategories/categorymanager'; + +export default class extends BaseComponent { + + create(descriptor) { + this.name = descriptor.element.id; + this.classes = { + SHOWDESCRIPTIONS: 'showdescriptions', + }; + } + + /** + * Static method to create a component instance. + * + * @param {string} target the DOM main element or its ID + * @param {object} selectors optional css selector overrides + * @return {Component} + */ + static init(target, selectors) { + return new this({ + element: document.querySelector(target), + selectors, + reactive: categorymanager, + }); + } + + /** + * Watch for changes to the page state. + * + * @return {Array} A list of watchers. + */ + getWatchers() { + return [ + // Watch for descriptions being toggled. + {watch: `page.showdescriptions:updated`, handler: this.toggleDescriptions} + ]; + } + + /** + * Show or hide descriptions when the flag in the state is changed. + * + * @param {Object} args + * @param {Object} args.element The updated page state. + */ + toggleDescriptions({element}){ + if (element.showdescriptions) { + this.getElement().classList.add(this.classes.SHOWDESCRIPTIONS); + } else { + this.getElement().classList.remove(this.classes.SHOWDESCRIPTIONS); + } + } +} \ No newline at end of file diff --git a/question/bank/managecategories/amd/src/list.js b/question/bank/managecategories/amd/src/list.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/question/bank/managecategories/amd/src/mutations.js b/question/bank/managecategories/amd/src/mutations.js index 4cc7d87f29196..889c54ba2ae14 100644 --- a/question/bank/managecategories/amd/src/mutations.js +++ b/question/bank/managecategories/amd/src/mutations.js @@ -13,12 +13,20 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +import {setUserPreference} from 'core_user/repository'; + /** * Default mutation manager * * @module qbank_managecategories/mutations */ class Mutations { + async toggleDescriptions(stateManager, showDescriptions) { + stateManager.setReadOnly(false); + await setUserPreference('qbank_managecategories_showdescriptions', showDescriptions); + stateManager.state.page.showdescriptions = showDescriptions; + stateManager.setReadOnly(true); + } } export const mutations = new Mutations(); \ No newline at end of file diff --git a/question/bank/managecategories/amd/src/newchild.js b/question/bank/managecategories/amd/src/newchild.js index f2e6b2e232163..c037fae690ead 100644 --- a/question/bank/managecategories/amd/src/newchild.js +++ b/question/bank/managecategories/amd/src/newchild.js @@ -16,36 +16,36 @@ /** * The newchild component. * - * @module qbank_managecategories/categorylist - * @class qbank_managecategories/categorylist + * This is a drop target for moving a category to an as-yet-nonexistant child list under another category. + * + * @module qbank_managecategories/newchild + * @class qbank_managecategories/newchild */ import {BaseComponent, DragDrop} from 'core/reactive'; import {categorymanager} from 'qbank_managecategories/categorymanager'; export default class extends BaseComponent { - create(descriptor) { this.name = descriptor.element.id; this.selectors = { NEW_CHILD: '.qbank_managecategories-newchild', + CATEGORY_ID: id => `#category-${id}` }; + this.classes = { + DROP_TARGET: 'qbank_managecategories-category-droptarget', + } + this.ids = { + CATEGORY: id => `category-${id}`, + } } stateReady() { - this.initDragDrop(); + this.dragdrop = new DragDrop(this); } destroy() { // The draggable element must be unregistered. - this.deInitDragDrop(); - } - - initDragDrop() { - this.dragdrop = new DragDrop(this); - } - - deInitDragDrop() { if (this.dragdrop !== undefined) { this.dragdrop.unregister(); this.dragdrop = undefined; @@ -68,18 +68,29 @@ export default class extends BaseComponent { }); } - validateDropData() { + /** + * Cannot drop a category as a new child of its own decendant. + * + * @param {Object} dropData + * @param {Event} event + * @return {boolean} + */ + validateDropData(dropData, event) { + const dropTarget = event.target.closest(this.selectors.NEW_CHILD); + if (dropTarget.closest(this.selectors.CATEGORY_ID(dropData.id))) { + return false; + } return true; } showDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.NEW_CHILD); - dropTarget.classList.add('qbank_managecategories-category-droptarget'); + dropTarget.classList.add(this.classes.DROP_TARGET); } hideDropZone(dropData, event) { const dropTarget = event.target.closest(this.selectors.NEW_CHILD); - dropTarget.classList.remove('qbank_managecategories-category-droptarget'); + dropTarget.classList.remove(this.classes.DROP_TARGET); } drop(dropData, event) { @@ -89,17 +100,16 @@ export default class extends BaseComponent { return; } - const source = document.getElementById(`category-${dropData.id}`); + const source = document.getElementById(this.ids.CATEGORY(dropData.id)); if (!source) { return; } const targetParentId = dropTarget.dataset.parent; - const precedingSibling = null; - // Insert the category after the target category - categorymanager.setCatOrder(dropData.id, targetParentId, precedingSibling?.dataset.categoryid); + // Insert the category as the first child of the new parent. + categorymanager.moveCategory(dropData.id, targetParentId); } /** @@ -109,6 +119,7 @@ export default class extends BaseComponent { */ getWatchers() { return [ + // Watch for any category having its parent changed. {watch: `categories.parent:updated`, handler: this.checkNewChild}, ]; } diff --git a/question/bank/managecategories/amd/src/showdescriptions.js b/question/bank/managecategories/amd/src/showdescriptions.js index 90825fd2406a9..901cf1e86453b 100644 --- a/question/bank/managecategories/amd/src/showdescriptions.js +++ b/question/bank/managecategories/amd/src/showdescriptions.js @@ -22,7 +22,6 @@ import {BaseComponent} from 'core/reactive'; import {categorymanager} from 'qbank_managecategories/categorymanager'; -import {setUserPreference} from 'core_user/repository'; export default class extends BaseComponent { @@ -30,7 +29,6 @@ export default class extends BaseComponent { this.name = descriptor.element.id; this.selectors = { TOGGLE: '#showdescriptions-toggle', - CATEGORIES_ROOT: '#categoriesrendered', }; } @@ -39,7 +37,7 @@ export default class extends BaseComponent { } /** - * Static method to create a component instance form the mustahce template. + * Static method to create a component instance. * * @param {string} target the DOM main element or its ID * @param {object} selectors optional css selector overrides @@ -54,14 +52,14 @@ export default class extends BaseComponent { }); } - updateShowDescriptions(event) { + /** + * Dispatch a mutation to toggle the showDescriptions setting. + * + * @param {Event} event The toggle change event. + * @return {Promise} + */ + async updateShowDescriptions(event) { const checked = event.target.checked; - const categoriesRoot = document.querySelector(this.selectors.CATEGORIES_ROOT); - if (checked) { - categoriesRoot.classList.add('showdescriptions'); - } else { - categoriesRoot.classList.remove('showdescriptions'); - } - setUserPreference('qbank_managecategories_showdescriptions', checked); + this.reactive.dispatch('toggleDescriptions', checked); } } diff --git a/question/bank/managecategories/templates/categories.mustache b/question/bank/managecategories/templates/categories.mustache index ec4501ab2be57..419e60395a2c6 100644 --- a/question/bank/managecategories/templates/categories.mustache +++ b/question/bank/managecategories/templates/categories.mustache @@ -48,7 +48,7 @@ }] } }} -
{{#categoriesrendered}} @@ -66,6 +66,9 @@ {{#js}} + require(['qbank_managecategories/categoryroot'], (categoryroot) => { + categoryroot.init('#categoryroot'); + }); require(['qbank_managecategories/categorylist'], (categorylist) => { // Initialise top-level lists. const categoryLists = document.querySelectorAll('.qbank_managecategories-categorylist[data-contextid]');