diff --git a/docs/core/makeup-screenreader-trap/index.min.js b/docs/core/makeup-screenreader-trap/index.min.js index 53d5a53f..4c47b911 100644 --- a/docs/core/makeup-screenreader-trap/index.min.js +++ b/docs/core/makeup-screenreader-trap/index.min.js @@ -149,29 +149,23 @@ const filterAncestor = item => item.nodeType === 1 && item.tagName.toLowerCase() // filter function for sibling elements const filterSibling = item => item.nodeType === 1 && item.tagName.toLowerCase() !== "script"; - -// recursive function to get previous sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees function getPreviousSiblings(el) { - let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const previousSibling = el.previousSibling; - if (!previousSibling) { - return siblings; + const siblings = []; + let current = el.previousSibling; + while (current) { + siblings.push(current); + current = current.previousSibling; } - siblings.push(previousSibling); - return getPreviousSiblings(previousSibling, siblings); + return siblings; } - -// recursive function to get next sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees function getNextSiblings(el) { - let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const nextSibling = el.nextSibling; - if (!nextSibling) { - return siblings; + const siblings = []; + let current = el.nextSibling; + while (current) { + siblings.push(current); + current = current.nextSibling; } - siblings.push(nextSibling); - return getNextSiblings(nextSibling, siblings); + return siblings; } // returns all sibling element nodes of given element @@ -180,20 +174,15 @@ function getSiblings(el) { return allSiblings.filter(filterSibling); } -// recursive function to get all ancestor nodes of given element -function getAllAncestors(el) { - let ancestors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const nextAncestor = el.parentNode; - if (!nextAncestor) { - return ancestors; - } - ancestors.push(nextAncestor); - return getAllAncestors(nextAncestor, ancestors); -} - // get ancestor nodes of given element function getAncestors(el) { - return getAllAncestors(el).filter(filterAncestor); + const ancestors = []; + let current = el.parentNode; + while (current) { + ancestors.push(current); + current = current.parentNode; + } + return ancestors.filter(filterAncestor); } // get siblings of ancestors (i.e. aunts and uncles) of given el diff --git a/docs/core/makeup-screenreader-trap/index.min.js.map b/docs/core/makeup-screenreader-trap/index.min.js.map index ef8d76fd..4236c288 100644 --- a/docs/core/makeup-screenreader-trap/index.min.js.map +++ b/docs/core/makeup-screenreader-trap/index.min.js.map @@ -1 +1 @@ -{"version":3,"file":"makeup-screenreader-trap/index.min.js","mappings":";;;;;;;AAAa;;AAEb,8CAA6C;AAC7C;AACA,CAAC,EAAC;AACF,YAAY;AACZ,cAAc;AACd,mCAAmC,mBAAO,CAAC,GAAW;AACtD,yCAAyC,4EAA4E,oDAAoD,uCAAuC,gBAAgB,+BAA+B,4EAA4E,qBAAqB,+BAA+B,eAAe,wCAAwC,2JAA2J,WAAW;AAC5lB;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;AC3Ha;;AAEb,8CAA6C;AAC7C;AACA,CAAC,EAAC;AACF,oBAAoB;AACpB,mBAAmB;AACnB,8BAA8B;AAC9B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;UC/DA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;ACtBa;;AAEb,8BAA8B,mBAAO,CAAC,GAA0B;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH,CAAC;AACD;AACA;AACA;AACA;AACA,CAAC,E","sources":["webpack://root/./packages/core/makeup-screenreader-trap/dist/cjs/index.js","webpack://root/./packages/core/makeup-screenreader-trap/dist/cjs/util.js","webpack://root/webpack/bootstrap","webpack://root/./docs/core/makeup-screenreader-trap/index.compiled.js"],"sourcesContent":["\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.trap = trap;\nexports.untrap = untrap;\nvar util = _interopRequireWildcard(require(\"./util.js\"));\nfunction _interopRequireWildcard(e, t) { if (\"function\" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || \"object\" != typeof e && \"function\" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) \"default\" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }\n// the main landmark\nlet mainEl;\n\n// the element that will be trapped\nlet trappedEl;\n\n// collection of elements that get 'dirtied' with aria-hidden attr or hidden prop\nlet dirtyObjects;\n\n// filter function for svg elements\nconst filterSvg = item => item.tagName.toLowerCase() !== \"svg\";\nfunction showElementPrep(el, useHiddenProperty) {\n if (useHiddenProperty === false) {\n return prepareElement(el, \"aria-hidden\", \"false\");\n } else {\n return prepareElement(el, \"hidden\", false);\n }\n}\nfunction hideElementPrep(el, useHiddenProperty) {\n if (useHiddenProperty === false) {\n return prepareElement(el, \"aria-hidden\", \"true\");\n } else {\n return prepareElement(el, \"hidden\", true);\n }\n}\nfunction prepareElement(el, attributeName, dirtyValue) {\n const isProperty = typeof dirtyValue === \"boolean\";\n return {\n el,\n attributeName,\n cleanValue: isProperty ? el[attributeName] : el.getAttribute(attributeName),\n dirtyValue,\n isProperty\n };\n}\nfunction dirtyElement(preparedObj) {\n if (preparedObj.isProperty === true) {\n preparedObj.el[preparedObj.attributeName] = preparedObj.dirtyValue;\n } else {\n preparedObj.el.setAttribute(preparedObj.attributeName, preparedObj.dirtyValue);\n }\n}\nfunction cleanElement(preparedObj) {\n if (preparedObj.cleanValue) {\n if (preparedObj.isProperty === true) {\n preparedObj.el[preparedObj.attributeName] = preparedObj.cleanValue;\n } else {\n preparedObj.el.setAttribute(preparedObj.attributeName, preparedObj.cleanValue);\n }\n } else {\n preparedObj.el.removeAttribute(preparedObj.attributeName);\n }\n}\nfunction untrap() {\n if (trappedEl) {\n // restore 'dirtied' elements to their original state\n dirtyObjects.forEach(item => cleanElement(item));\n dirtyObjects = [];\n\n // 're-enable' the main landmark\n if (mainEl) {\n mainEl.setAttribute(\"role\", \"main\");\n }\n\n // let observers know the screenreader is now untrapped\n trappedEl.dispatchEvent(new CustomEvent(\"screenreaderUntrap\", {\n bubbles: true\n }));\n trappedEl = null;\n }\n}\nconst defaultOptions = {\n useHiddenProperty: false\n};\nfunction trap(el, selectedOptions) {\n // ensure current trap is deactivated\n untrap();\n const options = {\n ...defaultOptions,\n ...selectedOptions\n };\n\n // update the trapped el reference\n trappedEl = el;\n\n // update the main landmark reference\n mainEl = document.querySelector('main, [role=\"main\"]');\n\n // we must remove the main landmark to avoid issues on voiceover iOS\n if (mainEl) {\n mainEl.setAttribute(\"role\", \"presentation\");\n }\n\n // cache all ancestors, siblings & siblings of ancestors for trappedEl\n const ancestors = util.getAncestors(trappedEl);\n let siblings = util.getSiblings(trappedEl);\n let siblingsOfAncestors = util.getSiblingsOfAncestors(trappedEl);\n\n // if using hidden property, filter out SVG elements as they do not support this property\n if (options.useHiddenProperty === true) {\n siblings = siblings.filter(filterSvg);\n siblingsOfAncestors = siblingsOfAncestors.filter(filterSvg);\n }\n\n // prepare elements\n dirtyObjects = [showElementPrep(trappedEl, options.useHiddenProperty), ...ancestors.map(item => showElementPrep(item, options.useHiddenProperty)), ...siblings.map(item => hideElementPrep(item, options.useHiddenProperty)), ...siblingsOfAncestors.map(item => hideElementPrep(item, options.useHiddenProperty))];\n\n // update DOM\n dirtyObjects.forEach(item => dirtyElement(item));\n\n // let observers know the screenreader is now trapped\n trappedEl.dispatchEvent(new CustomEvent(\"screenreaderTrap\", {\n bubbles: true\n }));\n}\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.getAncestors = getAncestors;\nexports.getSiblings = getSiblings;\nexports.getSiblingsOfAncestors = getSiblingsOfAncestors;\n// filter function for ancestor elements\nconst filterAncestor = item => item.nodeType === 1 && item.tagName.toLowerCase() !== \"body\" && item.tagName.toLowerCase() !== \"html\";\n\n// filter function for sibling elements\nconst filterSibling = item => item.nodeType === 1 && item.tagName.toLowerCase() !== \"script\";\n\n// recursive function to get previous sibling nodes of given element\n// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees\nfunction getPreviousSiblings(el) {\n let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n const previousSibling = el.previousSibling;\n if (!previousSibling) {\n return siblings;\n }\n siblings.push(previousSibling);\n return getPreviousSiblings(previousSibling, siblings);\n}\n\n// recursive function to get next sibling nodes of given element\n// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees\nfunction getNextSiblings(el) {\n let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n const nextSibling = el.nextSibling;\n if (!nextSibling) {\n return siblings;\n }\n siblings.push(nextSibling);\n return getNextSiblings(nextSibling, siblings);\n}\n\n// returns all sibling element nodes of given element\nfunction getSiblings(el) {\n const allSiblings = getPreviousSiblings(el).concat(getNextSiblings(el));\n return allSiblings.filter(filterSibling);\n}\n\n// recursive function to get all ancestor nodes of given element\nfunction getAllAncestors(el) {\n let ancestors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n const nextAncestor = el.parentNode;\n if (!nextAncestor) {\n return ancestors;\n }\n ancestors.push(nextAncestor);\n return getAllAncestors(nextAncestor, ancestors);\n}\n\n// get ancestor nodes of given element\nfunction getAncestors(el) {\n return getAllAncestors(el).filter(filterAncestor);\n}\n\n// get siblings of ancestors (i.e. aunts and uncles) of given el\nfunction getSiblingsOfAncestors(el) {\n return getAncestors(el).map(item => getSiblings(item)).flat();\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","\"use strict\";\n\nvar _makeupScreenreaderTrap = require(\"makeup-screenreader-trap\");\nconst logEl = document.getElementById(\"log\");\nfunction logEvent(eventName) {\n const item = document.createElement(\"li\");\n item.textContent = eventName;\n logEl.prepend(item);\n}\ndocument.querySelectorAll(\".trap\").forEach(btn => {\n btn.addEventListener(\"click\", () => {\n if (btn.getAttribute(\"aria-pressed\") === \"true\") {\n (0, _makeupScreenreaderTrap.untrap)();\n } else {\n (0, _makeupScreenreaderTrap.trap)(btn, {\n useHiddenProperty: btn.hasAttribute(\"data-use-hidden-property\")\n });\n }\n });\n btn.addEventListener(\"screenreaderTrap\", () => {\n btn.textContent = \"Untrap\";\n btn.setAttribute(\"aria-pressed\", \"true\");\n });\n btn.addEventListener(\"screenreaderUntrap\", () => {\n btn.textContent = \"Trap\";\n btn.setAttribute(\"aria-pressed\", \"false\");\n });\n});\ndocument.addEventListener(\"screenreaderTrap\", () => logEvent(\"screenreaderTrap\"));\ndocument.addEventListener(\"screenreaderUntrap\", () => logEvent(\"screenreaderUntrap\"));\ndocument.getElementById(\"clear\").addEventListener(\"click\", () => {\n logEl.innerHTML = \"\";\n});"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"makeup-screenreader-trap/index.min.js","mappings":";;;;;;;AAAa;;AAEb,8CAA6C;AAC7C;AACA,CAAC,EAAC;AACF,YAAY;AACZ,cAAc;AACd,mCAAmC,mBAAO,CAAC,GAAW;AACtD,yCAAyC,4EAA4E,oDAAoD,uCAAuC,gBAAgB,+BAA+B,4EAA4E,qBAAqB,+BAA+B,eAAe,wCAAwC,2JAA2J,WAAW;AAC5lB;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;AC3Ha;;AAEb,8CAA6C;AAC7C;AACA,CAAC,EAAC;AACF,oBAAoB;AACpB,mBAAmB;AACnB,8BAA8B;AAC9B;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;UCpDA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;ACtBa;;AAEb,8BAA8B,mBAAO,CAAC,GAA0B;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH,CAAC;AACD;AACA;AACA;AACA;AACA,CAAC,E","sources":["webpack://root/./packages/core/makeup-screenreader-trap/dist/cjs/index.js","webpack://root/./packages/core/makeup-screenreader-trap/dist/cjs/util.js","webpack://root/webpack/bootstrap","webpack://root/./docs/core/makeup-screenreader-trap/index.compiled.js"],"sourcesContent":["\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.trap = trap;\nexports.untrap = untrap;\nvar util = _interopRequireWildcard(require(\"./util.js\"));\nfunction _interopRequireWildcard(e, t) { if (\"function\" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || \"object\" != typeof e && \"function\" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) \"default\" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }\n// the main landmark\nlet mainEl;\n\n// the element that will be trapped\nlet trappedEl;\n\n// collection of elements that get 'dirtied' with aria-hidden attr or hidden prop\nlet dirtyObjects;\n\n// filter function for svg elements\nconst filterSvg = item => item.tagName.toLowerCase() !== \"svg\";\nfunction showElementPrep(el, useHiddenProperty) {\n if (useHiddenProperty === false) {\n return prepareElement(el, \"aria-hidden\", \"false\");\n } else {\n return prepareElement(el, \"hidden\", false);\n }\n}\nfunction hideElementPrep(el, useHiddenProperty) {\n if (useHiddenProperty === false) {\n return prepareElement(el, \"aria-hidden\", \"true\");\n } else {\n return prepareElement(el, \"hidden\", true);\n }\n}\nfunction prepareElement(el, attributeName, dirtyValue) {\n const isProperty = typeof dirtyValue === \"boolean\";\n return {\n el,\n attributeName,\n cleanValue: isProperty ? el[attributeName] : el.getAttribute(attributeName),\n dirtyValue,\n isProperty\n };\n}\nfunction dirtyElement(preparedObj) {\n if (preparedObj.isProperty === true) {\n preparedObj.el[preparedObj.attributeName] = preparedObj.dirtyValue;\n } else {\n preparedObj.el.setAttribute(preparedObj.attributeName, preparedObj.dirtyValue);\n }\n}\nfunction cleanElement(preparedObj) {\n if (preparedObj.cleanValue) {\n if (preparedObj.isProperty === true) {\n preparedObj.el[preparedObj.attributeName] = preparedObj.cleanValue;\n } else {\n preparedObj.el.setAttribute(preparedObj.attributeName, preparedObj.cleanValue);\n }\n } else {\n preparedObj.el.removeAttribute(preparedObj.attributeName);\n }\n}\nfunction untrap() {\n if (trappedEl) {\n // restore 'dirtied' elements to their original state\n dirtyObjects.forEach(item => cleanElement(item));\n dirtyObjects = [];\n\n // 're-enable' the main landmark\n if (mainEl) {\n mainEl.setAttribute(\"role\", \"main\");\n }\n\n // let observers know the screenreader is now untrapped\n trappedEl.dispatchEvent(new CustomEvent(\"screenreaderUntrap\", {\n bubbles: true\n }));\n trappedEl = null;\n }\n}\nconst defaultOptions = {\n useHiddenProperty: false\n};\nfunction trap(el, selectedOptions) {\n // ensure current trap is deactivated\n untrap();\n const options = {\n ...defaultOptions,\n ...selectedOptions\n };\n\n // update the trapped el reference\n trappedEl = el;\n\n // update the main landmark reference\n mainEl = document.querySelector('main, [role=\"main\"]');\n\n // we must remove the main landmark to avoid issues on voiceover iOS\n if (mainEl) {\n mainEl.setAttribute(\"role\", \"presentation\");\n }\n\n // cache all ancestors, siblings & siblings of ancestors for trappedEl\n const ancestors = util.getAncestors(trappedEl);\n let siblings = util.getSiblings(trappedEl);\n let siblingsOfAncestors = util.getSiblingsOfAncestors(trappedEl);\n\n // if using hidden property, filter out SVG elements as they do not support this property\n if (options.useHiddenProperty === true) {\n siblings = siblings.filter(filterSvg);\n siblingsOfAncestors = siblingsOfAncestors.filter(filterSvg);\n }\n\n // prepare elements\n dirtyObjects = [showElementPrep(trappedEl, options.useHiddenProperty), ...ancestors.map(item => showElementPrep(item, options.useHiddenProperty)), ...siblings.map(item => hideElementPrep(item, options.useHiddenProperty)), ...siblingsOfAncestors.map(item => hideElementPrep(item, options.useHiddenProperty))];\n\n // update DOM\n dirtyObjects.forEach(item => dirtyElement(item));\n\n // let observers know the screenreader is now trapped\n trappedEl.dispatchEvent(new CustomEvent(\"screenreaderTrap\", {\n bubbles: true\n }));\n}\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.getAncestors = getAncestors;\nexports.getSiblings = getSiblings;\nexports.getSiblingsOfAncestors = getSiblingsOfAncestors;\n// filter function for ancestor elements\nconst filterAncestor = item => item.nodeType === 1 && item.tagName.toLowerCase() !== \"body\" && item.tagName.toLowerCase() !== \"html\";\n\n// filter function for sibling elements\nconst filterSibling = item => item.nodeType === 1 && item.tagName.toLowerCase() !== \"script\";\nfunction getPreviousSiblings(el) {\n const siblings = [];\n let current = el.previousSibling;\n while (current) {\n siblings.push(current);\n current = current.previousSibling;\n }\n return siblings;\n}\nfunction getNextSiblings(el) {\n const siblings = [];\n let current = el.nextSibling;\n while (current) {\n siblings.push(current);\n current = current.nextSibling;\n }\n return siblings;\n}\n\n// returns all sibling element nodes of given element\nfunction getSiblings(el) {\n const allSiblings = getPreviousSiblings(el).concat(getNextSiblings(el));\n return allSiblings.filter(filterSibling);\n}\n\n// get ancestor nodes of given element\nfunction getAncestors(el) {\n const ancestors = [];\n let current = el.parentNode;\n while (current) {\n ancestors.push(current);\n current = current.parentNode;\n }\n return ancestors.filter(filterAncestor);\n}\n\n// get siblings of ancestors (i.e. aunts and uncles) of given el\nfunction getSiblingsOfAncestors(el) {\n return getAncestors(el).map(item => getSiblings(item)).flat();\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","\"use strict\";\n\nvar _makeupScreenreaderTrap = require(\"makeup-screenreader-trap\");\nconst logEl = document.getElementById(\"log\");\nfunction logEvent(eventName) {\n const item = document.createElement(\"li\");\n item.textContent = eventName;\n logEl.prepend(item);\n}\ndocument.querySelectorAll(\".trap\").forEach(btn => {\n btn.addEventListener(\"click\", () => {\n if (btn.getAttribute(\"aria-pressed\") === \"true\") {\n (0, _makeupScreenreaderTrap.untrap)();\n } else {\n (0, _makeupScreenreaderTrap.trap)(btn, {\n useHiddenProperty: btn.hasAttribute(\"data-use-hidden-property\")\n });\n }\n });\n btn.addEventListener(\"screenreaderTrap\", () => {\n btn.textContent = \"Untrap\";\n btn.setAttribute(\"aria-pressed\", \"true\");\n });\n btn.addEventListener(\"screenreaderUntrap\", () => {\n btn.textContent = \"Trap\";\n btn.setAttribute(\"aria-pressed\", \"false\");\n });\n});\ndocument.addEventListener(\"screenreaderTrap\", () => logEvent(\"screenreaderTrap\"));\ndocument.addEventListener(\"screenreaderUntrap\", () => logEvent(\"screenreaderUntrap\"));\ndocument.getElementById(\"clear\").addEventListener(\"click\", () => {\n logEl.innerHTML = \"\";\n});"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/packages/core/makeup-screenreader-trap/dist/cjs/util.js b/packages/core/makeup-screenreader-trap/dist/cjs/util.js index 8e98dad1..d8b74e84 100644 --- a/packages/core/makeup-screenreader-trap/dist/cjs/util.js +++ b/packages/core/makeup-screenreader-trap/dist/cjs/util.js @@ -11,29 +11,23 @@ const filterAncestor = item => item.nodeType === 1 && item.tagName.toLowerCase() // filter function for sibling elements const filterSibling = item => item.nodeType === 1 && item.tagName.toLowerCase() !== "script"; - -// recursive function to get previous sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees function getPreviousSiblings(el) { - let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const previousSibling = el.previousSibling; - if (!previousSibling) { - return siblings; + const siblings = []; + let current = el.previousSibling; + while (current) { + siblings.push(current); + current = current.previousSibling; } - siblings.push(previousSibling); - return getPreviousSiblings(previousSibling, siblings); + return siblings; } - -// recursive function to get next sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees function getNextSiblings(el) { - let siblings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const nextSibling = el.nextSibling; - if (!nextSibling) { - return siblings; + const siblings = []; + let current = el.nextSibling; + while (current) { + siblings.push(current); + current = current.nextSibling; } - siblings.push(nextSibling); - return getNextSiblings(nextSibling, siblings); + return siblings; } // returns all sibling element nodes of given element @@ -42,20 +36,15 @@ function getSiblings(el) { return allSiblings.filter(filterSibling); } -// recursive function to get all ancestor nodes of given element -function getAllAncestors(el) { - let ancestors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - const nextAncestor = el.parentNode; - if (!nextAncestor) { - return ancestors; - } - ancestors.push(nextAncestor); - return getAllAncestors(nextAncestor, ancestors); -} - // get ancestor nodes of given element function getAncestors(el) { - return getAllAncestors(el).filter(filterAncestor); + const ancestors = []; + let current = el.parentNode; + while (current) { + ancestors.push(current); + current = current.parentNode; + } + return ancestors.filter(filterAncestor); } // get siblings of ancestors (i.e. aunts and uncles) of given el diff --git a/packages/core/makeup-screenreader-trap/dist/mjs/util.js b/packages/core/makeup-screenreader-trap/dist/mjs/util.js index f8c4ba77..5ed0cb91 100644 --- a/packages/core/makeup-screenreader-trap/dist/mjs/util.js +++ b/packages/core/makeup-screenreader-trap/dist/mjs/util.js @@ -1,35 +1,35 @@ const filterAncestor = (item) => item.nodeType === 1 && item.tagName.toLowerCase() !== "body" && item.tagName.toLowerCase() !== "html"; const filterSibling = (item) => item.nodeType === 1 && item.tagName.toLowerCase() !== "script"; -function getPreviousSiblings(el, siblings = []) { - const previousSibling = el.previousSibling; - if (!previousSibling) { - return siblings; +function getPreviousSiblings(el) { + const siblings = []; + let current = el.previousSibling; + while (current) { + siblings.push(current); + current = current.previousSibling; } - siblings.push(previousSibling); - return getPreviousSiblings(previousSibling, siblings); + return siblings; } -function getNextSiblings(el, siblings = []) { - const nextSibling = el.nextSibling; - if (!nextSibling) { - return siblings; +function getNextSiblings(el) { + const siblings = []; + let current = el.nextSibling; + while (current) { + siblings.push(current); + current = current.nextSibling; } - siblings.push(nextSibling); - return getNextSiblings(nextSibling, siblings); + return siblings; } function getSiblings(el) { const allSiblings = getPreviousSiblings(el).concat(getNextSiblings(el)); return allSiblings.filter(filterSibling); } -function getAllAncestors(el, ancestors = []) { - const nextAncestor = el.parentNode; - if (!nextAncestor) { - return ancestors; - } - ancestors.push(nextAncestor); - return getAllAncestors(nextAncestor, ancestors); -} function getAncestors(el) { - return getAllAncestors(el).filter(filterAncestor); + const ancestors = []; + let current = el.parentNode; + while (current) { + ancestors.push(current); + current = current.parentNode; + } + return ancestors.filter(filterAncestor); } function getSiblingsOfAncestors(el) { return getAncestors(el).map((item) => getSiblings(item)).flat(); diff --git a/packages/core/makeup-screenreader-trap/src/util.js b/packages/core/makeup-screenreader-trap/src/util.js index 001d8b80..0b979308 100644 --- a/packages/core/makeup-screenreader-trap/src/util.js +++ b/packages/core/makeup-screenreader-trap/src/util.js @@ -5,32 +5,24 @@ const filterAncestor = (item) => // filter function for sibling elements const filterSibling = (item) => item.nodeType === 1 && item.tagName.toLowerCase() !== "script"; -// recursive function to get previous sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees -function getPreviousSiblings(el, siblings = []) { - const previousSibling = el.previousSibling; - - if (!previousSibling) { - return siblings; +function getPreviousSiblings(el) { + const siblings = []; + let current = el.previousSibling; + while (current) { + siblings.push(current); + current = current.previousSibling; } - - siblings.push(previousSibling); - - return getPreviousSiblings(previousSibling, siblings); + return siblings; } -// recursive function to get next sibling nodes of given element -// TODO: rewrite as iterative loop to avoid stack overflow risk in large DOM trees -function getNextSiblings(el, siblings = []) { - const nextSibling = el.nextSibling; - - if (!nextSibling) { - return siblings; +function getNextSiblings(el) { + const siblings = []; + let current = el.nextSibling; + while (current) { + siblings.push(current); + current = current.nextSibling; } - - siblings.push(nextSibling); - - return getNextSiblings(nextSibling, siblings); + return siblings; } // returns all sibling element nodes of given element @@ -40,22 +32,15 @@ function getSiblings(el) { return allSiblings.filter(filterSibling); } -// recursive function to get all ancestor nodes of given element -function getAllAncestors(el, ancestors = []) { - const nextAncestor = el.parentNode; - - if (!nextAncestor) { - return ancestors; - } - - ancestors.push(nextAncestor); - - return getAllAncestors(nextAncestor, ancestors); -} - // get ancestor nodes of given element function getAncestors(el) { - return getAllAncestors(el).filter(filterAncestor); + const ancestors = []; + let current = el.parentNode; + while (current) { + ancestors.push(current); + current = current.parentNode; + } + return ancestors.filter(filterAncestor); } // get siblings of ancestors (i.e. aunts and uncles) of given el