Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert javascript snippets to standalone embedded js files (part 2) #873

Merged
merged 1 commit into from May 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
161 changes: 25 additions & 136 deletions js.go
@@ -1,170 +1,59 @@
package chromedp

const (
import (
_ "embed"
)

var (
// textJS is a javascript snippet that returns the innerText of the specified
// visible (ie, offsetWidth || offsetHeight || getClientRects().length ) element.
textJS = `function text() {
if (this.offsetWidth || this.offsetHeight || this.getClientRects().length) {
return this.innerText;
}
return '';
}`
//go:embed js/text.js
textJS string

// textContentJS is a javascript snippet that returns the textContent of the
// specified element.
textContentJS = `function textContent() {
return this.textContent;
}`
//go:embed js/textContent.js
textContentJS string

// blurJS is a javascript snippet that blurs the specified element.
blurJS = `function blur() {
this.blur();
return true;
}`
//go:embed js/blur.js
blurJS string

// submitJS is a javascript snippet that will call the containing form's
// submit function, returning true or false if the call was successful.
submitJS = `function submit() {
if (this.nodeName === 'FORM') {
HTMLFormElement.prototype.submit.call(this);
return true;
} else if (this.form !== null) {
HTMLFormElement.prototype.submit.call(this.form);
return true;
}
return false;
}`
//go:embed js/submit.js
submitJS string

// resetJS is a javascript snippet that will call the containing form's
// reset function, returning true or false if the call was successful.
resetJS = `function reset() {
if (this.nodeName === 'FORM') {
HTMLFormElement.prototype.reset.call(this);
return true;
} else if (this.form !== null) {
HTMLFormElement.prototype.reset.call(this.form);
return true;
}
return false;
}`
//go:embed js/reset.js
resetJS string

// attributeJS is a javascript snippet that returns the attribute of a specified
// node.
attributeJS = `function attribute(n) {
return this[n];
}`
//go:embed js/attribute.js
attributeJS string

// setAttributeJS is a javascript snippet that sets the value of the specified
// node, and returns the value.
setAttributeJS = `function setAttribute(n, v) {
this[n] = v;
if (n === 'value') {
this.dispatchEvent(new Event('input', { bubbles: true }));
this.dispatchEvent(new Event('change', { bubbles: true }));
}
return this[n];
}`
//go:embed js/setAttribute.js
setAttributeJS string

// visibleJS is a javascript snippet that returns true or false depending on if
// the specified node's offsetWidth, offsetHeight or getClientRects().length is
// not null.
visibleJS = `function visible() {
return Boolean( this.offsetWidth || this.offsetHeight || this.getClientRects().length );
}`
//go:embed js/visible.js
visibleJS string

// getClientRectJS is a javascript snippet that returns the information about the
// size of the specified node and its position relative to its owner document.
getClientRectJS = `function getClientRect() {
const e = this.getBoundingClientRect(),
t = this.ownerDocument.documentElement.getBoundingClientRect();
return {
x: e.left - t.left,
y: e.top - t.top,
width: e.width,
height: e.height,
};
}`
//go:embed js/getClientRect.js
getClientRectJS string

// waitForPredicatePageFunction is a javascript snippet that runs the polling in the
// browser. It's copied from puppeteer. See
// https://github.com/puppeteer/puppeteer/blob/669f04a7a6e96cc8353a8cb152898edbc25e7c15/src/common/DOMWorld.ts#L870-L944
// It's modified to make mutation polling respect timeout even when there is not DOM mutation.
waitForPredicatePageFunction = `async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) {
const predicate = new Function('...args', predicateBody);
let timedOut = false;
if (timeout)
setTimeout(() => (timedOut = true), timeout);
if (polling === 'raf')
return await pollRaf();
if (polling === 'mutation')
return await pollMutation();
if (typeof polling === 'number')
return await pollInterval(polling);
/**
* @returns {!Promise<*>}
*/
async function pollMutation() {
const success = await predicate(...args);
if (success)
return Promise.resolve(success);
let fulfill;
const result = new Promise((x) => (fulfill = x));
const observer = new MutationObserver(async () => {
if (timedOut) {
observer.disconnect();
fulfill();
}
const success = await predicate(...args);
if (success) {
observer.disconnect();
fulfill(success);
}
});
observer.observe(document, {
childList: true,
subtree: true,
attributes: true,
});
if (timeout)
setTimeout(() => {
observer.disconnect();
fulfill();
}, timeout);
return result;
}
async function pollRaf() {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onRaf();
return result;
async function onRaf() {
if (timedOut) {
fulfill();
return;
}
const success = await predicate(...args);
if (success)
fulfill(success);
else
requestAnimationFrame(onRaf);
}
}
async function pollInterval(pollInterval) {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onTimeout();
return result;
async function onTimeout() {
if (timedOut) {
fulfill();
return;
}
const success = await predicate(...args);
if (success)
fulfill(success);
else
setTimeout(onTimeout, pollInterval);
}
}
}`
//go:embed js/waitForPredicatePageFunction.js
waitForPredicatePageFunction string
)
3 changes: 3 additions & 0 deletions js/attribute.js
@@ -0,0 +1,3 @@
function attribute(n) {
return this[n];
}
4 changes: 4 additions & 0 deletions js/blur.js
@@ -0,0 +1,4 @@
function blur() {
this.blur();
return true;
}
10 changes: 10 additions & 0 deletions js/getClientRect.js
@@ -0,0 +1,10 @@
function getClientRect() {
const e = this.getBoundingClientRect(),
t = this.ownerDocument.documentElement.getBoundingClientRect();
return {
x: e.left - t.left,
y: e.top - t.top,
width: e.width,
height: e.height,
};
}
10 changes: 10 additions & 0 deletions js/reset.js
@@ -0,0 +1,10 @@
function reset() {
if (this.nodeName === 'FORM') {
HTMLFormElement.prototype.reset.call(this);
return true;
} else if (this.form !== null) {
HTMLFormElement.prototype.reset.call(this.form);
return true;
}
return false;
}
8 changes: 8 additions & 0 deletions js/setAttribute.js
@@ -0,0 +1,8 @@
function setAttribute(n, v) {
this[n] = v;
if (n === 'value') {
this.dispatchEvent(new Event('input', {bubbles: true}));
this.dispatchEvent(new Event('change', {bubbles: true}));
}
return this[n];
}
10 changes: 10 additions & 0 deletions js/submit.js
@@ -0,0 +1,10 @@
function submit() {
if (this.nodeName === 'FORM') {
HTMLFormElement.prototype.submit.call(this);
return true;
} else if (this.form !== null) {
HTMLFormElement.prototype.submit.call(this.form);
return true;
}
return false;
}
6 changes: 6 additions & 0 deletions js/text.js
@@ -0,0 +1,6 @@
function text() {
if (this.offsetWidth || this.offsetHeight || this.getClientRects().length) {
return this.innerText;
}
return '';
}
3 changes: 3 additions & 0 deletions js/textContent.js
@@ -0,0 +1,3 @@
function textContent() {
return this.textContent;
}
3 changes: 3 additions & 0 deletions js/visible.js
@@ -0,0 +1,3 @@
function visible() {
return Boolean(this.offsetWidth || this.offsetHeight || this.getClientRects().length);
}
83 changes: 83 additions & 0 deletions js/waitForPredicatePageFunction.js
@@ -0,0 +1,83 @@
async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) {
const predicate = new Function('...args', predicateBody);
let timedOut = false;
if (timeout)
setTimeout(() => (timedOut = true), timeout);
if (polling === 'raf')
return await pollRaf();
if (polling === 'mutation')
return await pollMutation();
if (typeof polling === 'number')
return await pollInterval(polling);

/**
* @returns {!Promise<*>}
*/
async function pollMutation() {
const success = await predicate(...args);
if (success)
return Promise.resolve(success);
let fulfill;
const result = new Promise((x) => (fulfill = x));
const observer = new MutationObserver(async () => {
if (timedOut) {
observer.disconnect();
fulfill();
}
const success = await predicate(...args);
if (success) {
observer.disconnect();
fulfill(success);
}
});
observer.observe(document, {
childList: true,
subtree: true,
attributes: true,
});
if (timeout)
setTimeout(() => {
observer.disconnect();
fulfill();
}, timeout);
return result;
}

async function pollRaf() {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onRaf();
return result;

async function onRaf() {
if (timedOut) {
fulfill();
return;
}
const success = await predicate(...args);
if (success)
fulfill(success);
else
requestAnimationFrame(onRaf);
}
}

async function pollInterval(pollInterval) {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onTimeout();
return result;

async function onTimeout() {
if (timedOut) {
fulfill();
return;
}
const success = await predicate(...args);
if (success)
fulfill(success);
else
setTimeout(onTimeout, pollInterval);
}
}
}