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({
|
||||
name: 'run-at-html-element.fn',
|
||||
fn: runAtHtmlElement,
|
||||
fn: runAtHtmlElementFn,
|
||||
});
|
||||
function runAtHtmlElement(fn) {
|
||||
function runAtHtmlElementFn(fn) {
|
||||
if ( document.documentElement ) {
|
||||
fn();
|
||||
return;
|
||||
|
@ -1160,7 +1160,7 @@ builtinScriptlets.push({
|
|||
// Issues to mind before changing anything:
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
||||
function abortCurrentScript(...args) {
|
||||
runAtHtmlElement(( ) => {
|
||||
runAtHtmlElementFn(( ) => {
|
||||
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