mount-observer 0.0.112 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Events.js +62 -26
- package/Events.ts +52 -30
- package/MountObserver.js +285 -514
- package/MountObserver.ts +362 -538
- package/README.md +149 -56
- package/SharedMutationObserver.js +70 -0
- package/SharedMutationObserver.ts +96 -0
- package/attrCoordinates.js +93 -0
- package/attrCoordinates.ts +122 -0
- package/index.js +3 -0
- package/index.ts +22 -0
- package/loadImports.js +47 -0
- package/loadImports.ts +56 -0
- package/mediaQuery.js +86 -0
- package/mediaQuery.ts +113 -0
- package/package.json +11 -119
- package/playwright.config.ts +0 -1
- package/types.d.ts +104 -0
- package/whereAttr.js +174 -0
- package/whereAttr.ts +221 -0
- package/LICENSE +0 -21
- package/Newish.js +0 -145
- package/Newish.ts +0 -169
- package/ObsAttr.js +0 -18
- package/ObsAttr.ts +0 -18
- package/RootMutObs.js +0 -49
- package/RootMutObs.ts +0 -58
- package/Synthesizer.js +0 -125
- package/Synthesizer.ts +0 -130
- package/bindish.js +0 -15
- package/bindish.ts +0 -22
- package/compose.js +0 -148
- package/compose.ts +0 -164
- package/doCleanup.js +0 -31
- package/doCleanup.ts +0 -34
- package/getWhereAttrSelector.js +0 -83
- package/getWhereAttrSelector.ts +0 -92
- package/preloadContent.js +0 -44
- package/preloadContent.ts +0 -47
- package/readAttrs.ts +0 -60
- package/refid/README.md +0 -259
- package/refid/arr.js +0 -4
- package/refid/arr.ts +0 -4
- package/refid/camelToKebab.js +0 -4
- package/refid/camelToKebab.ts +0 -4
- package/refid/genIds.js +0 -190
- package/refid/genIds.ts +0 -177
- package/refid/getAdjRefs.js +0 -38
- package/refid/getAdjRefs.ts +0 -38
- package/refid/getContext.js +0 -13
- package/refid/getContext.ts +0 -14
- package/refid/getCount.js +0 -8
- package/refid/getCount.ts +0 -8
- package/refid/getIsh.js +0 -35
- package/refid/getIsh.ts +0 -37
- package/refid/hostish.js +0 -18
- package/refid/hostish.ts +0 -20
- package/refid/ism.js +0 -78
- package/refid/ism.ts +0 -81
- package/refid/itemprops.js +0 -60
- package/refid/itemprops.ts +0 -67
- package/refid/joinMatching.js +0 -56
- package/refid/joinMatching.ts +0 -54
- package/refid/nudge.js +0 -23
- package/refid/nudge.ts +0 -23
- package/refid/regIsh.js +0 -27
- package/refid/regIsh.ts +0 -31
- package/refid/secretKeys.js +0 -5
- package/refid/secretKeys.ts +0 -5
- package/refid/splitRefs.js +0 -6
- package/refid/splitRefs.ts +0 -6
- package/refid/stdVal.js +0 -15
- package/refid/stdVal.ts +0 -15
- package/refid/via.js +0 -114
- package/refid/via.ts +0 -113
- package/slotkin/affine.js +0 -39
- package/slotkin/affine.ts +0 -46
- package/slotkin/beKindred.js +0 -45
- package/slotkin/beKindred.ts +0 -55
- package/slotkin/getBreadth.js +0 -19
- package/slotkin/getBreadth.ts +0 -21
- package/slotkin/getFrag.js +0 -22
- package/slotkin/getFrag.ts +0 -21
- package/slotkin/toQuery.js +0 -12
- package/slotkin/toQuery.ts +0 -13
- package/slotkin/wrap.js +0 -13
- package/slotkin/wrap.ts +0 -18
- package/ts-refs/LICENSE +0 -21
- package/ts-refs/README.md +0 -18
- package/ts-refs/be-a-beacon/types.d.ts +0 -22
- package/ts-refs/be-alit/types.d.ts +0 -1
- package/ts-refs/be-based/types.d.ts +0 -32
- package/ts-refs/be-bound/types.d.ts +0 -65
- package/ts-refs/be-buttoned-up/types.d.ts +0 -21
- package/ts-refs/be-calculating/types.d.ts +0 -57
- package/ts-refs/be-clonable/types.d.ts +0 -28
- package/ts-refs/be-committed/types.d.ts +0 -26
- package/ts-refs/be-consoling/types.d.ts +0 -25
- package/ts-refs/be-counted/types.d.ts +0 -88
- package/ts-refs/be-delible/types.d.ts +0 -26
- package/ts-refs/be-directive/types.d.ts +0 -43
- package/ts-refs/be-dispatching/types.d.ts +0 -41
- package/ts-refs/be-elevating/types.d.ts +0 -55
- package/ts-refs/be-enhanced/types.d.ts +0 -32
- package/ts-refs/be-enhancing/types.d.ts +0 -31
- package/ts-refs/be-evanescent/types.d.ts +0 -20
- package/ts-refs/be-eventing/types.d.ts +0 -27
- package/ts-refs/be-exportable/types.d.ts +0 -26
- package/ts-refs/be-fetching/types.d.ts +0 -73
- package/ts-refs/be-flashy/types.d.ts +0 -27
- package/ts-refs/be-formalizing/types.d.ts +0 -29
- package/ts-refs/be-formidable/types.d.ts +0 -64
- package/ts-refs/be-giddy/types.d.ts +0 -26
- package/ts-refs/be-gingerly/types.d.ts +0 -19
- package/ts-refs/be-gone/types.d.ts +0 -24
- package/ts-refs/be-hashing-out/types.d.ts +0 -22
- package/ts-refs/be-hive/types.d.ts +0 -18
- package/ts-refs/be-imbued/types.d.ts +0 -30
- package/ts-refs/be-included/types.d.ts +0 -20
- package/ts-refs/be-inclusive/types.d.ts +0 -30
- package/ts-refs/be-intersectional/types.d.ts +0 -37
- package/ts-refs/be-intl/types.d.ts +0 -28
- package/ts-refs/be-invoking/types.d.ts +0 -28
- package/ts-refs/be-joining/types.d.ts +0 -26
- package/ts-refs/be-kvetching/types.d.ts +0 -24
- package/ts-refs/be-lazy/types.d.ts +0 -29
- package/ts-refs/be-literate/types.d.ts +0 -29
- package/ts-refs/be-mediating/types.d.ts +0 -34
- package/ts-refs/be-methodical/types.d.ts +0 -20
- package/ts-refs/be-modding/types.d.ts +0 -18
- package/ts-refs/be-observant/types.d.ts +0 -27
- package/ts-refs/be-observing/types.d.ts +0 -84
- package/ts-refs/be-parsed/types.d.ts +0 -19
- package/ts-refs/be-parsing/types.d.ts +0 -37
- package/ts-refs/be-persistent/types.d.ts +0 -66
- package/ts-refs/be-propagating/types.d.ts +0 -26
- package/ts-refs/be-reformable/types.d.ts +0 -48
- package/ts-refs/be-render-neutral/types.d.ts +0 -31
- package/ts-refs/be-scoped/types.d.ts +0 -24
- package/ts-refs/be-sharing/types.d.ts +0 -17
- package/ts-refs/be-switched/types.d.ts +0 -155
- package/ts-refs/be-typed/types.d.ts +0 -36
- package/ts-refs/be-value-added/types.d.ts +0 -34
- package/ts-refs/be-valued/types.d.ts +0 -22
- package/ts-refs/be-written/types.d.ts +0 -59
- package/ts-refs/css-charts/types.d.ts +0 -38
- package/ts-refs/css-echarts/types.d.ts +0 -13
- package/ts-refs/data-props/types.d.ts +0 -27
- package/ts-refs/do-inc/types.d.ts +0 -28
- package/ts-refs/do-invoke/types.d.ts +0 -28
- package/ts-refs/do-toggle/types.d.ts +0 -27
- package/ts-refs/em-bower/types.d.ts +0 -24
- package/ts-refs/fetch-for/types.d.ts +0 -37
- package/ts-refs/folder-picker/types.d.ts +0 -43
- package/ts-refs/for-fetch/doc.d.ts +0 -98
- package/ts-refs/for-fetch/types.d.ts +0 -83
- package/ts-refs/mount-observer/types.d.ts +0 -248
- package/ts-refs/mt-si/types.d.ts +0 -21
- package/ts-refs/per-each/types.d.ts +0 -51
- package/ts-refs/soak-up/types.d.ts +0 -36
- package/ts-refs/trans-render/XV/types.d.ts +0 -69
- package/ts-refs/trans-render/asmr/types.d.ts +0 -138
- package/ts-refs/trans-render/be/types.d.ts +0 -198
- package/ts-refs/trans-render/dss/types.d.ts +0 -57
- package/ts-refs/trans-render/froop/types.d.ts +0 -416
- package/ts-refs/trans-render/funions/types.d.ts +0 -12
- package/ts-refs/trans-render/lib/mixins/types.d.ts +0 -42
- package/ts-refs/trans-render/lib/prs/types.d.ts +0 -40
- package/ts-refs/trans-render/lib/types.d.ts +0 -489
- package/ts-refs/trans-render/types.d.ts +0 -583
- package/ts-refs/wc-info/SimpleWCInfo.d.ts +0 -15
- package/ts-refs/when-resolved/types.d.ts +0 -30
- package/ts-refs/xp-as/types.d.ts +0 -20
- package/ts-refs/xtal-element/types.d.ts +0 -43
- package/ts-refs/xtal-frappe-chart/types.d.ts +0 -193
- package/upShadowSearch.js +0 -25
- package/upShadowSearch.ts +0 -23
- package/waitForEvent.js +0 -12
- package/waitForEvent.ts +0 -13
- package/waitForIsh.js +0 -21
- package/waitForIsh.ts +0 -20
package/MountObserver.js
CHANGED
|
@@ -1,574 +1,345 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import './refid/hostish.js'; // gets embedded even if not used
|
|
4
|
-
export const guid = '5Pv6bHOVH0ae07opRZ8N/g';
|
|
5
|
-
export const wasItemReffed = Symbol.for('8aA6xB8+PkScmivaslBk5Q');
|
|
6
|
-
export const mutationObserverLookup = new WeakMap();
|
|
7
|
-
const refCount = new WeakMap();
|
|
1
|
+
import { MountEvent, DismountEvent, DisconnectEvent, LoadEvent, AttrChangeEvent } from './Events.js';
|
|
2
|
+
import { registerSharedObserver, unregisterSharedObserver } from './SharedMutationObserver.js';
|
|
8
3
|
export class MountObserver extends EventTarget {
|
|
9
|
-
#
|
|
4
|
+
#init;
|
|
10
5
|
#options;
|
|
11
|
-
//#rootMutObs: RootMutObs | undefined;
|
|
12
6
|
#abortController;
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
#modules = [];
|
|
8
|
+
#mountedElements = new WeakSet();
|
|
9
|
+
#processedElements = new WeakSet();
|
|
10
|
+
#mutationCallback;
|
|
11
|
+
#rootNode;
|
|
12
|
+
#importsLoaded = false;
|
|
13
|
+
#elementAttrStates = new WeakMap();
|
|
14
|
+
#elementOnceAttrs = new WeakMap();
|
|
15
|
+
#matchesWhereAttrFn = null;
|
|
16
|
+
#buildAttrCoordinateMapFn = null;
|
|
17
|
+
#mediaQueryCleanup;
|
|
18
|
+
#mediaMatches = true;
|
|
19
|
+
constructor(init, options = {}) {
|
|
20
20
|
super();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//TODO: study this problem further. Starting to think this is basically not polyfillable
|
|
24
|
-
if (on !== undefined) {
|
|
25
|
-
const reducedMatch = on.replaceAll(':not(', '');
|
|
26
|
-
isComplex = reducedMatch.includes(' ') || (reducedMatch.includes(':') && reducedMatch.includes('('));
|
|
27
|
-
}
|
|
28
|
-
this.#isComplex = isComplex;
|
|
29
|
-
if (whereElementIntersectsWith)
|
|
30
|
-
throw 'NI'; //not implemented
|
|
31
|
-
this.#mountInit = init;
|
|
21
|
+
this.#init = init;
|
|
22
|
+
this.#options = options;
|
|
32
23
|
this.#abortController = new AbortController();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.#disconnected = new WeakSet();
|
|
38
|
-
//this.#unmounted = new WeakSet();
|
|
39
|
-
}
|
|
40
|
-
#calculatedSelector;
|
|
41
|
-
#attrParts;
|
|
42
|
-
#fullListOfEnhancementAttrs;
|
|
43
|
-
async observedAttrs() {
|
|
44
|
-
await this.#selector();
|
|
45
|
-
return this.#fullListOfEnhancementAttrs;
|
|
46
|
-
}
|
|
47
|
-
//get #attrVals
|
|
48
|
-
async #selector() {
|
|
49
|
-
if (this.#calculatedSelector !== undefined)
|
|
50
|
-
return this.#calculatedSelector;
|
|
51
|
-
const { on, whereAttr } = this.#mountInit;
|
|
52
|
-
const withoutAttrs = on || '*';
|
|
53
|
-
if (whereAttr === undefined)
|
|
54
|
-
return withoutAttrs;
|
|
55
|
-
const { getWhereAttrSelector } = await import('./getWhereAttrSelector.js');
|
|
56
|
-
const info = await getWhereAttrSelector(whereAttr, withoutAttrs);
|
|
57
|
-
const { fullListOfAttrs, calculatedSelector, partitionedAttrs } = info;
|
|
58
|
-
this.#fullListOfEnhancementAttrs = fullListOfAttrs;
|
|
59
|
-
this.#attrParts = partitionedAttrs;
|
|
60
|
-
this.#calculatedSelector = calculatedSelector;
|
|
61
|
-
return this.#calculatedSelector;
|
|
62
|
-
}
|
|
63
|
-
//This method is called publicly from outside mount-observer -- keep it public
|
|
64
|
-
async composeFragment(fragment, level) {
|
|
65
|
-
const bis = fragment.querySelectorAll(`${inclTemplQry}`);
|
|
66
|
-
for (const bi of bis) {
|
|
67
|
-
if (bi.getAttribute('rel') === 'preload') {
|
|
68
|
-
(await import('./preloadContent.js')).preloadContent(bi);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
await this.#compose(bi, level);
|
|
72
|
-
}
|
|
24
|
+
if (options.disconnectedSignal) {
|
|
25
|
+
options.disconnectedSignal.addEventListener('abort', () => {
|
|
26
|
+
this.disconnect();
|
|
27
|
+
});
|
|
73
28
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const src = el.getAttribute('src');
|
|
78
|
-
if (src === null || src.length < 2)
|
|
79
|
-
return;
|
|
80
|
-
const refType = src[0];
|
|
81
|
-
if (!['!', '#'].includes(refType))
|
|
82
|
-
return;
|
|
83
|
-
const { compose } = await import('./compose.js');
|
|
84
|
-
await compose(this, el, level, src.substring(1), refType);
|
|
85
|
-
}
|
|
86
|
-
#templLookUp = new Map();
|
|
87
|
-
#searchForComment(refName, fragment) {
|
|
88
|
-
//get rid of
|
|
89
|
-
const iterator = document.evaluate(`//comment()[.="${refName}"]`, fragment, null, XPathResult.ANY_TYPE, null);
|
|
90
|
-
//console.log({xpathResult})
|
|
91
|
-
try {
|
|
92
|
-
let thisNode = iterator.iterateNext();
|
|
93
|
-
return thisNode;
|
|
29
|
+
// Preload whereAttr utilities if needed
|
|
30
|
+
if (init.whereAttr) {
|
|
31
|
+
this.#preloadWhereAttrUtilities();
|
|
94
32
|
}
|
|
95
|
-
|
|
96
|
-
|
|
33
|
+
// Start loading imports if eager
|
|
34
|
+
if (init.loadingEagerness === 'eager' && init.import) {
|
|
35
|
+
this.#loadImports();
|
|
97
36
|
}
|
|
98
37
|
}
|
|
99
|
-
async
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return this.#templLookUp.get(refName);
|
|
104
|
-
let templ = null;
|
|
105
|
-
templ = refType === '#' ? fragment.querySelector(`#${refName}`) : this.#searchForComment(refName, fragment);
|
|
106
|
-
if (templ === null) {
|
|
107
|
-
let rootToSearchOutwardFrom = ((fragment.isConnected ? fragment.getRootNode() : this.#mountInit.withTargetShadowRoot) || document);
|
|
108
|
-
templ = refType === '#' ? rootToSearchOutwardFrom.getElementById(refName) : this.#searchForComment(refName, rootToSearchOutwardFrom);
|
|
109
|
-
while (templ === null && rootToSearchOutwardFrom !== document) {
|
|
110
|
-
rootToSearchOutwardFrom = (rootToSearchOutwardFrom.host || rootToSearchOutwardFrom).getRootNode();
|
|
111
|
-
templ = refType === '#' ? rootToSearchOutwardFrom.getElementById(refName) : this.#searchForComment(refName, rootToSearchOutwardFrom);
|
|
112
|
-
}
|
|
38
|
+
async #preloadWhereAttrUtilities() {
|
|
39
|
+
if (!this.#matchesWhereAttrFn) {
|
|
40
|
+
const { matchesWhereAttr } = await import('./whereAttr.js');
|
|
41
|
+
this.#matchesWhereAttrFn = matchesWhereAttr;
|
|
113
42
|
}
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const { getAdjRefs } = await import('./refid/getAdjRefs.js');
|
|
118
|
-
const adjRefs = getAdjRefs(templ);
|
|
119
|
-
// if(adjRefs.length > 1){
|
|
120
|
-
// (<any>newTempl)[wasItemReffed] = true;
|
|
121
|
-
// adjRefs[0].setAttribute('itemref', '<autogen>');
|
|
122
|
-
// }
|
|
123
|
-
const fragment = document.createDocumentFragment();
|
|
124
|
-
let first = true;
|
|
125
|
-
for (const adjRef of adjRefs) {
|
|
126
|
-
const clone = adjRef.cloneNode(true);
|
|
127
|
-
if (refType === '#' && clone instanceof Element) {
|
|
128
|
-
if (first && adjRefs.length > 1) {
|
|
129
|
-
clone.setAttribute('itemref', '<autogen>');
|
|
130
|
-
newTempl[wasItemReffed] = true;
|
|
131
|
-
first = false;
|
|
132
|
-
}
|
|
133
|
-
clone.removeAttribute('id');
|
|
134
|
-
}
|
|
135
|
-
fragment.appendChild(clone);
|
|
136
|
-
}
|
|
137
|
-
if (templ instanceof Element) {
|
|
138
|
-
const { doCleanup } = await import('./doCleanup.js');
|
|
139
|
-
doCleanup(templ, fragment);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
//TODO: cleanup
|
|
143
|
-
}
|
|
144
|
-
newTempl.content.appendChild(fragment);
|
|
145
|
-
templ = newTempl;
|
|
146
|
-
}
|
|
147
|
-
this.#templLookUp.set(refName, templ);
|
|
43
|
+
if (!this.#buildAttrCoordinateMapFn) {
|
|
44
|
+
const { buildAttrCoordinateMap } = await import('./attrCoordinates.js');
|
|
45
|
+
this.#buildAttrCoordinateMapFn = buildAttrCoordinateMap;
|
|
148
46
|
}
|
|
149
|
-
return templ;
|
|
150
47
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (currentCount !== undefined) {
|
|
155
|
-
if (currentCount <= 1) {
|
|
156
|
-
const observer = mutationObserverLookup.get(nodeToMonitor);
|
|
157
|
-
if (observer === undefined) {
|
|
158
|
-
console.warn(refCountErr);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
observer.disconnect();
|
|
162
|
-
mutationObserverLookup.delete(nodeToMonitor);
|
|
163
|
-
refCount.delete(nodeToMonitor);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
refCount.set(nodeToMonitor, currentCount + 1);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
if (mutationObserverLookup.has(nodeToMonitor)) {
|
|
172
|
-
console.warn(refCountErr);
|
|
173
|
-
}
|
|
48
|
+
async #setupMediaQuery() {
|
|
49
|
+
if (!this.#rootNode) {
|
|
50
|
+
throw new Error('Cannot setup media query before observe() is called');
|
|
174
51
|
}
|
|
175
|
-
|
|
52
|
+
const { setupMediaQuery } = await import('./mediaQuery.js');
|
|
53
|
+
const result = setupMediaQuery(this.#init, this.#rootNode, this.#mountedElements, this.#modules, this, (node) => this.#processNode(node));
|
|
54
|
+
this.#mediaMatches = result.mediaMatches;
|
|
55
|
+
this.#mediaQueryCleanup = result.cleanup;
|
|
176
56
|
}
|
|
177
|
-
|
|
178
|
-
this.#
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
return;
|
|
57
|
+
get disconnectedSignal() {
|
|
58
|
+
return this.#abortController.signal;
|
|
59
|
+
}
|
|
60
|
+
async observe(rootNode) {
|
|
61
|
+
if (this.#rootNode) {
|
|
62
|
+
throw new Error('Already observing');
|
|
184
63
|
}
|
|
185
|
-
|
|
186
|
-
if (
|
|
187
|
-
|
|
64
|
+
this.#rootNode = new WeakRef(rootNode);
|
|
65
|
+
// Set up media query if specified (needs rootNode to be set first)
|
|
66
|
+
if (this.#init.whereMediaMatches) {
|
|
67
|
+
await this.#setupMediaQuery();
|
|
188
68
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
await this.#observe2(within);
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
await this.#mountAll();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
if (this.objNde !== undefined) {
|
|
200
|
-
await this.#dismountAll();
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
async #observe2(within) {
|
|
206
|
-
await this.#selector();
|
|
207
|
-
this.objNde = new WeakRef(within);
|
|
208
|
-
const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
|
|
209
|
-
if (!mutationObserverLookup.has(nodeToMonitor)) {
|
|
210
|
-
mutationObserverLookup.set(nodeToMonitor, new RootMutObs(nodeToMonitor, this.#mountInit));
|
|
211
|
-
refCount.set(nodeToMonitor, 1);
|
|
69
|
+
// Wait for whereAttr utilities to load if needed
|
|
70
|
+
if (this.#init.whereAttr && !this.#matchesWhereAttrFn) {
|
|
71
|
+
await this.#preloadWhereAttrUtilities();
|
|
212
72
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
console.warn(refCountErr);
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
refCount.set(nodeToMonitor, currentCount + 1);
|
|
220
|
-
}
|
|
73
|
+
// Process existing elements only if media matches
|
|
74
|
+
if (this.#mediaMatches) {
|
|
75
|
+
this.#processNode(rootNode);
|
|
221
76
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (this.#isComplex) {
|
|
227
|
-
this.#inspectWithin(within, false);
|
|
77
|
+
// Create mutation callback
|
|
78
|
+
this.#mutationCallback = (mutations) => {
|
|
79
|
+
// Skip processing if media doesn't match
|
|
80
|
+
if (!this.#mediaMatches) {
|
|
228
81
|
return;
|
|
229
82
|
}
|
|
230
|
-
const
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const { addedNodes, type, removedNodes } = mutationRecord;
|
|
237
|
-
const addedElements = Array.from(addedNodes).filter(x => x instanceof Element);
|
|
238
|
-
addedElements.forEach(x => elsToInspect.push(x));
|
|
239
|
-
if (type === 'attributes') {
|
|
240
|
-
const { target, attributeName, oldValue } = mutationRecord;
|
|
241
|
-
if (target instanceof Element && attributeName !== null /*&& this.#mounted.has(target)*/) {
|
|
242
|
-
if (fullListOfAttrs !== undefined) {
|
|
243
|
-
const idx = fullListOfAttrs.indexOf(attributeName);
|
|
244
|
-
if (idx !== -1) {
|
|
245
|
-
if (attrChangeInfosMap === undefined)
|
|
246
|
-
attrChangeInfosMap = new Map();
|
|
247
|
-
let attrChangeInfos = attrChangeInfosMap.get(target);
|
|
248
|
-
if (attrChangeInfos === undefined) {
|
|
249
|
-
attrChangeInfos = [];
|
|
250
|
-
attrChangeInfosMap.set(target, attrChangeInfos);
|
|
251
|
-
}
|
|
252
|
-
const newValue = target.getAttribute(attributeName);
|
|
253
|
-
const parts = this.#attrParts[idx];
|
|
254
|
-
const attrChangeInfo = {
|
|
255
|
-
isSOfTAttr: false,
|
|
256
|
-
oldValue,
|
|
257
|
-
name: attributeName,
|
|
258
|
-
newValue,
|
|
259
|
-
idx,
|
|
260
|
-
parts
|
|
261
|
-
};
|
|
262
|
-
attrChangeInfos.push(attrChangeInfo);
|
|
263
|
-
}
|
|
83
|
+
const attrChanges = [];
|
|
84
|
+
for (const mutation of mutations) {
|
|
85
|
+
if (mutation.type === 'childList') {
|
|
86
|
+
for (const node of mutation.addedNodes) {
|
|
87
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
88
|
+
this.#processNode(node);
|
|
264
89
|
}
|
|
265
90
|
}
|
|
266
|
-
|
|
91
|
+
mutation.removedNodes.forEach(node => {
|
|
92
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
93
|
+
this.#handleRemoval(node);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
267
96
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.#
|
|
272
|
-
|
|
273
|
-
|
|
97
|
+
else if (mutation.type === 'attributes' && mutation.target.nodeType === Node.ELEMENT_NODE) {
|
|
98
|
+
// Handle attribute changes for mounted elements
|
|
99
|
+
const element = mutation.target;
|
|
100
|
+
if (this.#mountedElements.has(element) && this.#init.whereAttr) {
|
|
101
|
+
const changes = this.#checkAttrChanges(element);
|
|
102
|
+
attrChanges.push(...changes);
|
|
274
103
|
}
|
|
275
|
-
this.dispatchEvent(new DisconnectEvent(deletedElement));
|
|
276
104
|
}
|
|
277
105
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.dispatchEvent(new AttrChangeEvent(key, value));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
this.#filterAndMount(elsToInspect, within, true, false);
|
|
285
|
-
for (const el of elsToInspect) {
|
|
286
|
-
await this.#inspectWithin(el, false);
|
|
287
|
-
}
|
|
288
|
-
}, { signal: this.#abortController.signal });
|
|
289
|
-
await this.#inspectWithin(within, true);
|
|
290
|
-
}
|
|
291
|
-
static synthesize(within, customElement, mose) {
|
|
292
|
-
//TODO: make external
|
|
293
|
-
mose.type = 'mountobserver';
|
|
294
|
-
const name = customElements.getName(customElement);
|
|
295
|
-
if (name === null)
|
|
296
|
-
throw 400;
|
|
297
|
-
let instance = within.querySelector(name);
|
|
298
|
-
if (instance === null) {
|
|
299
|
-
instance = new customElement();
|
|
300
|
-
if (within === document) {
|
|
301
|
-
within.head.appendChild(instance);
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
within.appendChild(instance);
|
|
106
|
+
// Batch and dispatch attribute changes
|
|
107
|
+
if (attrChanges.length > 0) {
|
|
108
|
+
this.dispatchEvent(new AttrChangeEvent(attrChanges, this.#init));
|
|
305
109
|
}
|
|
110
|
+
};
|
|
111
|
+
const observerConfig = {
|
|
112
|
+
childList: true,
|
|
113
|
+
subtree: true
|
|
114
|
+
};
|
|
115
|
+
// Add attribute observation if whereAttr is configured
|
|
116
|
+
if (this.#init.whereAttr) {
|
|
117
|
+
observerConfig.attributes = true;
|
|
118
|
+
observerConfig.attributeOldValue = true;
|
|
306
119
|
}
|
|
307
|
-
|
|
120
|
+
// Register with shared mutation observer
|
|
121
|
+
registerSharedObserver(rootNode, this.#mutationCallback, observerConfig);
|
|
308
122
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
123
|
+
disconnect() {
|
|
124
|
+
const rootNode = this.#rootNode?.deref();
|
|
125
|
+
// Unregister from shared mutation observer
|
|
126
|
+
if (rootNode && this.#mutationCallback) {
|
|
127
|
+
unregisterSharedObserver(rootNode, this.#mutationCallback);
|
|
128
|
+
this.#mutationCallback = undefined;
|
|
313
129
|
}
|
|
314
|
-
|
|
130
|
+
// Remove media query listener
|
|
131
|
+
if (this.#mediaQueryCleanup) {
|
|
132
|
+
this.#mediaQueryCleanup();
|
|
133
|
+
this.#mediaQueryCleanup = undefined;
|
|
134
|
+
}
|
|
135
|
+
this.#abortController.abort();
|
|
136
|
+
this.#rootNode = undefined;
|
|
315
137
|
}
|
|
316
|
-
async #
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const mount = this.#mountInit.do?.mount;
|
|
320
|
-
const { import: imp } = this.#mountInit;
|
|
321
|
-
const me = this.mountedElements;
|
|
322
|
-
const options = this.#options;
|
|
323
|
-
for (const match of matching) {
|
|
324
|
-
if (alreadyMounted.has(match))
|
|
325
|
-
continue;
|
|
326
|
-
if (!me.weakSet.has(match)) {
|
|
327
|
-
me.setWeak.add(new WeakRef(match));
|
|
328
|
-
me.weakSet.add(match);
|
|
329
|
-
}
|
|
330
|
-
if (imp !== undefined) {
|
|
331
|
-
switch (typeof imp) {
|
|
332
|
-
case 'string':
|
|
333
|
-
this.module = await import(imp);
|
|
334
|
-
break;
|
|
335
|
-
case 'object':
|
|
336
|
-
if (Array.isArray(imp)) {
|
|
337
|
-
throw 'NI: Firefox';
|
|
338
|
-
}
|
|
339
|
-
break;
|
|
340
|
-
case 'function':
|
|
341
|
-
this.module = await imp(match, this, {
|
|
342
|
-
stage: 'Import',
|
|
343
|
-
initializing
|
|
344
|
-
});
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
if (mount !== undefined) {
|
|
349
|
-
mount(match, this, {
|
|
350
|
-
stage: 'PostImport',
|
|
351
|
-
initializing
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
if (options?.leaveBreadcrumb) {
|
|
355
|
-
if (match[guid] === undefined) {
|
|
356
|
-
match[guid] = new Set();
|
|
357
|
-
}
|
|
358
|
-
match[guid].add(this);
|
|
359
|
-
}
|
|
360
|
-
const { MountEvent } = await import('./Events.js');
|
|
361
|
-
this.dispatchEvent(new MountEvent(match, initializing));
|
|
362
|
-
//should we automatically call readAttrs?
|
|
363
|
-
//the thinking is it might make more sense to call that after mounting
|
|
364
|
-
this.#mountedList?.push(new WeakRef(match));
|
|
138
|
+
async #loadImports() {
|
|
139
|
+
if (this.#importsLoaded || !this.#init.import) {
|
|
140
|
+
return;
|
|
365
141
|
}
|
|
142
|
+
// Dynamically load the import utilities only when needed
|
|
143
|
+
const { loadImports } = await import('./loadImports.js');
|
|
144
|
+
this.#modules = await loadImports(this.#init.import);
|
|
145
|
+
this.#importsLoaded = true;
|
|
146
|
+
this.dispatchEvent(new LoadEvent(this.#modules, this.#init));
|
|
366
147
|
}
|
|
367
|
-
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const attrParts = this.#attrParts;
|
|
374
|
-
for (let idx = 0, ii = fullListOfAttrs.length; idx < ii; idx++) {
|
|
375
|
-
const parts = attrParts[idx];
|
|
376
|
-
const { branchIdx } = parts;
|
|
377
|
-
if (branchIndexes !== undefined) {
|
|
378
|
-
if (!branchIndexes.has(branchIdx))
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
const name = fullListOfAttrs[idx];
|
|
382
|
-
const newValue = match.getAttribute(name);
|
|
383
|
-
attrChangeInfos.push({
|
|
384
|
-
idx,
|
|
385
|
-
isSOfTAttr: false,
|
|
386
|
-
newValue,
|
|
387
|
-
oldValue,
|
|
388
|
-
name,
|
|
389
|
-
parts
|
|
390
|
-
});
|
|
148
|
+
#processNode(node) {
|
|
149
|
+
// If it's an element node, check if it matches
|
|
150
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
151
|
+
const element = node;
|
|
152
|
+
if (this.#matchesSelector(element)) {
|
|
153
|
+
this.#handleMatch(element);
|
|
391
154
|
}
|
|
392
155
|
}
|
|
393
|
-
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if (!attrIsString) {
|
|
401
|
-
const { customParser, instanceOf, mapsTo: mt, valIfNull } = observedAttr;
|
|
402
|
-
if (instanceOf || customParser)
|
|
403
|
-
throw 'NI';
|
|
404
|
-
if (newValue === null)
|
|
405
|
-
newValue = valIfNull;
|
|
406
|
-
mapsTo = mt;
|
|
156
|
+
// Process children
|
|
157
|
+
if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE) {
|
|
158
|
+
const root = node;
|
|
159
|
+
// Get all elements matching the CSS selector first
|
|
160
|
+
root.querySelectorAll(this.#init.whereElementMatches).forEach(child => {
|
|
161
|
+
if (this.#matchesSelector(child)) {
|
|
162
|
+
this.#handleMatch(child);
|
|
407
163
|
}
|
|
408
|
-
|
|
409
|
-
isSOfTAttr: true,
|
|
410
|
-
newValue,
|
|
411
|
-
oldValue,
|
|
412
|
-
name,
|
|
413
|
-
mapsTo
|
|
414
|
-
});
|
|
415
|
-
}
|
|
164
|
+
});
|
|
416
165
|
}
|
|
417
|
-
return attrChangeInfos;
|
|
418
166
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
this.dispatchEvent(new DismountEvent(unmatch));
|
|
167
|
+
#matchesSelector(element) {
|
|
168
|
+
//TODO: reduce redundncy with this.#init?
|
|
169
|
+
// Check whereElementMatches condition
|
|
170
|
+
const matchesElement = element.matches(this.#init.whereElementMatches);
|
|
171
|
+
if (!matchesElement) {
|
|
172
|
+
return false;
|
|
427
173
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
this.#dismount(mounted.map(x => x.deref()).filter(x => x !== undefined));
|
|
434
|
-
}
|
|
435
|
-
async #mountAll() {
|
|
436
|
-
//TODO: copilot created, check if needed
|
|
437
|
-
const { whereSatisfies, whereInstanceOf } = this.#mountInit;
|
|
438
|
-
const match = await this.#selector();
|
|
439
|
-
const els = Array.from(document.querySelectorAll(match));
|
|
440
|
-
this.#filterAndMount(els, document.body, false, true);
|
|
441
|
-
}
|
|
442
|
-
async #filterAndDismount() {
|
|
443
|
-
const returnSet = new Set();
|
|
444
|
-
if (this.#mountedList !== undefined) {
|
|
445
|
-
const previouslyMounted = this.#mountedList.map(x => x.deref());
|
|
446
|
-
const { whereSatisfies, whereInstanceOf } = this.#mountInit;
|
|
447
|
-
const match = await this.#selector();
|
|
448
|
-
const elsToUnMount = previouslyMounted.filter(x => {
|
|
449
|
-
if (x === undefined)
|
|
450
|
-
return false;
|
|
451
|
-
if (!x.matches(match))
|
|
452
|
-
return true;
|
|
453
|
-
//TODO: add check for outside
|
|
454
|
-
if (whereSatisfies !== undefined) {
|
|
455
|
-
if (!whereSatisfies(x, this, { stage: 'Inspecting', initializing: false }))
|
|
456
|
-
return true;
|
|
457
|
-
}
|
|
458
|
-
returnSet.add(x);
|
|
174
|
+
// Check whereAttr condition if specified
|
|
175
|
+
if (this.#init.whereAttr) {
|
|
176
|
+
// Use cached function (should be loaded by now from constructor)
|
|
177
|
+
if (!this.#matchesWhereAttrFn) {
|
|
178
|
+
console.warn('whereAttr utilities not loaded yet');
|
|
459
179
|
return false;
|
|
460
|
-
}
|
|
461
|
-
this.#
|
|
180
|
+
}
|
|
181
|
+
if (!this.#matchesWhereAttrFn(element, this.#init.whereAttr)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
462
184
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
185
|
+
// Check whereInstanceOf condition if specified
|
|
186
|
+
if (this.#init.whereInstanceOf) {
|
|
187
|
+
const constructors = Array.isArray(this.#init.whereInstanceOf)
|
|
188
|
+
? this.#init.whereInstanceOf
|
|
189
|
+
: [this.#init.whereInstanceOf];
|
|
190
|
+
// Element must be an instance of at least one constructor (OR logic for array)
|
|
191
|
+
const matchesInstanceOf = constructors.some(constructor => element instanceof constructor);
|
|
192
|
+
if (!matchesInstanceOf) {
|
|
470
193
|
return false;
|
|
194
|
+
}
|
|
471
195
|
}
|
|
196
|
+
// All conditions passed
|
|
472
197
|
return true;
|
|
473
198
|
}
|
|
474
|
-
async #
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
199
|
+
async #handleMatch(element) {
|
|
200
|
+
if (this.#processedElements.has(element)) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Load imports if not already loaded
|
|
204
|
+
if (!this.#importsLoaded && this.#init.import) {
|
|
205
|
+
await this.#loadImports();
|
|
206
|
+
}
|
|
207
|
+
this.#processedElements.add(element);
|
|
208
|
+
this.#mountedElements.add(element);
|
|
209
|
+
const rootNode = this.#rootNode?.deref();
|
|
210
|
+
if (!rootNode) {
|
|
211
|
+
// Root node was garbage collected
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const context = {
|
|
215
|
+
modules: this.#modules,
|
|
216
|
+
observer: this,
|
|
217
|
+
observeInfo: {
|
|
218
|
+
rootNode
|
|
482
219
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
220
|
+
};
|
|
221
|
+
// Apply assignGingerly if specified
|
|
222
|
+
if (this.#init.assignGingerly) {
|
|
223
|
+
const { assignGingerly } = await import('assign-gingerly/index.js');
|
|
224
|
+
assignGingerly(element, this.#init.assignGingerly);
|
|
225
|
+
}
|
|
226
|
+
// Call do callback
|
|
227
|
+
if (this.#init.do) {
|
|
228
|
+
if (typeof this.#init.do === 'function') {
|
|
229
|
+
this.#init.do(element, context);
|
|
486
230
|
}
|
|
487
|
-
if (
|
|
488
|
-
|
|
489
|
-
return false;
|
|
231
|
+
else if (this.#init.do.mount) {
|
|
232
|
+
this.#init.do.mount(element, context);
|
|
490
233
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
234
|
+
}
|
|
235
|
+
// Dispatch mount event
|
|
236
|
+
this.dispatchEvent(new MountEvent(element, this.#modules, this.#init));
|
|
237
|
+
// Check for initial attribute changes if whereAttr is configured
|
|
238
|
+
if (this.#init.whereAttr) {
|
|
239
|
+
const changes = this.#checkAttrChanges(element);
|
|
240
|
+
if (changes.length > 0) {
|
|
241
|
+
this.dispatchEvent(new AttrChangeEvent(changes, this.#init));
|
|
494
242
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
#checkAttrChanges(element) {
|
|
246
|
+
if (!this.#init.whereAttr || !this.#buildAttrCoordinateMapFn) {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
const isCustomElement = element.tagName.toLowerCase().includes('-');
|
|
250
|
+
const attrCoordMap = this.#buildAttrCoordinateMapFn(this.#init.whereAttr, isCustomElement);
|
|
251
|
+
// Get or create the attribute state for this element
|
|
252
|
+
let attrState = this.#elementAttrStates.get(element);
|
|
253
|
+
if (!attrState) {
|
|
254
|
+
attrState = new Map();
|
|
255
|
+
this.#elementAttrStates.set(element, attrState);
|
|
256
|
+
}
|
|
257
|
+
const changes = [];
|
|
258
|
+
const currentAttrs = new Set();
|
|
259
|
+
// Check all possible attributes from the coordinate map
|
|
260
|
+
for (const attrName of Object.keys(attrCoordMap)) {
|
|
261
|
+
const coordinate = attrCoordMap[attrName];
|
|
262
|
+
const currentValue = element.getAttribute(attrName);
|
|
263
|
+
const previousValue = attrState.get(attrName);
|
|
264
|
+
if (currentValue !== null) {
|
|
265
|
+
currentAttrs.add(attrName);
|
|
266
|
+
}
|
|
267
|
+
// Check if this attribute has "once: true" in its map entry
|
|
268
|
+
const mapEntry = this.#init.map?.[coordinate] || null;
|
|
269
|
+
const isOnce = mapEntry?.once === true;
|
|
270
|
+
// If "once" is true, check if we've already seen this attribute
|
|
271
|
+
if (isOnce) {
|
|
272
|
+
let onceAttrs = this.#elementOnceAttrs.get(element);
|
|
273
|
+
if (!onceAttrs) {
|
|
274
|
+
onceAttrs = new Set();
|
|
275
|
+
this.#elementOnceAttrs.set(element, onceAttrs);
|
|
276
|
+
}
|
|
277
|
+
// If we've already seen this attribute, skip it
|
|
278
|
+
if (onceAttrs.has(attrName)) {
|
|
279
|
+
continue;
|
|
501
280
|
}
|
|
502
|
-
|
|
503
|
-
|
|
281
|
+
// Mark this attribute as seen if it currently has a value
|
|
282
|
+
if (currentValue !== null) {
|
|
283
|
+
onceAttrs.add(attrName);
|
|
504
284
|
}
|
|
505
285
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
286
|
+
// Include if: currently has value OR previously had value but now removed
|
|
287
|
+
if (currentValue !== null || (previousValue !== undefined && currentValue === null)) {
|
|
288
|
+
// Check if value changed
|
|
289
|
+
if (currentValue !== previousValue) {
|
|
290
|
+
const attrNode = currentValue !== null ? element.getAttributeNode(attrName) : null;
|
|
291
|
+
changes.push({
|
|
292
|
+
value: currentValue,
|
|
293
|
+
attrNode,
|
|
294
|
+
mapEntry,
|
|
295
|
+
attrName,
|
|
296
|
+
coordinate,
|
|
297
|
+
element
|
|
298
|
+
});
|
|
299
|
+
// Update state
|
|
300
|
+
if (currentValue !== null) {
|
|
301
|
+
attrState.set(attrName, currentValue);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
attrState.delete(attrName);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
523
307
|
}
|
|
524
308
|
}
|
|
525
|
-
|
|
526
|
-
await this.composeFragment(within, 0);
|
|
527
|
-
const match = await this.#selector();
|
|
528
|
-
const els = Array.from(within.querySelectorAll(match));
|
|
529
|
-
this.#filterAndMount(els, within, false, initializing);
|
|
309
|
+
return changes;
|
|
530
310
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const mountInit = {
|
|
535
|
-
idleTimeout
|
|
536
|
-
};
|
|
537
|
-
return new Promise((resolve) => {
|
|
538
|
-
const mutObservers = [];
|
|
539
|
-
for (const node of nodes) {
|
|
540
|
-
const mutObs = mutationObserverLookup.get(node);
|
|
541
|
-
if (mutObs !== undefined) {
|
|
542
|
-
mutObservers.push(mutObs);
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
const currentCount = refCount.get(node) || 0;
|
|
546
|
-
const newMutObs = new RootMutObs(node, mountInit);
|
|
547
|
-
mutationObserverLookup.set(node, newMutObs);
|
|
548
|
-
refCount.set(node, currentCount + 1);
|
|
549
|
-
mutObservers.push(newMutObs);
|
|
550
|
-
}
|
|
311
|
+
#handleRemoval(element) {
|
|
312
|
+
if (!this.#mountedElements.has(element)) {
|
|
313
|
+
return;
|
|
551
314
|
}
|
|
552
|
-
|
|
553
|
-
|
|
315
|
+
this.#mountedElements.delete(element);
|
|
316
|
+
const rootNode = this.#rootNode?.deref();
|
|
317
|
+
if (!rootNode) {
|
|
318
|
+
// Root node was garbage collected
|
|
319
|
+
return;
|
|
554
320
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
}
|
|
321
|
+
const context = {
|
|
322
|
+
modules: this.#modules,
|
|
323
|
+
observer: this,
|
|
324
|
+
observeInfo: {
|
|
325
|
+
rootNode
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
// Call dismount callback
|
|
329
|
+
if (this.#init.do && typeof this.#init.do !== 'function' && this.#init.do.dismount) {
|
|
330
|
+
this.#init.do.dismount(element, context);
|
|
561
331
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
332
|
+
// Dispatch dismount event
|
|
333
|
+
this.dispatchEvent(new DismountEvent(element, 'where-element-matches-failed', this.#init));
|
|
334
|
+
// Check if element is being moved within the same root
|
|
335
|
+
// If it's truly disconnected, dispatch disconnect event
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
if (!rootNode.contains(element)) {
|
|
338
|
+
if (this.#init.do && typeof this.#init.do !== 'function' && this.#init.do.disconnect) {
|
|
339
|
+
this.#init.do.disconnect(element, context);
|
|
340
|
+
}
|
|
341
|
+
this.dispatchEvent(new DisconnectEvent(element, this.#init));
|
|
342
|
+
}
|
|
343
|
+
}, 0);
|
|
569
344
|
}
|
|
570
|
-
return true;
|
|
571
345
|
}
|
|
572
|
-
const refCountErr = 'mount-observer ref count mismatch';
|
|
573
|
-
export const inclTemplQry = 'template[src^="#"]:not([hidden]),template[src^="!"]:not([hidden])';
|
|
574
|
-
//const hasRootInDefault = ['data', 'enh', 'data-enh']
|