Initial code commit

This commit is contained in:
Victor Westerlund 2024-09-11 16:49:29 +02:00
parent c602dbe39d
commit 6f254bf581
4 changed files with 147 additions and 0 deletions

16
.gitignore vendored Executable file
View file

@ -0,0 +1,16 @@
# Bootstrapping #
#################
vendor
.env.ini
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
.directory

16
.npmignore Normal file
View file

@ -0,0 +1,16 @@
# Bootstrapping #
#################
vendor
.env.ini
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
.directory

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "elevent",
"version": "1.1.2",
"main": "src/Elevent.mjs",
"type": "module",
"exports": {
".": {
"import": {
"default": "./src/Elevent.mjs"
}
}
}
}

102
src/Elevent.mjs Normal file
View file

@ -0,0 +1,102 @@
export class Elevent {
_type;
_callback;
_selector;
_boundElements = new WeakSet();
_controller = new AbortController();
_observer = new MutationObserver((mutations) => this.#mutationEvent(mutations));
/**
* Create a new Elevent instance.
* @param {string|null} eventType
* @param {HTMLCollection|HTMLElement|string|null} target Strings will be treated as CSS selectors, null will create a template instance
* @param {function} callback
*/
constructor(eventType = null, target = null, callback) {
this._type = eventType;
this._callback = callback;
if (target) {
switch (target.constructor) {
case HTMLCollection:
this.#bindHTMLCollection(target);
break;
case String:
this._selector = target;
this.#bindHTMLCollection(document.querySelectorAll(target));
// Automatically bind new DOM elements that match the provided CSS selector string
this._observer.observe(document.body, {
subtree: true,
childList: true
});
break;
default:
if (target instanceof HTMLElement) {
this.bind(target);
}
}
}
}
/**
* Event handler for this._observer
* @param {array} mutations
*/
#mutationEvent(mutations) {
// Iterate over all MutationRecords
mutations.forEach(mutation => mutation.addedNodes.forEach(node => {
// Bind new element if its CSS selector matches and has not already been bound
if (node.matches(this._selector) && !this._boundElements.has(node)) {
this.bind(node);
}
}));
}
/**
* Bind all HTMLElements inside an HTMLCollection
* @param {HTMLCollection} collection
*/
#bindHTMLCollection(collection) {
[...collection].forEach(element => this.bind(element));
}
/**
* Bind an element to this instance.
* @param {HTMLElement} target
*/
bind(target) {
/**
* Bind event listener of EventType on target element.
* The instance provided callback will only be executed if the target element is present in the bound elements Set.
*/
target.addEventListener(this._type, (event) => this._boundElements.has(target) && this._callback(event, this), {
signal: this._controller.signal
});
this._boundElements.add(target);
}
/**
* Remove all event listeners created from this instance.
* @param {HTMLElement} [target=null] An optional HTMLElement can be provided to soft-remove a specific element.
*/
remove(target = null) {
/**
* Soft-remove a single element from the bound elements Set.
* This will still trigger the event listener but the instance provided callback will not be executed.
*/
if (target) {
this._boundElements.delete(target);
return;
}
this._controller.abort();
this._observer.disconnect();
this._boundElements = new WeakSet();
}
}