Skip to content

Commit

Permalink
AG-35644 Fix 'trusted-create-element' — do not add element on every D…
Browse files Browse the repository at this point in the history
…OM changes. #450

Squashed commit of the following:

commit d3dc9d5
Author: Adam Wróblewski <adam@adguard.com>
Date:   Thu Sep 12 11:17:20 2024 +0200

    Fix issue with re-adding element on every DOM change in 'trusted-create-element' scriptlet
  • Loading branch information
AdamWr committed Sep 12, 2024
1 parent 51a1496 commit f093bc6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic

### Fixed

- issue with re-adding element on every DOM change in `trusted-create-element` scriptlet [#450]
- setting cookie which name has special prefix `__Host-` or `__Secure-` by
`trusted-set-cookie` and `trusted-set-cookie-reload` scriptlets [#448]

[Unreleased]: https://github.com/AdguardTeam/Scriptlets/compare/v1.11.27...HEAD
[#450]: https://github.com/AdguardTeam/Scriptlets/issues/450
[#448]: https://github.com/AdguardTeam/Scriptlets/issues/448

## [v1.11.27] - 2024-08-29
Expand Down
8 changes: 6 additions & 2 deletions src/scriptlets/trusted-create-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export function trustedCreateElement(

let timerId: ReturnType<typeof setTimeout>;

let elementCreated = false;
let elementRemoved = false;

/**
Expand Down Expand Up @@ -157,10 +158,13 @@ export function trustedCreateElement(
}

try {
parentEl.append(el);
if (!parentEl.contains(el)) {
parentEl.append(el);
}
if (el instanceof HTMLIFrameElement && el.contentWindow) {
el.contentWindow.name = IFRAME_WINDOW_NAME;
}
elementCreated = true;
hit(source);
} catch (e) {
logError(`Cannot append child to parent by selector '${parentElSelector}'`, e);
Expand All @@ -180,7 +184,7 @@ export function trustedCreateElement(

if (!findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) {
observeDocumentWithTimeout((mutations, observer) => {
if (elementRemoved || findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) {
if (elementRemoved || elementCreated || findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) {
observer.disconnect();
}
});
Expand Down
69 changes: 69 additions & 0 deletions tests/scriptlets/trusted-create-element.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,75 @@ test('creating empty div', (assert) => {
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('creating two elements', async (assert) => {
const childTagName1 = 'div';
const childTagName2 = 'span';

runScriptlet(name, [ROOT_SELECTOR, childTagName1]);
runScriptlet(name, [ROOT_SELECTOR, childTagName2]);

const { children } = createRoot(ROOT_ID);

assert.strictEqual(children.length, 0, 'Parent element has no children yet');

const done = assert.async();

// Wait for elements to be added
setTimeout(() => {
assert.strictEqual(children.length, 2, 'Only specified children were appended');

const child1 = children[0];
const child2 = children[1];

assert.strictEqual(child1.tagName.toLowerCase(), childTagName1, 'Tag name is set correctly');
assert.strictEqual(child1.textContent, '', 'Text content is set correctly');
assert.strictEqual(child1.attributes.length, 0, 'No attributes were set');

assert.strictEqual(child2.tagName.toLowerCase(), childTagName2, 'Tag name is set correctly');
assert.strictEqual(child2.textContent, '', 'Text content is set correctly');
assert.strictEqual(child2.attributes.length, 0, 'No attributes were set');

assert.strictEqual(window.hit, 'FIRED', 'hit fired');

done();
}, 10);
});

test('creating two elements - one inside another', async (assert) => {
const childTagName1 = 'div';
const childTagName2 = 'div';
const child2ClassName = 'adsbygoogle';

runScriptlet(name, [ROOT_SELECTOR, childTagName1]);
runScriptlet(name, [`${ROOT_SELECTOR} > ${childTagName1}`, childTagName2, `class="${child2ClassName}"`]);

const { children } = createRoot(ROOT_ID);

assert.strictEqual(children.length, 0, 'Parent element has no children yet');

const done = assert.async();

// Wait for elements to be added
setTimeout(() => {
assert.strictEqual(children.length, 1, 'Only specified children were appended');

const child1 = children[0];
const child2 = child1.querySelector('div.adsbygoogle');

assert.strictEqual(child1.tagName.toLowerCase(), childTagName1, 'Tag name is set correctly');
assert.strictEqual(child1.textContent, '', 'Text content is set correctly');
assert.strictEqual(child1.attributes.length, 0, 'No attributes were set');

assert.strictEqual(child2.tagName.toLowerCase(), childTagName2, 'Tag name is set correctly');
assert.strictEqual(child2.textContent, '', 'Text content is set correctly');
assert.strictEqual(child2.classList.contains('adsbygoogle'), true, '"adsbygoogle" class is set correctly');

assert.strictEqual(window.hit, 'FIRED', 'hit fired');

done();
}, 10);
});

test('setting text content', (assert) => {
const { children } = createRoot(ROOT_ID);

Expand Down

0 comments on commit f093bc6

Please sign in to comment.