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 { }) this.devtoolsController.addSelectedElementPathListener(async (newPath) => { this.setState( { selectedElemPath: newPath }); + this.setPath(newPath); }) this.devtoolsController.addFocusModeListener(async (newValue) => { this.setState({ focusMode: newValue }) @@ -196,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 @@ -259,7 +263,7 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { 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 +272,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 +304,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..f50f52b1b 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts @@ -151,58 +151,182 @@ 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(` + Object.defineProperty(window, '__getACEPath', { + value: 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; + } + + // Walk from an