mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: move query selectors to injection script (#8980)
This commit is contained in:
parent
dda85944b8
commit
5a4eb38083
@ -197,91 +197,29 @@ const defaultHandler = createPuppeteerQueryHandler({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const pierceHandler = createPuppeteerQueryHandler({
|
const pierceHandler = createPuppeteerQueryHandler({
|
||||||
queryOne: (element, selector) => {
|
queryOne: (element, selector, {pierceQuerySelector}) => {
|
||||||
let found: Node | null = null;
|
return pierceQuerySelector(element, selector);
|
||||||
const search = (root: Node) => {
|
|
||||||
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
||||||
do {
|
|
||||||
const currentNode = iter.currentNode as HTMLElement;
|
|
||||||
if (currentNode.shadowRoot) {
|
|
||||||
search(currentNode.shadowRoot);
|
|
||||||
}
|
|
||||||
if (currentNode instanceof ShadowRoot) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (currentNode !== root && !found && currentNode.matches(selector)) {
|
|
||||||
found = currentNode;
|
|
||||||
}
|
|
||||||
} while (!found && iter.nextNode());
|
|
||||||
};
|
|
||||||
if (element instanceof Document) {
|
|
||||||
element = element.documentElement;
|
|
||||||
}
|
|
||||||
search(element);
|
|
||||||
return found;
|
|
||||||
},
|
},
|
||||||
|
queryAll: (element, selector, {pierceQuerySelectorAll}) => {
|
||||||
queryAll: (element, selector) => {
|
return pierceQuerySelectorAll(element, selector);
|
||||||
const result: Node[] = [];
|
|
||||||
const collect = (root: Node) => {
|
|
||||||
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
||||||
do {
|
|
||||||
const currentNode = iter.currentNode as HTMLElement;
|
|
||||||
if (currentNode.shadowRoot) {
|
|
||||||
collect(currentNode.shadowRoot);
|
|
||||||
}
|
|
||||||
if (currentNode instanceof ShadowRoot) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (currentNode !== root && currentNode.matches(selector)) {
|
|
||||||
result.push(currentNode);
|
|
||||||
}
|
|
||||||
} while (iter.nextNode());
|
|
||||||
};
|
|
||||||
if (element instanceof Document) {
|
|
||||||
element = element.documentElement;
|
|
||||||
}
|
|
||||||
collect(element);
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const xpathHandler = createPuppeteerQueryHandler({
|
const xpathHandler = createPuppeteerQueryHandler({
|
||||||
queryOne: (element, selector) => {
|
queryOne: (element, selector, {xpathQuerySelector}) => {
|
||||||
const doc = element.ownerDocument || document;
|
return xpathQuerySelector(element, selector);
|
||||||
const result = doc.evaluate(
|
|
||||||
selector,
|
|
||||||
element,
|
|
||||||
null,
|
|
||||||
XPathResult.FIRST_ORDERED_NODE_TYPE
|
|
||||||
);
|
|
||||||
return result.singleNodeValue;
|
|
||||||
},
|
},
|
||||||
|
queryAll: (element, selector, {xpathQuerySelectorAll}) => {
|
||||||
queryAll: (element, selector) => {
|
return xpathQuerySelectorAll(element, selector);
|
||||||
const doc = element.ownerDocument || document;
|
|
||||||
const iterator = doc.evaluate(
|
|
||||||
selector,
|
|
||||||
element,
|
|
||||||
null,
|
|
||||||
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
|
||||||
);
|
|
||||||
const array: Node[] = [];
|
|
||||||
let item;
|
|
||||||
while ((item = iterator.iterateNext())) {
|
|
||||||
array.push(item);
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const textQueryHandler = createPuppeteerQueryHandler({
|
const textQueryHandler = createPuppeteerQueryHandler({
|
||||||
queryOne: (element, selector, {textQuerySelector}) => {
|
queryOne: (element, selector, {textQuerySelector}) => {
|
||||||
return textQuerySelector(selector, element);
|
return textQuerySelector(element, selector);
|
||||||
},
|
},
|
||||||
|
|
||||||
queryAll: (element, selector, {textQuerySelectorAll}) => {
|
queryAll: (element, selector, {textQuerySelectorAll}) => {
|
||||||
return textQuerySelectorAll(selector, element);
|
return textQuerySelectorAll(element, selector);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
67
src/injected/PierceQuerySelector.ts
Normal file
67
src/injected/PierceQuerySelector.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
export const pierceQuerySelector = (
|
||||||
|
root: Node,
|
||||||
|
selector: string
|
||||||
|
): Element | null => {
|
||||||
|
let found: Node | null = null;
|
||||||
|
const search = (root: Node) => {
|
||||||
|
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||||
|
do {
|
||||||
|
const currentNode = iter.currentNode as Element;
|
||||||
|
if (currentNode.shadowRoot) {
|
||||||
|
search(currentNode.shadowRoot);
|
||||||
|
}
|
||||||
|
if (currentNode instanceof ShadowRoot) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (currentNode !== root && !found && currentNode.matches(selector)) {
|
||||||
|
found = currentNode;
|
||||||
|
}
|
||||||
|
} while (!found && iter.nextNode());
|
||||||
|
};
|
||||||
|
if (root instanceof Document) {
|
||||||
|
root = root.documentElement;
|
||||||
|
}
|
||||||
|
search(root);
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pierceQuerySelectorAll = (
|
||||||
|
element: Node,
|
||||||
|
selector: string
|
||||||
|
): Element[] => {
|
||||||
|
const result: Element[] = [];
|
||||||
|
const collect = (root: Node) => {
|
||||||
|
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||||
|
do {
|
||||||
|
const currentNode = iter.currentNode as Element;
|
||||||
|
if (currentNode.shadowRoot) {
|
||||||
|
collect(currentNode.shadowRoot);
|
||||||
|
}
|
||||||
|
if (currentNode instanceof ShadowRoot) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (currentNode !== root && currentNode.matches(selector)) {
|
||||||
|
result.push(currentNode);
|
||||||
|
}
|
||||||
|
} while (iter.nextNode());
|
||||||
|
};
|
||||||
|
if (element instanceof Document) {
|
||||||
|
element = element.documentElement;
|
||||||
|
}
|
||||||
|
collect(element);
|
||||||
|
return result;
|
||||||
|
};
|
@ -25,16 +25,16 @@ import {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const textQuerySelector = (
|
export const textQuerySelector = (
|
||||||
selector: string,
|
root: Node,
|
||||||
root: Node
|
selector: string
|
||||||
): Element | null => {
|
): Element | null => {
|
||||||
for (const node of root.childNodes) {
|
for (const node of root.childNodes) {
|
||||||
if (node instanceof Element && isSuitableNodeForTextMatching(node)) {
|
if (node instanceof Element && isSuitableNodeForTextMatching(node)) {
|
||||||
let matchedNode: Element | null;
|
let matchedNode: Element | null;
|
||||||
if (node.shadowRoot) {
|
if (node.shadowRoot) {
|
||||||
matchedNode = textQuerySelector(selector, node.shadowRoot);
|
matchedNode = textQuerySelector(node.shadowRoot, selector);
|
||||||
} else {
|
} else {
|
||||||
matchedNode = textQuerySelector(selector, node);
|
matchedNode = textQuerySelector(node, selector);
|
||||||
}
|
}
|
||||||
if (matchedNode) {
|
if (matchedNode) {
|
||||||
return matchedNode;
|
return matchedNode;
|
||||||
@ -57,17 +57,17 @@ export const textQuerySelector = (
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const textQuerySelectorAll = (
|
export const textQuerySelectorAll = (
|
||||||
selector: string,
|
root: Node,
|
||||||
root: Node
|
selector: string
|
||||||
): Element[] => {
|
): Element[] => {
|
||||||
let results: Element[] = [];
|
let results: Element[] = [];
|
||||||
for (const node of root.childNodes) {
|
for (const node of root.childNodes) {
|
||||||
if (node instanceof Element) {
|
if (node instanceof Element) {
|
||||||
let matchedNodes: Element[];
|
let matchedNodes: Element[];
|
||||||
if (node.shadowRoot) {
|
if (node.shadowRoot) {
|
||||||
matchedNodes = textQuerySelectorAll(selector, node.shadowRoot);
|
matchedNodes = textQuerySelectorAll(node.shadowRoot, selector);
|
||||||
} else {
|
} else {
|
||||||
matchedNodes = textQuerySelectorAll(selector, node);
|
matchedNodes = textQuerySelectorAll(node, selector);
|
||||||
}
|
}
|
||||||
results = results.concat(matchedNodes);
|
results = results.concat(matchedNodes);
|
||||||
}
|
}
|
45
src/injected/XPathQuerySelector.ts
Normal file
45
src/injected/XPathQuerySelector.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2022 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const xpathQuerySelector = (
|
||||||
|
root: Node,
|
||||||
|
selector: string
|
||||||
|
): Node | null => {
|
||||||
|
const doc = root.ownerDocument || document;
|
||||||
|
const result = doc.evaluate(
|
||||||
|
selector,
|
||||||
|
root,
|
||||||
|
null,
|
||||||
|
XPathResult.FIRST_ORDERED_NODE_TYPE
|
||||||
|
);
|
||||||
|
return result.singleNodeValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const xpathQuerySelectorAll = (root: Node, selector: string): Node[] => {
|
||||||
|
const doc = root.ownerDocument || document;
|
||||||
|
const iterator = doc.evaluate(
|
||||||
|
selector,
|
||||||
|
root,
|
||||||
|
null,
|
||||||
|
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
||||||
|
);
|
||||||
|
const array: Node[] = [];
|
||||||
|
let item;
|
||||||
|
while ((item = iterator.iterateNext())) {
|
||||||
|
array.push(item);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
};
|
@ -17,14 +17,18 @@
|
|||||||
import {createDeferredPromise} from '../util/DeferredPromise.js';
|
import {createDeferredPromise} from '../util/DeferredPromise.js';
|
||||||
import * as Poller from './Poller.js';
|
import * as Poller from './Poller.js';
|
||||||
import * as TextContent from './TextContent.js';
|
import * as TextContent from './TextContent.js';
|
||||||
import * as TextSelector from './TextSelector.js';
|
import * as TextQuerySelector from './TextQuerySelector.js';
|
||||||
|
import * as XPathQuerySelector from './XPathQuerySelector.js';
|
||||||
|
import * as PierceQuerySelector from './PierceQuerySelector.js';
|
||||||
import * as util from './util.js';
|
import * as util from './util.js';
|
||||||
|
|
||||||
const PuppeteerUtil = Object.freeze({
|
const PuppeteerUtil = Object.freeze({
|
||||||
...util,
|
...util,
|
||||||
...Poller,
|
...Poller,
|
||||||
...TextContent,
|
...TextContent,
|
||||||
...TextSelector,
|
...TextQuerySelector,
|
||||||
|
...XPathQuerySelector,
|
||||||
|
...PierceQuerySelector,
|
||||||
createDeferredPromise,
|
createDeferredPromise,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user