diff --git a/CHANGES.md b/CHANGES.md index bcdb132b654..195900d07f7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,10 @@ moodle-theme_boost_union Changes ------- +### Unreleased + +* 2024-03-18 - Improvement: Add prefixes to the sessionStorage keys in the scrollspy implementation, resolves #598. + ### v4.3-r9 * 2024-03-13 - Improvement: In smart menus, dynamic courses can now pick up the courses from all subcategories, resolves #395. diff --git a/amd/build/scrollspy.min.js b/amd/build/scrollspy.min.js index 31f0f33bef8..94c6a440a48 100644 --- a/amd/build/scrollspy.min.js +++ b/amd/build/scrollspy.min.js @@ -7,6 +7,6 @@ define("theme_boost_union/scrollspy",["exports"],(function(_exports){Object.defi * @copyright based on code from theme_fordson by Chris Kenniburg. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -const initScrollSpy=()=>{if(document.querySelector(".section.main")){let editToggle=document.querySelector("form.editmode-switch-form");if(!editToggle)return;if(editToggle.addEventListener("click",(()=>{window.sessionStorage.setItem("edittoggled",!0);let viewporttop=window.scrollY,closest=null,closestoffset=null;document.querySelectorAll(".section.main").forEach((node=>{let thisoffset=node.offsetTop;closest&&closest.offsetTop&&(closestoffset=closest.offsetTop),(null===closest||Math.abs(thisoffset-viewporttop){var callback;callback=initScrollSpy,"complete"===document.readyState||"interactive"===document.readyState?setTimeout(callback,1):document.addEventListener("DOMContentLoaded",callback)}})); +const initScrollSpy=()=>{if(document.querySelector(".section.main")){let editToggle=document.querySelector("form.editmode-switch-form");if(!editToggle)return;if(editToggle.addEventListener("click",(()=>{window.sessionStorage.setItem("theme_boost_union_scrollspy_edittoggled",!0);let viewporttop=window.scrollY,closest=null,closestoffset=null;document.querySelectorAll(".section.main").forEach((node=>{let thisoffset=node.offsetTop;closest&&closest.offsetTop&&(closestoffset=closest.offsetTop),(null===closest||Math.abs(thisoffset-viewporttop){var callback;callback=initScrollSpy,"complete"===document.readyState||"interactive"===document.readyState?setTimeout(callback,1):document.addEventListener("DOMContentLoaded",callback)}})); //# sourceMappingURL=scrollspy.min.js.map \ No newline at end of file diff --git a/amd/build/scrollspy.min.js.map b/amd/build/scrollspy.min.js.map index c51e2b44579..e29c0c88964 100644 --- a/amd/build/scrollspy.min.js.map +++ b/amd/build/scrollspy.min.js.map @@ -1 +1 @@ -{"version":3,"file":"scrollspy.min.js","sources":["../src/scrollspy.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 * Theme Boost Union - JS code scroll-spy\n *\n * @module theme_boost_union/scrollspy\n * @copyright 2022 Josha Bartsch \n * @copyright based on code from theme_fordson by Chris Kenniburg.\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Runs once at initial load, and once at editmode-switch toggle.\n * Incase of initial load, checks sessionStorage whether a position was set and jumps to the appropriate position.\n *\n * Incase of a click on the switch, iterates over central elements (selector .section.main), determines element\n * with minimal distance between pixel-toprow of view and pixel-toprow of the element.\n * Writes element ID + distance of view from element into session storage.\n *\n * Saving a reference point + relative distance grants leeway for varying page elements.\n * (See original implementation: https://raw.githubusercontent.com/dbnschools/moodle-theme_fordson/master/javascript/scrollspy.js)\n */\nconst initScrollSpy = () => {\n // Check if .section.main exist.\n if (document.querySelector('.section.main')) {\n // Unfortunately the editmode-switch carries no unique ID\n let editToggle = document.querySelector('form.editmode-switch-form');\n if (!editToggle) {\n // Do not continue when there is no edit toggle.\n return;\n }\n editToggle.addEventListener('click', () => {\n\n window.sessionStorage.setItem('edittoggled', true);\n\n let viewporttop = window.scrollY;\n let closest = null;\n let closestoffset = null;\n\n document.querySelectorAll('.section.main').forEach((node) => {\n let thisoffset = node.offsetTop;\n\n if (closest && closest.offsetTop) {\n closestoffset = closest.offsetTop;\n }\n if (closest === null || Math.abs(thisoffset - viewporttop) < Math.abs(closestoffset - viewporttop)) {\n closest = node;\n }\n });\n\n window.sessionStorage.setItem('closestid', closest.id);\n window.sessionStorage.setItem('closestdelta', viewporttop - closest.offsetTop);\n });\n let edittoggled = window.sessionStorage.getItem('edittoggled');\n if (edittoggled) {\n\n let closestid = window.sessionStorage.getItem('closestid');\n let closestdelta = window.sessionStorage.getItem('closestdelta');\n\n if (closestid && closestdelta) {\n let closest = document.getElementById(closestid);\n let y = closest.offsetTop + parseInt(closestdelta);\n\n window.scrollTo(0, y);\n }\n\n window.sessionStorage.removeItem('edittoggled');\n window.sessionStorage.removeItem('closestid');\n window.sessionStorage.removeItem('closestdelta');\n }\n }\n};\n\n/**\n * Ensures the passed function will be called after the DOM is ready/loaded:\n * Incase DOM is fully loaded when JS is called, call within next tick.\n * Otherwise sets an eventlistener for DOMEventLoaded\n *\n * @param {*} callback\n */\nconst docReady = (callback) => {\n if (document.readyState === \"complete\" || document.readyState === \"interactive\") {\n setTimeout(callback, 1);\n } else {\n document.addEventListener('DOMContentLoaded', callback);\n }\n};\n\nexport const init = () => {\n docReady(initScrollSpy);\n};\n"],"names":["initScrollSpy","document","querySelector","editToggle","addEventListener","window","sessionStorage","setItem","viewporttop","scrollY","closest","closestoffset","querySelectorAll","forEach","node","thisoffset","offsetTop","Math","abs","id","getItem","closestid","closestdelta","y","getElementById","parseInt","scrollTo","removeItem","callback","readyState","setTimeout"],"mappings":";;;;;;;;;MAmCMA,cAAgB,QAEdC,SAASC,cAAc,iBAAkB,KAErCC,WAAaF,SAASC,cAAc,iCACnCC,qBAILA,WAAWC,iBAAiB,SAAS,KAEjCC,OAAOC,eAAeC,QAAQ,eAAe,OAEzCC,YAAcH,OAAOI,QACrBC,QAAU,KACVC,cAAgB,KAEpBV,SAASW,iBAAiB,iBAAiBC,SAASC,WAC5CC,WAAaD,KAAKE,UAElBN,SAAWA,QAAQM,YACnBL,cAAgBD,QAAQM,YAEZ,OAAZN,SAAoBO,KAAKC,IAAIH,WAAaP,aAAeS,KAAKC,IAAIP,cAAgBH,gBAClFE,QAAUI,SAIlBT,OAAOC,eAAeC,QAAQ,YAAaG,QAAQS,IACnDd,OAAOC,eAAeC,QAAQ,eAAgBC,YAAcE,QAAQM,cAEtDX,OAAOC,eAAec,QAAQ,eAC/B,KAETC,UAAYhB,OAAOC,eAAec,QAAQ,aAC1CE,aAAejB,OAAOC,eAAec,QAAQ,mBAE7CC,WAAaC,aAAc,KAEvBC,EADUtB,SAASuB,eAAeH,WACtBL,UAAYS,SAASH,cAErCjB,OAAOqB,SAAS,EAAGH,GAGvBlB,OAAOC,eAAeqB,WAAW,eACjCtB,OAAOC,eAAeqB,WAAW,aACjCtB,OAAOC,eAAeqB,WAAW,iCAoBzB,KARFC,IAAAA,SAAAA,SASL5B,cARmB,aAAxBC,SAAS4B,YAAqD,gBAAxB5B,SAAS4B,WAC/CC,WAAWF,SAAU,GAErB3B,SAASG,iBAAiB,mBAAoBwB"} \ No newline at end of file +{"version":3,"file":"scrollspy.min.js","sources":["../src/scrollspy.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 * Theme Boost Union - JS code scroll-spy\n *\n * @module theme_boost_union/scrollspy\n * @copyright 2022 Josha Bartsch \n * @copyright based on code from theme_fordson by Chris Kenniburg.\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Runs once at initial load, and once at editmode-switch toggle.\n * Incase of initial load, checks sessionStorage whether a position was set and jumps to the appropriate position.\n *\n * Incase of a click on the switch, iterates over central elements (selector .section.main), determines element\n * with minimal distance between pixel-toprow of view and pixel-toprow of the element.\n * Writes element ID + distance of view from element into session storage.\n *\n * Saving a reference point + relative distance grants leeway for varying page elements.\n * (See original implementation: https://raw.githubusercontent.com/dbnschools/moodle-theme_fordson/master/javascript/scrollspy.js)\n */\nconst initScrollSpy = () => {\n // Check if .section.main exist.\n if (document.querySelector('.section.main')) {\n // Unfortunately the editmode-switch carries no unique ID\n let editToggle = document.querySelector('form.editmode-switch-form');\n if (!editToggle) {\n // Do not continue when there is no edit toggle.\n return;\n }\n editToggle.addEventListener('click', () => {\n\n window.sessionStorage.setItem('theme_boost_union_scrollspy_edittoggled', true);\n\n let viewporttop = window.scrollY;\n let closest = null;\n let closestoffset = null;\n\n document.querySelectorAll('.section.main').forEach((node) => {\n let thisoffset = node.offsetTop;\n\n if (closest && closest.offsetTop) {\n closestoffset = closest.offsetTop;\n }\n if (closest === null || Math.abs(thisoffset - viewporttop) < Math.abs(closestoffset - viewporttop)) {\n closest = node;\n }\n });\n\n window.sessionStorage.setItem('theme_boost_union_scrollspy_closestid', closest.id);\n window.sessionStorage.setItem('theme_boost_union_scrollspy_closestdelta', viewporttop - closest.offsetTop);\n });\n let edittoggled = window.sessionStorage.getItem('theme_boost_union_scrollspy_edittoggled');\n if (edittoggled) {\n\n let closestid = window.sessionStorage.getItem('theme_boost_union_scrollspy_closestid');\n let closestdelta = window.sessionStorage.getItem('theme_boost_union_scrollspy_closestdelta');\n\n if (closestid && closestdelta) {\n let closest = document.getElementById(closestid);\n let y = closest.offsetTop + parseInt(closestdelta);\n\n window.scrollTo(0, y);\n }\n\n window.sessionStorage.removeItem('theme_boost_union_scrollspy_edittoggled');\n window.sessionStorage.removeItem('theme_boost_union_scrollspy_closestid');\n window.sessionStorage.removeItem('theme_boost_union_scrollspy_closestdelta');\n }\n }\n};\n\n/**\n * Ensures the passed function will be called after the DOM is ready/loaded:\n * Incase DOM is fully loaded when JS is called, call within next tick.\n * Otherwise sets an eventlistener for DOMEventLoaded\n *\n * @param {*} callback\n */\nconst docReady = (callback) => {\n if (document.readyState === \"complete\" || document.readyState === \"interactive\") {\n setTimeout(callback, 1);\n } else {\n document.addEventListener('DOMContentLoaded', callback);\n }\n};\n\nexport const init = () => {\n docReady(initScrollSpy);\n};\n"],"names":["initScrollSpy","document","querySelector","editToggle","addEventListener","window","sessionStorage","setItem","viewporttop","scrollY","closest","closestoffset","querySelectorAll","forEach","node","thisoffset","offsetTop","Math","abs","id","getItem","closestid","closestdelta","y","getElementById","parseInt","scrollTo","removeItem","callback","readyState","setTimeout"],"mappings":";;;;;;;;;MAmCMA,cAAgB,QAEdC,SAASC,cAAc,iBAAkB,KAErCC,WAAaF,SAASC,cAAc,iCACnCC,qBAILA,WAAWC,iBAAiB,SAAS,KAEjCC,OAAOC,eAAeC,QAAQ,2CAA2C,OAErEC,YAAcH,OAAOI,QACrBC,QAAU,KACVC,cAAgB,KAEpBV,SAASW,iBAAiB,iBAAiBC,SAASC,WAC5CC,WAAaD,KAAKE,UAElBN,SAAWA,QAAQM,YACnBL,cAAgBD,QAAQM,YAEZ,OAAZN,SAAoBO,KAAKC,IAAIH,WAAaP,aAAeS,KAAKC,IAAIP,cAAgBH,gBAClFE,QAAUI,SAIlBT,OAAOC,eAAeC,QAAQ,wCAAyCG,QAAQS,IAC/Ed,OAAOC,eAAeC,QAAQ,2CAA4CC,YAAcE,QAAQM,cAElFX,OAAOC,eAAec,QAAQ,2CAC/B,KAETC,UAAYhB,OAAOC,eAAec,QAAQ,yCAC1CE,aAAejB,OAAOC,eAAec,QAAQ,+CAE7CC,WAAaC,aAAc,KAEvBC,EADUtB,SAASuB,eAAeH,WACtBL,UAAYS,SAASH,cAErCjB,OAAOqB,SAAS,EAAGH,GAGvBlB,OAAOC,eAAeqB,WAAW,2CACjCtB,OAAOC,eAAeqB,WAAW,yCACjCtB,OAAOC,eAAeqB,WAAW,6DAoBzB,KARFC,IAAAA,SAAAA,SASL5B,cARmB,aAAxBC,SAAS4B,YAAqD,gBAAxB5B,SAAS4B,WAC/CC,WAAWF,SAAU,GAErB3B,SAASG,iBAAiB,mBAAoBwB"} \ No newline at end of file diff --git a/amd/src/scrollspy.js b/amd/src/scrollspy.js index dba17cee558..234b93ac9c6 100644 --- a/amd/src/scrollspy.js +++ b/amd/src/scrollspy.js @@ -44,7 +44,7 @@ const initScrollSpy = () => { } editToggle.addEventListener('click', () => { - window.sessionStorage.setItem('edittoggled', true); + window.sessionStorage.setItem('theme_boost_union_scrollspy_edittoggled', true); let viewporttop = window.scrollY; let closest = null; @@ -61,14 +61,14 @@ const initScrollSpy = () => { } }); - window.sessionStorage.setItem('closestid', closest.id); - window.sessionStorage.setItem('closestdelta', viewporttop - closest.offsetTop); + window.sessionStorage.setItem('theme_boost_union_scrollspy_closestid', closest.id); + window.sessionStorage.setItem('theme_boost_union_scrollspy_closestdelta', viewporttop - closest.offsetTop); }); - let edittoggled = window.sessionStorage.getItem('edittoggled'); + let edittoggled = window.sessionStorage.getItem('theme_boost_union_scrollspy_edittoggled'); if (edittoggled) { - let closestid = window.sessionStorage.getItem('closestid'); - let closestdelta = window.sessionStorage.getItem('closestdelta'); + let closestid = window.sessionStorage.getItem('theme_boost_union_scrollspy_closestid'); + let closestdelta = window.sessionStorage.getItem('theme_boost_union_scrollspy_closestdelta'); if (closestid && closestdelta) { let closest = document.getElementById(closestid); @@ -77,9 +77,9 @@ const initScrollSpy = () => { window.scrollTo(0, y); } - window.sessionStorage.removeItem('edittoggled'); - window.sessionStorage.removeItem('closestid'); - window.sessionStorage.removeItem('closestdelta'); + window.sessionStorage.removeItem('theme_boost_union_scrollspy_edittoggled'); + window.sessionStorage.removeItem('theme_boost_union_scrollspy_closestid'); + window.sessionStorage.removeItem('theme_boost_union_scrollspy_closestdelta'); } } };