-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AG-27676 Add trusted-dispatch-event scriptlet. #382
Squashed commit of the following: commit f174452 Author: Adam Wróblewski <adam@adguard.com> Date: Fri Apr 12 10:52:11 2024 +0200 Refactor trustedDispatchEvent and rename variables commit 88a5dd8 Author: Slava Leleka <v.leleka@adguard.com> Date: Thu Apr 11 18:26:17 2024 +0300 Update description commit b8cf974 Author: Adam Wróblewski <adam@adguard.com> Date: Thu Apr 11 17:20:03 2024 +0200 Update description commit 3736c8d Author: Adam Wróblewski <adam@adguard.com> Date: Thu Apr 11 16:32:35 2024 +0200 Rename `element` to `target` commit c6eee57 Author: Adam Wróblewski <adam@adguard.com> Date: Thu Apr 11 11:13:55 2024 +0200 Use common event types in examples commit edc0b49 Author: Slava Leleka <v.leleka@adguard.com> Date: Thu Apr 11 12:00:35 2024 +0300 Update docs commit cff3174 Author: Slava Leleka <v.leleka@adguard.com> Date: Thu Apr 11 12:00:01 2024 +0300 Update changelog commit c95fd26 Merge: 1f62260 62144fc Author: Adam Wróblewski <adam@adguard.com> Date: Tue Apr 9 10:20:33 2024 +0200 Merge branch 'master' into feature/AG-27676 commit 1f62260 Author: Adam Wróblewski <adam@adguard.com> Date: Fri Apr 5 13:36:03 2024 +0200 Change to trusted scriptlet commit 9382072 Author: Adam Wróblewski <adam@adguard.com> Date: Fri Apr 5 13:27:39 2024 +0200 Add ability to dispatch events on the window object commit 8007b06 Author: Adam Wróblewski <adam@adguard.com> Date: Thu Apr 4 16:07:47 2024 +0200 Add dispatch-event scriptlet
- Loading branch information
Showing
4 changed files
with
213 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { | ||
hit, | ||
} from '../helpers/index'; | ||
|
||
/** | ||
* @trustedScriptlet trusted-dispatch-event | ||
* | ||
* @description | ||
* Dispatches a custom event on a specified target. | ||
* | ||
* ### Syntax | ||
* ```text | ||
* example.org#%#//scriptlet('trusted-dispatch-event', event[, target]) | ||
* ``` | ||
* | ||
* - `event` — required, name of the event to dispatch | ||
* - `target` — optional, target on which event will be invoked. Possible values: | ||
* - CSS selector — dispatch event on the element with the specified selector | ||
* - `window` — dispatch event on the window object | ||
* - if not set, then "document" is used — it's default value | ||
* | ||
* ### Examples | ||
* | ||
* 1. Dispatches a custom event "click" on the document. | ||
* | ||
* ```adblock | ||
* example.org#%#//scriptlet('trusted-dispatch-event', 'click') | ||
* ``` | ||
* | ||
* 2. Dispatches a custom event "submit" on the element with the class "test". | ||
* | ||
* ```adblock | ||
* example.org#%#//scriptlet('trusted-dispatch-event', 'submit', '.test') | ||
* ``` | ||
* | ||
* 3. Dispatches a custom event "load" on the window object. | ||
* | ||
* ```adblock | ||
* example.org#%#//scriptlet('trusted-dispatch-event', 'load', 'window') | ||
* ``` | ||
* | ||
* @added unknown. | ||
*/ | ||
|
||
export function trustedDispatchEvent( | ||
source: Source, | ||
event: string, | ||
target: string, | ||
) { | ||
if (!event) { | ||
return; | ||
} | ||
|
||
let hasBeenDispatched = false; | ||
|
||
let eventTarget: typeof window | Document | Element | null = document; | ||
if (target === 'window') { | ||
eventTarget = window; | ||
} | ||
|
||
const events = new Set<string>(); | ||
|
||
const dispatch = () => { | ||
const customEvent = new Event(event); | ||
|
||
if (typeof target === 'string' && target !== 'window') { | ||
eventTarget = document.querySelector(target); | ||
} | ||
|
||
const isEventAdded = events.has(event); | ||
if (!hasBeenDispatched && isEventAdded && eventTarget) { | ||
hasBeenDispatched = true; | ||
hit(source); | ||
eventTarget.dispatchEvent(customEvent); | ||
} | ||
}; | ||
|
||
const wrapper = ( | ||
eventListener: typeof EventTarget.prototype.addEventListener, | ||
thisArg: Element, | ||
args: string[], | ||
) => { | ||
const eventName = args[0]; | ||
if (thisArg && eventName) { | ||
events.add(eventName); | ||
setTimeout(() => { | ||
dispatch(); | ||
}, 1); | ||
} | ||
return Reflect.apply(eventListener, thisArg, args); | ||
}; | ||
|
||
const handler = { | ||
apply: wrapper, | ||
}; | ||
EventTarget.prototype.addEventListener = new Proxy(EventTarget.prototype.addEventListener, handler); | ||
} | ||
|
||
trustedDispatchEvent.names = [ | ||
'trusted-dispatch-event', | ||
]; | ||
|
||
trustedDispatchEvent.injections = [ | ||
hit, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* eslint-disable no-underscore-dangle, no-console */ | ||
import { runScriptlet, clearGlobalProps } from '../helpers'; | ||
|
||
const { test, module } = QUnit; | ||
const name = 'trusted-dispatch-event'; | ||
|
||
const createElem = () => { | ||
const div = document.createElement('div'); | ||
div.setAttribute('id', 'testElem'); | ||
|
||
document.body.appendChild(div); | ||
return div; | ||
}; | ||
|
||
const removeElem = () => { | ||
const elem = document.getElementById('testElem'); | ||
if (elem) { | ||
elem.remove(); | ||
} | ||
}; | ||
|
||
const beforeEach = () => { | ||
window.__debug = () => { | ||
window.hit = 'FIRED'; | ||
}; | ||
}; | ||
|
||
const afterEach = () => { | ||
clearGlobalProps('hit', '__debug'); | ||
removeElem(); | ||
}; | ||
|
||
module(name, { beforeEach, afterEach }); | ||
|
||
test('Dispatch event - document', (assert) => { | ||
const event = 'testEvent1'; | ||
|
||
let eventFired = false; | ||
|
||
const scriptletArgs = [event]; | ||
runScriptlet(name, scriptletArgs); | ||
|
||
assert.strictEqual(eventFired, false, 'Event not fired yet'); | ||
|
||
document.addEventListener('testEvent1', () => { | ||
eventFired = true; | ||
}); | ||
|
||
const done = assert.async(); | ||
setTimeout(() => { | ||
assert.strictEqual(eventFired, true, 'Event fired'); | ||
assert.strictEqual(window.hit, 'FIRED'); | ||
done(); | ||
}, 10); | ||
}); | ||
|
||
test('Dispatch event - specific element', (assert) => { | ||
const event = 'testEvent2'; | ||
const selector = '#testElem'; | ||
|
||
let eventFired = false; | ||
|
||
const scriptletArgs = [event, selector]; | ||
runScriptlet(name, scriptletArgs); | ||
|
||
const elem = createElem(); | ||
|
||
assert.strictEqual(eventFired, false, 'Event not fired yet'); | ||
|
||
elem.addEventListener('testEvent2', () => { | ||
eventFired = true; | ||
}); | ||
|
||
const done = assert.async(); | ||
setTimeout(() => { | ||
assert.strictEqual(eventFired, true, 'Event fired'); | ||
assert.strictEqual(window.hit, 'FIRED'); | ||
done(); | ||
}, 10); | ||
}); | ||
|
||
test('Dispatch event - window object', (assert) => { | ||
const event = 'windowObj'; | ||
const selector = 'window'; | ||
|
||
let eventFired = false; | ||
|
||
const scriptletArgs = [event, selector]; | ||
runScriptlet(name, scriptletArgs); | ||
|
||
assert.strictEqual(eventFired, false, 'Event not fired yet'); | ||
|
||
window.addEventListener('windowObj', () => { | ||
eventFired = true; | ||
}); | ||
|
||
const done = assert.async(); | ||
setTimeout(() => { | ||
assert.strictEqual(eventFired, true, 'Event fired'); | ||
assert.strictEqual(window.hit, 'FIRED'); | ||
done(); | ||
}, 10); | ||
}); |