mount-observer 0.0.14 → 0.0.16
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/MountObserver.js +8 -101
- package/README.md +19 -17
- package/birtualizeMatch.js +92 -0
- package/package.json +1 -1
- package/types.d.ts +19 -9
- package/doWhereAttr.js +0 -43
package/MountObserver.js
CHANGED
|
@@ -10,7 +10,7 @@ export class MountObserver extends EventTarget {
|
|
|
10
10
|
#disconnected;
|
|
11
11
|
//#unmounted: WeakSet<Element>;
|
|
12
12
|
#isComplex;
|
|
13
|
-
|
|
13
|
+
objNde;
|
|
14
14
|
constructor(init) {
|
|
15
15
|
super();
|
|
16
16
|
const { on, whereElementIntersectsWith, whereMediaMatches } = init;
|
|
@@ -45,97 +45,18 @@ export class MountObserver extends EventTarget {
|
|
|
45
45
|
this.#calculatedSelector = calculatedSelector;
|
|
46
46
|
return this.#calculatedSelector;
|
|
47
47
|
}
|
|
48
|
-
async
|
|
48
|
+
async birtualizeFragment(fragment, level) {
|
|
49
49
|
const bis = fragment.querySelectorAll(inclTemplQry);
|
|
50
50
|
for (const bi of bis) {
|
|
51
51
|
await this.#birtalizeMatch(bi, level);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
async #birtalizeMatch(el, level) {
|
|
55
|
-
const
|
|
56
|
-
el
|
|
57
|
-
const templID = href.substring(1);
|
|
58
|
-
const fragment = this.#observe?.deref();
|
|
59
|
-
if (fragment === undefined)
|
|
60
|
-
return;
|
|
61
|
-
const templ = this.#findByID(templID, fragment);
|
|
62
|
-
if (!(templ instanceof HTMLTemplateElement))
|
|
63
|
-
throw 404;
|
|
64
|
-
const clone = templ.content.cloneNode(true);
|
|
65
|
-
const slots = el.content.querySelectorAll(`[slot]`);
|
|
66
|
-
for (const slot of slots) {
|
|
67
|
-
const name = slot.getAttribute('slot');
|
|
68
|
-
const slotQry = `slot[name="${name}"]`;
|
|
69
|
-
const targets = Array.from(clone.querySelectorAll(slotQry));
|
|
70
|
-
const innerTempls = clone.querySelectorAll(inclTemplQry);
|
|
71
|
-
for (const innerTempl of innerTempls) {
|
|
72
|
-
const innerSlots = innerTempl.content.querySelectorAll(slotQry);
|
|
73
|
-
for (const innerSlot of innerSlots) {
|
|
74
|
-
targets.push(innerSlot);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
for (const target of targets) {
|
|
78
|
-
const slotClone = slot.cloneNode(true);
|
|
79
|
-
target.after(slotClone);
|
|
80
|
-
target.remove();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
await this.#birtualizeFragment(clone, level + 1);
|
|
84
|
-
const shadowRootModeOnLoad = el.getAttribute('shadowRootModeOnLoad');
|
|
85
|
-
if (shadowRootModeOnLoad === null && level === 0) {
|
|
86
|
-
const slotMap = el.getAttribute('slotmap');
|
|
87
|
-
let map = slotMap === null ? undefined : JSON.parse(slotMap);
|
|
88
|
-
const slots = clone.querySelectorAll('[slot]');
|
|
89
|
-
for (const slot of slots) {
|
|
90
|
-
if (map !== undefined) {
|
|
91
|
-
const slotName = slot.slot;
|
|
92
|
-
for (const key in map) {
|
|
93
|
-
if (slot.matches(key)) {
|
|
94
|
-
const targetAttSymbols = map[key];
|
|
95
|
-
for (const sym of targetAttSymbols) {
|
|
96
|
-
switch (sym) {
|
|
97
|
-
case '|':
|
|
98
|
-
slot.setAttribute('itemprop', slotName);
|
|
99
|
-
break;
|
|
100
|
-
case '$':
|
|
101
|
-
slot.setAttribute('itemscope', '');
|
|
102
|
-
slot.setAttribute('itemprop', slotName);
|
|
103
|
-
break;
|
|
104
|
-
case '@':
|
|
105
|
-
slot.setAttribute('name', slotName);
|
|
106
|
-
break;
|
|
107
|
-
case '.':
|
|
108
|
-
slot.classList.add(slotName);
|
|
109
|
-
break;
|
|
110
|
-
case '%':
|
|
111
|
-
slot.part.add(slotName);
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
slot.removeAttribute('slot');
|
|
119
|
-
}
|
|
120
|
-
el.dispatchEvent(new LoadEvent(clone));
|
|
121
|
-
//console.log('dispatched')
|
|
122
|
-
}
|
|
123
|
-
if (shadowRootModeOnLoad !== null) {
|
|
124
|
-
const parent = el.parentElement;
|
|
125
|
-
if (parent === null)
|
|
126
|
-
throw 404;
|
|
127
|
-
if (parent.shadowRoot === null)
|
|
128
|
-
parent.attachShadow({ mode: shadowRootModeOnLoad });
|
|
129
|
-
parent.shadowRoot?.append(clone);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
el.after(clone);
|
|
133
|
-
}
|
|
134
|
-
if (level !== 0 || slots.length === 0)
|
|
135
|
-
el.remove();
|
|
55
|
+
const { birtualizeMatch } = await import('./birtualizeMatch.js');
|
|
56
|
+
await birtualizeMatch(this, el, level);
|
|
136
57
|
}
|
|
137
58
|
#templLookUp = new Map();
|
|
138
|
-
|
|
59
|
+
findByID(id, fragment) {
|
|
139
60
|
if (this.#templLookUp.has(id))
|
|
140
61
|
return this.#templLookUp.get(id);
|
|
141
62
|
let templ = fragment.getElementById(id);
|
|
@@ -177,7 +98,7 @@ export class MountObserver extends EventTarget {
|
|
|
177
98
|
}
|
|
178
99
|
}
|
|
179
100
|
async observe(within) {
|
|
180
|
-
this
|
|
101
|
+
this.objNde = new WeakRef(within);
|
|
181
102
|
const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
|
|
182
103
|
if (!mutationObserverLookup.has(nodeToMonitor)) {
|
|
183
104
|
mutationObserverLookup.set(nodeToMonitor, new RootMutObs(nodeToMonitor));
|
|
@@ -238,9 +159,6 @@ export class MountObserver extends EventTarget {
|
|
|
238
159
|
}
|
|
239
160
|
const deletedElements = Array.from(removedNodes).filter(x => x instanceof Element);
|
|
240
161
|
for (const deletedElement of deletedElements) {
|
|
241
|
-
// if(!this.#mounted.has(deletedElement)) continue;
|
|
242
|
-
// this.#mounted.delete(deletedElement);
|
|
243
|
-
// this.#mountedList = this.#mountedList?.filter(x => x.deref() !== deletedElement);
|
|
244
162
|
this.#disconnected.add(deletedElement);
|
|
245
163
|
if (doDisconnect !== undefined) {
|
|
246
164
|
doDisconnect(deletedElement, this, {});
|
|
@@ -250,9 +168,7 @@ export class MountObserver extends EventTarget {
|
|
|
250
168
|
}
|
|
251
169
|
this.#filterAndMount(elsToInspect, true, false);
|
|
252
170
|
}, { signal: this.#abortController.signal });
|
|
253
|
-
//if(ignoreInitialMatches !== true){
|
|
254
171
|
await this.#inspectWithin(within, true);
|
|
255
|
-
//}
|
|
256
172
|
}
|
|
257
173
|
#confirmInstanceOf(el, whereInstanceOf) {
|
|
258
174
|
for (const test of whereInstanceOf) {
|
|
@@ -279,7 +195,6 @@ export class MountObserver extends EventTarget {
|
|
|
279
195
|
case 'object':
|
|
280
196
|
if (Array.isArray(imp)) {
|
|
281
197
|
throw 'NI: Firefox';
|
|
282
|
-
//this.module = await import(imp[0], imp[1]);
|
|
283
198
|
}
|
|
284
199
|
break;
|
|
285
200
|
case 'function':
|
|
@@ -387,13 +302,13 @@ export class MountObserver extends EventTarget {
|
|
|
387
302
|
this.#mount(elsToMount, initializing);
|
|
388
303
|
}
|
|
389
304
|
async #inspectWithin(within, initializing) {
|
|
390
|
-
await this
|
|
305
|
+
await this.birtualizeFragment(within, 0);
|
|
391
306
|
const els = Array.from(within.querySelectorAll(await this.#selector()));
|
|
392
307
|
this.#filterAndMount(els, false, initializing);
|
|
393
308
|
}
|
|
394
309
|
}
|
|
395
310
|
const refCountErr = 'mount-observer ref count mismatch';
|
|
396
|
-
const inclTemplQry = 'template[href^="#"]:not([hidden])';
|
|
311
|
+
export const inclTemplQry = 'template[href^="#"]:not([hidden])';
|
|
397
312
|
// https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
|
|
398
313
|
/**
|
|
399
314
|
* The `mutation-event` event represents something that happened.
|
|
@@ -435,12 +350,4 @@ export class AttrChangeEvent extends Event {
|
|
|
435
350
|
this.attrChangeInfo = attrChangeInfo;
|
|
436
351
|
}
|
|
437
352
|
}
|
|
438
|
-
export class LoadEvent extends Event {
|
|
439
|
-
clone;
|
|
440
|
-
static eventName = 'load';
|
|
441
|
-
constructor(clone) {
|
|
442
|
-
super(LoadEvent.eventName);
|
|
443
|
-
this.clone = clone;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
353
|
//const hasRootInDefault = ['data', 'enh', 'data-enh']
|
package/README.md
CHANGED
|
@@ -11,13 +11,13 @@ Author: Bruce B. Anderson
|
|
|
11
11
|
|
|
12
12
|
Issues / pr's / polyfill: [mount-observer](https://github.com/bahrus/mount-observer)
|
|
13
13
|
|
|
14
|
-
Last Update: 2024-2-
|
|
14
|
+
Last Update: 2024-2-20
|
|
15
15
|
|
|
16
16
|
## Benefits of this API
|
|
17
17
|
|
|
18
18
|
What follows is a far more ambitious alternative to the [lazy custom element proposal](https://github.com/w3c/webcomponents/issues/782). The goals of the MountObserver api are more encompassing, and less focused on registering custom elements. In fact, this proposal addresses numerous use cases in one api. It is basically mapping common filtering conditions in the DOM, to mounting a "campaign" of some sort, like importing a resource, and/or progressively enhancing an element, and/or "binding from a distance".
|
|
19
19
|
|
|
20
|
-
["Binding from a distance"](https://github.com/WICG/webcomponents/issues/1035#issuecomment-1806393525) refers to empowering the developer to essentially manage their own "stylesheets" -- but rather than for purposes of styling, using these rules to attach behaviors, set property values, etc, to the HTML as it streams in. Libraries that take this approach include [Corset](https://corset.dev/) and [trans-render](https://github.com/bahrus/trans-render). The concept has been promoted by a [number](https://bkardell.com/blog/CSSLike.html) [of](https://www.w3.org/TR/NOTE-AS) prominent voices in the community.
|
|
20
|
+
["Binding from a distance"](https://github.com/WICG/webcomponents/issues/1035#issuecomment-1806393525) refers to empowering the developer to essentially manage their own "stylesheets" -- but rather than for purposes of styling, using these rules to attach behaviors, set property values, etc, to the HTML as it streams in. Libraries that take this approach include [Corset](https://corset.dev/) and [trans-render](https://github.com/bahrus/trans-render). The concept has been promoted by a [number](https://bkardell.com/blog/CSSLike.html) [of](https://www.w3.org/TR/NOTE-AS) [prominent](https://www.xanthir.com/blog/b4K_0) voices in the community.
|
|
21
21
|
|
|
22
22
|
The underlying theme is this api is meant to make it easy for the developer to do the right thing, by encouraging lazy loading and smaller footprints. It rolls up most all the other observer api's into one.
|
|
23
23
|
|
|
@@ -284,9 +284,9 @@ So let's say we want to insist that on custom elements, we must have the data- p
|
|
|
284
284
|
|
|
285
285
|
And we want to support an alternative, more semantic sounding prefix to data, say enh-*, endorsed by [this proposal](https://github.com/WICG/webcomponents/issues/1000).
|
|
286
286
|
|
|
287
|
-
Here's what the api
|
|
287
|
+
Here's what the api **doesn't** provide:
|
|
288
288
|
|
|
289
|
-
##
|
|
289
|
+
## Rejected option -- The carpal syndrome syntax
|
|
290
290
|
|
|
291
291
|
```JavaScript
|
|
292
292
|
import {MountObserver} from '../MountObserver.js';
|
|
@@ -320,7 +320,7 @@ const mo = new MountObserver({
|
|
|
320
320
|
});
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
-
##
|
|
323
|
+
## Supported -- The DRY Way
|
|
324
324
|
|
|
325
325
|
```JavaScript
|
|
326
326
|
import {MountObserver} from '../MountObserver.js';
|
|
@@ -360,16 +360,18 @@ MountObserver provides a breakdown of the matching attribute when encountered:
|
|
|
360
360
|
console.log(e);
|
|
361
361
|
// {
|
|
362
362
|
// matchingElement,
|
|
363
|
-
// attrChangeInfo:{
|
|
364
|
-
// name: 'data-my-enhancement-first-aspect-wow-this-is-deep'
|
|
365
|
-
// root: 'data',
|
|
366
|
-
// base: 'my-enhancement',
|
|
367
|
-
// branch: 'first-aspect',
|
|
368
|
-
// leaf: 'wow-this-is-deep',
|
|
369
|
-
// oldValue: null,
|
|
370
|
-
// newValue: 'good-bye'
|
|
363
|
+
// attrChangeInfo:[{
|
|
371
364
|
// idx: 0,
|
|
372
|
-
//
|
|
365
|
+
// oldValue: null,
|
|
366
|
+
// newValue: 'good-bye',
|
|
367
|
+
// parts:{
|
|
368
|
+
// name: 'data-my-enhancement-first-aspect-wow-this-is-deep'
|
|
369
|
+
// root: 'data',
|
|
370
|
+
// base: 'my-enhancement',
|
|
371
|
+
// branch: 'first-aspect',
|
|
372
|
+
// leaf: 'wow-this-is-deep',
|
|
373
|
+
// }
|
|
374
|
+
// }]
|
|
373
375
|
// }
|
|
374
376
|
});
|
|
375
377
|
mo.observe(div);
|
|
@@ -443,9 +445,9 @@ So what this does is only check for the presence of an element with tag name "my
|
|
|
443
445
|
|
|
444
446
|
This proposal "sneaks in" one more feature, that perhaps should stand separately as its own proposal. Because the MountObserver api allows us to attach behaviors on the fly based on css matching, and because the MountObserver would provide developers the "first point of contact" for such functionality, the efficiency argument seemingly "screams out" for this feature.
|
|
445
447
|
|
|
446
|
-
Also, this proposal is partly focused on better management of importing resources "from a distance", in particular via imports carried out via http. Is it such a stretch to look closely at scenarios where that distance happens to be shorter?
|
|
448
|
+
Also, this proposal is partly focused on better management of importing resources "from a distance", in particular via imports carried out via http. Is it such a stretch to look closely at scenarios where that distance happens to be shorter, i.e. found somewhere [in the document tree structure](https://github.com/tc39/proposal-module-expressions)?
|
|
447
449
|
|
|
448
|
-
The mount-observer is always on the lookout for
|
|
450
|
+
The mount-observer is always on the lookout for template tags with an href attribute starting with #:
|
|
449
451
|
|
|
450
452
|
```html
|
|
451
453
|
<template href=#id-of-source-template></template>
|
|
@@ -487,7 +489,7 @@ This is an example of a snippet of HTML that appears repeatedly.
|
|
|
487
489
|
|
|
488
490
|
Some significant differences with genuine slot support as used with (ShadowDOM'd) custom elements
|
|
489
491
|
|
|
490
|
-
1. There is no mechanism for updating the slots. That is something under investigation with this userland [custom enhancement](https://github.com/bahrus/be-inclusive), that could possibly lead to a future implementation request tied to template instantiation.
|
|
492
|
+
1. There is no mechanism for updating the slots. That is something under investigation with this userland [custom enhancement](https://github.com/bahrus/be-inclusive), that could possibly lead to a future implementation request tied to template instantiation. It takes the approach of morphing from slots to a JS host object model that binds to where all the slots were "from a distance".
|
|
491
493
|
2. ShadowDOM's slots act on a "many to one" basis. Multiple light children with identical slot identifiers all get merged into a single (first?) matching slot within the Shadow DOM. These "birtual" (birth-only, virtual) inclusions, instead, follow the opposite approach -- a single element with a slot identifier can get cloned into multiple slot targets as it weaves itself into the templates as they get merged together.
|
|
492
494
|
|
|
493
495
|
## Intra document html imports with Shadow DOM support
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { inclTemplQry } from './MountObserver.js';
|
|
2
|
+
export async function birtualizeMatch(self, el, level) {
|
|
3
|
+
const href = el.getAttribute('href');
|
|
4
|
+
el.removeAttribute('href');
|
|
5
|
+
const templID = href.substring(1);
|
|
6
|
+
const fragment = self.objNde?.deref();
|
|
7
|
+
if (fragment === undefined)
|
|
8
|
+
return;
|
|
9
|
+
const templ = self.findByID(templID, fragment);
|
|
10
|
+
if (!(templ instanceof HTMLTemplateElement))
|
|
11
|
+
throw 404;
|
|
12
|
+
const clone = templ.content.cloneNode(true);
|
|
13
|
+
const slots = el.content.querySelectorAll(`[slot]`);
|
|
14
|
+
for (const slot of slots) {
|
|
15
|
+
const name = slot.getAttribute('slot');
|
|
16
|
+
const slotQry = `slot[name="${name}"]`;
|
|
17
|
+
const targets = Array.from(clone.querySelectorAll(slotQry));
|
|
18
|
+
const innerTempls = clone.querySelectorAll(inclTemplQry);
|
|
19
|
+
for (const innerTempl of innerTempls) {
|
|
20
|
+
const innerSlots = innerTempl.content.querySelectorAll(slotQry);
|
|
21
|
+
for (const innerSlot of innerSlots) {
|
|
22
|
+
targets.push(innerSlot);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const target of targets) {
|
|
26
|
+
const slotClone = slot.cloneNode(true);
|
|
27
|
+
target.after(slotClone);
|
|
28
|
+
target.remove();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
await self.birtualizeFragment(clone, level + 1);
|
|
32
|
+
const shadowRootModeOnLoad = el.getAttribute('shadowRootModeOnLoad');
|
|
33
|
+
if (shadowRootModeOnLoad === null && level === 0) {
|
|
34
|
+
const slotMap = el.getAttribute('slotmap');
|
|
35
|
+
let map = slotMap === null ? undefined : JSON.parse(slotMap);
|
|
36
|
+
const slots = clone.querySelectorAll('[slot]');
|
|
37
|
+
for (const slot of slots) {
|
|
38
|
+
if (map !== undefined) {
|
|
39
|
+
const slotName = slot.slot;
|
|
40
|
+
for (const key in map) {
|
|
41
|
+
if (slot.matches(key)) {
|
|
42
|
+
const targetAttSymbols = map[key];
|
|
43
|
+
for (const sym of targetAttSymbols) {
|
|
44
|
+
switch (sym) {
|
|
45
|
+
case '|':
|
|
46
|
+
slot.setAttribute('itemprop', slotName);
|
|
47
|
+
break;
|
|
48
|
+
case '$':
|
|
49
|
+
slot.setAttribute('itemscope', '');
|
|
50
|
+
slot.setAttribute('itemprop', slotName);
|
|
51
|
+
break;
|
|
52
|
+
case '@':
|
|
53
|
+
slot.setAttribute('name', slotName);
|
|
54
|
+
break;
|
|
55
|
+
case '.':
|
|
56
|
+
slot.classList.add(slotName);
|
|
57
|
+
break;
|
|
58
|
+
case '%':
|
|
59
|
+
slot.part.add(slotName);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
slot.removeAttribute('slot');
|
|
67
|
+
}
|
|
68
|
+
el.dispatchEvent(new LoadEvent(clone));
|
|
69
|
+
//console.log('dispatched')
|
|
70
|
+
}
|
|
71
|
+
if (shadowRootModeOnLoad !== null) {
|
|
72
|
+
const parent = el.parentElement;
|
|
73
|
+
if (parent === null)
|
|
74
|
+
throw 404;
|
|
75
|
+
if (parent.shadowRoot === null)
|
|
76
|
+
parent.attachShadow({ mode: shadowRootModeOnLoad });
|
|
77
|
+
parent.shadowRoot?.append(clone);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
el.after(clone);
|
|
81
|
+
}
|
|
82
|
+
if (level !== 0 || slots.length === 0)
|
|
83
|
+
el.remove();
|
|
84
|
+
}
|
|
85
|
+
export class LoadEvent extends Event {
|
|
86
|
+
clone;
|
|
87
|
+
static eventName = 'load';
|
|
88
|
+
constructor(clone) {
|
|
89
|
+
super(LoadEvent.eventName);
|
|
90
|
+
this.clone = clone;
|
|
91
|
+
}
|
|
92
|
+
}
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface MountInit{
|
|
|
5
5
|
readonly whereAttr?: WhereAttr,
|
|
6
6
|
readonly whereElementIntersectsWith?: IntersectionObserverInit,
|
|
7
7
|
readonly whereMediaMatches?: MediaQuery,
|
|
8
|
-
readonly whereInstanceOf?: Array<
|
|
8
|
+
readonly whereInstanceOf?: Array<{new(): Element}>,
|
|
9
9
|
readonly whereSatisfies?: PipelineProcessor<boolean>,
|
|
10
10
|
readonly import?: ImportString | [ImportString, ImportAssertions] | PipelineProcessor,
|
|
11
11
|
readonly do?: {
|
|
@@ -21,13 +21,18 @@ export interface MountInit{
|
|
|
21
21
|
// */
|
|
22
22
|
// readonly ignoreInitialMatches?: boolean,
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
export interface RootCnfg{
|
|
26
|
+
start: string,
|
|
27
|
+
context: 'BuiltIn' | 'CustomElement' | 'Both'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//export type RootAttrOptions = Array<string | RootCnfg>;
|
|
31
|
+
export type delimiter = string;
|
|
24
32
|
export interface WhereAttr{
|
|
25
|
-
hasBase: string | [
|
|
26
|
-
hasBranchIn?: Array<string> | [
|
|
27
|
-
hasRootIn?: Array<
|
|
28
|
-
path: string,
|
|
29
|
-
context: 'BuiltIn' | 'CustomElement' | 'Both'
|
|
30
|
-
}>,
|
|
33
|
+
hasBase: string | [delimiter, string],
|
|
34
|
+
hasBranchIn?: Array<string> | [delimiter, Array<string>],
|
|
35
|
+
hasRootIn?: Array<RootCnfg>,
|
|
31
36
|
}
|
|
32
37
|
type CSSMatch = string;
|
|
33
38
|
type ImportString = string;
|
|
@@ -70,15 +75,20 @@ export interface AddMutationEventListener {
|
|
|
70
75
|
}
|
|
71
76
|
//#endregion
|
|
72
77
|
|
|
73
|
-
interface
|
|
78
|
+
interface AttrParts{
|
|
74
79
|
name: string,
|
|
75
80
|
root?: string,
|
|
76
81
|
base?: string,
|
|
77
82
|
branch?: string,
|
|
78
83
|
leaf?: string, //TODO
|
|
84
|
+
rootCnfg?: RootCnfg
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface AttrChangeInfo{
|
|
79
88
|
oldValue: string | null,
|
|
80
89
|
newValue: string | null,
|
|
81
90
|
idx: number,
|
|
91
|
+
parts: AttrParts,
|
|
82
92
|
//parsedNewValue?: any,
|
|
83
93
|
}
|
|
84
94
|
|
|
@@ -123,7 +133,7 @@ export interface AddDisconnectEventListener {
|
|
|
123
133
|
//#region attribute change event
|
|
124
134
|
export type attrChangeEventName = 'attr-change';
|
|
125
135
|
export interface IAttrChangeEvent extends IMountEvent {
|
|
126
|
-
|
|
136
|
+
attrChangeInfos: Array<AttrChangeInfo>,
|
|
127
137
|
}
|
|
128
138
|
export type attrChangeEventHandler = (e: IAttrChangeEvent) => void;
|
|
129
139
|
export interface AddAttrChangeEventListener{
|
package/doWhereAttr.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { AttrChangeEvent } from "./MountObserver.js";
|
|
2
|
-
export function doWhereAttr(whereAttr, attributeName, target, oldValue, mo) {
|
|
3
|
-
const { hasRootIn, hasBase, hasBranchIn } = whereAttr;
|
|
4
|
-
const name = attributeName;
|
|
5
|
-
let restOfName = name;
|
|
6
|
-
let root;
|
|
7
|
-
let branch;
|
|
8
|
-
let idx = 0;
|
|
9
|
-
const hasBaseIsString = typeof hasBase === 'string';
|
|
10
|
-
const baseSelector = hasBaseIsString ? hasBase : hasBase[1];
|
|
11
|
-
const rootToBaseDelimiter = hasBaseIsString ? '-' : hasBase[0];
|
|
12
|
-
if (hasRootIn !== undefined) {
|
|
13
|
-
for (const rootTest in hasRootIn) {
|
|
14
|
-
if (restOfName.startsWith(rootTest)) {
|
|
15
|
-
root = rootTest;
|
|
16
|
-
restOfName = restOfName.substring(root.length + rootToBaseDelimiter.length);
|
|
17
|
-
break;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (!restOfName.startsWith(baseSelector))
|
|
22
|
-
return;
|
|
23
|
-
restOfName = restOfName.substring(hasBase.length);
|
|
24
|
-
if (hasBranchIn) {
|
|
25
|
-
for (const branchTest in hasBranchIn) {
|
|
26
|
-
if (restOfName.startsWith(branchTest)) {
|
|
27
|
-
branch = branchTest;
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const newValue = target.getAttribute(attributeName);
|
|
33
|
-
const attrChangeInfo = {
|
|
34
|
-
name,
|
|
35
|
-
root,
|
|
36
|
-
base: baseSelector,
|
|
37
|
-
branch,
|
|
38
|
-
oldValue,
|
|
39
|
-
newValue,
|
|
40
|
-
idx
|
|
41
|
-
};
|
|
42
|
-
mo.dispatchEvent(new AttrChangeEvent(target, attrChangeInfo));
|
|
43
|
-
}
|