diff --git a/question/bank/managecategories/amd/build/category.min.js b/question/bank/managecategories/amd/build/category.min.js index ca9e8a4a44d..7b77cbe7bad 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",CATEGORY_ITEM:".qbank_managecategories-item[data-categoryid]",CATEGORY_CONTENTS:".qbank_managecategories-item > .container",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:".qbank_managecategories-details",CATEGORY_ID:id=>"#category-".concat(id),CONTENT_CONTAINER:id=>"#category-".concat(id," .qbank_managecategories-childlistcontainer"),CHILD_LIST:id=>'ul[data-categoryid="'.concat(id,'"]'),PREVIOUS_SIBLING:sortorder=>':scope > [data-sortorder="'.concat(sortorder,'"]')},this.classes={NO_BOTTOM_PADDING:"pb-0",DRAGHANDLE:"draghandle",DROPTARGET:"qbank_managecategories-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(){return!0}showDropZone(dropData){return!this.getElement().closest(this.selectors.CATEGORY_ID(dropData.id))&&(this.getElement().classList.add(this.classes.DROPTARGET),!0)}hideDropZone(){this.getElement().classList.remove(this.classes.DROPTARGET)}drop(dropData,event){var _precedingSibling;const dropTarget=event.target.closest(this.selectors.CATEGORY_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_details",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.CATEGORY_CONTENTS).classList.add(this.classes.NO_BOTTOM_PADDING),childList}async updatePosition(_ref2){let newParent,{element:element}=_ref2;window.console.log("updating",this.getElement()),window.console.log("new state",element);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,window.console.log("newParent",newParent),newParent.firstElementChild&&parseInt(element.sortorder)<=parseInt(newParent.firstElementChild.dataset.sortorder))?nextSibling=newParent.firstElementChild:(previousSibling=newParent.querySelector(this.selectors.PREVIOUS_SIBLING(element.sortorder-1)),nextSibling=null===(_previousSibling=previousSibling)||void 0===_previousSibling?void 0:_previousSibling.nextElementSibling);window.console.log("previousSibling",previousSibling),window.console.log("nextSibling",nextSibling);const moved=newParent!==this.getElement().parentElement||nextSibling!==this.getElement();window.console.log("moved",moved),moved&&(nextSibling?(window.console.log("insertBefore"),newParent.insertBefore(this.getElement(),nextSibling)):(window.console.log("appendChild"),newParent.appendChild(this.getElement()))),originParent!==newParent&&this.reactive.stateManager.processUpdates([{name:"categoryLists",action:"put",fields:{id:originParent.dataset.categoryid,childCount:originParent.querySelectorAll(this.selectors.CATEGORY_ITEM).length}},{name:"categoryLists",action:"put",fields:{id:newParent.dataset.categoryid,childCount:newParent.querySelectorAll(this.selectors.CATEGORY_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;return element.parent!==this.getElement().dataset.categoryid||this.getElement(this.selectors.CATEGORY_LIST)?null: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",CATEGORY_ITEM:".qbank_managecategories-item[data-categoryid]",CATEGORY_CONTENTS:".qbank_managecategories-item > .container",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:".qbank_managecategories-details",CATEGORY_ID:id=>"#category-".concat(id),CONTENT_CONTAINER:id=>"#category-".concat(id," .qbank_managecategories-childlistcontainer"),CHILD_LIST:id=>'ul[data-categoryid="'.concat(id,'"]'),PREVIOUS_SIBLING:sortorder=>':scope > [data-sortorder="'.concat(sortorder,'"]')},this.classes={NO_BOTTOM_PADDING:"pb-0",DRAGHANDLE:"draghandle",DROPTARGET:"qbank_managecategories-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(){return!0}showDropZone(dropData){return!this.getElement().closest(this.selectors.CATEGORY_ID(dropData.id))&&(this.getElement().classList.add(this.classes.DROPTARGET),!0)}hideDropZone(){this.getElement().classList.remove(this.classes.DROPTARGET)}drop(dropData,event){var _precedingSibling;const dropTarget=event.target.closest(this.selectors.CATEGORY_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_details",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.CATEGORY_CONTENTS).classList.add(this.classes.NO_BOTTOM_PADDING),childList}async updatePosition(_ref2){let newParent,{element:element}=_ref2;window.console.log("updating",this.getElement()),window.console.log("new state",element);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,window.console.log("newParent",newParent),newParent.firstElementChild&&parseInt(element.sortorder)<=parseInt(newParent.firstElementChild.dataset.sortorder))?nextSibling=newParent.firstElementChild:(previousSibling=newParent.querySelector(this.selectors.PREVIOUS_SIBLING(element.sortorder-1)),nextSibling=null===(_previousSibling=previousSibling)||void 0===_previousSibling?void 0:_previousSibling.nextElementSibling);window.console.log("previousSibling",previousSibling),window.console.log("nextSibling",nextSibling);const moved=newParent!==this.getElement().parentElement||nextSibling!==this.getElement();window.console.log("moved",moved),moved&&(nextSibling?(window.console.log("insertBefore"),newParent.insertBefore(this.getElement(),nextSibling)):(window.console.log("appendChild"),newParent.appendChild(this.getElement()))),originParent!==newParent&&this.reactive.stateManager.processUpdates([{name:"categoryLists",action:"put",fields:{id:originParent.dataset.categoryid,childCount:originParent.querySelectorAll(this.selectors.CATEGORY_ITEM).length}},{name:"categoryLists",action:"put",fields:{id:newParent.dataset.categoryid,childCount:newParent.querySelectorAll(this.selectors.CATEGORY_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;if(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})),precedingSibling){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;return element.parent!==this.getElement().dataset.categoryid||this.getElement(this.selectors.CATEGORY_LIST)?null: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 02d1baab322..748614d91a0 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 CATEGORY_ITEM: '.qbank_managecategories-item[data-categoryid]',\n CATEGORY_CONTENTS: '.qbank_managecategories-item > .container',\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: '.qbank_managecategories-details',\n CATEGORY_ID: id => `#category-${id}`,\n CONTENT_CONTAINER: id => `#category-${id} .qbank_managecategories-childlistcontainer`,\n CHILD_LIST: id => `ul[data-categoryid=\"${id}\"]`,\n PREVIOUS_SIBLING: sortorder => `:scope > [data-sortorder=\"${sortorder}\"]`,\n };\n this.classes = {\n NO_BOTTOM_PADDING: 'pb-0',\n DRAGHANDLE: 'draghandle',\n DROPTARGET: 'qbank_managecategories-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 validateDropData() {\n return true;\n }\n\n /**\n * Highlight the top border of the category item.\n *\n * @param {Object} dropData\n */\n showDropZone(dropData) {\n if (this.getElement().closest(this.selectors.CATEGORY_ID(dropData.id))) {\n // Can't drop onto itself or its own child.\n return false;\n }\n this.getElement().classList.add(this.classes.DROPTARGET);\n return true;\n }\n\n /**\n * Remove highlighting.\n */\n hideDropZone() {\n this.getElement().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.CATEGORY_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} args\n * @param {Element} args.element\n * @return {Promise}\n */\n async rerender({element}) {\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/category_details',\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.CATEGORY_CONTENTS).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 {Object} args\n * @param {Object} args.element\n * @return {Promise}\n */\n async updatePosition({element}) {\n window.console.log('updating', this.getElement());\n window.console.log('new state', 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 window.console.log('newParent', newParent);\n\n // Move to a new position within the parent.\n let previousSibling;\n let nextSibling;\n if (newParent.firstElementChild && parseInt(element.sortorder) <= parseInt(newParent.firstElementChild.dataset.sortorder)) {\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 - 1));\n nextSibling = previousSibling?.nextElementSibling;\n }\n window.console.log('previousSibling', previousSibling);\n window.console.log('nextSibling', nextSibling);\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.getElement().parentElement || nextSibling !== this.getElement());\n\n window.console.log('moved', moved);\n\n if (moved) {\n if (nextSibling) {\n window.console.log('insertBefore');\n // Move to the specified position in the list.\n newParent.insertBefore(this.getElement(), nextSibling);\n } else {\n window.console.log('appendChild');\n // Move to the end of the list (may also be the top of the list is empty).\n newParent.appendChild(this.getElement());\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.CATEGORY_ITEM).length\n }\n },\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: newParent.dataset.categoryid,\n childCount: newParent.querySelectorAll(this.selectors.CATEGORY_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 {Array}\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 {Object} args\n * @param {Element} args.element The new category.\n * @return {Promise}\n */\n async checkChildList({element}) {\n if (element.parent !== this.getElement().dataset.categoryid) {\n return null; // Not for me.\n }\n let childList = this.getElement(this.selectors.CATEGORY_LIST);\n if (childList) {\n return null; // 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","CATEGORY_ITEM","CATEGORY_CONTENTS","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","showDropZone","dropData","closest","add","hideDropZone","remove","drop","event","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","window","console","log","originParent","previousSibling","nextSibling","parseInt","createChildList","parentElement","_previousSibling","nextElementSibling","moved","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 +{"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 CATEGORY_ITEM: '.qbank_managecategories-item[data-categoryid]',\n CATEGORY_CONTENTS: '.qbank_managecategories-item > .container',\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: '.qbank_managecategories-details',\n CATEGORY_ID: id => `#category-${id}`,\n CONTENT_CONTAINER: id => `#category-${id} .qbank_managecategories-childlistcontainer`,\n CHILD_LIST: id => `ul[data-categoryid=\"${id}\"]`,\n PREVIOUS_SIBLING: sortorder => `:scope > [data-sortorder=\"${sortorder}\"]`,\n };\n this.classes = {\n NO_BOTTOM_PADDING: 'pb-0',\n DRAGHANDLE: 'draghandle',\n DROPTARGET: 'qbank_managecategories-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 validateDropData() {\n return true;\n }\n\n /**\n * Highlight the top border of the category item.\n *\n * @param {Object} dropData\n */\n showDropZone(dropData) {\n if (this.getElement().closest(this.selectors.CATEGORY_ID(dropData.id))) {\n // Can't drop onto itself or its own child.\n return false;\n }\n this.getElement().classList.add(this.classes.DROPTARGET);\n return true;\n }\n\n /**\n * Remove highlighting.\n */\n hideDropZone() {\n this.getElement().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.CATEGORY_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} args\n * @param {Element} args.element\n * @return {Promise}\n */\n async rerender({element}) {\n const {html, js} = await Templates.renderForPromise(\n 'qbank_managecategories/category_details',\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.CATEGORY_CONTENTS).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 {Object} args\n * @param {Object} args.element\n * @return {Promise}\n */\n async updatePosition({element}) {\n window.console.log('updating', this.getElement());\n window.console.log('new state', 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 window.console.log('newParent', newParent);\n\n // Move to a new position within the parent.\n let previousSibling;\n let nextSibling;\n if (newParent.firstElementChild && parseInt(element.sortorder) <= parseInt(newParent.firstElementChild.dataset.sortorder)) {\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 - 1));\n nextSibling = previousSibling?.nextElementSibling;\n }\n window.console.log('previousSibling', previousSibling);\n window.console.log('nextSibling', nextSibling);\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.getElement().parentElement || nextSibling !== this.getElement());\n\n window.console.log('moved', moved);\n\n if (moved) {\n if (nextSibling) {\n window.console.log('insertBefore');\n // Move to the specified position in the list.\n newParent.insertBefore(this.getElement(), nextSibling);\n } else {\n window.console.log('appendChild');\n // Move to the end of the list (may also be the top of the list is empty).\n newParent.appendChild(this.getElement());\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.CATEGORY_ITEM).length\n }\n },\n {\n name: 'categoryLists',\n action: 'put',\n fields: {\n id: newParent.dataset.categoryid,\n childCount: newParent.querySelectorAll(this.selectors.CATEGORY_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 {Array}\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 if (precedingSibling) {\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 }\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 {Object} args\n * @param {Element} args.element The new category.\n * @return {Promise}\n */\n async checkChildList({element}) {\n if (element.parent !== this.getElement().dataset.categoryid) {\n return null; // Not for me.\n }\n let childList = this.getElement(this.selectors.CATEGORY_LIST);\n if (childList) {\n return null; // 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","CATEGORY_ITEM","CATEGORY_CONTENTS","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","showDropZone","dropData","closest","add","hideDropZone","remove","drop","event","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","window","console","log","originParent","previousSibling","nextSibling","parseInt","createChildList","parentElement","_previousSibling","nextElementSibling","moved","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/src/category.js b/question/bank/managecategories/amd/src/category.js index d74b43ca983..ad16a023155 100644 --- a/question/bank/managecategories/amd/src/category.js +++ b/question/bank/managecategories/amd/src/category.js @@ -372,17 +372,19 @@ export default class extends BaseComponent { categories.push(child); precedingSibling = category; }); - 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: movingCategoryId, - precedingsiblingid: precedingId, - parent: precedingSibling.dataset.parent, - categoryname: precedingSibling.dataset.categoryname, - categories: null, - lastchild: true, - }); + if (precedingSibling) { + 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: movingCategoryId, + precedingsiblingid: precedingId, + parent: precedingSibling.dataset.parent, + categoryname: precedingSibling.dataset.categoryname, + categories: null, + lastchild: true, + }); + } } } return categories;