native-document 1.0.17-1.4 → 1.0.17-1.5
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/package.json +1 -1
- package/src/core/data/ObservableItem.js +19 -9
- package/src/core/elements/anchor/anchor.js +4 -3
- package/src/core/elements/anchor/one-child-anchor-overwriting.js +4 -4
- package/src/core/elements/control/for-each-array-cache.js +59 -0
- package/src/core/elements/control/for-each-array.js +2 -1
- package/src/core/wrappers/AttributesWrapper.js +7 -7
- package/src/core/wrappers/ElementCreator.js +14 -9
- package/src/core/wrappers/HtmlElementWrapper.js +9 -4
- package/src/core/wrappers/NDElement.js +13 -6
- package/src/core/wrappers/NdPrototype.js +1 -1
- package/src/core/wrappers/constants.js +12 -12
- package/src/core/wrappers/prototypes/nd-element-extensions.js +56 -17
- package/src/ui/components/accordion/AccordionItemRender.js +6 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-document",
|
|
3
|
-
"version": "1.0.171.
|
|
3
|
+
"version": "1.0.171.5",
|
|
4
4
|
"description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
|
|
5
5
|
"author": "AfroCodeur <https://github.com/afrocodeur>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -160,6 +160,7 @@ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations)
|
|
|
160
160
|
this.triggerFirstListener(operations);
|
|
161
161
|
};
|
|
162
162
|
|
|
163
|
+
|
|
163
164
|
/**
|
|
164
165
|
* Selects and assigns the optimal trigger strategy based on the current
|
|
165
166
|
* combination of listeners and watchers (internal).
|
|
@@ -167,31 +168,40 @@ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations)
|
|
|
167
168
|
*
|
|
168
169
|
* @internal
|
|
169
170
|
*/
|
|
170
|
-
ObservableItem.prototype
|
|
171
|
+
ObservableItem.prototype.$runAssocTrigger = function() {
|
|
171
172
|
this.$firstListener = null;
|
|
172
173
|
if(this.$watchers?.size && this.$listeners?.length) {
|
|
173
|
-
this.$
|
|
174
|
-
this.trigger = this.$firstListener.length === 0 ? this.$firstListener : this.triggerFirstListener;
|
|
175
|
-
this.trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
174
|
+
this.$trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
176
175
|
return;
|
|
177
176
|
}
|
|
178
177
|
if(this.$listeners?.length) {
|
|
179
178
|
if(this.$listeners.length === 1) {
|
|
180
179
|
this.$firstListener = this.$listeners[0];
|
|
181
|
-
this
|
|
180
|
+
this.$trigger = this.$firstListener.length === 0 ? this.$firstListener : this.triggerFirstListener;
|
|
182
181
|
}
|
|
183
182
|
else {
|
|
184
|
-
this
|
|
183
|
+
this.$trigger = this.triggerListeners;
|
|
185
184
|
}
|
|
186
185
|
return;
|
|
187
186
|
}
|
|
188
187
|
if(this.$watchers?.size) {
|
|
189
|
-
this
|
|
188
|
+
this.$trigger = this.triggerWatchers;
|
|
190
189
|
return;
|
|
191
190
|
}
|
|
192
|
-
this
|
|
191
|
+
this.$trigger = noneTrigger;
|
|
192
|
+
};
|
|
193
|
+
ObservableItem.prototype.assocTrigger = function() {
|
|
194
|
+
this.$trigger = null;
|
|
193
195
|
};
|
|
194
|
-
ObservableItem.prototype
|
|
196
|
+
Object.defineProperty(ObservableItem.prototype, 'trigger', {
|
|
197
|
+
value: function (operations) {
|
|
198
|
+
if(!this.$trigger) {
|
|
199
|
+
this.$runAssocTrigger();
|
|
200
|
+
}
|
|
201
|
+
return this.$trigger(operations);
|
|
202
|
+
},
|
|
203
|
+
configurable: false,
|
|
204
|
+
});
|
|
195
205
|
|
|
196
206
|
|
|
197
207
|
const $setOperation = { action: 'set' };
|
|
@@ -2,6 +2,7 @@ import Validator from '../../utils/validator';
|
|
|
2
2
|
import {ElementCreator} from '../../wrappers/ElementCreator';
|
|
3
3
|
import AnchorWithSentinel from './anchor-with-sentinel';
|
|
4
4
|
import oneChildAnchorOverwriting from './one-child-anchor-overwriting';
|
|
5
|
+
import DebugManager from '../../utils/debug-manager';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Creates an anchor fragment — a managed DocumentFragment delimited by comment sentinels.
|
|
@@ -34,7 +35,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
34
35
|
? () => true: (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
|
|
35
36
|
|
|
36
37
|
const insertBefore = (parent, child, target) => {
|
|
37
|
-
const childElement =
|
|
38
|
+
const childElement = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
38
39
|
insertBeforeRaw(parent, childElement, target);
|
|
39
40
|
};
|
|
40
41
|
|
|
@@ -84,7 +85,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
84
85
|
anchorFragment.appendRaw = anchorFragment.appendChildRaw;
|
|
85
86
|
|
|
86
87
|
anchorFragment.insertAtStart = function(child) {
|
|
87
|
-
child =
|
|
88
|
+
child = child.__$isNativeNode? child : ElementCreator.getChild(child);
|
|
88
89
|
anchorFragment.insertAtStartRaw(child);
|
|
89
90
|
};
|
|
90
91
|
|
|
@@ -141,7 +142,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
141
142
|
anchorFragment.delete = anchorFragment.removeWithAnchors;
|
|
142
143
|
|
|
143
144
|
anchorFragment.replaceContent = function(child) {
|
|
144
|
-
const childElement =
|
|
145
|
+
const childElement = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
145
146
|
anchorFragment.replaceContentRaw(childElement);
|
|
146
147
|
};
|
|
147
148
|
|
|
@@ -10,7 +10,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
10
10
|
anchor.getParent = () => parent;
|
|
11
11
|
|
|
12
12
|
anchor.appendChild = (child) => {
|
|
13
|
-
child =
|
|
13
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
14
14
|
parent.appendChild(child);
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
19
19
|
anchor.appendRaw = anchor.appendChildRaw;
|
|
20
20
|
|
|
21
21
|
anchor.insertAtStart = (child) => {
|
|
22
|
-
child =
|
|
22
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
23
23
|
parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
|
|
24
24
|
};
|
|
25
25
|
anchor.insertAtStartRaw = (child) => {
|
|
@@ -33,7 +33,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
anchor.replaceContent = function(content) {
|
|
36
|
-
const child =
|
|
36
|
+
const child = (content && content.__$isNativeNode) ? content : ElementCreator.getChild(content);
|
|
37
37
|
parent.replaceChildren(child);
|
|
38
38
|
};
|
|
39
39
|
|
|
@@ -43,7 +43,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
43
43
|
anchor.setContent = anchor.replaceContent;
|
|
44
44
|
|
|
45
45
|
anchor.insertBefore = (child, anchor) => {
|
|
46
|
-
child =
|
|
46
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
47
47
|
parent.insertBefore(child, anchor);
|
|
48
48
|
};
|
|
49
49
|
anchor.insertBeforeRaw = (child, anchor) => {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export default function ForEachArrayCache(isIndexesRequired) {
|
|
4
|
+
this.$nodes = new Map();
|
|
5
|
+
this.$indexes = isIndexesRequired ? new Map() : null;
|
|
6
|
+
|
|
7
|
+
this.has = this.$nodes.has.bind(this.$nodes);
|
|
8
|
+
|
|
9
|
+
this.keys = function() {
|
|
10
|
+
return Array.from(this.$nodes.keys());
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
if(isIndexesRequired) {
|
|
14
|
+
this.delete = function(item) {
|
|
15
|
+
this.$nodes.get(item)?.nd.destroy();
|
|
16
|
+
this.$nodes.delete(item);
|
|
17
|
+
this.$indexes.delete(item);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
this.set = function(item, child, index) {
|
|
21
|
+
this.$nodes.set(item, child);
|
|
22
|
+
this.$indexes.set(item, index);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
this.clear = function() {
|
|
26
|
+
for(const [_, node] in this.$nodes.entries()) {
|
|
27
|
+
node.nd.destroy();
|
|
28
|
+
}
|
|
29
|
+
this.$nodes.clear();
|
|
30
|
+
this.$indexes.clear();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
this.get = function(item) {
|
|
34
|
+
return {
|
|
35
|
+
child: this.$nodes.get(item),
|
|
36
|
+
indexObserver: this.$indexes.get(item),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
|
|
41
|
+
this.delete = (item) => {
|
|
42
|
+
this.$nodes.get(item)?.nd.destroy();
|
|
43
|
+
this.$nodes.delete(item);
|
|
44
|
+
};
|
|
45
|
+
this.set = this.$nodes.set.bind(this.$nodes);
|
|
46
|
+
this.clear = function() {
|
|
47
|
+
for(const [_, node] in this.$nodes.entries()) {
|
|
48
|
+
node.nd.destroy();
|
|
49
|
+
}
|
|
50
|
+
this.$nodes.clear();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.get = function(item) {
|
|
54
|
+
return { child: this.$nodes.get(item), indexObserver: null };
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Anchor from '../anchor/anchor';
|
|
2
2
|
import { ElementCreator } from '../../wrappers/ElementCreator';
|
|
3
3
|
import NativeDocumentError from '../../errors/NativeDocumentError';
|
|
4
|
+
import ForEachArrayCache from './for-each-array-cache';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
const CREATE_AND_CACHE_ACTIONS = new Set(['clear', 'push', 'unshift', 'replace']);
|
|
@@ -30,9 +31,9 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
30
31
|
const element = Anchor('ForEach Array', configs.isParentUniqueChild);
|
|
31
32
|
const blockEnd = element.endElement();
|
|
32
33
|
|
|
33
|
-
const cache = new Map();
|
|
34
34
|
let lastNumberOfItems = 0;
|
|
35
35
|
const isIndexRequired = callback.length >= 2;
|
|
36
|
+
const cache = new ForEachArrayCache(isIndexRequired);
|
|
36
37
|
|
|
37
38
|
const clear = (items) => {
|
|
38
39
|
element.removeChildren();
|
|
@@ -99,7 +99,7 @@ export const bindBooleanAttribute = (element, attributeName, value) => {
|
|
|
99
99
|
const isObservable = value.__$Observable;
|
|
100
100
|
const defaultValue = isObservable? value.val() : value;
|
|
101
101
|
|
|
102
|
-
const attributeRealName = BOOL_ATTRIBUTES_NAME[attributeName];
|
|
102
|
+
const attributeRealName = BOOL_ATTRIBUTES_NAME[attributeName] || attributeName;
|
|
103
103
|
|
|
104
104
|
if(typeof defaultValue === 'boolean') {
|
|
105
105
|
element[attributeRealName] = defaultValue;
|
|
@@ -145,29 +145,29 @@ export const bindAttributeWithObservable = (element, attributeName, value) => {
|
|
|
145
145
|
* @param {HTMLElement} element
|
|
146
146
|
* @param {Object} attributes
|
|
147
147
|
*/
|
|
148
|
-
const AttributesWrapper = (element, attributes) => {
|
|
148
|
+
const AttributesWrapper = (element, attributes = {}) => {
|
|
149
149
|
|
|
150
150
|
if(process.env.NODE_ENV === 'development') {
|
|
151
151
|
Validator.validateAttributes(attributes);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
for(const
|
|
155
|
-
const value = attributes[
|
|
154
|
+
for(const attributeName in attributes) {
|
|
155
|
+
const value = attributes[attributeName];
|
|
156
156
|
if(value == null) {
|
|
157
157
|
continue;
|
|
158
158
|
}
|
|
159
159
|
const type = typeof value;
|
|
160
160
|
if(type === 'string' || type === 'number') {
|
|
161
|
-
element.setAttribute(
|
|
161
|
+
element.setAttribute(attributeName, value);
|
|
162
162
|
continue;
|
|
163
163
|
}
|
|
164
|
-
const attributeName = originalAttributeName.toLowerCase();
|
|
164
|
+
// const attributeName = originalAttributeName.toLowerCase();
|
|
165
165
|
if(value.__$Observable) {
|
|
166
166
|
if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
|
|
167
167
|
bindBooleanAttribute(element, attributeName, value);
|
|
168
168
|
continue;
|
|
169
169
|
}
|
|
170
|
-
bindAttributeWithObservable(element,
|
|
170
|
+
bindAttributeWithObservable(element, attributeName, value);
|
|
171
171
|
continue;
|
|
172
172
|
}
|
|
173
173
|
if(type === 'object') {
|
|
@@ -7,7 +7,7 @@ export const ElementCreator = {
|
|
|
7
7
|
createTextNode() {
|
|
8
8
|
if(!$textNodeCache) {
|
|
9
9
|
$textNodeCache = document.createTextNode('');
|
|
10
|
-
ElementCreator.createTextNode =
|
|
10
|
+
ElementCreator.createTextNode = $textNodeCache.cloneNode.bind($textNodeCache);
|
|
11
11
|
}
|
|
12
12
|
return $textNodeCache.cloneNode();
|
|
13
13
|
},
|
|
@@ -57,6 +57,11 @@ export const ElementCreator = {
|
|
|
57
57
|
parent && parent.appendChild(text);
|
|
58
58
|
return text;
|
|
59
59
|
},
|
|
60
|
+
createStaticTextNodeWithoutParent: (value) => {
|
|
61
|
+
const text = ElementCreator.createTextNode();
|
|
62
|
+
text.nodeValue = value;
|
|
63
|
+
return text;
|
|
64
|
+
},
|
|
60
65
|
/**
|
|
61
66
|
*
|
|
62
67
|
* @param {string} name
|
|
@@ -80,29 +85,29 @@ export const ElementCreator = {
|
|
|
80
85
|
* @param {HTMLElement|DocumentFragment} parent
|
|
81
86
|
*/
|
|
82
87
|
processChildren: (children, parent) => {
|
|
83
|
-
if(children === null) return;
|
|
84
88
|
if(process.env.NODE_ENV === 'development') {
|
|
85
89
|
PluginsManager.emit('BeforeProcessChildren', parent);
|
|
86
90
|
}
|
|
87
91
|
const child = ElementCreator.getChild(children);
|
|
88
|
-
|
|
89
|
-
parent.appendChild(child);
|
|
90
|
-
}
|
|
92
|
+
parent.appendChild(child);
|
|
91
93
|
if(process.env.NODE_ENV === 'development') {
|
|
92
94
|
PluginsManager.emit('AfterProcessChildren', parent);
|
|
93
95
|
}
|
|
94
96
|
},
|
|
95
97
|
async safeRemove(element) {
|
|
96
98
|
await element.remove();
|
|
97
|
-
|
|
98
99
|
},
|
|
99
100
|
getChild: (child) => {
|
|
100
|
-
if (child == null)
|
|
101
|
+
if (child == null) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
101
104
|
|
|
102
105
|
child = child.toNdElement();
|
|
103
|
-
if (child
|
|
106
|
+
if (child && child.__$isNativeNode) {
|
|
107
|
+
return child;
|
|
108
|
+
}
|
|
104
109
|
|
|
105
|
-
while (child != null && !
|
|
110
|
+
while (child != null && !child.__$isNativeNode) {
|
|
106
111
|
child = child.toNdElement?.();
|
|
107
112
|
}
|
|
108
113
|
|
|
@@ -36,10 +36,11 @@ export const createTextNode = (value) => {
|
|
|
36
36
|
* @returns {HTMLElement} The configured element
|
|
37
37
|
*/
|
|
38
38
|
export const createVoidHtmlElement = (element, attributes) => {
|
|
39
|
-
ElementCreator.processAttributes(element, attributes);
|
|
39
|
+
attributes && ElementCreator.processAttributes(element, attributes);
|
|
40
40
|
return element;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
|
|
43
44
|
const OBJECT_PROTOTYPE = Object.prototype;
|
|
44
45
|
/**
|
|
45
46
|
* Applies attributes and children to an existing HTMLElement.
|
|
@@ -53,13 +54,17 @@ const OBJECT_PROTOTYPE = Object.prototype;
|
|
|
53
54
|
*/
|
|
54
55
|
export const createHtmlElement = (element, _attributes, _children = null) => {
|
|
55
56
|
let attributes = _attributes, children = _children;
|
|
56
|
-
if(
|
|
57
|
+
if(_attributes.__$isValidNdChild) { // If attributes is a ValidChild
|
|
57
58
|
attributes = _children;
|
|
58
59
|
children = _attributes;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
if(attributes) {
|
|
63
|
+
ElementCreator.processAttributes(element, attributes);
|
|
64
|
+
}
|
|
65
|
+
if(children) {
|
|
66
|
+
ElementCreator.processChildren(children, element);
|
|
67
|
+
}
|
|
63
68
|
return element;
|
|
64
69
|
};
|
|
65
70
|
|
|
@@ -195,19 +195,26 @@ NDElement.prototype.destroy = function() {
|
|
|
195
195
|
observer.disconnect();
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
const
|
|
198
|
+
const treewalk = document.createTreeWalker(this.$element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
|
|
199
|
+
const nodes = [];
|
|
200
|
+
while(treewalk.nextNode()) {
|
|
201
|
+
nodes.push(treewalk.currentNode);
|
|
202
|
+
}
|
|
199
203
|
|
|
200
|
-
for(let i = 0, length =
|
|
201
|
-
const child =
|
|
204
|
+
for(let i = 0, length = nodes.length; i < length; i++) {
|
|
205
|
+
const child = nodes[i];
|
|
202
206
|
child.remove();
|
|
203
|
-
child.__$controller
|
|
204
|
-
|
|
205
|
-
|
|
207
|
+
if(child.__$controller) {
|
|
208
|
+
child.__$controller.abort();
|
|
209
|
+
child.__$controller = null;
|
|
210
|
+
$lifeCycleObservers.delete(child);
|
|
211
|
+
}
|
|
206
212
|
}
|
|
207
213
|
|
|
208
214
|
this.$element.__$controller?.abort();
|
|
209
215
|
this.$element.__$controller = null;
|
|
210
216
|
$lifeCycleObservers.delete(this.$element);
|
|
217
|
+
this.$element.remove();
|
|
211
218
|
this.$element = null;
|
|
212
219
|
};
|
|
213
220
|
|
|
@@ -74,7 +74,7 @@ EVENTS_WITH_PREVENT.forEach(eventSourceName => {
|
|
|
74
74
|
*/
|
|
75
75
|
NDElement.prototype.$getSignal = function() {
|
|
76
76
|
if(!this.$element.__$controller) {
|
|
77
|
-
this.$element.__$controller = new AbortController();
|
|
77
|
+
// this.$element.__$controller = new AbortController();
|
|
78
78
|
}
|
|
79
79
|
return this.$element.__$controller.signal;
|
|
80
80
|
};
|
|
@@ -3,19 +3,19 @@ export const BOOLEAN_ATTRIBUTES = new Set([
|
|
|
3
3
|
'checked',
|
|
4
4
|
'selected',
|
|
5
5
|
'disabled',
|
|
6
|
-
'readonly',
|
|
6
|
+
'readonly', 'readOnly',
|
|
7
7
|
'required',
|
|
8
|
-
'autofocus',
|
|
8
|
+
'autofocus', 'autoFocus',
|
|
9
9
|
'multiple',
|
|
10
|
-
'autocomplete',
|
|
10
|
+
'autocomplete', 'autoComplete',
|
|
11
11
|
'hidden',
|
|
12
|
-
'contenteditable',
|
|
13
|
-
'spellcheck',
|
|
12
|
+
'contenteditable', 'contentEditable',
|
|
13
|
+
'spellcheck', 'spellCheck',
|
|
14
14
|
'translate',
|
|
15
15
|
'draggable',
|
|
16
16
|
'async',
|
|
17
17
|
'defer',
|
|
18
|
-
'autoplay',
|
|
18
|
+
'autoplay', 'autoPlay',
|
|
19
19
|
'controls',
|
|
20
20
|
'loop',
|
|
21
21
|
'muted',
|
|
@@ -23,13 +23,13 @@ export const BOOLEAN_ATTRIBUTES = new Set([
|
|
|
23
23
|
'reversed',
|
|
24
24
|
'open',
|
|
25
25
|
'default',
|
|
26
|
-
'formnovalidate',
|
|
27
|
-
'novalidate',
|
|
26
|
+
'formnovalidate', 'formNoValidate',
|
|
27
|
+
'novalidate', 'noValidate',
|
|
28
28
|
'scoped',
|
|
29
|
-
'itemscope',
|
|
30
|
-
'allowfullscreen',
|
|
31
|
-
'allowpaymentrequest',
|
|
32
|
-
'playsinline',
|
|
29
|
+
'itemscope', 'itemScope',
|
|
30
|
+
'allowfullscreen', 'allowFullscreen',
|
|
31
|
+
'allowpaymentrequest', 'allowPaymentRequest',
|
|
32
|
+
'playsinline', 'playsInline',
|
|
33
33
|
]);
|
|
34
34
|
|
|
35
35
|
export const BOOL_ATTRIBUTES_NAME = {
|
|
@@ -20,9 +20,62 @@ const defineToNdElement = (target, fn) => {
|
|
|
20
20
|
});
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Marks a prototype as a valid NativeDocument child node.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} target - The prototype to mark
|
|
27
|
+
*/
|
|
28
|
+
const defineValidNdChild = (target) => {
|
|
29
|
+
Object.defineProperty(target, '__$isValidNdChild', {
|
|
30
|
+
value: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
enumerable: false,
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Marks a prototype as a native DOM node.
|
|
39
|
+
* Faster alternative to instanceof Node for hot paths.
|
|
40
|
+
*
|
|
41
|
+
* @param {object} target - The prototype to mark
|
|
42
|
+
*/
|
|
43
|
+
const defineNativeNode = (target) => {
|
|
44
|
+
Object.defineProperty(target, '__$isNativeNode', {
|
|
45
|
+
value: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
enumerable: false,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
23
52
|
NDElement.$getChild = ElementCreator.getChild;
|
|
24
53
|
|
|
25
|
-
// --
|
|
54
|
+
// -- __$isNativeNode ----------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
defineNativeNode(Element.prototype);
|
|
57
|
+
defineNativeNode(Text.prototype);
|
|
58
|
+
defineNativeNode(Comment.prototype);
|
|
59
|
+
defineNativeNode(Document.prototype);
|
|
60
|
+
defineNativeNode(DocumentFragment.prototype);
|
|
61
|
+
|
|
62
|
+
// -- __$isValidNdChild --------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
defineValidNdChild(String.prototype);
|
|
65
|
+
defineValidNdChild(Number.prototype);
|
|
66
|
+
defineValidNdChild(Boolean.prototype);
|
|
67
|
+
defineValidNdChild(Array.prototype);
|
|
68
|
+
defineValidNdChild(Element.prototype);
|
|
69
|
+
defineValidNdChild(Text.prototype);
|
|
70
|
+
defineValidNdChild(Comment.prototype);
|
|
71
|
+
defineValidNdChild(DocumentFragment.prototype);
|
|
72
|
+
defineValidNdChild(NDElement.prototype);
|
|
73
|
+
defineValidNdChild(ObservableItem.prototype);
|
|
74
|
+
defineValidNdChild(ObservableChecker.prototype);
|
|
75
|
+
defineValidNdChild(TemplateBinding.prototype);
|
|
76
|
+
defineValidNdChild(Function.prototype);
|
|
77
|
+
|
|
78
|
+
// -- toNdElement --------------------------------------------------------------
|
|
26
79
|
|
|
27
80
|
/**
|
|
28
81
|
* Converts a string to a static text node.
|
|
@@ -30,22 +83,18 @@ NDElement.$getChild = ElementCreator.getChild;
|
|
|
30
83
|
* @returns {Text}
|
|
31
84
|
*/
|
|
32
85
|
defineToNdElement(String.prototype, function () {
|
|
33
|
-
return ElementCreator.
|
|
86
|
+
return ElementCreator.createStaticTextNodeWithoutParent(this);
|
|
34
87
|
});
|
|
35
88
|
|
|
36
|
-
// -- Number -------------------------------------------------------------------
|
|
37
|
-
|
|
38
89
|
/**
|
|
39
90
|
* Converts a number to a static text node.
|
|
40
91
|
*
|
|
41
92
|
* @returns {Text}
|
|
42
93
|
*/
|
|
43
94
|
defineToNdElement(Number.prototype, function () {
|
|
44
|
-
return ElementCreator.
|
|
95
|
+
return ElementCreator.createStaticTextNodeWithoutParent(this.toString());
|
|
45
96
|
});
|
|
46
97
|
|
|
47
|
-
// -- DOM nodes (identity) -----------------------------------------------------
|
|
48
|
-
|
|
49
98
|
/**
|
|
50
99
|
* Returns the DOM node itself (identity).
|
|
51
100
|
*
|
|
@@ -57,8 +106,6 @@ defineToNdElement(Comment.prototype, function () { return this; });
|
|
|
57
106
|
defineToNdElement(Document.prototype, function () { return this; });
|
|
58
107
|
defineToNdElement(DocumentFragment.prototype, function () { return this; });
|
|
59
108
|
|
|
60
|
-
// -- ObservableItem -----------------------------------------------------------
|
|
61
|
-
|
|
62
109
|
/**
|
|
63
110
|
* Converts an ObservableItem to a reactive text node that updates when the value changes.
|
|
64
111
|
*
|
|
@@ -70,8 +117,6 @@ defineToNdElement(ObservableItem.prototype, function () {
|
|
|
70
117
|
|
|
71
118
|
ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
|
|
72
119
|
|
|
73
|
-
// -- NDElement ----------------------------------------------------------------
|
|
74
|
-
|
|
75
120
|
/**
|
|
76
121
|
* Returns the underlying HTMLElement of this NDElement.
|
|
77
122
|
*
|
|
@@ -81,8 +126,6 @@ defineToNdElement(NDElement.prototype, function () {
|
|
|
81
126
|
return this.$element;
|
|
82
127
|
});
|
|
83
128
|
|
|
84
|
-
// -- Array --------------------------------------------------------------------
|
|
85
|
-
|
|
86
129
|
/**
|
|
87
130
|
* Converts the array to a DocumentFragment containing all child elements.
|
|
88
131
|
*
|
|
@@ -98,8 +141,6 @@ defineToNdElement(Array.prototype, function () {
|
|
|
98
141
|
return fragment;
|
|
99
142
|
});
|
|
100
143
|
|
|
101
|
-
// -- Function -----------------------------------------------------------------
|
|
102
|
-
|
|
103
144
|
/**
|
|
104
145
|
* Calls the function and converts its return value to a DOM node.
|
|
105
146
|
*
|
|
@@ -113,8 +154,6 @@ defineToNdElement(Function.prototype, function () {
|
|
|
113
154
|
return ElementCreator.getChild(child());
|
|
114
155
|
});
|
|
115
156
|
|
|
116
|
-
// -- TemplateBinding ----------------------------------------------------------
|
|
117
|
-
|
|
118
157
|
/**
|
|
119
158
|
* Converts the TemplateBinding to a hydratable DOM node.
|
|
120
159
|
*
|
|
@@ -36,8 +36,8 @@ const buildHeader = ($desc, instance, headerId, panelId) => {
|
|
|
36
36
|
];
|
|
37
37
|
|
|
38
38
|
const header = Div({
|
|
39
|
-
class:
|
|
40
|
-
id:
|
|
39
|
+
class: 'accordion-header',
|
|
40
|
+
id: headerId,
|
|
41
41
|
// [a11y] aria-expanded reactive, aria-controls points to panel
|
|
42
42
|
'aria-expanded': $desc.expanded.transform((v) => String(v)),
|
|
43
43
|
'aria-controls': panelId,
|
|
@@ -64,12 +64,12 @@ const buildIndicator = ($desc) => {
|
|
|
64
64
|
}, '▾');
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
const buildContent = ($desc, instance) => {
|
|
67
|
+
const buildContent = ($desc, instance, headerId, panelId) => {
|
|
68
68
|
// [a11y] role=region + aria-labelledby on panel
|
|
69
69
|
const panelProps = {
|
|
70
|
-
class:
|
|
71
|
-
id:
|
|
72
|
-
role:
|
|
70
|
+
class: 'accordion-content',
|
|
71
|
+
id: panelId,
|
|
72
|
+
role: 'region',
|
|
73
73
|
'aria-labelledby': headerId,
|
|
74
74
|
};
|
|
75
75
|
|