Skip to content

Commit

Permalink
add special [attribute-name] param value
Browse files Browse the repository at this point in the history
  • Loading branch information
stanislav-atr committed Feb 2, 2024
1 parent 8e47996 commit 88c365f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 22 deletions.
47 changes: 36 additions & 11 deletions src/helpers/attribute-utils.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,53 @@
import { hit } from './hit';
import { logMessage } from './log-message';
import { hit } from './hit';

/**
* Sets attribute with given value to given element.
*
* @param elem
* @param attribute
* @param value
* @returns
*/
const defaultAttributeSetter = (
elem: Element,
attribute: string,
value: string,
): void => elem.setAttribute(attribute, value);

/**
* Sets attribute with given value to all elements matching given selector
*
* @param source source object
* @param source source
* @param selector CSS selector
* @param attr attribute name to set
* @param attribute attribute name to set
* @param value attribute value to set
* @param attributeSetter function to apply to each element,
* defaults to native .setAttribute
*/
export const setAttributeToSelection = (
export const setAttributeBySelector = (
source: Source,
selector: string,
attr: string,
attribute: string,
value: string,
attributeSetter = defaultAttributeSetter,
): void => {
let elements;
try {
elements = document.querySelectorAll(selector);
} catch {
logMessage(source, `Failed to find elements matching selector "${selector}"`);
return;
}

if (!elements || elements.length === 0) {
return;
}

try {
const nodes = document.querySelectorAll(selector);
if (nodes.length === 0) {
return;
}
nodes.forEach((node) => node.setAttribute(attr, value));
elements.forEach((elem) => attributeSetter(elem, attribute, value));
hit(source);
} catch {
logMessage(source, `Failed to set attribute "${attr}" to "${value}" on "${selector}"`);
logMessage(source, `Failed to set [${attribute}="${value}"] to each of selected elements.`);
}
};
45 changes: 38 additions & 7 deletions src/scriptlets/set-attr.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
setAttributeToSelection,
setAttributeBySelector,
observeDOMChanges,
nativeIsNaN,
// following helpers should be imported and injected
Expand Down Expand Up @@ -32,6 +32,7 @@ import {
* - `''` — empty string
* - positive decimal integer `<= 32767`
* - `true` / `false` in any case variation
* - `[attribute-name]` copy the value from attribute `attribute-name` on the same element.
*
* ### Examples
*
Expand Down Expand Up @@ -97,6 +98,20 @@ import {
* <a class="class" test-attribute="fAlse">Some text</div>
* ```
*
* 1. Copy attribute value from the target element
*
* ```adblock
* example.org#%#//scriptlet('set-attr', 'iframe[data-cur]', 'href', '[data-cur]')
* ```
*
* ```html
* <!-- before -->
* <iframe data-cur="good-url.com" href="bad-url.org"></iframe>
*
* <!-- after -->
* <iframe data-cur="good-url.com" href="good-url.com"></iframe>
* ```
*
* @added v1.5.0.
*/
/* eslint-enable max-len */
Expand All @@ -107,17 +122,33 @@ export function setAttr(source, selector, attr, value = '') {

const allowedValues = ['true', 'false'];

// Drop strings that cant be parsed into number, negative numbers and numbers below 32767
if (value.length !== 0
const shouldCopyValue = value.startsWith('[') && value.endsWith(']');
const isIllegalValue = value.length !== 0
&& (nativeIsNaN(parseInt(value, 10))
|| parseInt(value, 10) < 0
|| parseInt(value, 10) > 32767)
&& !allowedValues.includes(value.toLowerCase())) {
&& !allowedValues.includes(value.toLowerCase());

if (!shouldCopyValue && isIllegalValue) {
logMessage(source, 'Illegal attribute value provided');
return;
}

setAttributeToSelection(source, selector, attr, value);
observeDOMChanges(() => setAttributeToSelection(source, selector, attr, value), true);
/**
* Defining value extraction logic here allows us to remove
* excessive `shouldCopyValue` checks in observer callback.
* Setting plain value is a default behavior.
*/
let attributeHandler;
if (shouldCopyValue) {
attributeHandler = (elem, attr, value) => {
const valueToCopy = elem.getAttribute(value.slice(1, -1));
elem.setAttribute(attr, valueToCopy);
};
}

setAttributeBySelector(source, selector, attr, value, attributeHandler);
observeDOMChanges(() => setAttributeBySelector(source, selector, attr, value, attributeHandler), true);
}

setAttr.names = [
Expand All @@ -129,7 +160,7 @@ setAttr.names = [
];

setAttr.injections = [
setAttributeToSelection,
setAttributeBySelector,
observeDOMChanges,
nativeIsNaN,
// following helpers should be imported and injected
Expand Down
8 changes: 4 additions & 4 deletions src/scriptlets/trusted-set-attr.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
setAttributeToSelection,
setAttributeBySelector,
observeDOMChanges,
nativeIsNaN,
// following helpers should be imported and injected
Expand Down Expand Up @@ -99,8 +99,8 @@ export function trustedSetAttr(source, selector, attr, value = '') {
return;
}

setAttributeToSelection(source, selector, attr, value);
observeDOMChanges(() => setAttributeToSelection(source, selector, attr, value), true);
setAttributeBySelector(source, selector, attr, value);
observeDOMChanges(() => setAttributeBySelector(source, selector, attr, value), true);
}

trustedSetAttr.names = [
Expand All @@ -109,7 +109,7 @@ trustedSetAttr.names = [
];

trustedSetAttr.injections = [
setAttributeToSelection,
setAttributeBySelector,
observeDOMChanges,
nativeIsNaN,
// following helpers should be imported and injected
Expand Down

0 comments on commit 88c365f

Please sign in to comment.