From c6f4fe2b7b2b8dcdda1225c9bd58d7a1dc1a8a53 Mon Sep 17 00:00:00 2001 From: rxliuli Date: Fri, 22 Aug 2025 21:58:57 +0800 Subject: [PATCH] feat: auto pierce deep shadow dom (#297) * feat: auto pierce deep shadow dom * fix: observe all shadow DOM child element changes * chore: remove >>> selector require note for shadow DOM --- package.json | 4 +++- pnpm-lock.yaml | 8 ++++++++ src/config/i18n.js | 6 +++--- src/libs/translator.js | 21 +++++++++++++++++++-- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3ca8e58..9e3fd25 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@mui/icons-material": "^5.15.15", "@mui/lab": "5.0.0-alpha.170", "@mui/material": "^5.15.15", + "query-selector-shadow-dom": "^1.0.1", "query-string": "^8.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -70,5 +71,6 @@ "@babel/preset-env": "^7.22.20", "prettier": "3.6.2", "react-app-rewired": "^2.2.1" - } + }, + "packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce0217c..d5a00a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@mui/material': specifier: ^5.15.15 version: 5.15.15(@emotion/react@11.11.1(@types/react@18.2.79)(react@18.2.0))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.2.79)(react@18.2.0))(@types/react@18.2.79)(react@18.2.0))(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + query-selector-shadow-dom: + specifier: ^1.0.1 + version: 1.0.1 query-string: specifier: ^8.1.0 version: 8.1.0 @@ -4782,6 +4785,9 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + query-string@8.1.0: resolution: {integrity: sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==} engines: {node: '>=14.16'} @@ -11527,6 +11533,8 @@ snapshots: dependencies: side-channel: 1.0.4 + query-selector-shadow-dom@1.0.1: {} + query-string@8.1.0: dependencies: decode-uri-component: 0.4.1 diff --git a/src/config/i18n.js b/src/config/i18n.js index e7d1e4b..165e003 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -543,9 +543,9 @@ export const I18N = { zh_TW: `1. 支援星號 (*) 萬用字元。2. 多個 URL 請以換行或英文逗號「,」分隔。`, }, selector_helper: { - zh: `1、遵循CSS选择器语法。2、多个CSS选择器之间用“;”隔开。3、“shadow root”选择器和内部选择器用“>>>”隔开。`, - en: `1. Follow CSS selector syntax. 2. Separate multiple CSS selectors with ";". 3. The "shadow root" selector and the internal selector are separated by ">>>".`, - zh_TW: `1. 遵循 CSS 選擇器語法。2. 多個 CSS 選擇器以「;」分隔。3.「shadow root」與內部選擇器以「>>>」分隔。`, + zh: `1、遵循CSS选择器语法。2、多个CSS选择器之间用“;”隔开。`, + en: `1. Follow CSS selector syntax. 2. Separate multiple CSS selectors with ";".`, + zh_TW: `1. 遵循 CSS 選擇器語法。2. 多個 CSS 選擇器以「;」分隔。`, }, translate_switch: { zh: `开启翻译`, diff --git a/src/libs/translator.js b/src/libs/translator.js index 37a2742..f8c0b46 100644 --- a/src/libs/translator.js +++ b/src/libs/translator.js @@ -16,6 +16,7 @@ import { DEFAULT_FETCH_LIMIT, DEFAULT_FETCH_INTERVAL, } from "../config"; +import { querySelectorAllDeep } from "query-selector-shadow-dom"; import Content from "../views/Content"; import { updateFetchPool, clearFetchPool } from "./fetch"; import { debounce, genEventName, getHtmlText } from "./utils"; @@ -206,9 +207,14 @@ export class Translator { _querySelectorAll = (selector, node) => { try { - return Array.from(node.querySelectorAll(selector)); + return querySelectorAllDeep(selector, node); } catch (err) { - kissLog(selector, "querySelectorAll err"); + kissLog(selector, "querySelectorAllDeep err"); + try { + return Array.from(node.querySelectorAll(selector)); + } catch (fallbackErr) { + kissLog(selector, "querySelectorAll fallback err"); + } } return []; }; @@ -235,6 +241,16 @@ export class Translator { }); }; + _addAllShadowRootsToMonitoring = (rootNode) => { + Array.from(rootNode.querySelectorAll("*")) + .map((item) => item.shadowRoot) + .filter(Boolean) + .forEach((shadowRoot) => { + this._rootNodes.add(shadowRoot); + this._addAllShadowRootsToMonitoring(shadowRoot); + }); + }; + _queryNodes = (rootNode = document) => { // const childRoots = Array.from(rootNode.querySelectorAll("*")) // .map((item) => item.shadowRoot) @@ -275,6 +291,7 @@ export class Translator { this._tranNodes.set(item, ""); } }); + this._addAllShadowRootsToMonitoring(rootNode); } }); };