From a35222c55821e201baef484915f09ea6c3bfe9b0 Mon Sep 17 00:00:00 2001 From: nam-singh Date: Mon, 29 Jun 2026 18:14:36 +0530 Subject: [PATCH 1/4] fix: correct shadow DOM path generation for focus mod --- .../src/ts/contentScripts/DomPathUtils.ts | 8 +- .../ts/devtools/components/reportSection.tsx | 7 +- .../ts/devtools/components/reportTreeGrid.tsx | 3 +- .../ts/devtools/components/scanSection.tsx | 9 +- .../src/ts/devtools/devtoolsAppController.ts | 136 ++++++++++++------ .../src/ts/util/PathMatcher.ts | 32 +++++ 6 files changed, 144 insertions(+), 51 deletions(-) create mode 100644 accessibility-checker-extension/src/ts/util/PathMatcher.ts diff --git a/accessibility-checker-extension/src/ts/contentScripts/DomPathUtils.ts b/accessibility-checker-extension/src/ts/contentScripts/DomPathUtils.ts index bafbf5f0c..fee3e6229 100644 --- a/accessibility-checker-extension/src/ts/contentScripts/DomPathUtils.ts +++ b/accessibility-checker-extension/src/ts/contentScripts/DomPathUtils.ts @@ -113,8 +113,12 @@ export default class DomPathUtils { let slotParts = parts[2].match(/(slot\[\d+\])\/([^[]*)\[(\d+)\]/)!; let slot = this.docDomPathToElement(doc, parts[1]+slotParts[1]); let count = parseInt(slotParts[3]); - for (let slotIdx=0; slotIdx < (slot as any).assignedNodes().length; ++slotIdx) { - let slotNode = (slot as any).assignedNodes()[slotIdx]; + // Use assignedElements() if available, otherwise filter assignedNodes() for element nodes + let assignedElems = (slot as any).assignedElements + ? (slot as any).assignedElements() + : (slot as any).assignedNodes().filter((n: Node) => n.nodeType === 1); + for (let slotIdx=0; slotIdx < assignedElems.length; ++slotIdx) { + let slotNode = assignedElems[slotIdx]; if (slotNode.nodeName.toLowerCase() === slotParts[2].toLowerCase()) { --count; if (count === 0) { diff --git a/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx b/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx index df8d8be0c..f0d30e10d 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx @@ -26,6 +26,7 @@ import { MenuItemSelectable } from "@carbon/react"; import { UtilIssue } from '../../util/UtilIssue'; +import { PathMatcher } from '../../util/PathMatcher'; import { Information @@ -190,11 +191,11 @@ export class ReportSection extends React.Component { issue.ignored = this.state.ignoredIssues.some(ignoredIssue => issueBaselineMatch(ignoredIssue, issue)); const checked = this.devtoolsAppController.getLevelFilters(); - let retVal = ( ((checked["Hidden"] && issue.ignored) || checked[UtilIssue.valueToStringSingular(issue.value) as eFilterLevel]) + let retVal = ( ((checked["Hidden"] && issue.ignored) || checked[UtilIssue.valueToStringSingular(issue.value) as eFilterLevel]) && (!this.state.focusMode || !this.state.selectedPath - || issue.path.dom.startsWith(this.state.selectedPath) - ) + || PathMatcher.matchesPath(issue.path.dom, this.state.selectedPath) + ) ); if (!checked["Hidden"] && issue.ignored) { return false; // JCH is this an override diff --git a/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx b/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx index 54f3a0ab8..96343c90d 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx @@ -40,6 +40,7 @@ import { ePanel, getDevtoolsController, ViewState } from '../devtoolsController' import { UtilIssue } from '../../util/UtilIssue'; import { UtilIssueReact } from '../../util/UtilIssueReact'; import { getBGController, issueBaselineMatch } from '../../background/backgroundController'; +import { PathMatcher } from '../../util/PathMatcher'; export interface IRowGroup { id: string; @@ -783,7 +784,7 @@ export class ReportTreeGrid extends React.Component { for (const issue of issues) { let sing = UtilIssue.valueToStringSingular(issue.value); ++counts[sing as eLevel].total; - if (!this.state.selectedPath || issue.path.dom.startsWith(this.state.selectedPath)) { + if (!this.state.selectedPath || PathMatcher.matchesPath(issue.path.dom, this.state.selectedPath)) { ++counts[sing as eLevel].focused; } } @@ -268,12 +269,12 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { for (const ignoredIssue of this.state.ignoredIssues) { if (!issues.some(issue => issueBaselineMatch(issue, ignoredIssue))) continue; ++counts["Hidden" as eLevel].total; - if (!this.state.selectedPath || ignoredIssue.path.dom.startsWith(this.state.selectedPath)) { + if (!this.state.selectedPath || PathMatcher.matchesPath(ignoredIssue.path.dom, this.state.selectedPath)) { ++counts["Hidden" as eLevel].focused; } let sing = UtilIssue.valueToStringSingular(ignoredIssue.value); --counts[sing as eLevel].total; - if (!this.state.selectedPath || ignoredIssue.path.dom.startsWith(this.state.selectedPath)) { + if (!this.state.selectedPath || PathMatcher.matchesPath(ignoredIssue.path.dom, this.state.selectedPath)) { --counts[sing as eLevel].focused; } } @@ -300,7 +301,7 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { let retVal = (this.state.checked[UtilIssue.valueToStringSingular(issue.value) as eLevel] && (!this.state.focusMode || !this.state.selectedPath - || issue.path.dom.startsWith(this.state.selectedPath) + || PathMatcher.matchesPath(issue.path.dom, this.state.selectedPath) ) ); return retVal; diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts index b9d7980bc..733b5dacf 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts @@ -151,57 +151,111 @@ export class DevtoolsAppController { } public hookSelectionChange() { - chrome.devtools.panels.elements.onSelectionChanged.addListener(() => { - chrome.devtools.inspectedWindow.eval(`((node) => { - let countNode = (node) => { - let count = 0; - let findName = node.nodeName; - while (node) { - if (node.nodeName === findName) { - ++count; + const injectPathGenerator = () => { + chrome.devtools.inspectedWindow.eval(` + window.__getACEPath = function(node) { + function getIndex(n) { + let count = 1; + let sib = n.previousElementSibling; + while (sib) { + if (sib.localName === n.localName) count++; + sib = sib.previousElementSibling; } - node = node.previousElementSibling; + return "/" + n.localName + "[" + count + "]"; } - return "/"+findName.toLowerCase()+"["+count+"]"; - } - try { - let retVal = ""; - while (node && node.nodeType === 1) { - retVal = countNode(node)+retVal; - if (node.parentElement) { - node = node.parentElement; - } else { - let parentElement = null; - try { - // Check if we're in a shadow DOM - if (node.parentNode && node.parentNode.nodeType === 11) { - parentElement = node.parentNode.host; - retVal = "/#document-fragment[1]"+retVal; + + function getSlotIndex(slot) { + const slotName = slot.getAttribute('name') || ''; + let count = 1; + let sib = slot.previousElementSibling; + while (sib) { + if (sib.localName === 'slot') { + const sibName = sib.getAttribute('name') || ''; + if (sibName === slotName) count++; + } + sib = sib.previousElementSibling; + } + return count; + } + + try { + let segments = ""; + let current = node; + + while (current && current.nodeType === 1) { + const assignedSlot = current.assignedSlot; + + if (assignedSlot) { + segments = getIndex(current) + segments; + const slotIdx = getSlotIndex(assignedSlot); + segments = "/slot[" + slotIdx + "]" + segments; + const slotRoot = assignedSlot.getRootNode(); + if (slotRoot.nodeType === 11) { + segments = "/#document-fragment[1]" + segments; + current = slotRoot.host; } else { + break; + } + } else { + segments = getIndex(current) + segments; + let parent = current.parentNode; + + if (!parent) { // Check if we're in an iframe - let parentWin = node.ownerDocument.defaultView.parent; - let iframes = parentWin.document.documentElement.querySelectorAll("iframe"); - for (const iframe of iframes) { - try { - if (iframe.contentDocument === node.ownerDocument) { - parentElement = iframe; - break; + try { + const currentDoc = current.ownerDocument; + const parentWin = currentDoc.defaultView.parent; + if (parentWin !== currentDoc.defaultView) { + const iframes = parentWin.document.querySelectorAll("iframe"); + for (const iframe of iframes) { + try { + if (iframe.contentDocument === currentDoc) { + current = iframe; + parent = current.parentNode; + break; + } + } catch (e) {} } - } catch (e) {} - } + } + } catch (e) {} + + if (!parent) break; } - } catch (e) {} - node = parentElement; + + if (parent.nodeType === 11) { + segments = "/#document-fragment[1]" + segments; + current = parent.host; + } else if (parent.nodeType === 9) { + break; + } else if (parent.nodeType === 1) { + current = parent; + } else { + break; + } + } } + + return segments; + } catch(err) { + return ""; } - return retVal; - } catch (err) { - console.error(err); + }; + `); + }; + + injectPathGenerator(); + chrome.devtools.network.onNavigated.addListener(() => { + injectPathGenerator(); + }); + chrome.devtools.panels.elements.onSelectionChanged.addListener(() => { + chrome.devtools.inspectedWindow.eval( + `window.__getACEPath($0)`, + async (result: string) => { + await this.devToolsController.setSelectedElementPath(result, true); } - })($0)`, async (result: string) => { - await this.devToolsController.setSelectedElementPath(result, true); - }); + ); }); + chrome.devtools.inspectedWindow.eval(`inspect(document.documentElement);`); } diff --git a/accessibility-checker-extension/src/ts/util/PathMatcher.ts b/accessibility-checker-extension/src/ts/util/PathMatcher.ts new file mode 100644 index 000000000..1a0074b4c --- /dev/null +++ b/accessibility-checker-extension/src/ts/util/PathMatcher.ts @@ -0,0 +1,32 @@ +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*****************************************************************************/ + +/** + * Utility class for matching DOM paths. + */ +export class PathMatcher { + /** + * Check if a child path matches or is a descendant of a parent path. + * + * @param childPath - The path to check (e.g., issue path from scanner) + * @param parentPath - The parent path to match against (e.g., selected element path) + * @returns true if childPath matches or is a descendant of parentPath + */ + static matchesPath(childPath: string, parentPath: string): boolean { + return childPath === parentPath || childPath.startsWith(parentPath + "/"); + } +} + From 1df6376381639bdf0b8ea4404ec8a59b53ed6c68 Mon Sep 17 00:00:00 2001 From: nam-singh Date: Thu, 2 Jul 2026 19:24:49 +0530 Subject: [PATCH 2/4] Fix focus mode: correct path generation and element/descendant-only filtering --- .../ts/devtools/components/scanSection.tsx | 9 +- .../src/ts/devtools/devtoolsAppController.ts | 190 ++++++++++-------- .../src/ts/devtools/devtoolsController.ts | 51 ++--- .../src/ts/util/PathMatcher.ts | 19 +- 4 files changed, 146 insertions(+), 123 deletions(-) diff --git a/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx b/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx index 8e633d030..2a9fbfd75 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx @@ -177,6 +177,7 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { }) this.devtoolsController.addSelectedElementPathListener(async (newPath) => { this.setState( { selectedElemPath: newPath }); + this.setPath(newPath); }) this.devtoolsController.addFocusModeListener(async (newValue) => { this.setState({ focusMode: newValue }) @@ -197,10 +198,12 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { } }) this.reportListener((await this.devtoolsController.getReport())!); - this.setState({ - viewState: (await this.devtoolsController.getViewState())!, + const currentPath = (await this.devtoolsController.getSelectedElementPath())!; + this.setState({ + viewState: (await this.devtoolsController.getViewState())!, storeReports: (await this.devtoolsController.getStoreReports()), - selectedElemPath: (await this.devtoolsController.getSelectedElementPath())! || "/html", + selectedElemPath: currentPath || "/html", + selectedPath: currentPath || null, focusMode: (await this.devtoolsController.getFocusMode()), storedReportsCount: (await this.devtoolsController.getStoredReportsMeta()).length, canScan: (await this.bgController.getTabInfo(tabId)).canScan diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts index 733b5dacf..ed54412e5 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts @@ -153,93 +153,106 @@ export class DevtoolsAppController { public hookSelectionChange() { const injectPathGenerator = () => { chrome.devtools.inspectedWindow.eval(` - window.__getACEPath = function(node) { - function getIndex(n) { - let count = 1; - let sib = n.previousElementSibling; - while (sib) { - if (sib.localName === n.localName) count++; - sib = sib.previousElementSibling; - } - return "/" + n.localName + "[" + count + "]"; - } - - function getSlotIndex(slot) { - const slotName = slot.getAttribute('name') || ''; - let count = 1; - let sib = slot.previousElementSibling; - while (sib) { - if (sib.localName === 'slot') { - const sibName = sib.getAttribute('name') || ''; - if (sibName === slotName) count++; - } - sib = sib.previousElementSibling; - } - return count; - } - - try { - let segments = ""; - let current = node; - - while (current && current.nodeType === 1) { - const assignedSlot = current.assignedSlot; - - if (assignedSlot) { - segments = getIndex(current) + segments; - const slotIdx = getSlotIndex(assignedSlot); - segments = "/slot[" + slotIdx + "]" + segments; - const slotRoot = assignedSlot.getRootNode(); - if (slotRoot.nodeType === 11) { - segments = "/#document-fragment[1]" + segments; - current = slotRoot.host; - } else { - break; - } - } else { - segments = getIndex(current) + segments; - let parent = current.parentNode; - - if (!parent) { - // Check if we're in an iframe - try { - const currentDoc = current.ownerDocument; - const parentWin = currentDoc.defaultView.parent; - if (parentWin !== currentDoc.defaultView) { - const iframes = parentWin.document.querySelectorAll("iframe"); - for (const iframe of iframes) { - try { - if (iframe.contentDocument === currentDoc) { - current = iframe; - parent = current.parentNode; - break; - } - } catch (e) {} - } - } - } catch (e) {} - - if (!parent) break; - } - - if (parent.nodeType === 11) { - segments = "/#document-fragment[1]" + segments; - current = parent.host; - } else if (parent.nodeType === 9) { - break; - } else if (parent.nodeType === 1) { - current = parent; - } else { - break; - } - } - } - - return segments; - } catch(err) { - return ""; - } - }; + window.__getACEPath = function(node) { + function getIndex(n) { + if (n.assignedSlot) { + const assigned = n.assignedSlot.assignedElements + ? n.assignedSlot.assignedElements() + : Array.from(n.assignedSlot.assignedNodes()).filter(x => x.nodeType === 1); + let count = 0; + for (const el of assigned) { + if (el === n) break; + if (el.localName === n.localName) count++; + } + return "/" + n.localName + "[" + (count + 1) + "]"; + } + const parent = n.parentNode; + if (!parent) return "/" + n.localName + "[1]"; + let count = 0; + const children = parent.children; + for (let i = 0; i < children.length; i++) { + if (children[i] === n) break; + if (children[i].localName === n.localName) count++; + } + return "/" + n.localName + "[" + (count + 1) + "]"; + } + + function getSlotIndex(slot) { + let count = 1; + let sib = slot.previousElementSibling; + while (sib) { + if (sib.localName === 'slot') count++; + sib = sib.previousElementSibling; + } + return count; + } + + try { + let current = node; + + // If $0 is a slot, use first assigned element or walk to host + while (current && current.localName === 'slot') { + const assigned = current.assignedElements + ? current.assignedElements() + : Array.from(current.assignedNodes()).filter(n => n.nodeType === 1); + if (assigned.length > 0) { + current = assigned[0]; + } else { + const parent = current.parentNode; + if (!parent) break; + if (parent.nodeType === 11) current = parent.host; + else if (parent.nodeType === 1) current = parent; + else break; + } + } + + if (!current || current.nodeType !== 1) return ""; + + let segments = ""; + + while (current && current.nodeType === 1) { + const assignedSlot = current.assignedSlot; + + if (assignedSlot) { + segments = getIndex(current) + segments; + segments = "/slot[" + getSlotIndex(assignedSlot) + "]" + segments; + const slotParent = assignedSlot.parentNode; + if (!slotParent) break; + if (slotParent.nodeType === 11) { + segments = "/#document-fragment[1]" + segments; + current = slotParent.host; + } else if (slotParent.nodeType === 9) { + segments = "/html[1]" + segments; + break; + } else if (slotParent.nodeType === 1) { + current = slotParent; + } else { + break; + } + } else { + segments = getIndex(current) + segments; + const parent = current.parentNode; + if (!parent) break; + + if (parent.nodeType === 11) { + segments = "/#document-fragment[1]" + segments; + current = parent.host; + } else if (parent.nodeType === 9) { + // parent is the document — current is . Stop; /html[1] is already in segments. + break; + } else if (parent.nodeType === 1) { + current = parent; + } else { + break; + } + } + } + + return segments; + } catch(err) { + return ""; + } +}; `); }; @@ -247,6 +260,7 @@ export class DevtoolsAppController { chrome.devtools.network.onNavigated.addListener(() => { injectPathGenerator(); }); + chrome.devtools.panels.elements.onSelectionChanged.addListener(() => { chrome.devtools.inspectedWindow.eval( `window.__getACEPath($0)`, @@ -255,8 +269,6 @@ export class DevtoolsAppController { } ); }); - - chrome.devtools.inspectedWindow.eval(`inspect(document.documentElement);`); } /////////////////////////////////////////////////////////////////////////// diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts index 44b58663e..e04e26d0c 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts @@ -15,6 +15,7 @@ *****************************************************************************/ import { getBGController, issueBaselineMatch, TabChangeType } from "../background/backgroundController"; +import { PathMatcher } from "../util/PathMatcher"; import { IBasicTableRowRecord, IIssue, IMessage, IReport, IStoredReportMeta, UIIssue } from "../interfaces/interfaces"; import { CommonMessaging } from "../messaging/commonMessaging"; import { Controller, eControllerType, ListenerType } from "../messaging/controller"; @@ -431,36 +432,38 @@ export class DevtoolsController extends Controller { */ public async setSelectedElementPath(path: string | null, fromElemChange?: boolean) : Promise { return this.hook("setSelectedElementPath", { path, fromElemChange }, async () => { + const previousPath = devtoolsState!.lastElementPath; devtoolsState!.lastElementPath = path; if (fromElemChange === true) { - // This path came from the Elements panel selection changing - if (!this.programmaticInspect) { - // User clicked on this - if (Config.ELEM_FOCUS_MODE) { - await this.setFocusMode(true); - } - if (path && path !== devtoolsState!.lastElementPath) { - // if (path) { - let report = await this.getReport(); - if (report) { - let newIssue : IIssue | null = null; - for (const issue of report.results) { - if (issue.value[1] !== "PASS" && issue.path.dom === path) { - newIssue = issue; - break; - } else if (!newIssue && issue.value[1] !== "PASS" && issue.path.dom.startsWith(path)) { - newIssue = issue; - } + // This path came from the Elements panel selection changing. + // Always activate focus mode and update the selected element path. + // The programmaticInspect flag only suppresses auto-selecting a new + // issue — it must not block focus mode, because inspectPath is called + // precisely WHEN the user already has an issue selected and we want + // to keep showing the filtered view for that element. + if (Config.ELEM_FOCUS_MODE) { + await this.setFocusMode(true); + } + if (this.programmaticInspect) { + // Echo from inspectPath's own inspect(element) call — clear flag, + // do not auto-select a different issue. + this.programmaticInspect = false; + } else if (path && path !== previousPath) { + // Genuine user navigation — auto-select the nearest matching issue. + let report = await this.getReport(); + if (report) { + let newIssue : IIssue | null = null; + for (const issue of report.results) { + if (issue.value[1] !== "PASS" && issue.path.dom === path) { + newIssue = issue; + break; + } else if (!newIssue && issue.value[1] !== "PASS" && PathMatcher.matchesPath(issue.path.dom, path)) { + newIssue = issue; } - await this.setSelectedIssue(newIssue); } + await this.setSelectedIssue(newIssue); } - } else { - // Side effect of inspectPath - this.programmaticInspect = false; } - } else { - // Called by some other process } setTimeout(() => { this.notifyEventListeners("DT_onSelectedElementPath", this.ctrlDest.tabId, path); diff --git a/accessibility-checker-extension/src/ts/util/PathMatcher.ts b/accessibility-checker-extension/src/ts/util/PathMatcher.ts index 1a0074b4c..2621ac4f9 100644 --- a/accessibility-checker-extension/src/ts/util/PathMatcher.ts +++ b/accessibility-checker-extension/src/ts/util/PathMatcher.ts @@ -19,14 +19,19 @@ */ export class PathMatcher { /** - * Check if a child path matches or is a descendant of a parent path. - * - * @param childPath - The path to check (e.g., issue path from scanner) - * @param parentPath - The parent path to match against (e.g., selected element path) - * @returns true if childPath matches or is a descendant of parentPath + * Returns true if the issue element is the selected element or a descendant + * of it — i.e. the issue path equals the selected path or starts with it. + * + * Ancestor matching (selectedPath.startsWith(issuePath)) is intentionally + * excluded: when the user selects a specific element they only want to see + * issues on that element and its children, not on its ancestors. + * + * @param issuePath - The DOM path of the issue (from the scanner result) + * @param selectedPath - The DOM path of the currently selected element */ - static matchesPath(childPath: string, parentPath: string): boolean { - return childPath === parentPath || childPath.startsWith(parentPath + "/"); + static matchesPath(issuePath: string, selectedPath: string): boolean { + return issuePath === selectedPath + || issuePath.startsWith(selectedPath + "/"); } } From e7ecb085667cfcd425c6d1befee0e7ef85da15c4 Mon Sep 17 00:00:00 2001 From: nam-singh Date: Mon, 6 Jul 2026 16:13:24 +0530 Subject: [PATCH 3/4] fix path --- .../src/ts/devtools/devtoolsAppController.ts | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts index ed54412e5..be17f4c0f 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts @@ -187,28 +187,36 @@ export class DevtoolsAppController { return count; } - try { - let current = node; - - // If $0 is a slot, use first assigned element or walk to host - while (current && current.localName === 'slot') { - const assigned = current.assignedElements - ? current.assignedElements() - : Array.from(current.assignedNodes()).filter(n => n.nodeType === 1); - if (assigned.length > 0) { - current = assigned[0]; + // Walk from an