@thomas-siegfried/tapout 0.0.1 → 0.0.2
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/LICENSE +21 -21
- package/README.md +1205 -1205
- package/package.json +55 -55
- package/src/applyBindings.ts +372 -372
- package/src/arrayToDomMapping.ts +300 -300
- package/src/attributeInterpolationMarkup.ts +91 -91
- package/src/bindingContext.ts +207 -207
- package/src/bindingEvent.ts +198 -198
- package/src/bindingProvider.ts +260 -260
- package/src/bindings.ts +963 -963
- package/src/compareArrays.ts +122 -122
- package/src/componentBinding.ts +318 -318
- package/src/componentDecorator.ts +62 -62
- package/src/components.ts +367 -367
- package/src/computed.ts +439 -439
- package/src/configure.ts +52 -52
- package/src/controlFlowBindings.ts +206 -206
- package/src/core.ts +60 -60
- package/src/decorators.ts +407 -407
- package/src/dependencyDetection.ts +76 -76
- package/src/disposable.ts +36 -36
- package/src/domData.ts +42 -42
- package/src/domNodeDisposal.ts +94 -94
- package/src/effects.ts +29 -29
- package/src/event.ts +173 -173
- package/src/expressionRewriting.ts +219 -219
- package/src/extenders.ts +102 -102
- package/src/filters.ts +91 -91
- package/src/index.ts +150 -150
- package/src/interpolationMarkup.ts +130 -130
- package/src/memoization.ts +71 -71
- package/src/namespacedBindings.ts +132 -132
- package/src/observable.ts +48 -48
- package/src/observableArray.ts +397 -397
- package/src/options.ts +25 -25
- package/src/selectExtensions.ts +68 -68
- package/src/slotBinding.ts +84 -84
- package/src/subscribable.ts +266 -266
- package/src/tasks.ts +79 -79
- package/src/templateEngine.ts +108 -108
- package/src/templateRendering.ts +399 -399
- package/src/templateRewriting.ts +94 -94
- package/src/templateSources.ts +134 -134
- package/src/utils.ts +123 -123
- package/src/utilsDom.ts +87 -87
- package/src/virtualElements.ts +153 -153
- package/src/wireParams.ts +49 -49
package/src/utils.ts
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
import { PureComputed } from './computed.js';
|
|
2
|
-
import { isReadableSubscribable } from './subscribable.js';
|
|
3
|
-
import type { ReadableSubscribable, Subscription } from './subscribable.js';
|
|
4
|
-
import { options } from './options.js';
|
|
5
|
-
|
|
6
|
-
const MAX_NESTED_OBSERVABLE_DEPTH = 10;
|
|
7
|
-
|
|
8
|
-
export function unwrapObservable(value: unknown): unknown {
|
|
9
|
-
for (let i = 0; isReadableSubscribable(value) && i < MAX_NESTED_OBSERVABLE_DEPTH; i++) {
|
|
10
|
-
value = value.get();
|
|
11
|
-
}
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function peekObservable(value: unknown): unknown {
|
|
16
|
-
for (let i = 0; isReadableSubscribable(value) && i < MAX_NESTED_OBSERVABLE_DEPTH; i++) {
|
|
17
|
-
value = value.peek();
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function canHaveProperties(obj: unknown): obj is Record<string | number, unknown> {
|
|
23
|
-
return (
|
|
24
|
-
typeof obj === 'object' &&
|
|
25
|
-
obj !== null &&
|
|
26
|
-
!(obj instanceof RegExp) &&
|
|
27
|
-
!(obj instanceof Date) &&
|
|
28
|
-
!(obj instanceof String) &&
|
|
29
|
-
!(obj instanceof Number) &&
|
|
30
|
-
!(obj instanceof Boolean)
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function mapJsObjectGraph(
|
|
35
|
-
rootObject: unknown,
|
|
36
|
-
visited: Map<object, unknown>,
|
|
37
|
-
): unknown {
|
|
38
|
-
rootObject = peekObservable(rootObject);
|
|
39
|
-
|
|
40
|
-
if (!canHaveProperties(rootObject)) {
|
|
41
|
-
return rootObject;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const previouslyMapped = visited.get(rootObject);
|
|
45
|
-
if (previouslyMapped !== undefined) {
|
|
46
|
-
return previouslyMapped;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const isArray = Array.isArray(rootObject);
|
|
50
|
-
const output: Record<string, unknown> | unknown[] = isArray ? [] as unknown[] : {};
|
|
51
|
-
visited.set(rootObject, output);
|
|
52
|
-
|
|
53
|
-
if (isArray) {
|
|
54
|
-
const arr = rootObject as unknown as unknown[];
|
|
55
|
-
const out = output as unknown[];
|
|
56
|
-
for (let i = 0; i < arr.length; i++) {
|
|
57
|
-
const propertyValue = peekObservable(arr[i]);
|
|
58
|
-
out[i] = canHaveProperties(propertyValue)
|
|
59
|
-
? (visited.get(propertyValue as object) ?? mapJsObjectGraph(propertyValue, visited))
|
|
60
|
-
: propertyValue;
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
const out = output as Record<string, unknown>;
|
|
64
|
-
for (const key in rootObject) {
|
|
65
|
-
const propertyValue = peekObservable(rootObject[key]);
|
|
66
|
-
out[key] = canHaveProperties(propertyValue)
|
|
67
|
-
? (visited.get(propertyValue as object) ?? mapJsObjectGraph(propertyValue, visited))
|
|
68
|
-
: propertyValue;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return output;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function toJS<T>(rootObject: T): unknown {
|
|
76
|
-
return mapJsObjectGraph(rootObject, new Map());
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function toJSON(
|
|
80
|
-
rootObject: unknown,
|
|
81
|
-
replacer?: (key: string, value: unknown) => unknown,
|
|
82
|
-
space?: string | number,
|
|
83
|
-
): string {
|
|
84
|
-
const plainObject = toJS(rootObject);
|
|
85
|
-
return JSON.stringify(plainObject, replacer as Parameters<typeof JSON.stringify>[1], space);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function when(
|
|
89
|
-
predicate: () => unknown,
|
|
90
|
-
callback?: (value: unknown) => void,
|
|
91
|
-
): Promise<unknown> | Subscription<unknown> {
|
|
92
|
-
function kowhen(resolve: (value: unknown) => void): Subscription<unknown> {
|
|
93
|
-
const observable = new PureComputed(predicate);
|
|
94
|
-
observable.extend({ notify: 'always' });
|
|
95
|
-
const subscription = observable.subscribe((value: unknown) => {
|
|
96
|
-
if (value) {
|
|
97
|
-
subscription.dispose();
|
|
98
|
-
observable.dispose();
|
|
99
|
-
resolve(value);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
observable.notifySubscribers(observable.peek());
|
|
103
|
-
return subscription;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!callback) {
|
|
107
|
-
return new Promise(kowhen);
|
|
108
|
-
} else {
|
|
109
|
-
return kowhen(callback);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function catchFunctionErrors<T extends (...args: never[]) => unknown>(delegate: T): T {
|
|
114
|
-
if (!options.onError) return delegate;
|
|
115
|
-
return function (this: unknown, ...args: Parameters<T>) {
|
|
116
|
-
try {
|
|
117
|
-
return delegate.apply(this, args);
|
|
118
|
-
} catch (e) {
|
|
119
|
-
options.onError?.(e);
|
|
120
|
-
throw e;
|
|
121
|
-
}
|
|
122
|
-
} as unknown as T;
|
|
123
|
-
}
|
|
1
|
+
import { PureComputed } from './computed.js';
|
|
2
|
+
import { isReadableSubscribable } from './subscribable.js';
|
|
3
|
+
import type { ReadableSubscribable, Subscription } from './subscribable.js';
|
|
4
|
+
import { options } from './options.js';
|
|
5
|
+
|
|
6
|
+
const MAX_NESTED_OBSERVABLE_DEPTH = 10;
|
|
7
|
+
|
|
8
|
+
export function unwrapObservable(value: unknown): unknown {
|
|
9
|
+
for (let i = 0; isReadableSubscribable(value) && i < MAX_NESTED_OBSERVABLE_DEPTH; i++) {
|
|
10
|
+
value = value.get();
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function peekObservable(value: unknown): unknown {
|
|
16
|
+
for (let i = 0; isReadableSubscribable(value) && i < MAX_NESTED_OBSERVABLE_DEPTH; i++) {
|
|
17
|
+
value = value.peek();
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function canHaveProperties(obj: unknown): obj is Record<string | number, unknown> {
|
|
23
|
+
return (
|
|
24
|
+
typeof obj === 'object' &&
|
|
25
|
+
obj !== null &&
|
|
26
|
+
!(obj instanceof RegExp) &&
|
|
27
|
+
!(obj instanceof Date) &&
|
|
28
|
+
!(obj instanceof String) &&
|
|
29
|
+
!(obj instanceof Number) &&
|
|
30
|
+
!(obj instanceof Boolean)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function mapJsObjectGraph(
|
|
35
|
+
rootObject: unknown,
|
|
36
|
+
visited: Map<object, unknown>,
|
|
37
|
+
): unknown {
|
|
38
|
+
rootObject = peekObservable(rootObject);
|
|
39
|
+
|
|
40
|
+
if (!canHaveProperties(rootObject)) {
|
|
41
|
+
return rootObject;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const previouslyMapped = visited.get(rootObject);
|
|
45
|
+
if (previouslyMapped !== undefined) {
|
|
46
|
+
return previouslyMapped;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const isArray = Array.isArray(rootObject);
|
|
50
|
+
const output: Record<string, unknown> | unknown[] = isArray ? [] as unknown[] : {};
|
|
51
|
+
visited.set(rootObject, output);
|
|
52
|
+
|
|
53
|
+
if (isArray) {
|
|
54
|
+
const arr = rootObject as unknown as unknown[];
|
|
55
|
+
const out = output as unknown[];
|
|
56
|
+
for (let i = 0; i < arr.length; i++) {
|
|
57
|
+
const propertyValue = peekObservable(arr[i]);
|
|
58
|
+
out[i] = canHaveProperties(propertyValue)
|
|
59
|
+
? (visited.get(propertyValue as object) ?? mapJsObjectGraph(propertyValue, visited))
|
|
60
|
+
: propertyValue;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
const out = output as Record<string, unknown>;
|
|
64
|
+
for (const key in rootObject) {
|
|
65
|
+
const propertyValue = peekObservable(rootObject[key]);
|
|
66
|
+
out[key] = canHaveProperties(propertyValue)
|
|
67
|
+
? (visited.get(propertyValue as object) ?? mapJsObjectGraph(propertyValue, visited))
|
|
68
|
+
: propertyValue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function toJS<T>(rootObject: T): unknown {
|
|
76
|
+
return mapJsObjectGraph(rootObject, new Map());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function toJSON(
|
|
80
|
+
rootObject: unknown,
|
|
81
|
+
replacer?: (key: string, value: unknown) => unknown,
|
|
82
|
+
space?: string | number,
|
|
83
|
+
): string {
|
|
84
|
+
const plainObject = toJS(rootObject);
|
|
85
|
+
return JSON.stringify(plainObject, replacer as Parameters<typeof JSON.stringify>[1], space);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function when(
|
|
89
|
+
predicate: () => unknown,
|
|
90
|
+
callback?: (value: unknown) => void,
|
|
91
|
+
): Promise<unknown> | Subscription<unknown> {
|
|
92
|
+
function kowhen(resolve: (value: unknown) => void): Subscription<unknown> {
|
|
93
|
+
const observable = new PureComputed(predicate);
|
|
94
|
+
observable.extend({ notify: 'always' });
|
|
95
|
+
const subscription = observable.subscribe((value: unknown) => {
|
|
96
|
+
if (value) {
|
|
97
|
+
subscription.dispose();
|
|
98
|
+
observable.dispose();
|
|
99
|
+
resolve(value);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
observable.notifySubscribers(observable.peek());
|
|
103
|
+
return subscription;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!callback) {
|
|
107
|
+
return new Promise(kowhen);
|
|
108
|
+
} else {
|
|
109
|
+
return kowhen(callback);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function catchFunctionErrors<T extends (...args: never[]) => unknown>(delegate: T): T {
|
|
114
|
+
if (!options.onError) return delegate;
|
|
115
|
+
return function (this: unknown, ...args: Parameters<T>) {
|
|
116
|
+
try {
|
|
117
|
+
return delegate.apply(this, args);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
options.onError?.(e);
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
} as unknown as T;
|
|
123
|
+
}
|
package/src/utilsDom.ts
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
import { cleanNode, removeNode } from './domNodeDisposal.js';
|
|
2
|
-
|
|
3
|
-
export function cloneNodes(nodesArray: Node[], shouldCleanNodes?: boolean): Node[] {
|
|
4
|
-
const result: Node[] = [];
|
|
5
|
-
for (let i = 0; i < nodesArray.length; i++) {
|
|
6
|
-
const cloned = nodesArray[i].cloneNode(true);
|
|
7
|
-
result.push(shouldCleanNodes ? cleanNode(cloned) : cloned);
|
|
8
|
-
}
|
|
9
|
-
return result;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function fixUpContinuousNodeArray(continuousNodeArray: Node[], parentNode: Node): Node[] {
|
|
13
|
-
if (continuousNodeArray.length) {
|
|
14
|
-
parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;
|
|
15
|
-
|
|
16
|
-
// Rule [A]: Strip detached leading nodes
|
|
17
|
-
while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
|
|
18
|
-
continuousNodeArray.splice(0, 1);
|
|
19
|
-
|
|
20
|
-
// Rule [B]: Strip detached trailing nodes
|
|
21
|
-
while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)
|
|
22
|
-
continuousNodeArray.length--;
|
|
23
|
-
|
|
24
|
-
// Rule [C]: Fill in to maintain continuity
|
|
25
|
-
if (continuousNodeArray.length > 1) {
|
|
26
|
-
const first = continuousNodeArray[0];
|
|
27
|
-
const last = continuousNodeArray[continuousNodeArray.length - 1];
|
|
28
|
-
continuousNodeArray.length = 0;
|
|
29
|
-
let current: Node | null = first;
|
|
30
|
-
while (current !== last) {
|
|
31
|
-
continuousNodeArray.push(current!);
|
|
32
|
-
current = current!.nextSibling;
|
|
33
|
-
}
|
|
34
|
-
continuousNodeArray.push(last);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return continuousNodeArray;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function replaceDomNodes(nodeToReplaceOrNodeArray: Node | Node[], newNodesArray: Node[]): void {
|
|
41
|
-
const nodesToReplace = 'nodeType' in nodeToReplaceOrNodeArray
|
|
42
|
-
? [nodeToReplaceOrNodeArray as Node]
|
|
43
|
-
: nodeToReplaceOrNodeArray as Node[];
|
|
44
|
-
if (nodesToReplace.length > 0) {
|
|
45
|
-
const insertionPoint = nodesToReplace[0];
|
|
46
|
-
const parent = insertionPoint.parentNode!;
|
|
47
|
-
for (let i = 0; i < newNodesArray.length; i++)
|
|
48
|
-
parent.insertBefore(newNodesArray[i], insertionPoint);
|
|
49
|
-
for (let i = 0; i < nodesToReplace.length; i++)
|
|
50
|
-
removeNode(nodesToReplace[i]);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function moveCleanedNodesToContainerElement(nodes: ArrayLike<Node>): HTMLElement {
|
|
55
|
-
const nodesArray = Array.from(nodes);
|
|
56
|
-
const doc = (nodesArray[0] && nodesArray[0].ownerDocument) || document;
|
|
57
|
-
const container = doc.createElement('div');
|
|
58
|
-
for (let i = 0; i < nodesArray.length; i++) {
|
|
59
|
-
container.appendChild(cleanNode(nodesArray[i]));
|
|
60
|
-
}
|
|
61
|
-
return container;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function parseHtmlFragment(html: string, documentContext?: Document): Node[] {
|
|
65
|
-
const doc = documentContext || document;
|
|
66
|
-
const div = doc.createElement('div');
|
|
67
|
-
div.innerHTML = html;
|
|
68
|
-
return Array.from(div.childNodes);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function domNodeIsAttachedToDocument(node: Node): boolean {
|
|
72
|
-
let current: Node | null = node;
|
|
73
|
-
const root = node.ownerDocument?.documentElement;
|
|
74
|
-
if (!root) return false;
|
|
75
|
-
while (current) {
|
|
76
|
-
if (current === root) return true;
|
|
77
|
-
current = current.parentNode;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function anyDomNodeIsAttachedToDocument(nodes: Node[]): boolean {
|
|
83
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
84
|
-
if (domNodeIsAttachedToDocument(nodes[i])) return true;
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
1
|
+
import { cleanNode, removeNode } from './domNodeDisposal.js';
|
|
2
|
+
|
|
3
|
+
export function cloneNodes(nodesArray: Node[], shouldCleanNodes?: boolean): Node[] {
|
|
4
|
+
const result: Node[] = [];
|
|
5
|
+
for (let i = 0; i < nodesArray.length; i++) {
|
|
6
|
+
const cloned = nodesArray[i].cloneNode(true);
|
|
7
|
+
result.push(shouldCleanNodes ? cleanNode(cloned) : cloned);
|
|
8
|
+
}
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function fixUpContinuousNodeArray(continuousNodeArray: Node[], parentNode: Node): Node[] {
|
|
13
|
+
if (continuousNodeArray.length) {
|
|
14
|
+
parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;
|
|
15
|
+
|
|
16
|
+
// Rule [A]: Strip detached leading nodes
|
|
17
|
+
while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
|
|
18
|
+
continuousNodeArray.splice(0, 1);
|
|
19
|
+
|
|
20
|
+
// Rule [B]: Strip detached trailing nodes
|
|
21
|
+
while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)
|
|
22
|
+
continuousNodeArray.length--;
|
|
23
|
+
|
|
24
|
+
// Rule [C]: Fill in to maintain continuity
|
|
25
|
+
if (continuousNodeArray.length > 1) {
|
|
26
|
+
const first = continuousNodeArray[0];
|
|
27
|
+
const last = continuousNodeArray[continuousNodeArray.length - 1];
|
|
28
|
+
continuousNodeArray.length = 0;
|
|
29
|
+
let current: Node | null = first;
|
|
30
|
+
while (current !== last) {
|
|
31
|
+
continuousNodeArray.push(current!);
|
|
32
|
+
current = current!.nextSibling;
|
|
33
|
+
}
|
|
34
|
+
continuousNodeArray.push(last);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return continuousNodeArray;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function replaceDomNodes(nodeToReplaceOrNodeArray: Node | Node[], newNodesArray: Node[]): void {
|
|
41
|
+
const nodesToReplace = 'nodeType' in nodeToReplaceOrNodeArray
|
|
42
|
+
? [nodeToReplaceOrNodeArray as Node]
|
|
43
|
+
: nodeToReplaceOrNodeArray as Node[];
|
|
44
|
+
if (nodesToReplace.length > 0) {
|
|
45
|
+
const insertionPoint = nodesToReplace[0];
|
|
46
|
+
const parent = insertionPoint.parentNode!;
|
|
47
|
+
for (let i = 0; i < newNodesArray.length; i++)
|
|
48
|
+
parent.insertBefore(newNodesArray[i], insertionPoint);
|
|
49
|
+
for (let i = 0; i < nodesToReplace.length; i++)
|
|
50
|
+
removeNode(nodesToReplace[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function moveCleanedNodesToContainerElement(nodes: ArrayLike<Node>): HTMLElement {
|
|
55
|
+
const nodesArray = Array.from(nodes);
|
|
56
|
+
const doc = (nodesArray[0] && nodesArray[0].ownerDocument) || document;
|
|
57
|
+
const container = doc.createElement('div');
|
|
58
|
+
for (let i = 0; i < nodesArray.length; i++) {
|
|
59
|
+
container.appendChild(cleanNode(nodesArray[i]));
|
|
60
|
+
}
|
|
61
|
+
return container;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parseHtmlFragment(html: string, documentContext?: Document): Node[] {
|
|
65
|
+
const doc = documentContext || document;
|
|
66
|
+
const div = doc.createElement('div');
|
|
67
|
+
div.innerHTML = html;
|
|
68
|
+
return Array.from(div.childNodes);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function domNodeIsAttachedToDocument(node: Node): boolean {
|
|
72
|
+
let current: Node | null = node;
|
|
73
|
+
const root = node.ownerDocument?.documentElement;
|
|
74
|
+
if (!root) return false;
|
|
75
|
+
while (current) {
|
|
76
|
+
if (current === root) return true;
|
|
77
|
+
current = current.parentNode;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function anyDomNodeIsAttachedToDocument(nodes: Node[]): boolean {
|
|
83
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
84
|
+
if (domNodeIsAttachedToDocument(nodes[i])) return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|