@ibyar/core
Version:
Ibyar core, Implements Aurora's core functionality, low-level services, and utilities
172 lines • 5.8 kB
JavaScript
export class MutationObservable {
attributes = new Map();
remove = new WeakMap();
insert = new WeakMap();
emit(attributeName, value, oldValue) {
const calls = this.attributes.get(attributeName);
calls?.forEach(callback => {
try {
callback(value, oldValue);
}
catch (error) {
console.error(error);
}
});
}
emitNodeRemove(node) {
this.emitNode(this.remove, node);
}
emitNodeInsert(node) {
this.emitNode(this.insert, node);
}
emitNode(actionMap, node) {
const calls = actionMap.get(node);
calls?.forEach(callback => {
try {
callback();
}
catch (error) {
console.error(error);
}
});
}
subscribe(attributeName, callback) {
let calls = this.attributes.get(attributeName);
if (!calls) {
calls = [];
this.attributes.set(attributeName, calls);
}
calls.push(callback);
return new MutationSubscription(this, attributeName, callback);
}
subscribeOnRemoveNode(node, callback) {
return this.subscribeNodeAction(this.remove, node, callback);
}
subscribeOnInsertNode(node, callback) {
return this.subscribeNodeAction(this.insert, node, callback);
}
subscribeNodeAction(actionMap, node, callback) {
let calls = actionMap.get(node);
if (!calls) {
calls = [];
actionMap.set(node, calls);
}
calls.push(callback);
return new MutationSubscription(this, new WeakRef(node), callback);
}
unsubscribe(eventName, callback) {
const calls = this.attributes.get(eventName);
if (calls) {
const index = calls.indexOf(callback);
if (index !== -1) {
calls.splice(index, 1);
}
}
}
unsubscribeOnRemoveNode(node, callback) {
this.unsubscribeNodeAction(this.remove, node, callback);
}
unsubscribeOnInsertNode(node, callback) {
this.unsubscribeNodeAction(this.insert, node, callback);
}
unsubscribeNodeAction(actionMap, node, callback) {
const calls = actionMap.get(node);
if (calls) {
const index = calls.indexOf(callback);
if (index !== -1) {
calls.splice(index, 1);
}
}
}
destroy() {
this.attributes.clear();
}
}
export class MutationSubscription {
observable;
key;
callback;
type;
constructor(observable, key, callback) {
this.observable = observable;
this.key = key;
this.callback = callback;
this.type = typeof key === 'string' ? 'attribute' : 'remove';
}
unsubscribe() {
if (this.type === 'attribute') {
this.observable.unsubscribe(this.key, this.callback);
}
else {
const ref = this.key.deref();
if (ref) {
this.observable.unsubscribeOnRemoveNode(ref, this.callback);
}
}
}
}
export class ElementMutation {
static Mutation_OPTIONS = {
attributes: true,
childList: true,
subtree: true,
attributeOldValue: true,
};
observables = new WeakMap();
mutationCallback = (mutations, observer) => {
mutations.forEach((mut) => {
switch (mut.type) {
case 'childList':
{
// insert/remove events
if (mut.removedNodes.length > 0 && this.observables.has(mut.target)) {
const observable = this.observables.get(mut.target);
mut.removedNodes.forEach(node => observable.emitNodeRemove(node));
}
}
break;
case 'attributes':
default:
{
const observable = this.observables.get(mut.target);
observable && observable.emit(mut.attributeName, mut.target.nodeValue, mut.oldValue);
}
break;
}
});
};
mutationObserver = new MutationObserver(this.mutationCallback);
subscribe(target, attributeName, callback) {
let observable = this.observables.get(target);
if (!observable) {
observable = new MutationObservable();
this.observables.set(target, observable);
this.mutationObserver.observe(target, ElementMutation.Mutation_OPTIONS);
}
return observable.subscribe(attributeName, callback);
}
subscribeOnRemoveNode(target, node, callback) {
let observable = this.observables.get(target);
if (!observable) {
observable = new MutationObservable();
this.observables.set(target, observable);
this.mutationObserver.observe(target, ElementMutation.Mutation_OPTIONS);
}
return observable.subscribeOnRemoveNode(node, callback);
}
subscribeOnInsertNode(target, node, callback) {
let observable = this.observables.get(target);
if (!observable) {
observable = new MutationObservable();
this.observables.set(target, observable);
this.mutationObserver.observe(target, ElementMutation.Mutation_OPTIONS);
}
return observable.subscribeOnInsertNode(node, callback);
}
disconnect() {
const records = this.mutationObserver.takeRecords();
this.mutationObserver.disconnect();
this.mutationCallback(records, this.mutationObserver);
}
}
//# sourceMappingURL=mutation.js.map