igniteui-webcomponents
Version:
Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.
136 lines • 4.03 kB
JavaScript
import { isServer } from 'lit';
import { isDocument, isElement } from '../util.js';
const ID_REF_EMITTERS = new WeakMap();
const ID_REF_EVENT = 'id-refs-change';
function getEmitter(root) {
let emitter = ID_REF_EMITTERS.get(root);
if (!emitter) {
emitter = new IdRefChangeEmitter(root);
ID_REF_EMITTERS.set(root, emitter);
}
return emitter;
}
function refObserverCallback(mutations, emitter) {
const affected = new Set();
for (const mutation of mutations) {
if (mutation.type === 'attributes') {
if (!isElement(mutation.target))
continue;
const oldId = mutation.oldValue;
const newId = mutation.target.id;
if (oldId)
affected.add(oldId);
if (newId)
affected.add(newId);
}
else {
for (const node of mutation.addedNodes) {
if (!isElement(node))
continue;
if (node.id)
affected.add(node.id);
for (const child of node.querySelectorAll('[id]')) {
if (child.id)
affected.add(child.id);
}
}
for (const node of mutation.removedNodes) {
if (!isElement(node))
continue;
if (node.id)
affected.add(node.id);
for (const child of node.querySelectorAll('[id]')) {
if (child.id)
affected.add(child.id);
}
}
}
}
if (affected.size > 0) {
emitter.dispatchEvent(new CustomEvent(ID_REF_EVENT, { detail: affected }));
}
}
class IdRefChangeEmitter extends EventTarget {
constructor(root) {
super();
this._refCount = 0;
this._root = root;
if (!isServer) {
this._observer = new MutationObserver((mutations) => refObserverCallback(mutations, this));
}
}
retain() {
if (this._refCount++ === 0) {
const root = isDocument(this._root) ? this._root.body : this._root;
this._observer?.observe(root, {
attributeFilter: ['id'],
attributeOldValue: true,
subtree: true,
childList: true,
});
}
}
release() {
if (this._refCount > 0 && --this._refCount === 0) {
this._observer?.disconnect();
}
}
}
class IdRefResolverController {
constructor(host, callback) {
this._active = false;
this._connected = false;
this._emitter = null;
this._host = host;
this._host.addController(this);
this._callback = callback;
}
_observe() {
const root = this._host.getRootNode();
this._emitter = getEmitter(root);
this._emitter.retain();
this._emitter.addEventListener(ID_REF_EVENT, this);
}
_unobserve() {
if (this._emitter) {
this._emitter.removeEventListener(ID_REF_EVENT, this);
this._emitter.release();
this._emitter = null;
}
}
handleEvent(event) {
this._callback.call(this._host, event.detail);
}
hostConnected() {
this._connected = true;
if (this._active) {
this._observe();
}
}
hostDisconnected() {
if (this._active) {
this._unobserve();
}
this._connected = false;
}
observe() {
if (this._active)
return;
this._active = true;
if (this._connected) {
this._observe();
}
}
unobserve() {
if (!this._active)
return;
this._active = false;
if (this._connected) {
this._unobserve();
}
}
}
export function addIdRefResolver(host, callback) {
return new IdRefResolverController(host, callback);
}
//# sourceMappingURL=id-resolver.js.map