mount-observer 0.0.16 → 0.0.18

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 CHANGED
@@ -29,6 +29,7 @@ export class MountObserver extends EventTarget {
29
29
  //this.#unmounted = new WeakSet();
30
30
  }
31
31
  #calculatedSelector;
32
+ #attrParts;
32
33
  #fullListOfAttrs;
33
34
  //get #attrVals
34
35
  async #selector() {
@@ -40,8 +41,9 @@ export class MountObserver extends EventTarget {
40
41
  return withoutAttrs;
41
42
  const { getWhereAttrSelector } = await import('./getWhereAttrSelector.js');
42
43
  const info = getWhereAttrSelector(whereAttr, withoutAttrs);
43
- const { fullListOfAttrs, calculatedSelector } = info;
44
+ const { fullListOfAttrs, calculatedSelector, partitionedAttrs } = info;
44
45
  this.#fullListOfAttrs = fullListOfAttrs;
46
+ this.#attrParts = partitionedAttrs;
45
47
  this.#calculatedSelector = calculatedSelector;
46
48
  return this.#calculatedSelector;
47
49
  }
@@ -98,6 +100,7 @@ export class MountObserver extends EventTarget {
98
100
  }
99
101
  }
100
102
  async observe(within) {
103
+ await this.#selector();
101
104
  this.objNde = new WeakRef(within);
102
105
  const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
103
106
  if (!mutationObserverLookup.has(nodeToMonitor)) {
@@ -114,7 +117,6 @@ export class MountObserver extends EventTarget {
114
117
  }
115
118
  }
116
119
  const rootMutObs = mutationObserverLookup.get(within);
117
- //const {whereAttr} = this.#mountInit;
118
120
  const fullListOfAttrs = this.#fullListOfAttrs;
119
121
  rootMutObs.addEventListener('mutation-event', async (e) => {
120
122
  //TODO: disconnected
@@ -126,32 +128,33 @@ export class MountObserver extends EventTarget {
126
128
  const elsToInspect = [];
127
129
  //const elsToDisconnect: Array<Element> = [];
128
130
  const doDisconnect = this.#mountInit.do?.disconnect;
131
+ let attrChangeInfosMap;
129
132
  for (const mutationRecord of mutationRecords) {
130
133
  const { addedNodes, type, removedNodes } = mutationRecord;
131
- //console.log(mutationRecord);
132
134
  const addedElements = Array.from(addedNodes).filter(x => x instanceof Element);
133
135
  addedElements.forEach(x => elsToInspect.push(x));
134
136
  if (type === 'attributes') {
135
137
  const { target, attributeName, oldValue } = mutationRecord;
136
- if (target instanceof Element && attributeName !== null && this.#mounted.has(target)) {
138
+ if (target instanceof Element && attributeName !== null /*&& this.#mounted.has(target)*/) {
137
139
  if (fullListOfAttrs !== undefined) {
138
140
  const idx = fullListOfAttrs.indexOf(attributeName);
139
- if (idx > -1) {
141
+ if (idx !== -1) {
142
+ if (attrChangeInfosMap === undefined)
143
+ attrChangeInfosMap = new Map();
144
+ let attrChangeInfos = attrChangeInfosMap.get(target);
145
+ if (attrChangeInfos === undefined) {
146
+ attrChangeInfos = [];
147
+ attrChangeInfosMap.set(target, attrChangeInfos);
148
+ }
140
149
  const newValue = target.getAttribute(attributeName);
150
+ const parts = this.#attrParts[idx];
141
151
  const attrChangeInfo = {
142
- name: attributeName,
143
152
  oldValue,
144
153
  newValue,
145
- idx
154
+ idx,
155
+ parts
146
156
  };
147
- this.dispatchEvent(new AttrChangeEvent(target, attrChangeInfo));
148
- }
149
- }
150
- else {
151
- const { whereAttr } = this.#mountInit;
152
- if (whereAttr !== undefined) {
153
- const { doWhereAttr } = await import('./doWhereAttr.js');
154
- doWhereAttr(whereAttr, attributeName, target, oldValue, this);
157
+ attrChangeInfos.push(attrChangeInfo);
155
158
  }
156
159
  }
157
160
  }
@@ -166,6 +169,11 @@ export class MountObserver extends EventTarget {
166
169
  this.dispatchEvent(new DisconnectEvent(deletedElement));
167
170
  }
168
171
  }
172
+ if (attrChangeInfosMap !== undefined) {
173
+ for (const [key, value] of attrChangeInfosMap) {
174
+ this.dispatchEvent(new AttrChangeEvent(key, value));
175
+ }
176
+ }
169
177
  this.#filterAndMount(elsToInspect, true, false);
170
178
  }, { signal: this.#abortController.signal });
171
179
  await this.#inspectWithin(within, true);
@@ -182,7 +190,6 @@ export class MountObserver extends EventTarget {
182
190
  const alreadyMounted = await this.#filterAndDismount();
183
191
  const mount = this.#mountInit.do?.mount;
184
192
  const { import: imp } = this.#mountInit;
185
- const fullListOfAttrs = this.#fullListOfAttrs;
186
193
  for (const match of matching) {
187
194
  if (alreadyMounted.has(match))
188
195
  continue;
@@ -212,37 +219,36 @@ export class MountObserver extends EventTarget {
212
219
  });
213
220
  }
214
221
  this.dispatchEvent(new MountEvent(match, initializing));
215
- if (fullListOfAttrs !== undefined) {
216
- const { whereAttr } = this.#mountInit;
217
- for (const name of fullListOfAttrs) {
218
- if (whereAttr !== undefined) {
219
- const { doWhereAttr } = await import('./doWhereAttr.js');
220
- doWhereAttr(whereAttr, name, match, null, this);
221
- }
222
+ //should we automatically call readAttrs?
223
+ //the thinking is it might make more sense to call that after mounting
224
+ this.#mountedList?.push(new WeakRef(match));
225
+ }
226
+ }
227
+ readAttrs(match, branchIndexes) {
228
+ const fullListOfAttrs = this.#fullListOfAttrs;
229
+ const attrChangeInfos = [];
230
+ if (fullListOfAttrs !== undefined) {
231
+ const attrParts = this.#attrParts;
232
+ for (let idx = 0, ii = fullListOfAttrs.length; idx < ii; idx++) {
233
+ const parts = attrParts[idx];
234
+ const { branchIdx } = parts;
235
+ if (branchIndexes !== undefined) {
236
+ if (!branchIndexes.has(branchIdx))
237
+ continue;
222
238
  }
223
- // let idx = 0;
224
- // for(const attribMatch of attribMatches){
225
- // let newValue = null;
226
- // const {names} = attribMatch;
227
- // let nonNullName = names[0];
228
- // for(const name of names){
229
- // const attrVal = match.getAttribute(name);
230
- // if(attrVal !== null) nonNullName = name;
231
- // newValue = newValue || attrVal;
232
- // }
233
- // const attribInfo: AttrChangeInfo = {
234
- // oldValue: null,
235
- // newValue,
236
- // idx,
237
- // name: nonNullName
238
- // };
239
- // this.dispatchEvent(new AttrChangeEvent(match, attribInfo));
240
- // idx++;
241
- // }
239
+ const name = fullListOfAttrs[idx];
240
+ const oldValue = null;
241
+ const newValue = match.getAttribute(name);
242
+ attrChangeInfos.push({
243
+ idx,
244
+ newValue,
245
+ oldValue,
246
+ parts
247
+ });
242
248
  }
243
- this.#mountedList?.push(new WeakRef(match));
244
- //if(this.#unmounted.has(match)) this.#unmounted.delete(match);
249
+ //this.dispatchEvent(new AttrChangeEvent(match, attrChangeInfos));
245
250
  }
251
+ return attrChangeInfos;
246
252
  }
247
253
  async #dismount(unmatching) {
248
254
  const onDismount = this.#mountInit.do?.dismount;
@@ -342,12 +348,12 @@ export class DisconnectEvent extends Event {
342
348
  }
343
349
  export class AttrChangeEvent extends Event {
344
350
  mountedElement;
345
- attrChangeInfo;
351
+ attrChangeInfos;
346
352
  static eventName = 'attr-change';
347
- constructor(mountedElement, attrChangeInfo) {
353
+ constructor(mountedElement, attrChangeInfos) {
348
354
  super(AttrChangeEvent.eventName);
349
355
  this.mountedElement = mountedElement;
350
- this.attrChangeInfo = attrChangeInfo;
356
+ this.attrChangeInfos = attrChangeInfos;
351
357
  }
352
358
  }
353
359
  //const hasRootInDefault = ['data', 'enh', 'data-enh']
@@ -66,7 +66,6 @@ export async function birtualizeMatch(self, el, level) {
66
66
  slot.removeAttribute('slot');
67
67
  }
68
68
  el.dispatchEvent(new LoadEvent(clone));
69
- //console.log('dispatched')
70
69
  }
71
70
  if (shadowRootModeOnLoad !== null) {
72
71
  const parent = el.parentElement;
@@ -1,12 +1,15 @@
1
1
  export function getWhereAttrSelector(whereAttr, withoutAttrs) {
2
2
  const { hasBase, hasBranchIn, hasRootIn } = whereAttr;
3
+ const hasRootInGuaranteed = hasRootIn || [{
4
+ start: '',
5
+ context: 'Both'
6
+ }];
3
7
  const fullListOfAttrs = [];
4
- //TODO: share this block with doWhereAttr?
8
+ const partitionedAttrs = [];
9
+ let prefixLessMatches = [];
5
10
  const hasBaseIsString = typeof hasBase === 'string';
6
11
  const baseSelector = hasBaseIsString ? hasBase : hasBase[1];
7
12
  const rootToBaseDelimiter = hasBaseIsString ? '-' : hasBase[0];
8
- //end TODO
9
- let prefixLessMatches = [baseSelector];
10
13
  if (hasBranchIn !== undefined) {
11
14
  let baseToBranchDelimiter = '-';
12
15
  let branches;
@@ -17,19 +20,61 @@ export function getWhereAttrSelector(whereAttr, withoutAttrs) {
17
20
  else {
18
21
  branches = hasBranchIn;
19
22
  }
20
- prefixLessMatches = branches.map(x => `${baseSelector}${baseToBranchDelimiter}x`);
23
+ prefixLessMatches = branches.map(x => ({
24
+ rootToBaseDelimiter,
25
+ base: baseSelector,
26
+ baseToBranchDelimiter: x ? baseToBranchDelimiter : '',
27
+ branch: x
28
+ }));
21
29
  }
22
- const stems = hasRootIn || [''];
23
- for (const stem of stems) {
24
- const prefix = typeof stem === 'string' ? stem : stem.path;
25
- for (const prefixLessMatch of prefixLessMatches) {
26
- fullListOfAttrs.push(prefix.length === 0 ? prefixLessMatch : `${prefix}${rootToBaseDelimiter}${prefixLessMatch}`);
30
+ else {
31
+ prefixLessMatches.push({
32
+ rootToBaseDelimiter,
33
+ base: baseSelector,
34
+ });
35
+ }
36
+ for (const rootCnfg of hasRootInGuaranteed) {
37
+ const { start } = rootCnfg;
38
+ for (const match of prefixLessMatches) {
39
+ const { base, baseToBranchDelimiter, branch, rootToBaseDelimiter } = match;
40
+ let branchIdx = 0;
41
+ for (const prefixLessMatch of prefixLessMatches) {
42
+ const { base, baseToBranchDelimiter, branch } = prefixLessMatch;
43
+ const startAndRootToBaseDelimiter = start ? `${start}${rootToBaseDelimiter}` : '';
44
+ //TODO: could probably reduce the size of the code below
45
+ if (branch) {
46
+ //will always have branch?
47
+ const name = `${startAndRootToBaseDelimiter}${base}${baseToBranchDelimiter}${branch}`;
48
+ fullListOfAttrs.push(name);
49
+ partitionedAttrs.push({
50
+ root: start,
51
+ name,
52
+ base,
53
+ branch,
54
+ branchIdx,
55
+ rootCnfg
56
+ });
57
+ }
58
+ else {
59
+ const name = `${startAndRootToBaseDelimiter}${base}`;
60
+ fullListOfAttrs.push(name);
61
+ partitionedAttrs.push({
62
+ root: start,
63
+ name,
64
+ base,
65
+ rootCnfg,
66
+ branchIdx
67
+ });
68
+ }
69
+ branchIdx++;
70
+ }
27
71
  }
28
72
  }
29
73
  const listOfSelectors = fullListOfAttrs.map(s => `${withoutAttrs}[${s}]`);
30
74
  const calculatedSelector = listOfSelectors.join(',');
31
75
  return {
32
76
  fullListOfAttrs,
33
- calculatedSelector
77
+ calculatedSelector,
78
+ partitionedAttrs,
34
79
  };
35
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
package/types.d.ts CHANGED
@@ -80,7 +80,9 @@ interface AttrParts{
80
80
  root?: string,
81
81
  base?: string,
82
82
  branch?: string,
83
+ branchIdx: number,
83
84
  leaf?: string, //TODO
85
+ leafIdx?: number, //TODO
84
86
  rootCnfg?: RootCnfg
85
87
  }
86
88