diff --git a/amd/build/courseformat/contenttabs/tabtree.min.js b/amd/build/courseformat/contenttabs/tabtree.min.js index c089634..d48caff 100644 --- a/amd/build/courseformat/contenttabs/tabtree.min.js +++ b/amd/build/courseformat/contenttabs/tabtree.min.js @@ -8,6 +8,6 @@ define("format_multitopic/courseformat/contenttabs/tabtree",["exports","core/rea * @copyright 2023 onwards James Calder and Otago Polytechnic * @copyright based on work by 2021 Ferran Recio * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_tab=_interopRequireDefault(_tab),_templates=_interopRequireDefault(_templates);class Component extends _reactive.BaseComponent{create(){this.name="contenttabs",this.selectors={TAB:"ul:first-of-type li",CHILDTAB:"ul:nth-child(2) li",SECTION_ITEM:"a.nav-link"},this.classes={ACTIVETAB:"active"},this.tabs={},this.childtabs={},this.activetab=[null,null],this.originalsinglesectionid=document.querySelector("ul.sections").dataset.originalsinglesectionid}static init(target){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)()})}stateReady(){this._indexContents()}getWatchers(){return[{watch:"course.sectionlist:updated",handler:this._refreshCourseSectionTabs}]}async _refreshCourseSectionTabs(_ref){let{element:element}=_ref;const originalSingleSection=this.reactive.get("section",this.originalsinglesectionid);let singleSectionId,singleSection,newActiveTab0id;originalSingleSection?(singleSectionId=originalSingleSection.levelsan<2?originalSingleSection.id:originalSingleSection.pageid,singleSection=singleSectionId==originalSingleSection.id?originalSingleSection:this.reactive.get("section",singleSectionId)):(singleSectionId=null,singleSection=null),newActiveTab0id=singleSection?singleSection.levelsan>=1?singleSection.parentid:singleSection.id:null;let tabsSecondRowDom=this.element.querySelector("ul:nth-of-type(2)");const tabsSecondRowShow=singleSection&&(element.tabsdata.length>1||element.tabsdata[0].subtree.length>1);if(tabsSecondRowShow&&!tabsSecondRowDom){this.element.querySelector("ul:first-of-type").insertAdjacentElement("afterend",tabsSecondRowDom=document.createElement("ul")),tabsSecondRowDom.className="nav nav-tabs mb-3";const addTab0Dom=this.element.querySelector("ul:first-of-type li:last-of-type");let data={level:1,active:!1,inactive:!1,link:[{link:addTab0Dom.querySelector("a").getAttribute("href").replace(/\binsertlevel=0\b/,"insertlevel=1")}],title:addTab0Dom.getAttribute("title"),text:''},item=document.createElement("li");tabsSecondRowDom.insertAdjacentElement("beforeend",item);let html=await _templates.default.render("format_multitopic/courseformat/contenttabs/tab",data);item=_templates.default.replaceNode(item,html,"")[0]}else tabsSecondRowDom&&!tabsSecondRowShow&&tabsSecondRowDom.remove();let toptabslist=[],childtabslist=[];for(let tabdata of element.tabsdata)if(toptabslist.push(tabdata.sectionid),tabdata.sectionid==newActiveTab0id)for(let tabdata2 of tabdata.subtree)childtabslist.push(tabdata2.sectionid);let toptabs=this.element.querySelector("ul:first-of-type");if(await this._fixOrder(toptabs,toptabslist,this.selectors.TAB,0,childtabslist.length>1),tabsSecondRowShow){let childtabs=this.element.querySelector("ul:nth-of-type(2)");await this._fixOrder(childtabs,childtabslist,this.selectors.CHILDTAB,1,!1)}this._changeActiveTabs(newActiveTab0id,tabsSecondRowShow?singleSection.id:null),this._indexContents()}_changeActiveTabs(newActiveTab0id,newActiveTab1id){if(newActiveTab0id!=this.activetab[0]){var _this$element$querySe,_this$element$querySe2;let anchor=null===(_this$element$querySe=this.element.querySelector('ul:first-of-type div[data-itemid="'+this.activetab[0]+'"]'))||void 0===_this$element$querySe?void 0:_this$element$querySe.parentElement;if(anchor){let section=this.reactive.get("section",this.activetab[0]);anchor.classList.remove("active"),anchor.href=section.sectionurl.replace("&","&")}if(this.activetab[0]=newActiveTab0id,anchor=null===(_this$element$querySe2=this.element.querySelector('ul:first-of-type div[data-itemid="'+this.activetab[0]+'"]'))||void 0===_this$element$querySe2?void 0:_this$element$querySe2.parentElement,anchor&&(anchor.classList.add("active"),anchor.removeAttribute("href")),newActiveTab1id){const addAnchor=this.element.querySelector("ul:nth-of-type(2) li:last-of-type a"),addLink=addAnchor.href.replace(/\binsertparentid=\d+\b/,"insertparentid="+this.activetab[0]);addAnchor.setAttribute("href",addLink)}}if(newActiveTab1id&&newActiveTab1id!=this.activetab[1]){var _this$element$querySe3,_this$element$querySe4;let anchor=null===(_this$element$querySe3=this.element.querySelector('ul:nth-of-type(2) div[data-itemid="'+this.activetab[1]+'"]'))||void 0===_this$element$querySe3?void 0:_this$element$querySe3.parentElement;if(anchor){let section=this.reactive.get("section",this.activetab[1]);anchor.classList.remove("active"),anchor.href=section.sectionurl.replace("&","&")}this.activetab[1]=newActiveTab1id,anchor=null===(_this$element$querySe4=this.element.querySelector('ul:nth-of-type(2) div[data-itemid="'+this.activetab[1]+'"]'))||void 0===_this$element$querySe4?void 0:_this$element$querySe4.parentElement,anchor&&(anchor.classList.add("active"),anchor.removeAttribute("href"))}this.activetab[1]=newActiveTab1id}_indexContents(){this._scanIndex(this.selectors.TAB,this.tabs,(item=>new _tab.default(item)),0),this._scanIndex(this.selectors.CHILDTAB,this.childtabs,(item=>new _tab.default(item)),1)}_scanIndex(selector,index,creationhandler,level){this.getElements("".concat(selector,":not([data-indexed])")).forEach((item=>{var _item$dataset;if(null==item||null===(_item$dataset=item.dataset)||void 0===_item$dataset||!_item$dataset.id)return;void 0!==index[item.dataset.id]&&index[item.dataset.id].unregister(),index[item.dataset.id]=creationhandler({...this,element:item}),item.querySelector("a").classList.contains(this.classes.ACTIVETAB)&&(this.activetab[level]=item.dataset.id),item.dataset.indexed=!0}))}async _fixOrder(container,neworder,selector,level,hassubtree){if(!neworder.length)return container.classList.add("hidden"),void(container.innerHTML="");container.classList.remove("hidden");for(const[index,itemid]of Object.entries(neworder)){const section=this.reactive.get("section",itemid),visible=(section.visible&§ion.available||0==section.section)&&(neworder.length>1||hassubtree),current=null!=section.currentnestedlevel&§ion.currentnestedlevel>=level;let item=this.getElement(selector,itemid);if(null===item){let data={sectionid:itemid,level:level,active:0,inactive:0,link:[{link:section.sectionurl}],title:section.name,text:'
'+section.title+"
"};item=document.createElement("li"),container.insertBefore(item,container.lastElementChild);let html=await _templates.default.render("format_multitopic/courseformat/contenttabs/tab",data);item=_templates.default.replaceNode(item,html,"")[0]}const content=item.querySelector("div.tab_content");content&&content.classList.contains("dimmed")==visible&&(visible?content.classList.remove("dimmed"):content.classList.add("dimmed")),content&&content.classList.contains("marker")!=current&&(current?content.classList.add("marker"):content.classList.remove("marker"));const currentitem=container.children[index];if(void 0===currentitem)return void container.append(item);currentitem!==item&&container.insertBefore(item,currentitem)}for(;container.children.length>neworder.length+1;)container.removeChild(container.lastElementChild.previousSibling)}}return _exports.default=Component,_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_tab=_interopRequireDefault(_tab),_templates=_interopRequireDefault(_templates);class Component extends _reactive.BaseComponent{create(){this.name="contenttabs",this.selectors={TAB:"ul:first-of-type li",CHILDTAB:"ul:nth-child(2) li",SECTION_ITEM:"a.nav-link"},this.classes={ACTIVETAB:"active"},this.tabs={},this.childtabs={},this.activetab=[null,null],this.originalsinglesectionid=document.querySelector("ul.sections").dataset.originalsinglesectionid}static init(target){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)()})}stateReady(){this._indexContents()}getWatchers(){return[{watch:"course.sectionlist:updated",handler:this._refreshCourseSectionTabs}]}async _refreshCourseSectionTabs(_ref){let{element:element}=_ref;const originalSingleSection=this.reactive.get("section",this.originalsinglesectionid);let singleSectionId,singleSection,newActiveTab0id;originalSingleSection?(singleSectionId=originalSingleSection.levelsan<2?originalSingleSection.id:originalSingleSection.pageid,singleSection=singleSectionId==originalSingleSection.id?originalSingleSection:this.reactive.get("section",singleSectionId)):(singleSectionId=null,singleSection=null),newActiveTab0id=singleSection?singleSection.levelsan>=1?singleSection.parentid:singleSection.id:null;let tabsSecondRowDom=this.element.querySelector("ul:nth-of-type(2)");const tabsSecondRowShow=singleSection&&(element.tabsdata.length>1||element.tabsdata[0].subtree.length>1);if(tabsSecondRowShow&&!tabsSecondRowDom){this.element.querySelector("ul:first-of-type").insertAdjacentElement("afterend",tabsSecondRowDom=document.createElement("ul")),tabsSecondRowDom.className="nav nav-tabs mb-3";const addTab0Dom=this.element.querySelector("ul:first-of-type li:last-of-type");let data={level:1,active:!1,inactive:!1,link:[{link:addTab0Dom.querySelector("a").getAttribute("href").replace(/\binsertlevel=0\b/,"insertlevel=1")}],title:addTab0Dom.getAttribute("title"),text:''},item=document.createElement("li");tabsSecondRowDom.insertAdjacentElement("beforeend",item);let html=await _templates.default.render("format_multitopic/courseformat/contenttabs/tab",data);item=_templates.default.replaceNode(item,html,"")[0]}else tabsSecondRowDom&&!tabsSecondRowShow&&tabsSecondRowDom.remove();let toptabslist=[],childtabslist=[];for(let tabdata of element.tabsdata)if(toptabslist.push(tabdata.sectionid),tabdata.sectionid==newActiveTab0id)for(let tabdata2 of tabdata.subtree)childtabslist.push(tabdata2.sectionid);let toptabs=this.element.querySelector("ul:first-of-type");if(await this._fixOrder(toptabs,toptabslist,this.selectors.TAB,0,element.tabsdata[0].subtree.length>1),tabsSecondRowShow){let childtabs=this.element.querySelector("ul:nth-of-type(2)");await this._fixOrder(childtabs,childtabslist,this.selectors.CHILDTAB,1,!1)}this._changeActiveTabs(newActiveTab0id,tabsSecondRowShow?singleSection.id:null),this._indexContents()}_changeActiveTabs(newActiveTab0id,newActiveTab1id){if(newActiveTab0id!=this.activetab[0]){var _this$element$querySe,_this$element$querySe2;let anchor=null===(_this$element$querySe=this.element.querySelector('ul:first-of-type div[data-itemid="'+this.activetab[0]+'"]'))||void 0===_this$element$querySe?void 0:_this$element$querySe.parentElement;if(anchor){let section=this.reactive.get("section",this.activetab[0]);anchor.classList.remove("active"),anchor.href=section.sectionurl.replace("&","&")}if(this.activetab[0]=newActiveTab0id,anchor=null===(_this$element$querySe2=this.element.querySelector('ul:first-of-type div[data-itemid="'+this.activetab[0]+'"]'))||void 0===_this$element$querySe2?void 0:_this$element$querySe2.parentElement,anchor&&(anchor.classList.add("active"),anchor.removeAttribute("href")),newActiveTab1id){const addAnchor=this.element.querySelector("ul:nth-of-type(2) li:last-of-type a"),addLink=addAnchor.href.replace(/\binsertparentid=\d+\b/,"insertparentid="+this.activetab[0]);addAnchor.setAttribute("href",addLink)}}if(newActiveTab1id&&newActiveTab1id!=this.activetab[1]){var _this$element$querySe3,_this$element$querySe4;let anchor=null===(_this$element$querySe3=this.element.querySelector('ul:nth-of-type(2) div[data-itemid="'+this.activetab[1]+'"]'))||void 0===_this$element$querySe3?void 0:_this$element$querySe3.parentElement;if(anchor){let section=this.reactive.get("section",this.activetab[1]);anchor.classList.remove("active"),anchor.href=section.sectionurl.replace("&","&")}this.activetab[1]=newActiveTab1id,anchor=null===(_this$element$querySe4=this.element.querySelector('ul:nth-of-type(2) div[data-itemid="'+this.activetab[1]+'"]'))||void 0===_this$element$querySe4?void 0:_this$element$querySe4.parentElement,anchor&&(anchor.classList.add("active"),anchor.removeAttribute("href"))}this.activetab[1]=newActiveTab1id}_indexContents(){this._scanIndex(this.selectors.TAB,this.tabs,(item=>new _tab.default(item)),0),this._scanIndex(this.selectors.CHILDTAB,this.childtabs,(item=>new _tab.default(item)),1)}_scanIndex(selector,index,creationhandler,level){this.getElements("".concat(selector,":not([data-indexed])")).forEach((item=>{var _item$dataset;if(null==item||null===(_item$dataset=item.dataset)||void 0===_item$dataset||!_item$dataset.id)return;void 0!==index[item.dataset.id]&&index[item.dataset.id].unregister(),index[item.dataset.id]=creationhandler({...this,element:item}),item.querySelector("a").classList.contains(this.classes.ACTIVETAB)&&(this.activetab[level]=item.dataset.id),item.dataset.indexed=!0}))}async _fixOrder(container,neworder,selector,level,hassubtree){if(!neworder.length)return container.classList.add("hidden"),void(container.innerHTML="");container.classList.remove("hidden");for(const[index,itemid]of Object.entries(neworder)){const section=this.reactive.get("section",itemid),visible=(section.visible&§ion.available||0==section.section)&&(neworder.length>1||hassubtree),current=null!=section.currentnestedlevel&§ion.currentnestedlevel>=level;let item=this.getElement(selector,itemid);if(null===item){let data={sectionid:itemid,level:level,active:0,inactive:0,link:[{link:section.sectionurl}],title:section.name,text:'
'+section.title+"
"};item=document.createElement("li"),container.insertBefore(item,container.lastElementChild);let html=await _templates.default.render("format_multitopic/courseformat/contenttabs/tab",data);item=_templates.default.replaceNode(item,html,"")[0]}const content=item.querySelector("div.tab_content");content&&content.classList.contains("dimmed")==visible&&(visible?content.classList.remove("dimmed"):content.classList.add("dimmed")),content&&content.classList.contains("marker")!=current&&(current?content.classList.add("marker"):content.classList.remove("marker"));const currentitem=container.children[index];if(void 0===currentitem)return void container.append(item);currentitem!==item&&container.insertBefore(item,currentitem)}for(;container.children.length>neworder.length+1;)container.removeChild(container.lastElementChild.previousSibling)}}return _exports.default=Component,_exports.default})); //# sourceMappingURL=tabtree.min.js.map \ No newline at end of file diff --git a/amd/build/courseformat/contenttabs/tabtree.min.js.map b/amd/build/courseformat/contenttabs/tabtree.min.js.map index a55ec1a..d67a776 100644 --- a/amd/build/courseformat/contenttabs/tabtree.min.js.map +++ b/amd/build/courseformat/contenttabs/tabtree.min.js.map @@ -1 +1 @@ -{"version":3,"file":"tabtree.min.js","sources":["../../../src/courseformat/contenttabs/tabtree.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 {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport Tab from 'format_multitopic/courseformat/contenttabs/tab';\nimport Templates from 'core/templates';\n\n\n/**\n * Course section tabs updater.\n *\n * @module format_multitopic/courseformat/contenttabs/tabtree\n * @class format_multitopic/courseformat/contenttabs/tabtree\n * @copyright 2022 Jeremy FitzPatrick and Te Wānanga o Aotearoa\n * @copyright 2023 onwards James Calder and Otago Polytechnic\n * @copyright based on work by 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'contenttabs';\n // Default query selectors.\n this.selectors = {\n TAB: `ul:first-of-type li`,\n CHILDTAB: `ul:nth-child(2) li`,\n SECTION_ITEM: `a.nav-link`,\n };\n // Default classes\n this.classes = {\n ACTIVETAB: 'active'\n };\n // Objects to keep tabs on the tabs\n this.tabs = {};\n this.childtabs = {};\n this.activetab = [null, null];\n\n this.originalsinglesectionid = document.querySelector(\"ul.sections\").dataset.originalsinglesectionid;\n }\n\n static init(target) {\n return new this({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n });\n }\n\n /**\n * Initial state ready method.\n *\n */\n stateReady() {\n this._indexContents();\n }\n\n getWatchers() {\n return [\n // Sections sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionTabs},\n ];\n }\n\n /**\n * Refresh the section tabs.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n async _refreshCourseSectionTabs({element}) {\n\n const originalSingleSection = this.reactive.get(\"section\", this.originalsinglesectionid);\n let singleSectionId;\n let singleSection;\n if (originalSingleSection) {\n singleSectionId = (originalSingleSection.levelsan < 2) ? originalSingleSection.id : originalSingleSection.pageid;\n singleSection = (singleSectionId == originalSingleSection.id) ?\n originalSingleSection : this.reactive.get(\"section\", singleSectionId);\n } else {\n singleSectionId = null;\n singleSection = null;\n }\n\n let newActiveTab0id;\n if (singleSection) {\n newActiveTab0id = (singleSection.levelsan >= 1) ? singleSection.parentid : singleSection.id;\n } else {\n newActiveTab0id = null;\n }\n\n // Add/remove the second-level tabs, if necessary.\n let tabsSecondRowDom = this.element.querySelector('ul:nth-of-type(2)');\n const tabsSecondRowShow = singleSection\n && ((element.tabsdata.length > 1)\n || (element.tabsdata[0].subtree.length > 1));\n if (tabsSecondRowShow && !tabsSecondRowDom) {\n // Create tab row.\n this.element.querySelector('ul:first-of-type').insertAdjacentElement(\n 'afterend', tabsSecondRowDom = document.createElement('ul')\n );\n tabsSecondRowDom.className = 'nav nav-tabs mb-3';\n // Create add tab.\n const addTab0Dom = this.element.querySelector('ul:first-of-type li:last-of-type');\n let data = {\n \"level\": 1,\n \"active\": false,\n \"inactive\": false,\n \"link\": [{\n \"link\": addTab0Dom.querySelector('a').getAttribute('href').replace(/\\binsertlevel=0\\b/, 'insertlevel=1'),\n }],\n \"title\": addTab0Dom.getAttribute('title'),\n \"text\": '',\n };\n let item = document.createElement(\"li\");\n tabsSecondRowDom.insertAdjacentElement('beforeend', item);\n let html = await Templates.render(\"format_multitopic/courseformat/contenttabs/tab\", data);\n item = Templates.replaceNode(item, html, \"\")[0];\n } else if (tabsSecondRowDom && !tabsSecondRowShow) {\n tabsSecondRowDom.remove();\n }\n\n let toptabslist = [];\n let childtabslist = [];\n for (let tabdata of element.tabsdata) {\n toptabslist.push(tabdata.sectionid);\n if (tabdata.sectionid == newActiveTab0id) {\n for (let tabdata2 of tabdata.subtree) {\n childtabslist.push(tabdata2.sectionid);\n }\n }\n }\n\n // Do things that make the first row tabs match firstsectionlist.\n let toptabs = this.element.querySelector('ul:first-of-type');\n await this._fixOrder(toptabs, toptabslist, this.selectors.TAB, 0, childtabslist.length > 1);\n\n // And the second row tabs match secondsectionlist.\n if (tabsSecondRowShow) {\n let childtabs = this.element.querySelector('ul:nth-of-type(2)');\n await this._fixOrder(childtabs, childtabslist, this.selectors.CHILDTAB, 1, false);\n }\n\n this._changeActiveTabs(newActiveTab0id, tabsSecondRowShow ? singleSection.id : null);\n\n this._indexContents();\n }\n\n /**\n * Change active tabs, if necessary.\n *\n * @param {int|null} newActiveTab0id\n * @param {int|null} newActiveTab1id\n */\n _changeActiveTabs(newActiveTab0id, newActiveTab1id) {\n\n // Change the active top-level tab, if necessary.\n if (newActiveTab0id != this.activetab[0]) {\n let anchor = this.element.querySelector('ul:first-of-type div[data-itemid=\"' + this.activetab[0] + '\"]')?.parentElement;\n if (anchor) {\n let section = this.reactive.get(\"section\", this.activetab[0]);\n anchor.classList.remove(\"active\");\n anchor.href = section.sectionurl.replace(\"&\", \"&\");\n }\n this.activetab[0] = newActiveTab0id;\n anchor = this.element.querySelector('ul:first-of-type div[data-itemid=\"' + this.activetab[0] + '\"]')?.parentElement;\n if (anchor) {\n anchor.classList.add(\"active\");\n anchor.removeAttribute(\"href\");\n }\n // Change the second-level add tab, if necessary.\n if (newActiveTab1id) {\n const addAnchor = this.element.querySelector('ul:nth-of-type(2) li:last-of-type a');\n const addLink = addAnchor.href.replace(/\\binsertparentid=\\d+\\b/, \"insertparentid=\" + this.activetab[0]);\n addAnchor.setAttribute(\"href\", addLink);\n }\n }\n\n // Change the active second-level tab, if necessary.\n if (newActiveTab1id && newActiveTab1id != this.activetab[1]) {\n let anchor = this.element.querySelector('ul:nth-of-type(2) div[data-itemid=\"' + this.activetab[1] + '\"]')\n ?.parentElement;\n if (anchor) {\n let section = this.reactive.get(\"section\", this.activetab[1]);\n anchor.classList.remove(\"active\");\n anchor.href = section.sectionurl.replace(\"&\", \"&\");\n }\n this.activetab[1] = newActiveTab1id;\n anchor = this.element.querySelector('ul:nth-of-type(2) div[data-itemid=\"' + this.activetab[1] + '\"]')?.parentElement;\n if (anchor) {\n anchor.classList.add(\"active\");\n anchor.removeAttribute(\"href\");\n }\n }\n this.activetab[1] = newActiveTab1id;\n\n }\n\n /**\n * Regenerate content indexes.\n *\n * This method is used when a legacy action refresh some content element.\n */\n _indexContents() {\n // Find unindexed tabs.\n this._scanIndex(\n this.selectors.TAB,\n this.tabs,\n (item) => {\n return new Tab(item);\n },\n 0\n );\n\n // Find unindexed child tabs.\n this._scanIndex(\n this.selectors.CHILDTAB,\n this.childtabs,\n (item) => {\n return new Tab(item);\n },\n 1\n );\n }\n\n /**\n * Reindex a tab.\n *\n * This method is used internally by _indexContents.\n *\n * @param {string} selector the DOM selector to scan\n * @param {*} index the index attribute to update\n * @param {*} creationhandler method to create a new indexed element\n * @param {int} level tab level\n */\n _scanIndex(selector, index, creationhandler, level) {\n const items = this.getElements(`${selector}:not([data-indexed])`);\n items.forEach((item) => {\n if (!item?.dataset?.id) {\n return;\n }\n // Delete previous item component.\n if (index[item.dataset.id] !== undefined) {\n index[item.dataset.id].unregister();\n }\n // Create the new component.\n index[item.dataset.id] = creationhandler({\n ...this,\n element: item,\n });\n // Update selected tab\n let classes = item.querySelector(\"a\").classList;\n if (classes.contains(this.classes.ACTIVETAB)) {\n this.activetab[level] = item.dataset.id;\n }\n // Mark as indexed.\n item.dataset.indexed = true;\n });\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {string} selector the element selector\n * @param {int} level the tab level\n * @param {boolean} hassubtree\n */\n async _fixOrder(container, neworder, selector, level, hassubtree) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n for (const [index, itemid] of Object.entries(neworder)) {\n const section = this.reactive.get(\"section\", itemid);\n const visible = (section.visible && section.available || section.section == 0)\n && (neworder.length > 1 || hassubtree);\n const current = (section.currentnestedlevel != undefined && section.currentnestedlevel >= level);\n let item = this.getElement(selector, itemid);\n if (item === null) {\n // If we don't have an item, create it.\n let data = {\n \"sectionid\": itemid,\n \"level\": level,\n \"active\": 0,\n \"inactive\": 0,\n \"link\": [{\n \"link\": section.sectionurl\n }],\n \"title\": section.name,\n \"text\": '
' + section.title + '
'\n };\n item = document.createElement(\"li\");\n container.insertBefore(item, container.lastElementChild);\n let html = await Templates.render(\"format_multitopic/courseformat/contenttabs/tab\", data);\n item = Templates.replaceNode(item, html, \"\")[0];\n }\n\n // Update visibility & current marker\n const content = item.querySelector(\"div.tab_content\");\n if (content && content.classList.contains(\"dimmed\") == visible) {\n if (visible) {\n content.classList.remove(\"dimmed\");\n } else {\n content.classList.add(\"dimmed\");\n }\n }\n if (content && content.classList.contains(\"marker\") != current) {\n if (current) {\n content.classList.add(\"marker\");\n } else {\n content.classList.remove(\"marker\");\n }\n }\n\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n }\n // Remove the remaining elements.\n // But we don't want the \"Add\" blown away.\n while (container.children.length > neworder.length + 1) {\n container.removeChild(container.lastElementChild.previousSibling);\n }\n\n }\n\n}"],"names":["Component","BaseComponent","create","name","selectors","TAB","CHILDTAB","SECTION_ITEM","classes","ACTIVETAB","tabs","childtabs","activetab","originalsinglesectionid","document","querySelector","dataset","target","this","element","getElementById","reactive","stateReady","_indexContents","getWatchers","watch","handler","_refreshCourseSectionTabs","originalSingleSection","get","singleSectionId","singleSection","newActiveTab0id","levelsan","id","pageid","parentid","tabsSecondRowDom","tabsSecondRowShow","tabsdata","length","subtree","insertAdjacentElement","createElement","className","addTab0Dom","data","getAttribute","replace","item","html","Templates","render","replaceNode","remove","toptabslist","childtabslist","tabdata","push","sectionid","tabdata2","toptabs","_fixOrder","_changeActiveTabs","newActiveTab1id","anchor","_this$element$querySe","parentElement","section","classList","href","sectionurl","_this$element$querySe2","add","removeAttribute","addAnchor","addLink","setAttribute","_this$element$querySe3","_this$element$querySe4","_scanIndex","Tab","selector","index","creationhandler","level","getElements","forEach","_item$dataset","undefined","unregister","contains","indexed","container","neworder","hassubtree","innerHTML","itemid","Object","entries","visible","available","current","currentnestedlevel","getElement","title","insertBefore","lastElementChild","content","currentitem","children","append","removeChild","previousSibling"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"tabtree.min.js","sources":["../../../src/courseformat/contenttabs/tabtree.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 {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport Tab from 'format_multitopic/courseformat/contenttabs/tab';\nimport Templates from 'core/templates';\n\n\n/**\n * Course section tabs updater.\n *\n * @module format_multitopic/courseformat/contenttabs/tabtree\n * @class format_multitopic/courseformat/contenttabs/tabtree\n * @copyright 2022 Jeremy FitzPatrick and Te Wānanga o Aotearoa\n * @copyright 2023 onwards James Calder and Otago Polytechnic\n * @copyright based on work by 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'contenttabs';\n // Default query selectors.\n this.selectors = {\n TAB: `ul:first-of-type li`,\n CHILDTAB: `ul:nth-child(2) li`,\n SECTION_ITEM: `a.nav-link`,\n };\n // Default classes\n this.classes = {\n ACTIVETAB: 'active'\n };\n // Objects to keep tabs on the tabs\n this.tabs = {};\n this.childtabs = {};\n this.activetab = [null, null];\n\n this.originalsinglesectionid = document.querySelector(\"ul.sections\").dataset.originalsinglesectionid;\n }\n\n static init(target) {\n return new this({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n });\n }\n\n /**\n * Initial state ready method.\n *\n */\n stateReady() {\n this._indexContents();\n }\n\n getWatchers() {\n return [\n // Sections sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionTabs},\n ];\n }\n\n /**\n * Refresh the section tabs.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n async _refreshCourseSectionTabs({element}) {\n\n const originalSingleSection = this.reactive.get(\"section\", this.originalsinglesectionid);\n let singleSectionId;\n let singleSection;\n if (originalSingleSection) {\n singleSectionId = (originalSingleSection.levelsan < 2) ? originalSingleSection.id : originalSingleSection.pageid;\n singleSection = (singleSectionId == originalSingleSection.id) ?\n originalSingleSection : this.reactive.get(\"section\", singleSectionId);\n } else {\n singleSectionId = null;\n singleSection = null;\n }\n\n let newActiveTab0id;\n if (singleSection) {\n newActiveTab0id = (singleSection.levelsan >= 1) ? singleSection.parentid : singleSection.id;\n } else {\n newActiveTab0id = null;\n }\n\n // Add/remove the second-level tabs, if necessary.\n let tabsSecondRowDom = this.element.querySelector('ul:nth-of-type(2)');\n const tabsSecondRowShow = singleSection\n && ((element.tabsdata.length > 1)\n || (element.tabsdata[0].subtree.length > 1));\n if (tabsSecondRowShow && !tabsSecondRowDom) {\n // Create tab row.\n this.element.querySelector('ul:first-of-type').insertAdjacentElement(\n 'afterend', tabsSecondRowDom = document.createElement('ul')\n );\n tabsSecondRowDom.className = 'nav nav-tabs mb-3';\n // Create add tab.\n const addTab0Dom = this.element.querySelector('ul:first-of-type li:last-of-type');\n let data = {\n \"level\": 1,\n \"active\": false,\n \"inactive\": false,\n \"link\": [{\n \"link\": addTab0Dom.querySelector('a').getAttribute('href').replace(/\\binsertlevel=0\\b/, 'insertlevel=1'),\n }],\n \"title\": addTab0Dom.getAttribute('title'),\n \"text\": '',\n };\n let item = document.createElement(\"li\");\n tabsSecondRowDom.insertAdjacentElement('beforeend', item);\n let html = await Templates.render(\"format_multitopic/courseformat/contenttabs/tab\", data);\n item = Templates.replaceNode(item, html, \"\")[0];\n } else if (tabsSecondRowDom && !tabsSecondRowShow) {\n tabsSecondRowDom.remove();\n }\n\n let toptabslist = [];\n let childtabslist = [];\n for (let tabdata of element.tabsdata) {\n toptabslist.push(tabdata.sectionid);\n if (tabdata.sectionid == newActiveTab0id) {\n for (let tabdata2 of tabdata.subtree) {\n childtabslist.push(tabdata2.sectionid);\n }\n }\n }\n\n // Do things that make the first row tabs match firstsectionlist.\n let toptabs = this.element.querySelector('ul:first-of-type');\n await this._fixOrder(toptabs, toptabslist, this.selectors.TAB, 0, element.tabsdata[0].subtree.length > 1);\n\n // And the second row tabs match secondsectionlist.\n if (tabsSecondRowShow) {\n let childtabs = this.element.querySelector('ul:nth-of-type(2)');\n await this._fixOrder(childtabs, childtabslist, this.selectors.CHILDTAB, 1, false);\n }\n\n this._changeActiveTabs(newActiveTab0id, tabsSecondRowShow ? singleSection.id : null);\n\n this._indexContents();\n }\n\n /**\n * Change active tabs, if necessary.\n *\n * @param {int|null} newActiveTab0id\n * @param {int|null} newActiveTab1id\n */\n _changeActiveTabs(newActiveTab0id, newActiveTab1id) {\n\n // Change the active top-level tab, if necessary.\n if (newActiveTab0id != this.activetab[0]) {\n let anchor = this.element.querySelector('ul:first-of-type div[data-itemid=\"' + this.activetab[0] + '\"]')?.parentElement;\n if (anchor) {\n let section = this.reactive.get(\"section\", this.activetab[0]);\n anchor.classList.remove(\"active\");\n anchor.href = section.sectionurl.replace(\"&\", \"&\");\n }\n this.activetab[0] = newActiveTab0id;\n anchor = this.element.querySelector('ul:first-of-type div[data-itemid=\"' + this.activetab[0] + '\"]')?.parentElement;\n if (anchor) {\n anchor.classList.add(\"active\");\n anchor.removeAttribute(\"href\");\n }\n // Change the second-level add tab, if necessary.\n if (newActiveTab1id) {\n const addAnchor = this.element.querySelector('ul:nth-of-type(2) li:last-of-type a');\n const addLink = addAnchor.href.replace(/\\binsertparentid=\\d+\\b/, \"insertparentid=\" + this.activetab[0]);\n addAnchor.setAttribute(\"href\", addLink);\n }\n }\n\n // Change the active second-level tab, if necessary.\n if (newActiveTab1id && newActiveTab1id != this.activetab[1]) {\n let anchor = this.element.querySelector('ul:nth-of-type(2) div[data-itemid=\"' + this.activetab[1] + '\"]')\n ?.parentElement;\n if (anchor) {\n let section = this.reactive.get(\"section\", this.activetab[1]);\n anchor.classList.remove(\"active\");\n anchor.href = section.sectionurl.replace(\"&\", \"&\");\n }\n this.activetab[1] = newActiveTab1id;\n anchor = this.element.querySelector('ul:nth-of-type(2) div[data-itemid=\"' + this.activetab[1] + '\"]')?.parentElement;\n if (anchor) {\n anchor.classList.add(\"active\");\n anchor.removeAttribute(\"href\");\n }\n }\n this.activetab[1] = newActiveTab1id;\n\n }\n\n /**\n * Regenerate content indexes.\n *\n * This method is used when a legacy action refresh some content element.\n */\n _indexContents() {\n // Find unindexed tabs.\n this._scanIndex(\n this.selectors.TAB,\n this.tabs,\n (item) => {\n return new Tab(item);\n },\n 0\n );\n\n // Find unindexed child tabs.\n this._scanIndex(\n this.selectors.CHILDTAB,\n this.childtabs,\n (item) => {\n return new Tab(item);\n },\n 1\n );\n }\n\n /**\n * Reindex a tab.\n *\n * This method is used internally by _indexContents.\n *\n * @param {string} selector the DOM selector to scan\n * @param {*} index the index attribute to update\n * @param {*} creationhandler method to create a new indexed element\n * @param {int} level tab level\n */\n _scanIndex(selector, index, creationhandler, level) {\n const items = this.getElements(`${selector}:not([data-indexed])`);\n items.forEach((item) => {\n if (!item?.dataset?.id) {\n return;\n }\n // Delete previous item component.\n if (index[item.dataset.id] !== undefined) {\n index[item.dataset.id].unregister();\n }\n // Create the new component.\n index[item.dataset.id] = creationhandler({\n ...this,\n element: item,\n });\n // Update selected tab\n let classes = item.querySelector(\"a\").classList;\n if (classes.contains(this.classes.ACTIVETAB)) {\n this.activetab[level] = item.dataset.id;\n }\n // Mark as indexed.\n item.dataset.indexed = true;\n });\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {string} selector the element selector\n * @param {int} level the tab level\n * @param {boolean} hassubtree\n */\n async _fixOrder(container, neworder, selector, level, hassubtree) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n for (const [index, itemid] of Object.entries(neworder)) {\n const section = this.reactive.get(\"section\", itemid);\n const visible = (section.visible && section.available || section.section == 0)\n && (neworder.length > 1 || hassubtree);\n const current = (section.currentnestedlevel != undefined && section.currentnestedlevel >= level);\n let item = this.getElement(selector, itemid);\n if (item === null) {\n // If we don't have an item, create it.\n let data = {\n \"sectionid\": itemid,\n \"level\": level,\n \"active\": 0,\n \"inactive\": 0,\n \"link\": [{\n \"link\": section.sectionurl\n }],\n \"title\": section.name,\n \"text\": '
' + section.title + '
'\n };\n item = document.createElement(\"li\");\n container.insertBefore(item, container.lastElementChild);\n let html = await Templates.render(\"format_multitopic/courseformat/contenttabs/tab\", data);\n item = Templates.replaceNode(item, html, \"\")[0];\n }\n\n // Update visibility & current marker\n const content = item.querySelector(\"div.tab_content\");\n if (content && content.classList.contains(\"dimmed\") == visible) {\n if (visible) {\n content.classList.remove(\"dimmed\");\n } else {\n content.classList.add(\"dimmed\");\n }\n }\n if (content && content.classList.contains(\"marker\") != current) {\n if (current) {\n content.classList.add(\"marker\");\n } else {\n content.classList.remove(\"marker\");\n }\n }\n\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n }\n // Remove the remaining elements.\n // But we don't want the \"Add\" blown away.\n while (container.children.length > neworder.length + 1) {\n container.removeChild(container.lastElementChild.previousSibling);\n }\n\n }\n\n}"],"names":["Component","BaseComponent","create","name","selectors","TAB","CHILDTAB","SECTION_ITEM","classes","ACTIVETAB","tabs","childtabs","activetab","originalsinglesectionid","document","querySelector","dataset","target","this","element","getElementById","reactive","stateReady","_indexContents","getWatchers","watch","handler","_refreshCourseSectionTabs","originalSingleSection","get","singleSectionId","singleSection","newActiveTab0id","levelsan","id","pageid","parentid","tabsSecondRowDom","tabsSecondRowShow","tabsdata","length","subtree","insertAdjacentElement","createElement","className","addTab0Dom","data","getAttribute","replace","item","html","Templates","render","replaceNode","remove","toptabslist","childtabslist","tabdata","push","sectionid","tabdata2","toptabs","_fixOrder","_changeActiveTabs","newActiveTab1id","anchor","_this$element$querySe","parentElement","section","classList","href","sectionurl","_this$element$querySe2","add","removeAttribute","addAnchor","addLink","setAttribute","_this$element$querySe3","_this$element$querySe4","_scanIndex","Tab","selector","index","creationhandler","level","getElements","forEach","_item$dataset","undefined","unregister","contains","indexed","container","neworder","hassubtree","innerHTML","itemid","Object","entries","visible","available","current","currentnestedlevel","getElement","title","insertBefore","lastElementChild","content","currentitem","children","append","removeChild","previousSibling"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/courseformat/courseindex/courseindex.min.js b/amd/build/courseformat/courseindex/courseindex.min.js index 83650a6..ba83e6f 100644 --- a/amd/build/courseformat/courseindex/courseindex.min.js +++ b/amd/build/courseformat/courseindex/courseindex.min.js @@ -8,6 +8,6 @@ define("format_multitopic/courseformat/courseindex/courseindex",["exports","core * @copyright 2022 Jeremy FitzPatrick and Te Wānanga o Aotearoa * @copyright based on work by 2021 Ferran Recio * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_courseindex=(obj=_courseindex)&&obj.__esModule?obj:{default:obj};class Component extends _courseindex.default{static init(target,selectors){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}_refreshCourseSectionlist(param){const element=param.state?param.state.course:param.element;let containers=[],containerlevels=[];const newcontainer={indent:-1,container:this.element,order:[]};containers.push(newcontainer),containerlevels.push(newcontainer);for(let sectionid of element.sectionlist){const section=this.reactive.get("section",sectionid);for(;containerlevels[containerlevels.length-1].indent>=section.indent;)containerlevels.pop();containerlevels[containerlevels.length-1].order.push(section.id);const newcontainer={indent:section.indent,container:this.sections[section.id].querySelector(":scope > .courseindex-item-content > .subsections"),order:[]};containers.push(newcontainer),containerlevels.push(newcontainer)}for(;containerlevels.length>0;)containerlevels.pop();for(let container of containers)this._fixOrder(container.container,container.order,this.sections);for(let sectionid of element.sectionlist){const section=this.reactive.get("section",sectionid),sectionDom=this.sections[sectionid],sectiontitledom=sectionDom.querySelector(":scope > .courseindex-item");sectiontitledom&&(sectiontitledom.style="padding-left: "+section.indent+"em;");const sectioncontentdom=sectionDom.querySelector(":scope > .courseindex-item-content > .courseindex-sectioncontent");sectioncontentdom&&(sectioncontentdom.style="padding-left: "+section.indent+"em;");const linkDom=sectionDom.querySelector("a.courseindex-link");if(linkDom){const link=section.sectionurl.replace("&","&");linkDom.href!=link&&(linkDom.href=link)}}}async _createSection(_ref){let{state:state,element:element}=_ref;const fakeelement=document.createElement("div");fakeelement.dataset.id=element.id,fakeelement.dataset.for="section",fakeelement.dataset.indent=element.indent,fakeelement.classList.add("bg-pulse-grey","w-100"),fakeelement.innerHTML=" ";const fakecontent=document.createElement("div");fakeelement.insertAdjacentElement("beforeend",fakecontent),fakecontent.setAttribute("class","courseindex-item-content");const fakesubsections=document.createElement("div");fakecontent.insertAdjacentElement("beforeend",fakesubsections),fakesubsections.setAttribute("class","subsections"),this.sections[element.id]=fakeelement,this._refreshCourseSectionlist({state:state,element:state.course});const data=this.reactive.getExporter().section(state,element),newelement=(await this.renderComponent(fakeelement,"format_multitopic/courseformat/courseindex/section",data)).getElement();this.sections[element.id]=newelement,fakeelement.parentNode.replaceChild(newelement,fakeelement),fakesubsections.children.length>0&&newelement.querySelector(".courseindex-item-content .subsections").replaceWith(fakesubsections)}}return _exports.default=Component,_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_courseindex=(obj=_courseindex)&&obj.__esModule?obj:{default:obj};class Component extends _courseindex.default{static init(target,selectors){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}_refreshCourseSectionlist(param){const element=param.state?param.state.course:param.element;let containers=[],containerlevels=[];const newcontainer={indent:-1,container:this.element,order:[]};containers.push(newcontainer),containerlevels.push(newcontainer);for(let sectionid of element.sectionlist){const section=this.reactive.get("section",sectionid);for(;containerlevels[containerlevels.length-1].indent>=section.indent;)containerlevels.pop();containerlevels[containerlevels.length-1].order.push(section.id);const newcontainer={indent:section.indent,container:this.sections[section.id].querySelector(":scope > .courseindex-item-content > .subsections"),order:[]};containers.push(newcontainer),containerlevels.push(newcontainer)}for(;containerlevels.length>0;)containerlevels.pop();for(let container of containers)this._fixOrder(container.container,container.order,this.sections);for(let sectionid of element.sectionlist){var _sectionDom$dataset;const section=this.reactive.get("section",sectionid),sectionDom=this.sections[sectionid];if((null===(_sectionDom$dataset=sectionDom.dataset)||void 0===_sectionDom$dataset?void 0:_sectionDom$dataset.indent)!=section.indent){const sectiontitledom=sectionDom.querySelector(":scope > .courseindex-item");sectiontitledom&&(sectiontitledom.style="padding-left: "+section.indent+"em;");const sectioncontentdom=sectionDom.querySelector(":scope > .courseindex-item-content > .courseindex-sectioncontent");sectioncontentdom&&(sectioncontentdom.style="padding-left: "+section.indent+"em;"),sectionDom.dataset.indent=section.indent}const linkDom=sectionDom.querySelector(":scope > .courseindex-item a.courseindex-link");if(linkDom){const link=section.sectionurl.replace("&","&");linkDom.href!=link&&(linkDom.href=link)}}}async _createSection(_ref){let{state:state,element:element}=_ref;const fakeelement=document.createElement("div");fakeelement.dataset.id=element.id,fakeelement.dataset.for="section",fakeelement.classList.add("bg-pulse-grey","w-100"),fakeelement.innerHTML=" ";const fakecontent=document.createElement("div");fakeelement.insertAdjacentElement("beforeend",fakecontent),fakecontent.setAttribute("class","courseindex-item-content");const fakesubsections=document.createElement("div");fakecontent.insertAdjacentElement("beforeend",fakesubsections),fakesubsections.setAttribute("class","subsections"),this.sections[element.id]=fakeelement,this._refreshCourseSectionlist({state:state,element:state.course});const data=this.reactive.getExporter().section(state,element),newelement=(await this.renderComponent(fakeelement,"format_multitopic/courseformat/courseindex/section",data)).getElement();this.sections[element.id]=newelement,fakeelement.parentNode.replaceChild(newelement,fakeelement),fakesubsections.children.length>0&&newelement.querySelector(".courseindex-item-content .subsections").replaceWith(fakesubsections)}}return _exports.default=Component,_exports.default})); //# sourceMappingURL=courseindex.min.js.map \ No newline at end of file diff --git a/amd/build/courseformat/courseindex/courseindex.min.js.map b/amd/build/courseformat/courseindex/courseindex.min.js.map index 84e4bfc..10aacc9 100644 --- a/amd/build/courseformat/courseindex/courseindex.min.js.map +++ b/amd/build/courseformat/courseindex/courseindex.min.js.map @@ -1 +1 @@ -{"version":3,"file":"courseindex.min.js","sources":["../../../src/courseformat/courseindex/courseindex.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 * Course index main component.\n *\n * @module format_multitopic/courseformat/courseindex/courseindex\n * @class format_multitopic/courseformat/courseindex/courseindex\n * @copyright 2022 onwards James Calder and Otago Polytechnic\n * @copyright 2022 Jeremy FitzPatrick and Te Wānanga o Aotearoa\n * @copyright based on work by 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BaseComponent from 'core_courseformat/local/courseindex/courseindex';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|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.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element (Moodle <4.4)\n * @param {Object} param.state (Moodle >=4.4)\n */\n _refreshCourseSectionlist(param) {\n const element = param.state ? param.state.course : param.element;\n\n let containers = [];\n let containerlevels = [];\n const newcontainer = {indent: -1, container: this.element, order: []};\n containers.push(newcontainer);\n containerlevels.push(newcontainer);\n\n for (let sectionid of element.sectionlist) {\n const section = this.reactive.get(\"section\", sectionid);\n while (containerlevels[containerlevels.length - 1].indent >= section.indent) {\n containerlevels.pop();\n }\n containerlevels[containerlevels.length - 1].order.push(section.id);\n const newcontainer = {\n indent: section.indent,\n container: this.sections[section.id].querySelector(\":scope > .courseindex-item-content > .subsections\"),\n order: []\n };\n containers.push(newcontainer);\n containerlevels.push(newcontainer);\n }\n while (containerlevels.length > 0) {\n containerlevels.pop();\n }\n\n for (let container of containers) {\n this._fixOrder(container.container, container.order, this.sections);\n }\n\n // Update indentation and URLs.\n for (let sectionid of element.sectionlist) {\n const section = this.reactive.get(\"section\", sectionid);\n const sectionDom = this.sections[sectionid];\n const sectiontitledom = sectionDom.querySelector(\":scope > .courseindex-item\");\n if (sectiontitledom) {\n sectiontitledom.style = \"padding-left: \" + section.indent + \"em;\";\n }\n const sectioncontentdom = sectionDom.querySelector(\":scope > .courseindex-item-content > .courseindex-sectioncontent\");\n if (sectioncontentdom) {\n sectioncontentdom.style = \"padding-left: \" + section.indent + \"em;\";\n }\n const linkDom = sectionDom.querySelector(\"a.courseindex-link\");\n if (linkDom) {\n const link = section.sectionurl.replace(\"&\", \"&\");\n if (linkDom.href != link) {\n linkDom.href = link;\n }\n }\n }\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.dataset.id = element.id;\n fakeelement.dataset.for = \"section\";\n fakeelement.dataset.indent = element.indent;\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n const fakecontent = document.createElement('div');\n fakeelement.insertAdjacentElement(\"beforeend\", fakecontent);\n fakecontent.setAttribute(\"class\", \"courseindex-item-content\");\n const fakesubsections = document.createElement('div');\n fakecontent.insertAdjacentElement(\"beforeend\", fakesubsections);\n fakesubsections.setAttribute(\"class\", \"subsections\");\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'format_multitopic/courseformat/courseindex/section', data);\n // CHANGED LINE ABOVE.\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n if (fakesubsections.children.length > 0) {\n newelement.querySelector(\".courseindex-item-content .subsections\").replaceWith(fakesubsections);\n }\n }\n\n}"],"names":["Component","BaseComponent","target","selectors","this","element","document","getElementById","reactive","_refreshCourseSectionlist","param","state","course","containers","containerlevels","newcontainer","indent","container","order","push","sectionid","sectionlist","section","get","length","pop","id","sections","querySelector","_fixOrder","sectionDom","sectiontitledom","style","sectioncontentdom","linkDom","link","sectionurl","replace","href","fakeelement","createElement","dataset","for","classList","add","innerHTML","fakecontent","insertAdjacentElement","setAttribute","fakesubsections","data","getExporter","newelement","renderComponent","getElement","parentNode","replaceChild","children","replaceWith"],"mappings":";;;;;;;;;;6JA6BqBA,kBAAkBC,iCAStBC,OAAQC,kBACV,IAAIC,KAAK,CACZC,QAASC,SAASC,eAAeL,QACjCM,UAAU,0CACVL,UAAAA,YAWRM,0BAA0BC,aAChBL,QAAUK,MAAMC,MAAQD,MAAMC,MAAMC,OAASF,MAAML,YAErDQ,WAAa,GACbC,gBAAkB,SAChBC,aAAe,CAACC,QAAS,EAAGC,UAAWb,KAAKC,QAASa,MAAO,IAClEL,WAAWM,KAAKJ,cAChBD,gBAAgBK,KAAKJ,kBAEhB,IAAIK,aAAaf,QAAQgB,YAAa,OACjCC,QAAUlB,KAAKI,SAASe,IAAI,UAAWH,gBACtCN,gBAAgBA,gBAAgBU,OAAS,GAAGR,QAAUM,QAAQN,QACjEF,gBAAgBW,MAEpBX,gBAAgBA,gBAAgBU,OAAS,GAAGN,MAAMC,KAAKG,QAAQI,UACzDX,aAAe,CACjBC,OAAQM,QAAQN,OAChBC,UAAWb,KAAKuB,SAASL,QAAQI,IAAIE,cAAc,qDACnDV,MAAO,IAEXL,WAAWM,KAAKJ,cAChBD,gBAAgBK,KAAKJ,mBAElBD,gBAAgBU,OAAS,GAC5BV,gBAAgBW,UAGf,IAAIR,aAAaJ,gBACbgB,UAAUZ,UAAUA,UAAWA,UAAUC,MAAOd,KAAKuB,cAIzD,IAAIP,aAAaf,QAAQgB,YAAa,OACjCC,QAAUlB,KAAKI,SAASe,IAAI,UAAWH,WACvCU,WAAa1B,KAAKuB,SAASP,WAC3BW,gBAAkBD,WAAWF,cAAc,8BAC7CG,kBACAA,gBAAgBC,MAAQ,iBAAmBV,QAAQN,OAAS,aAE1DiB,kBAAoBH,WAAWF,cAAc,oEAC/CK,oBACAA,kBAAkBD,MAAQ,iBAAmBV,QAAQN,OAAS,aAE5DkB,QAAUJ,WAAWF,cAAc,yBACrCM,QAAS,OACHC,KAAOb,QAAQc,WAAWC,QAAQ,QAAS,KAC7CH,QAAQI,MAAQH,OAChBD,QAAQI,KAAOH,uCAaVxB,MAACA,MAADN,QAAQA,oBAEnBkC,YAAcjC,SAASkC,cAAc,OAC3CD,YAAYE,QAAQf,GAAKrB,QAAQqB,GACjCa,YAAYE,QAAQC,IAAM,UAC1BH,YAAYE,QAAQzB,OAASX,QAAQW,OACrCuB,YAAYI,UAAUC,IAAI,gBAAiB,SAC3CL,YAAYM,UAAY,eAClBC,YAAcxC,SAASkC,cAAc,OAC3CD,YAAYQ,sBAAsB,YAAaD,aAC/CA,YAAYE,aAAa,QAAS,kCAC5BC,gBAAkB3C,SAASkC,cAAc,OAC/CM,YAAYC,sBAAsB,YAAaE,iBAC/CA,gBAAgBD,aAAa,QAAS,oBACjCrB,SAAStB,QAAQqB,IAAMa,iBAEvB9B,0BAA0B,CAC3BE,MAAAA,MACAN,QAASM,MAAMC,eAIbsC,KADW9C,KAAKI,SAAS2C,cACT7B,QAAQX,MAAON,SAK/B+C,kBAHqBhD,KAAKiD,gBAAgBd,YAAa,qDAAsDW,OAGnFI,kBAC3B3B,SAAStB,QAAQqB,IAAM0B,WAC5Bb,YAAYgB,WAAWC,aAAaJ,WAAYb,aAC5CU,gBAAgBQ,SAASjC,OAAS,GAClC4B,WAAWxB,cAAc,0CAA0C8B,YAAYT"} \ No newline at end of file +{"version":3,"file":"courseindex.min.js","sources":["../../../src/courseformat/courseindex/courseindex.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 * Course index main component.\n *\n * @module format_multitopic/courseformat/courseindex/courseindex\n * @class format_multitopic/courseformat/courseindex/courseindex\n * @copyright 2022 onwards James Calder and Otago Polytechnic\n * @copyright 2022 Jeremy FitzPatrick and Te Wānanga o Aotearoa\n * @copyright based on work by 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BaseComponent from 'core_courseformat/local/courseindex/courseindex';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|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.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element (Moodle <4.4)\n * @param {Object} param.state (Moodle >=4.4)\n */\n _refreshCourseSectionlist(param) {\n const element = param.state ? param.state.course : param.element;\n\n let containers = [];\n let containerlevels = [];\n const newcontainer = {indent: -1, container: this.element, order: []};\n containers.push(newcontainer);\n containerlevels.push(newcontainer);\n\n for (let sectionid of element.sectionlist) {\n const section = this.reactive.get(\"section\", sectionid);\n while (containerlevels[containerlevels.length - 1].indent >= section.indent) {\n containerlevels.pop();\n }\n containerlevels[containerlevels.length - 1].order.push(section.id);\n const newcontainer = {\n indent: section.indent,\n container: this.sections[section.id].querySelector(\":scope > .courseindex-item-content > .subsections\"),\n order: []\n };\n containers.push(newcontainer);\n containerlevels.push(newcontainer);\n }\n while (containerlevels.length > 0) {\n containerlevels.pop();\n }\n\n for (let container of containers) {\n this._fixOrder(container.container, container.order, this.sections);\n }\n\n // Update indentation and URLs.\n for (let sectionid of element.sectionlist) {\n const section = this.reactive.get(\"section\", sectionid);\n const sectionDom = this.sections[sectionid];\n if (sectionDom.dataset?.indent != section.indent) {\n const sectiontitledom = sectionDom.querySelector(\":scope > .courseindex-item\");\n if (sectiontitledom) {\n sectiontitledom.style = \"padding-left: \" + section.indent + \"em;\";\n }\n const sectioncontentdom = sectionDom.querySelector(\n \":scope > .courseindex-item-content > .courseindex-sectioncontent\"\n );\n if (sectioncontentdom) {\n sectioncontentdom.style = \"padding-left: \" + section.indent + \"em;\";\n }\n sectionDom.dataset.indent = section.indent;\n }\n const linkDom = sectionDom.querySelector(\":scope > .courseindex-item a.courseindex-link\");\n if (linkDom) {\n const link = section.sectionurl.replace(\"&\", \"&\");\n if (linkDom.href != link) {\n linkDom.href = link;\n }\n }\n }\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.dataset.id = element.id;\n fakeelement.dataset.for = \"section\";\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n const fakecontent = document.createElement('div');\n fakeelement.insertAdjacentElement(\"beforeend\", fakecontent);\n fakecontent.setAttribute(\"class\", \"courseindex-item-content\");\n const fakesubsections = document.createElement('div');\n fakecontent.insertAdjacentElement(\"beforeend\", fakesubsections);\n fakesubsections.setAttribute(\"class\", \"subsections\");\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'format_multitopic/courseformat/courseindex/section', data);\n // CHANGED LINE ABOVE.\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n if (fakesubsections.children.length > 0) {\n newelement.querySelector(\".courseindex-item-content .subsections\").replaceWith(fakesubsections);\n }\n }\n\n}"],"names":["Component","BaseComponent","target","selectors","this","element","document","getElementById","reactive","_refreshCourseSectionlist","param","state","course","containers","containerlevels","newcontainer","indent","container","order","push","sectionid","sectionlist","section","get","length","pop","id","sections","querySelector","_fixOrder","sectionDom","dataset","sectiontitledom","style","sectioncontentdom","linkDom","link","sectionurl","replace","href","fakeelement","createElement","for","classList","add","innerHTML","fakecontent","insertAdjacentElement","setAttribute","fakesubsections","data","getExporter","newelement","renderComponent","getElement","parentNode","replaceChild","children","replaceWith"],"mappings":";;;;;;;;;;6JA6BqBA,kBAAkBC,iCAStBC,OAAQC,kBACV,IAAIC,KAAK,CACZC,QAASC,SAASC,eAAeL,QACjCM,UAAU,0CACVL,UAAAA,YAWRM,0BAA0BC,aAChBL,QAAUK,MAAMC,MAAQD,MAAMC,MAAMC,OAASF,MAAML,YAErDQ,WAAa,GACbC,gBAAkB,SAChBC,aAAe,CAACC,QAAS,EAAGC,UAAWb,KAAKC,QAASa,MAAO,IAClEL,WAAWM,KAAKJ,cAChBD,gBAAgBK,KAAKJ,kBAEhB,IAAIK,aAAaf,QAAQgB,YAAa,OACjCC,QAAUlB,KAAKI,SAASe,IAAI,UAAWH,gBACtCN,gBAAgBA,gBAAgBU,OAAS,GAAGR,QAAUM,QAAQN,QACjEF,gBAAgBW,MAEpBX,gBAAgBA,gBAAgBU,OAAS,GAAGN,MAAMC,KAAKG,QAAQI,UACzDX,aAAe,CACjBC,OAAQM,QAAQN,OAChBC,UAAWb,KAAKuB,SAASL,QAAQI,IAAIE,cAAc,qDACnDV,MAAO,IAEXL,WAAWM,KAAKJ,cAChBD,gBAAgBK,KAAKJ,mBAElBD,gBAAgBU,OAAS,GAC5BV,gBAAgBW,UAGf,IAAIR,aAAaJ,gBACbgB,UAAUZ,UAAUA,UAAWA,UAAUC,MAAOd,KAAKuB,cAIzD,IAAIP,aAAaf,QAAQgB,YAAa,+BACjCC,QAAUlB,KAAKI,SAASe,IAAI,UAAWH,WACvCU,WAAa1B,KAAKuB,SAASP,2CAC7BU,WAAWC,kEAASf,SAAUM,QAAQN,OAAQ,OACxCgB,gBAAkBF,WAAWF,cAAc,8BAC7CI,kBACAA,gBAAgBC,MAAQ,iBAAmBX,QAAQN,OAAS,aAE1DkB,kBAAoBJ,WAAWF,cACjC,oEAEAM,oBACAA,kBAAkBD,MAAQ,iBAAmBX,QAAQN,OAAS,OAElEc,WAAWC,QAAQf,OAASM,QAAQN,aAElCmB,QAAUL,WAAWF,cAAc,oDACrCO,QAAS,OACHC,KAAOd,QAAQe,WAAWC,QAAQ,QAAS,KAC7CH,QAAQI,MAAQH,OAChBD,QAAQI,KAAOH,uCAaVzB,MAACA,MAADN,QAAQA,oBAEnBmC,YAAclC,SAASmC,cAAc,OAC3CD,YAAYT,QAAQL,GAAKrB,QAAQqB,GACjCc,YAAYT,QAAQW,IAAM,UAC1BF,YAAYG,UAAUC,IAAI,gBAAiB,SAC3CJ,YAAYK,UAAY,eAClBC,YAAcxC,SAASmC,cAAc,OAC3CD,YAAYO,sBAAsB,YAAaD,aAC/CA,YAAYE,aAAa,QAAS,kCAC5BC,gBAAkB3C,SAASmC,cAAc,OAC/CK,YAAYC,sBAAsB,YAAaE,iBAC/CA,gBAAgBD,aAAa,QAAS,oBACjCrB,SAAStB,QAAQqB,IAAMc,iBAEvB/B,0BAA0B,CAC3BE,MAAAA,MACAN,QAASM,MAAMC,eAIbsC,KADW9C,KAAKI,SAAS2C,cACT7B,QAAQX,MAAON,SAK/B+C,kBAHqBhD,KAAKiD,gBAAgBb,YAAa,qDAAsDU,OAGnFI,kBAC3B3B,SAAStB,QAAQqB,IAAM0B,WAC5BZ,YAAYe,WAAWC,aAAaJ,WAAYZ,aAC5CS,gBAAgBQ,SAASjC,OAAS,GAClC4B,WAAWxB,cAAc,0CAA0C8B,YAAYT"} \ No newline at end of file diff --git a/amd/src/courseformat/contenttabs/tabtree.js b/amd/src/courseformat/contenttabs/tabtree.js index 4bca6f5..74307f5 100644 --- a/amd/src/courseformat/contenttabs/tabtree.js +++ b/amd/src/courseformat/contenttabs/tabtree.js @@ -149,7 +149,7 @@ export default class Component extends BaseComponent { // Do things that make the first row tabs match firstsectionlist. let toptabs = this.element.querySelector('ul:first-of-type'); - await this._fixOrder(toptabs, toptabslist, this.selectors.TAB, 0, childtabslist.length > 1); + await this._fixOrder(toptabs, toptabslist, this.selectors.TAB, 0, element.tabsdata[0].subtree.length > 1); // And the second row tabs match secondsectionlist. if (tabsSecondRowShow) { diff --git a/amd/src/courseformat/courseindex/courseindex.js b/amd/src/courseformat/courseindex/courseindex.js index 7cd4350..aa11388 100644 --- a/amd/src/courseformat/courseindex/courseindex.js +++ b/amd/src/courseformat/courseindex/courseindex.js @@ -86,15 +86,20 @@ export default class Component extends BaseComponent { for (let sectionid of element.sectionlist) { const section = this.reactive.get("section", sectionid); const sectionDom = this.sections[sectionid]; - const sectiontitledom = sectionDom.querySelector(":scope > .courseindex-item"); - if (sectiontitledom) { - sectiontitledom.style = "padding-left: " + section.indent + "em;"; - } - const sectioncontentdom = sectionDom.querySelector(":scope > .courseindex-item-content > .courseindex-sectioncontent"); - if (sectioncontentdom) { - sectioncontentdom.style = "padding-left: " + section.indent + "em;"; + if (sectionDom.dataset?.indent != section.indent) { + const sectiontitledom = sectionDom.querySelector(":scope > .courseindex-item"); + if (sectiontitledom) { + sectiontitledom.style = "padding-left: " + section.indent + "em;"; + } + const sectioncontentdom = sectionDom.querySelector( + ":scope > .courseindex-item-content > .courseindex-sectioncontent" + ); + if (sectioncontentdom) { + sectioncontentdom.style = "padding-left: " + section.indent + "em;"; + } + sectionDom.dataset.indent = section.indent; } - const linkDom = sectionDom.querySelector("a.courseindex-link"); + const linkDom = sectionDom.querySelector(":scope > .courseindex-item a.courseindex-link"); if (linkDom) { const link = section.sectionurl.replace("&", "&"); if (linkDom.href != link) { @@ -116,7 +121,6 @@ export default class Component extends BaseComponent { const fakeelement = document.createElement('div'); fakeelement.dataset.id = element.id; fakeelement.dataset.for = "section"; - fakeelement.dataset.indent = element.indent; fakeelement.classList.add('bg-pulse-grey', 'w-100'); fakeelement.innerHTML = ' '; const fakecontent = document.createElement('div');