function(strategy, ancestorElement, query, firstResultOnly, timeoutDuration, callback) {
ancestorElement = ancestorElement || document;
switch (strategy) {
case "id":
strategy = "css selector";
query = "[id=\"" + escape(query) + "\"]";
break;
case "name":
strategy = "css selector";
query = "[name=\"" + escape(query) + "\"]";
break;
case "link text":
strategy = "xpath";
query = ".//a[@href][descendant-or-self::text() = \"" + escape(query) + "\"]";
break;
case "partial link text":
strategy = "xpath";
query = ".//a[@href][contains(descendant-or-self::text(), \"" + escape(query) + "\")]";
break;
}
switch (strategy) {
case "css selector":
case "tag name":
case "class name":
case "xpath":
break;
default:
throw { name: "InvalidParameter", message: ("Unsupported locator strategy: " + strategy + ".") };
}
function escape(string) {
return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
}
function tryToFindNode() {
try {
switch (strategy) {
case "css selector":
if (firstResultOnly)
return ancestorElement.querySelector(query) || null;
return Array.from(ancestorElement.querySelectorAll(query));
case "tag name":
let tagNameResult = ancestorElement.getElementsByTagName(query);
if (firstResultOnly)
return tagNameResult[0] || null;
return Array.from(tagNameResult);
case "class name":
let classNameResult = ancestorElement.getElementsByClassName(query);
if (firstResultOnly)
return classNameResult[0] || null;
return Array.from(classNameResult);
case "xpath":
if (firstResultOnly) {
let xpathResult = document.evaluate(query, ancestorElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (!xpathResult)
return null;
return xpathResult.singleNodeValue;
}
let xpathResult = document.evaluate(query, ancestorElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (!xpathResult || !xpathResult.snapshotLength)
return [];
let arrayResult = [];
for (let i = 0; i < xpathResult.snapshotLength; ++i)
arrayResult.push(xpathResult.snapshotItem(i));
return arrayResult;
}
} catch (error) {
if (error instanceof XPathException && error.code === XPathException.INVALID_EXPRESSION_ERR)
return "InvalidXPathExpression";
return firstResultOnly ? null : [];
}
}
const pollInterval = 50;
let pollUntil = performance.now() + timeoutDuration;
function pollForNode() {
let result = tryToFindNode();
if (typeof result === "string" || result instanceof Node || (result instanceof Array && result.length)) {
callback(result);
return;
}
let durationRemaining = pollUntil - performance.now();
if (durationRemaining < pollInterval) {
callback(firstResultOnly ? null : []);
return;
}
setTimeout(pollForNode, pollInterval);
}
pollForNode();
}