Skip to content

Commit

Permalink
Improve set-cookie scriptlet
Browse files Browse the repository at this point in the history
Allow negative integer as valid value.

Related issue:
#3927

Additionally, move cookie-related scriptlets/helpers into its own
source code file.
  • Loading branch information
gorhill committed Nov 7, 2024
1 parent 652f178 commit e613282
Show file tree
Hide file tree
Showing 3 changed files with 545 additions and 441 deletions.
104 changes: 104 additions & 0 deletions assets/resources/set-attr.js → assets/resources/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,108 @@ trustedSetAttr.details = {
world: 'ISOLATED',
};

/**
* @scriptlet remove-attr
*
* @description
* Remove one or more attributes from a set of elements.
*
* @param attribute
* The name of the attribute(s) to remove. This can be a list of space-
* separated attribute names.
*
* @param [selector]
* Optional. A CSS selector for the elements to target. Default to
* `[attribute]`, or `[attribute1],[attribute2],...` if more than one
* attribute name is specified.
*
* @param [behavior]
* Optional. Space-separated tokens which modify the default behavior.
* - `asap`: Try to remove the attribute as soon as possible. Default behavior
* is to remove the attribute(s) asynchronously.
* - `stay`: Keep trying to remove the specified attribute(s) on DOM mutations.
* */

export function removeAttr(
rawToken = '',
rawSelector = '',
behavior = ''
) {
if ( typeof rawToken !== 'string' ) { return; }
if ( rawToken === '' ) { return; }
const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('remove-attr', rawToken, rawSelector, behavior);
const tokens = rawToken.split(/\s*\|\s*/);
const selector = tokens
.map(a => `${rawSelector}[${CSS.escape(a)}]`)
.join(',');
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Target selector:\n\t${selector}`);
}
const asap = /\basap\b/.test(behavior);
let timerId;
const rmattrAsync = ( ) => {
if ( timerId !== undefined ) { return; }
timerId = safe.onIdle(( ) => {
timerId = undefined;
rmattr();
}, { timeout: 17 });
};
const rmattr = ( ) => {
if ( timerId !== undefined ) {
safe.offIdle(timerId);
timerId = undefined;
}
try {
const nodes = document.querySelectorAll(selector);
for ( const node of nodes ) {
for ( const attr of tokens ) {
if ( node.hasAttribute(attr) === false ) { continue; }
node.removeAttribute(attr);
safe.uboLog(logPrefix, `Removed attribute '${attr}'`);
}
}
} catch(ex) {
}
};
const mutationHandler = mutations => {
if ( timerId !== undefined ) { return; }
let skip = true;
for ( let i = 0; i < mutations.length && skip; i++ ) {
const { type, addedNodes, removedNodes } = mutations[i];
if ( type === 'attributes' ) { skip = false; }
for ( let j = 0; j < addedNodes.length && skip; j++ ) {
if ( addedNodes[j].nodeType === 1 ) { skip = false; break; }
}
for ( let j = 0; j < removedNodes.length && skip; j++ ) {
if ( removedNodes[j].nodeType === 1 ) { skip = false; break; }
}
}
if ( skip ) { return; }
asap ? rmattr() : rmattrAsync();
};
const start = ( ) => {
rmattr();
if ( /\bstay\b/.test(behavior) === false ) { return; }
const observer = new MutationObserver(mutationHandler);
observer.observe(document, {
attributes: true,
attributeFilter: tokens,
childList: true,
subtree: true,
});
};
runAt(( ) => { start(); }, behavior.split(/\s+/));
}
removeAttr.details = {
name: 'remove-attr.js',
aliases: [
'ra.js',
],
dependencies: [
runAt,
safeSelf,
],
};

/******************************************************************************/
Loading

0 comments on commit e613282

Please sign in to comment.