mount-observer 0.0.111 → 0.1.0
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 +28 -26
- package/Events.ts +34 -30
- package/MountObserver.js +235 -520
- package/MountObserver.ts +281 -542
- package/README.md +149 -56
- package/attrCoordinates.js +93 -0
- package/attrCoordinates.ts +122 -0
- package/constants.js +6 -0
- package/constants.ts +7 -0
- package/index.js +3 -0
- package/index.ts +19 -0
- package/loadImports.js +47 -0
- package/loadImports.ts +56 -0
- package/package.json +8 -115
- package/playwright.config.ts +0 -1
- package/types.d.ts +86 -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 -18
- 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 -190
- 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/whereAttr.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { WhereAttr } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cache for compiled CSS selectors to avoid rebuilding them on every check
|
|
5
|
+
* Stores both built-in and custom element selectors
|
|
6
|
+
*/
|
|
7
|
+
interface CachedSelectors {
|
|
8
|
+
builtIn: string;
|
|
9
|
+
custom: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const selectorCache = new WeakMap<WhereAttr, CachedSelectors>();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if an element matches the whereAttr configuration using CSS selector matching
|
|
16
|
+
*/
|
|
17
|
+
export function matchesWhereAttr(element: Element, whereAttr: WhereAttr): boolean {
|
|
18
|
+
// Get or build the CSS selectors for this whereAttr config
|
|
19
|
+
let selectors = selectorCache.get(whereAttr);
|
|
20
|
+
if (!selectors) {
|
|
21
|
+
selectors = {
|
|
22
|
+
builtIn: buildWhereAttrSelector(false, whereAttr),
|
|
23
|
+
custom: buildWhereAttrSelector(true, whereAttr)
|
|
24
|
+
};
|
|
25
|
+
selectorCache.set(whereAttr, selectors);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Determine which selector to use based on element type
|
|
29
|
+
const isCustomElement = element.tagName.toLowerCase().includes('-');
|
|
30
|
+
const selector = isCustomElement ? selectors.custom : selectors.builtIn;
|
|
31
|
+
|
|
32
|
+
// Use native CSS matching - optimized in Chrome/Blink
|
|
33
|
+
return element.matches(selector);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Builds a CSS selector string from the whereAttr configuration
|
|
38
|
+
* @param isCustomElement - Whether to build selector for custom elements (true) or built-in elements (false)
|
|
39
|
+
*/
|
|
40
|
+
function buildWhereAttrSelector(isCustomElement: boolean, whereAttr: WhereAttr): string {
|
|
41
|
+
const rootPrefixes = isCustomElement
|
|
42
|
+
? (whereAttr.hasCERootIn || [])
|
|
43
|
+
: (whereAttr.hasBuiltInRootIn || []);
|
|
44
|
+
|
|
45
|
+
// Parse base attribute for custom delimiter
|
|
46
|
+
const { delimiter: baseDelimiter, name: baseName } = parseDelimiter(whereAttr.hasBase);
|
|
47
|
+
|
|
48
|
+
const selectors: string[] = [];
|
|
49
|
+
|
|
50
|
+
// Build selectors for each valid prefix
|
|
51
|
+
for (const prefix of rootPrefixes) {
|
|
52
|
+
const baseAttrName = buildAttributeName(prefix, baseName, baseDelimiter);
|
|
53
|
+
const escapedBaseAttr = escapeAttributeName(baseAttrName);
|
|
54
|
+
|
|
55
|
+
// If no branches specified, just having the base attribute is enough
|
|
56
|
+
if (!whereAttr.hasBranchIn || whereAttr.hasBranchIn.length === 0) {
|
|
57
|
+
selectors.push(`[${escapedBaseAttr}]`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Build selectors for each branch combination
|
|
62
|
+
for (const branch of whereAttr.hasBranchIn) {
|
|
63
|
+
if (branch === '') {
|
|
64
|
+
// Empty string means base attribute alone is valid (no branch attributes)
|
|
65
|
+
// This requires base attr AND none of the branch attrs
|
|
66
|
+
// For CSS, we can only check for base attr presence
|
|
67
|
+
// The "no branch attrs" check needs to be done separately
|
|
68
|
+
selectors.push(`[${escapedBaseAttr}]`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (typeof branch === 'object') {
|
|
73
|
+
// Build selectors for each branch path
|
|
74
|
+
for (const [key, subBranches] of Object.entries(branch)) {
|
|
75
|
+
const branchSelectors = buildBranchSelectors(baseAttrName, key, subBranches);
|
|
76
|
+
selectors.push(...branchSelectors);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Join all selectors with comma (OR logic)
|
|
83
|
+
return selectors.join(',');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Builds CSS selectors for a branch and its sub-branches
|
|
88
|
+
*/
|
|
89
|
+
function buildBranchSelectors(
|
|
90
|
+
baseAttrName: string,
|
|
91
|
+
branchKey: string,
|
|
92
|
+
subBranches: any[]
|
|
93
|
+
): string[] {
|
|
94
|
+
const { delimiter: branchDelimiter, name: branchName } = parseDelimiter(branchKey);
|
|
95
|
+
const branchAttrName = baseAttrName + branchDelimiter + branchName;
|
|
96
|
+
const escapedBranchAttr = escapeAttributeName(branchAttrName);
|
|
97
|
+
|
|
98
|
+
const selectors: string[] = [];
|
|
99
|
+
|
|
100
|
+
// If no sub-branches specified, just the branch attribute itself
|
|
101
|
+
if (!subBranches || subBranches.length === 0) {
|
|
102
|
+
selectors.push(`[${escapedBranchAttr}]`);
|
|
103
|
+
return selectors;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Build selectors for each sub-branch - they form an OR condition
|
|
107
|
+
for (const subBranch of subBranches) {
|
|
108
|
+
if (subBranch === '') {
|
|
109
|
+
// Empty string means this branch level alone is valid
|
|
110
|
+
selectors.push(`[${escapedBranchAttr}]`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (typeof subBranch === 'string') {
|
|
115
|
+
// Simple string sub-branch - build the full path
|
|
116
|
+
const { delimiter: subDelimiter, name: subName } = parseDelimiter(subBranch);
|
|
117
|
+
const subAttrName = branchAttrName + subDelimiter + subName;
|
|
118
|
+
const escapedSubAttr = escapeAttributeName(subAttrName);
|
|
119
|
+
selectors.push(`[${escapedSubAttr}]`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof subBranch === 'object') {
|
|
124
|
+
// Nested object sub-branch - recursively build deeper paths
|
|
125
|
+
for (const [key, nestedBranches] of Object.entries(subBranch)) {
|
|
126
|
+
const nestedSelectors = buildNestedBranchSelectors(branchAttrName, key, nestedBranches as any[]);
|
|
127
|
+
selectors.push(...nestedSelectors);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return selectors;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Builds CSS selectors for nested branches recursively
|
|
137
|
+
*/
|
|
138
|
+
function buildNestedBranchSelectors(
|
|
139
|
+
parentAttrName: string,
|
|
140
|
+
branchKey: string,
|
|
141
|
+
subBranches: any[]
|
|
142
|
+
): string[] {
|
|
143
|
+
const { delimiter, name } = parseDelimiter(branchKey);
|
|
144
|
+
const attrName = parentAttrName + delimiter + name;
|
|
145
|
+
const escapedAttr = escapeAttributeName(attrName);
|
|
146
|
+
|
|
147
|
+
const selectors: string[] = [];
|
|
148
|
+
|
|
149
|
+
// If no sub-branches specified, just this attribute
|
|
150
|
+
if (!subBranches || subBranches.length === 0) {
|
|
151
|
+
selectors.push(`[${escapedAttr}]`);
|
|
152
|
+
return selectors;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Build selectors for each sub-branch - they form an OR condition
|
|
156
|
+
for (const subBranch of subBranches) {
|
|
157
|
+
if (subBranch === '') {
|
|
158
|
+
// Empty string means this level alone is valid
|
|
159
|
+
selectors.push(`[${escapedAttr}]`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (typeof subBranch === 'string') {
|
|
164
|
+
// Simple string sub-branch - build the full path
|
|
165
|
+
const { delimiter: subDelimiter, name: subName } = parseDelimiter(subBranch);
|
|
166
|
+
const subAttrName = attrName + subDelimiter + subName;
|
|
167
|
+
const escapedSubAttr = escapeAttributeName(subAttrName);
|
|
168
|
+
selectors.push(`[${escapedSubAttr}]`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (typeof subBranch === 'object') {
|
|
173
|
+
// Nested object - recursively build deeper paths
|
|
174
|
+
for (const [key, nestedBranches] of Object.entries(subBranch)) {
|
|
175
|
+
const nestedSelectors = buildNestedBranchSelectors(attrName, key, nestedBranches as any[]);
|
|
176
|
+
selectors.push(...nestedSelectors);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return selectors;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Escapes special characters in attribute names for CSS selectors
|
|
186
|
+
* Uses CSS.escape() API which handles all special characters including :
|
|
187
|
+
*/
|
|
188
|
+
function escapeAttributeName(attrName: string): string {
|
|
189
|
+
// CSS.escape() is available in all modern browsers
|
|
190
|
+
// It properly escapes special characters like : . [ ] etc.
|
|
191
|
+
return CSS.escape(attrName);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Parses a key to extract custom delimiter and name
|
|
196
|
+
* Format: [delimiter]name
|
|
197
|
+
* Example: "[_]my-custom" returns { delimiter: "_", name: "my-custom" }
|
|
198
|
+
*/
|
|
199
|
+
function parseDelimiter(key: string): { delimiter: string; name: string } {
|
|
200
|
+
const match = key.match(/^\[(.+?)\](.+)$/);
|
|
201
|
+
if (match) {
|
|
202
|
+
return {
|
|
203
|
+
delimiter: match[1],
|
|
204
|
+
name: match[2]
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
delimiter: '-',
|
|
209
|
+
name: key
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Builds the full attribute name from prefix, base name, and delimiter
|
|
215
|
+
*/
|
|
216
|
+
function buildAttributeName(prefix: string, baseName: string, delimiter: string): string {
|
|
217
|
+
if (prefix === '') {
|
|
218
|
+
return baseName;
|
|
219
|
+
}
|
|
220
|
+
return prefix + delimiter + baseName;
|
|
221
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Bruce B. Anderson
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/Newish.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
export { waitForEvent } from './waitForEvent.js';
|
|
2
|
-
import { ObsAttr } from './ObsAttr.js';
|
|
3
|
-
import { getIsh } from './refid/getIsh.js';
|
|
4
|
-
import { arr } from './refid/secretKeys.js';
|
|
5
|
-
export const attached = Symbol.for('xyyspnstnU+CDrNVa0VnxA');
|
|
6
|
-
export class Newish {
|
|
7
|
-
queue = [];
|
|
8
|
-
isResolved = false;
|
|
9
|
-
#ce;
|
|
10
|
-
#ref;
|
|
11
|
-
#options;
|
|
12
|
-
#args;
|
|
13
|
-
constructor(enhancedElement, target, itemscope, options) {
|
|
14
|
-
this.#args = [enhancedElement, target, itemscope];
|
|
15
|
-
this.#options = options || { assigner: Object.assign };
|
|
16
|
-
this.#ref = new WeakRef(enhancedElement);
|
|
17
|
-
}
|
|
18
|
-
async handleEvent() {
|
|
19
|
-
const enhancedElement = this.#ref.deref();
|
|
20
|
-
if (!enhancedElement)
|
|
21
|
-
return;
|
|
22
|
-
await this.#attachItemrefs(enhancedElement);
|
|
23
|
-
}
|
|
24
|
-
async do() {
|
|
25
|
-
const [enhancedElement, target, itemscope] = this.#args;
|
|
26
|
-
this.#args = undefined;
|
|
27
|
-
if (enhancedElement[attached] === true)
|
|
28
|
-
return;
|
|
29
|
-
enhancedElement[attached] = true;
|
|
30
|
-
const options = this.#options;
|
|
31
|
-
const { initPropVals, ctr } = options;
|
|
32
|
-
let ce;
|
|
33
|
-
if (ctr === undefined) {
|
|
34
|
-
const foundCtr = await getIsh(enhancedElement.isConnected ? enhancedElement : target, itemscope);
|
|
35
|
-
const initPropVals = enhancedElement['ish'];
|
|
36
|
-
const resolvedConstructor = foundCtr.constructor.name === 'AsyncFunction' ? await foundCtr() : foundCtr;
|
|
37
|
-
const isInstance = initPropVals instanceof resolvedConstructor;
|
|
38
|
-
ce = isInstance ? initPropVals : new resolvedConstructor();
|
|
39
|
-
if (initPropVals !== undefined && !isInstance)
|
|
40
|
-
this.queue.push(initPropVals);
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
ce = new ctr();
|
|
44
|
-
if (initPropVals !== undefined)
|
|
45
|
-
this.queue.push(initPropVals);
|
|
46
|
-
}
|
|
47
|
-
// if('tbd' in ce && typeof ce['tbd'] === 'function'){
|
|
48
|
-
// await ce['tbd'](ce, enhancedElement, this.#options);
|
|
49
|
-
// }
|
|
50
|
-
this.#ce = ce;
|
|
51
|
-
const self = this;
|
|
52
|
-
Object.defineProperty(enhancedElement, 'ish', {
|
|
53
|
-
get() {
|
|
54
|
-
return self.#ce;
|
|
55
|
-
},
|
|
56
|
-
set(nv) {
|
|
57
|
-
if (self.#ce === nv)
|
|
58
|
-
return;
|
|
59
|
-
self.queue.push(nv);
|
|
60
|
-
self.#assignGingerly(false);
|
|
61
|
-
},
|
|
62
|
-
enumerable: true,
|
|
63
|
-
configurable: true,
|
|
64
|
-
});
|
|
65
|
-
await this.#assignGingerly(true);
|
|
66
|
-
if ('<mount>' in ce && typeof ce['<mount>'] === 'function') {
|
|
67
|
-
await ce['<mount>'](ce, enhancedElement, this.#options);
|
|
68
|
-
}
|
|
69
|
-
//attach any itemref references
|
|
70
|
-
await this.#attachItemrefs(enhancedElement);
|
|
71
|
-
const et = ObsAttr(enhancedElement, 'itemref');
|
|
72
|
-
et.addEventListener('attr-changed', this);
|
|
73
|
-
this.isResolved = true;
|
|
74
|
-
return ce;
|
|
75
|
-
}
|
|
76
|
-
#alreadyAttached = new WeakSet;
|
|
77
|
-
async #attachItemrefs(enhancedElement) {
|
|
78
|
-
//TODO: watch for already attached itemrefs to be removed and remove them from the set
|
|
79
|
-
// and call outOfScopeCallback on them
|
|
80
|
-
if ('<inScope>' in this.#ce && enhancedElement.hasAttribute('itemref')) {
|
|
81
|
-
await import('./refid/via.js');
|
|
82
|
-
const itemref = enhancedElement.via.itemref;
|
|
83
|
-
const refs = itemref.children;
|
|
84
|
-
for (const ref of refs) {
|
|
85
|
-
if (this.#alreadyAttached.has(ref))
|
|
86
|
-
continue;
|
|
87
|
-
this.#ce['<inScope>'](this.#ce, ref, this.#options);
|
|
88
|
-
}
|
|
89
|
-
itemref.addEventListener('change', this);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async #assignGingerly(fromDo) {
|
|
93
|
-
const actions = new Set();
|
|
94
|
-
if (fromDo) {
|
|
95
|
-
actions.add('attached');
|
|
96
|
-
}
|
|
97
|
-
let ce = this.#ce;
|
|
98
|
-
if (ce === undefined) {
|
|
99
|
-
throw 500;
|
|
100
|
-
}
|
|
101
|
-
let foundArray = false;
|
|
102
|
-
const hasArrFilter = 'arr=>' in ce && typeof ce['arr=>'] === 'function';
|
|
103
|
-
const ref = this.#ref.deref();
|
|
104
|
-
while (this.queue.length > 0) {
|
|
105
|
-
const fi = this.queue.shift();
|
|
106
|
-
//TODO: Provide support for a virtual slice of a very large list
|
|
107
|
-
//TODO: Maybe should check if iterable rather than an array?
|
|
108
|
-
if (Array.isArray(fi)) {
|
|
109
|
-
foundArray = true;
|
|
110
|
-
let filtered = fi;
|
|
111
|
-
if (hasArrFilter) {
|
|
112
|
-
filtered = await (ce['arr=>'])(ce, fi, ref, this.#options);
|
|
113
|
-
}
|
|
114
|
-
ce[arr] = filtered;
|
|
115
|
-
actions.add('ishListAssigned');
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
let { assigner } = this.#options;
|
|
119
|
-
if (assigner === undefined) {
|
|
120
|
-
assigner = Object.assign;
|
|
121
|
-
}
|
|
122
|
-
await assigner(ce, fi);
|
|
123
|
-
actions.add('ishAssigned');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (fromDo && !foundArray && hasArrFilter) {
|
|
127
|
-
const filtered = await (ce['arr=>'])(ce, undefined, ref, this.#options);
|
|
128
|
-
if (filtered !== undefined) {
|
|
129
|
-
ce[arr] = filtered;
|
|
130
|
-
actions.add('ishListAssigned');
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
if (ref) {
|
|
134
|
-
ref.dispatchEvent(new IshEvent(Array.from(actions)));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
export class IshEvent extends Event {
|
|
139
|
-
actions;
|
|
140
|
-
static eventName = 'ish';
|
|
141
|
-
constructor(actions) {
|
|
142
|
-
super(IshEvent.eventName);
|
|
143
|
-
this.actions = actions;
|
|
144
|
-
}
|
|
145
|
-
}
|
package/Newish.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { BindishOptions, HasIsh, Ishcycle } from './ts-refs/mount-observer/types.js';
|
|
2
|
-
|
|
3
|
-
export {waitForEvent} from './waitForEvent.js';
|
|
4
|
-
import {ObsAttr} from './ObsAttr.js';
|
|
5
|
-
import {splitRefs} from './refid/splitRefs.js';
|
|
6
|
-
import {getIsh} from './refid/getIsh.js';
|
|
7
|
-
import {arr} from './refid/secretKeys.js';
|
|
8
|
-
export const attached = Symbol.for('xyyspnstnU+CDrNVa0VnxA');
|
|
9
|
-
export class Newish implements EventListenerObject {
|
|
10
|
-
queue: Array<any> = [];
|
|
11
|
-
isResolved = false;
|
|
12
|
-
#ce: Ishcycle | undefined;
|
|
13
|
-
#ref: WeakRef<Element>;
|
|
14
|
-
|
|
15
|
-
#options: BindishOptions;
|
|
16
|
-
#args: [enhancedElement: Element, target: Node, itemscope: string] | undefined;
|
|
17
|
-
constructor(
|
|
18
|
-
enhancedElement: Element,
|
|
19
|
-
target: Node,
|
|
20
|
-
itemscope: string,
|
|
21
|
-
options?: BindishOptions
|
|
22
|
-
){
|
|
23
|
-
this.#args = [enhancedElement, target, itemscope];
|
|
24
|
-
this.#options = options || {assigner: Object.assign};
|
|
25
|
-
this.#ref = new WeakRef(enhancedElement);
|
|
26
|
-
}
|
|
27
|
-
async handleEvent() {
|
|
28
|
-
const enhancedElement = this.#ref.deref();
|
|
29
|
-
if(!enhancedElement) return;
|
|
30
|
-
await this.#attachItemrefs(enhancedElement);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async do(){
|
|
34
|
-
const [enhancedElement, target, itemscope] = this.#args!;
|
|
35
|
-
this.#args = undefined;
|
|
36
|
-
if((<any>enhancedElement)[attached] === true) return;
|
|
37
|
-
(<any>enhancedElement)[attached] = true;
|
|
38
|
-
const options = this.#options;
|
|
39
|
-
const {initPropVals, ctr} = options;
|
|
40
|
-
let ce: Ishcycle;
|
|
41
|
-
if(ctr === undefined){
|
|
42
|
-
const foundCtr = await getIsh(enhancedElement.isConnected ? enhancedElement :target, itemscope)! as any;
|
|
43
|
-
|
|
44
|
-
const initPropVals = (<any>enhancedElement)['ish'];
|
|
45
|
-
|
|
46
|
-
const resolvedConstructor = foundCtr.constructor.name === 'AsyncFunction' ? await foundCtr() : foundCtr;
|
|
47
|
-
const isInstance = initPropVals instanceof resolvedConstructor
|
|
48
|
-
ce = isInstance ? initPropVals : new resolvedConstructor() as Ishcycle;
|
|
49
|
-
if(initPropVals !== undefined && !isInstance) this.queue.push(initPropVals);
|
|
50
|
-
}else{
|
|
51
|
-
ce = new (ctr as any)();
|
|
52
|
-
if(initPropVals !== undefined) this.queue.push(initPropVals);
|
|
53
|
-
}
|
|
54
|
-
// if('tbd' in ce && typeof ce['tbd'] === 'function'){
|
|
55
|
-
// await ce['tbd'](ce, enhancedElement, this.#options);
|
|
56
|
-
// }
|
|
57
|
-
|
|
58
|
-
this.#ce = ce;
|
|
59
|
-
const self = this;
|
|
60
|
-
Object.defineProperty(enhancedElement, 'ish', {
|
|
61
|
-
get(){
|
|
62
|
-
return self.#ce;
|
|
63
|
-
},
|
|
64
|
-
set(nv: any){
|
|
65
|
-
if(self.#ce === nv) return;
|
|
66
|
-
self.queue.push(nv);
|
|
67
|
-
self.#assignGingerly(false);
|
|
68
|
-
},
|
|
69
|
-
enumerable: true,
|
|
70
|
-
configurable: true,
|
|
71
|
-
});
|
|
72
|
-
await this.#assignGingerly(true);
|
|
73
|
-
if('<mount>' in ce && typeof ce['<mount>'] === 'function'){
|
|
74
|
-
await ce['<mount>'](ce, enhancedElement as HasIsh & Element, this.#options)
|
|
75
|
-
}
|
|
76
|
-
//attach any itemref references
|
|
77
|
-
await this.#attachItemrefs(enhancedElement);
|
|
78
|
-
const et = ObsAttr(enhancedElement, 'itemref');
|
|
79
|
-
et.addEventListener('attr-changed', this);
|
|
80
|
-
this.isResolved = true;
|
|
81
|
-
return ce;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
#alreadyAttached = new WeakSet<Element>;
|
|
87
|
-
|
|
88
|
-
async #attachItemrefs(enhancedElement: Element){
|
|
89
|
-
//TODO: watch for already attached itemrefs to be removed and remove them from the set
|
|
90
|
-
// and call outOfScopeCallback on them
|
|
91
|
-
if('<inScope>' in (<any>this.#ce) && enhancedElement.hasAttribute('itemref')){
|
|
92
|
-
await import('./refid/via.js');
|
|
93
|
-
const itemref = (<any>enhancedElement).via.itemref
|
|
94
|
-
const refs = itemref.children as Element[];
|
|
95
|
-
for(const ref of refs){
|
|
96
|
-
if(this.#alreadyAttached.has(ref)) continue;
|
|
97
|
-
(<any>this.#ce)['<inScope>'](this.#ce, ref, this.#options);
|
|
98
|
-
}
|
|
99
|
-
itemref.addEventListener('change', this);
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async #assignGingerly(fromDo: boolean){
|
|
106
|
-
const actions = new Set<Action>();
|
|
107
|
-
if(fromDo){
|
|
108
|
-
actions.add('attached');
|
|
109
|
-
}
|
|
110
|
-
let ce = this.#ce!;
|
|
111
|
-
if(ce === undefined){
|
|
112
|
-
throw 500;
|
|
113
|
-
}
|
|
114
|
-
let foundArray = false;
|
|
115
|
-
const hasArrFilter = 'arr=>' in ce && typeof ce['arr=>'] === 'function';
|
|
116
|
-
const ref = this.#ref.deref();
|
|
117
|
-
while(this.queue.length > 0 ){
|
|
118
|
-
const fi = this.queue.shift();
|
|
119
|
-
//TODO: Provide support for a virtual slice of a very large list
|
|
120
|
-
//TODO: Maybe should check if iterable rather than an array?
|
|
121
|
-
if(Array.isArray(fi)){
|
|
122
|
-
foundArray = true;
|
|
123
|
-
let filtered = fi as any | undefined;
|
|
124
|
-
if(hasArrFilter){
|
|
125
|
-
filtered = await (ce['arr=>']!)(ce, fi, ref! as HasIsh & Element, this.#options);
|
|
126
|
-
}
|
|
127
|
-
(<any>ce)[arr] = filtered;
|
|
128
|
-
actions.add('ishListAssigned');
|
|
129
|
-
}else{
|
|
130
|
-
let {assigner} = this.#options;
|
|
131
|
-
if(assigner === undefined){
|
|
132
|
-
assigner = Object.assign;
|
|
133
|
-
}
|
|
134
|
-
await assigner!(ce, fi);
|
|
135
|
-
actions.add('ishAssigned');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
if(fromDo && !foundArray && hasArrFilter){
|
|
140
|
-
const filtered = await (ce['arr=>']!)(ce, undefined, ref! as HasIsh & Element, this.#options);
|
|
141
|
-
if(filtered !== undefined){
|
|
142
|
-
(<any>ce)[arr] = filtered;
|
|
143
|
-
actions.add('ishListAssigned');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if(ref){
|
|
148
|
-
ref.dispatchEvent(new IshEvent(Array.from(actions)));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
type Action =
|
|
155
|
-
| 'attached'
|
|
156
|
-
| 'ishAssigned'
|
|
157
|
-
| 'ishListAssigned'
|
|
158
|
-
|
|
159
|
-
interface IIshEvent{
|
|
160
|
-
actions: Array<Action>;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export class IshEvent extends Event implements IIshEvent{
|
|
164
|
-
static eventName = 'ish';
|
|
165
|
-
|
|
166
|
-
constructor(public actions: Array<Action>){
|
|
167
|
-
super(IshEvent.eventName);
|
|
168
|
-
}
|
|
169
|
-
}
|
package/ObsAttr.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function ObsAttr(element, attr) {
|
|
2
|
-
const eventTarget = new EventTarget();
|
|
3
|
-
const obs = new MutationObserver((mutations) => {
|
|
4
|
-
eventTarget.dispatchEvent(new Event('attr-changed'));
|
|
5
|
-
// for(const mutation of mutations){
|
|
6
|
-
// if(mutation.type === 'attributes' && mutation.attributeName === attr){
|
|
7
|
-
// obs.disconnect();
|
|
8
|
-
// eventTarget.dispatchEvent(new Event('obsAttr'));
|
|
9
|
-
// break;
|
|
10
|
-
// }
|
|
11
|
-
// }
|
|
12
|
-
});
|
|
13
|
-
obs.observe(element, {
|
|
14
|
-
attributes: true,
|
|
15
|
-
attributeFilter: [attr],
|
|
16
|
-
});
|
|
17
|
-
return eventTarget;
|
|
18
|
-
}
|
package/ObsAttr.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function ObsAttr(element: Element, attr: string): EventTarget{
|
|
2
|
-
const eventTarget = new EventTarget();
|
|
3
|
-
const obs = new MutationObserver((mutations) => {
|
|
4
|
-
eventTarget.dispatchEvent(new Event('attr-changed'));
|
|
5
|
-
// for(const mutation of mutations){
|
|
6
|
-
// if(mutation.type === 'attributes' && mutation.attributeName === attr){
|
|
7
|
-
// obs.disconnect();
|
|
8
|
-
// eventTarget.dispatchEvent(new Event('obsAttr'));
|
|
9
|
-
// break;
|
|
10
|
-
// }
|
|
11
|
-
// }
|
|
12
|
-
});
|
|
13
|
-
obs.observe(element, {
|
|
14
|
-
attributes: true,
|
|
15
|
-
attributeFilter: [attr],
|
|
16
|
-
});
|
|
17
|
-
return eventTarget;
|
|
18
|
-
}
|
package/RootMutObs.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
export class RootMutObs extends EventTarget {
|
|
2
|
-
#idleTimeout; //TODO: make this configurable
|
|
3
|
-
#idlePointer = 0;
|
|
4
|
-
constructor(rootNode, options) {
|
|
5
|
-
super();
|
|
6
|
-
this.#idleTimeout = options?.idleTimeout ?? 30;
|
|
7
|
-
this.#mutationObserver = new MutationObserver(mutationRecords => {
|
|
8
|
-
this.dispatchEvent(new MutationEvent(mutationRecords));
|
|
9
|
-
this.#triggerIsIdle();
|
|
10
|
-
});
|
|
11
|
-
this.#mutationObserver.observe(rootNode, {
|
|
12
|
-
subtree: true,
|
|
13
|
-
childList: true,
|
|
14
|
-
attributes: true,
|
|
15
|
-
attributeOldValue: true,
|
|
16
|
-
});
|
|
17
|
-
this.#triggerIsIdle();
|
|
18
|
-
}
|
|
19
|
-
#isIdle = false;
|
|
20
|
-
get isIdle() {
|
|
21
|
-
return this.#isIdle;
|
|
22
|
-
}
|
|
23
|
-
#triggerIsIdle() {
|
|
24
|
-
this.#isIdle = false;
|
|
25
|
-
clearTimeout(this.#idlePointer);
|
|
26
|
-
this.#idlePointer = setTimeout(() => {
|
|
27
|
-
this.#isIdle = true;
|
|
28
|
-
this.dispatchEvent(new Event('is-idle'));
|
|
29
|
-
}, this.#idleTimeout);
|
|
30
|
-
}
|
|
31
|
-
#mutationObserver;
|
|
32
|
-
disconnect() {
|
|
33
|
-
this.#mutationObserver.disconnect();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
|
|
37
|
-
/**
|
|
38
|
-
* The `mutation-event` event represents something that happened.
|
|
39
|
-
* We can document it here.
|
|
40
|
-
*/
|
|
41
|
-
export class MutationEvent extends Event {
|
|
42
|
-
mutationRecords;
|
|
43
|
-
static eventName = 'mutation-event';
|
|
44
|
-
constructor(mutationRecords) {
|
|
45
|
-
// Since these are hard-coded, dispatchers can't get them wrong
|
|
46
|
-
super(MutationEvent.eventName);
|
|
47
|
-
this.mutationRecords = mutationRecords;
|
|
48
|
-
}
|
|
49
|
-
}
|