Skip to content

Commit aa028ea

Browse files
committed
Improve trusted-click-element scriptlet
If a selector is prefixed with `when-visible:`, the scriptlet will click the matching element only when it becomes visible to the user. Related case: uBlockOrigin/uAssets#33161
1 parent 32a4d64 commit aa028ea

1 file changed

Lines changed: 29 additions & 24 deletions

File tree

src/js/resources/scriptlets.js

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,34 +1945,39 @@ function trustedClickElement(
19451945
};
19461946

19471947
const waitForElement = selector => {
1948+
safe.uboLog(logPrefix, `Waiting for ${selector}`);
19481949
return new Promise(resolve => {
1949-
const elem = querySelectorEx(selector);
1950-
if ( elem !== null ) {
1951-
elem.click();
1952-
resolve();
1953-
return;
1954-
}
1955-
safe.uboLog(logPrefix, `Waiting for ${selector}`);
1956-
const observer = new MutationObserver(( ) => {
1957-
const elem = querySelectorEx(selector);
1958-
if ( elem === null ) { return; }
1959-
waitForElement.cancel();
1960-
elem.click();
1961-
resolve();
1962-
});
1963-
observer.observe(document, {
1964-
attributes: true,
1965-
childList: true,
1966-
subtree: true,
1967-
});
1968-
waitForElement.observer = observer;
1950+
waitForElement.check(selector, resolve);
19691951
});
19701952
};
1953+
waitForElement.lookup = directive => {
1954+
const beVisible = directive.startsWith('when-visible:');
1955+
const selector = beVisible ? directive.slice(13) : directive;
1956+
const elem = querySelectorEx(selector);
1957+
if ( Boolean(elem) === false ) { return null; }
1958+
if ( beVisible !== true ) { return elem; }
1959+
const isVisible = elem.checkVisibility({
1960+
opacityProperty: true,
1961+
visibilityProperty: true,
1962+
});
1963+
return isVisible ? elem : null;
1964+
};
1965+
waitForElement.check = (directive, resolve) => {
1966+
const elem = waitForElement.lookup(directive);
1967+
if ( elem ) {
1968+
waitForElement.cbid = undefined;
1969+
elem.click();
1970+
return resolve();
1971+
}
1972+
waitForElement.cbid = safe.onIdle(( ) => {
1973+
waitForElement.check(directive, resolve);
1974+
}, { timeout: 1009 });
1975+
};
19711976
waitForElement.cancel = ( ) => {
1972-
const { observer } = waitForElement;
1973-
if ( observer === undefined ) { return; }
1974-
waitForElement.observer = undefined;
1975-
observer.disconnect();
1977+
const { cbid } = waitForElement;
1978+
if ( cbid === undefined ) { return; }
1979+
waitForElement.cbid = undefined;
1980+
safe.offIdle(cbid);
19761981
};
19771982

19781983
const waitForTimeout = ms => {

0 commit comments

Comments
 (0)