mirror of https://github.com/gorhill/uBlock.git
Add `trusted-click-element` scriptlet
Implemented as per AdGuard API documentation: https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-trusted-scriptlets.md#trusted-click-element The current implementation in uBO does not support the `extraMatch` argument. If the extraMatch argument is not empty, the scriptlet will abort and do nothing. As for the rest, it complies with the documentation.
This commit is contained in:
parent
9a809a8e7c
commit
7af88b025d
|
@ -224,9 +224,9 @@ function runAt(fn, when) {
|
||||||
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'run-at-html-element.fn',
|
name: 'run-at-html-element.fn',
|
||||||
fn: runAtHtmlElement,
|
fn: runAtHtmlElementFn,
|
||||||
});
|
});
|
||||||
function runAtHtmlElement(fn) {
|
function runAtHtmlElementFn(fn) {
|
||||||
if ( document.documentElement ) {
|
if ( document.documentElement ) {
|
||||||
fn();
|
fn();
|
||||||
return;
|
return;
|
||||||
|
@ -1160,7 +1160,7 @@ builtinScriptlets.push({
|
||||||
// Issues to mind before changing anything:
|
// Issues to mind before changing anything:
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
||||||
function abortCurrentScript(...args) {
|
function abortCurrentScript(...args) {
|
||||||
runAtHtmlElement(( ) => {
|
runAtHtmlElementFn(( ) => {
|
||||||
abortCurrentScriptCore(...args);
|
abortCurrentScriptCore(...args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3882,4 +3882,113 @@ function trustedReplaceXhrResponse(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* trusted-click-element.js
|
||||||
|
*
|
||||||
|
* Reference API:
|
||||||
|
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-click-element.js
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
builtinScriptlets.push({
|
||||||
|
name: 'trusted-click-element.js',
|
||||||
|
requiresTrust: true,
|
||||||
|
fn: trustedClickElement,
|
||||||
|
world: 'ISOLATED',
|
||||||
|
dependencies: [
|
||||||
|
'run-at-html-element.fn',
|
||||||
|
'safe-self.fn',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
function trustedClickElement(
|
||||||
|
selectors = '',
|
||||||
|
extraMatch = '', // not yet supported
|
||||||
|
delay = ''
|
||||||
|
) {
|
||||||
|
if ( extraMatch !== '' ) { return; }
|
||||||
|
|
||||||
|
const selectorList = selectors.split(/\s*,\s*/)
|
||||||
|
.filter(s => {
|
||||||
|
try {
|
||||||
|
void document.querySelector(s);
|
||||||
|
} catch(_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if ( selectorList.length === 0 ) { return; }
|
||||||
|
|
||||||
|
const clickDelay = parseInt(delay, 10) || 1;
|
||||||
|
const t0 = Date.now();
|
||||||
|
const tbye = t0 + 10000;
|
||||||
|
let tnext = t0;
|
||||||
|
|
||||||
|
const terminate = ( ) => {
|
||||||
|
selectorList.length = 0;
|
||||||
|
next.stop();
|
||||||
|
observe.stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
const next = notFound => {
|
||||||
|
if ( selectorList.length === 0 ) { return terminate(); }
|
||||||
|
const tnow = Date.now();
|
||||||
|
if ( tnow >= tbye ) { return terminate(); }
|
||||||
|
if ( notFound ) { observe(); }
|
||||||
|
const delay = Math.max(notFound ? tbye - tnow : tnext - tnow, 1);
|
||||||
|
next.timer = setTimeout(( ) => {
|
||||||
|
next.timer = undefined;
|
||||||
|
process();
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
next.stop = ( ) => {
|
||||||
|
if ( next.timer === undefined ) { return; }
|
||||||
|
clearTimeout(next.timer);
|
||||||
|
next.timer = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const observe = ( ) => {
|
||||||
|
if ( observe.observer !== undefined ) { return; }
|
||||||
|
observe.observer = new MutationObserver(( ) => {
|
||||||
|
if ( observe.timer !== undefined ) { return; }
|
||||||
|
observe.timer = setTimeout(( ) => {
|
||||||
|
observe.timer = undefined;
|
||||||
|
process();
|
||||||
|
}, 20);
|
||||||
|
});
|
||||||
|
observe.observer.observe(document, {
|
||||||
|
attributes: true,
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
observe.stop = ( ) => {
|
||||||
|
if ( observe.timer !== undefined ) {
|
||||||
|
clearTimeout(observe.timer);
|
||||||
|
observe.timer = undefined;
|
||||||
|
}
|
||||||
|
if ( observe.observer ) {
|
||||||
|
observe.observer.disconnect();
|
||||||
|
observe.observer = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const process = ( ) => {
|
||||||
|
next.stop();
|
||||||
|
if ( Date.now() < tnext ) { return next(); }
|
||||||
|
const selector = selectorList.shift();
|
||||||
|
if ( selector === undefined ) { return terminate(); }
|
||||||
|
const elem = document.querySelector(selector);
|
||||||
|
if ( elem === null ) {
|
||||||
|
selectorList.unshift(selector);
|
||||||
|
return next(true);
|
||||||
|
}
|
||||||
|
elem.click();
|
||||||
|
tnext += clickDelay;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
runAtHtmlElementFn(process);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
Loading…
Reference in New Issue