native-document 1.0.86 → 1.0.88
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/dist/native-document.components.min.js +38 -50
- package/dist/native-document.dev.js +125 -87
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.devtools.min.js +1 -1
- package/dist/native-document.min.js +1 -1
- package/package.json +1 -1
- package/src/core/utils/validator.js +0 -1
- package/src/core/wrappers/AttributesWrapper.js +21 -41
- package/src/core/wrappers/ElementCreator.js +8 -0
- package/src/core/wrappers/TemplateCloner.js +10 -22
- package/src/router/RouterComponent.js +71 -8
|
@@ -9,26 +9,6 @@ export function toggleElementClass(element, className, shouldAdd) {
|
|
|
9
9
|
element.classes.toggle(className, shouldAdd);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function toggleElementStyle(element, styleName, newValue) {
|
|
13
|
-
element.style[styleName] = newValue;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function updateInputFromObserver(element, attributeName, newValue) {
|
|
17
|
-
if(Validator.isBoolean(newValue)) {
|
|
18
|
-
element[attributeName] = newValue;
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
element[attributeName] = newValue === element.value;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function updateObserverFromInput(element, attributeName, defaultValue, value) {
|
|
25
|
-
if(Validator.isBoolean(defaultValue)) {
|
|
26
|
-
value.set(element[attributeName]);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
value.set(element.value);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
12
|
/**
|
|
33
13
|
*
|
|
34
14
|
* @param {HTMLElement} element
|
|
@@ -37,12 +17,12 @@ export function updateObserverFromInput(element, attributeName, defaultValue, va
|
|
|
37
17
|
export function bindClassAttribute(element, data) {
|
|
38
18
|
for(let className in data) {
|
|
39
19
|
const value = data[className];
|
|
40
|
-
if(
|
|
20
|
+
if(value.__$isObservable) {
|
|
41
21
|
element.classes.toggle(className, value.val());
|
|
42
22
|
value.subscribe(toggleElementClass.bind(null, element, className));
|
|
43
23
|
continue;
|
|
44
24
|
}
|
|
45
|
-
if(
|
|
25
|
+
if(value.__$isObservableWhen) {
|
|
46
26
|
element.classes.toggle(className, value.isMath());
|
|
47
27
|
value.subscribe(toggleElementClass.bind(null, element, className));
|
|
48
28
|
continue;
|
|
@@ -64,9 +44,9 @@ export function bindClassAttribute(element, data) {
|
|
|
64
44
|
export function bindStyleAttribute(element, data) {
|
|
65
45
|
for(let styleName in data) {
|
|
66
46
|
const value = data[styleName];
|
|
67
|
-
if(
|
|
47
|
+
if(value.__$isObservable) {
|
|
68
48
|
element.style[styleName] = value.val();
|
|
69
|
-
value.subscribe(
|
|
49
|
+
value.subscribe((newValue) => element.style[styleName] = newValue);
|
|
70
50
|
continue;
|
|
71
51
|
}
|
|
72
52
|
element.style[styleName] = value;
|
|
@@ -80,18 +60,26 @@ export function bindStyleAttribute(element, data) {
|
|
|
80
60
|
* @param {boolean|number|Observable} value
|
|
81
61
|
*/
|
|
82
62
|
export function bindBooleanAttribute(element, attributeName, value) {
|
|
83
|
-
const
|
|
63
|
+
const isObservable = value.__$isObservable;
|
|
64
|
+
const defaultValue = isObservable? value.val() : value;
|
|
84
65
|
if(Validator.isBoolean(defaultValue)) {
|
|
85
66
|
element[attributeName] = defaultValue;
|
|
86
67
|
}
|
|
87
68
|
else {
|
|
88
69
|
element[attributeName] = defaultValue === element.value;
|
|
89
70
|
}
|
|
90
|
-
if(
|
|
91
|
-
if(
|
|
92
|
-
|
|
71
|
+
if(isObservable) {
|
|
72
|
+
if(attributeName === 'checked') {
|
|
73
|
+
if(typeof defaultValue === 'boolean') {
|
|
74
|
+
element.addEventListener('input', () => value.set(element[attributeName]));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
element.addEventListener('input', () => value.set(element.value));
|
|
78
|
+
}
|
|
79
|
+
value.subscribe((newValue) => element[attributeName] = newValue);
|
|
80
|
+
return;
|
|
93
81
|
}
|
|
94
|
-
value.subscribe(
|
|
82
|
+
value.subscribe((newValue) => element[attributeName] = (newValue === element.value));
|
|
95
83
|
}
|
|
96
84
|
}
|
|
97
85
|
|
|
@@ -103,19 +91,15 @@ export function bindBooleanAttribute(element, attributeName, value) {
|
|
|
103
91
|
* @param {Observable} value
|
|
104
92
|
*/
|
|
105
93
|
export function bindAttributeWithObservable(element, attributeName, value) {
|
|
106
|
-
const applyValue = (newValue) =>
|
|
107
|
-
if(attributeName === 'value') {
|
|
108
|
-
element.value = newValue;
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
element.setAttribute(attributeName, newValue);
|
|
112
|
-
};
|
|
113
|
-
applyValue(value.val());
|
|
94
|
+
const applyValue = attributeName === 'value' ? (newValue) => element.value = newValue : (newValue) => element.setAttribute(attributeName, newValue);
|
|
114
95
|
value.subscribe(applyValue);
|
|
115
96
|
|
|
116
97
|
if(attributeName === 'value') {
|
|
98
|
+
element.value = value.val();
|
|
117
99
|
element.addEventListener('input', () => value.set(element.value));
|
|
100
|
+
return;
|
|
118
101
|
}
|
|
102
|
+
element.setAttribute(attributeName, value.val());
|
|
119
103
|
}
|
|
120
104
|
|
|
121
105
|
/**
|
|
@@ -127,10 +111,6 @@ export default function AttributesWrapper(element, attributes) {
|
|
|
127
111
|
|
|
128
112
|
Validator.validateAttributes(attributes);
|
|
129
113
|
|
|
130
|
-
if(!Validator.isObject(attributes)) {
|
|
131
|
-
throw new NativeDocumentError('Attributes must be an object');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
114
|
for(let key in attributes) {
|
|
135
115
|
const attributeName = key.toLowerCase();
|
|
136
116
|
let value = attributes[attributeName];
|
|
@@ -69,6 +69,14 @@ export const ElementCreator = {
|
|
|
69
69
|
}
|
|
70
70
|
return Anchor('Fragment');
|
|
71
71
|
},
|
|
72
|
+
bindTextNode(textNode, value) {
|
|
73
|
+
if(value?.__$isObservable) {
|
|
74
|
+
value.subscribe(newValue => textNode.nodeValue = newValue);
|
|
75
|
+
textNode.nodeValue = value.val();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
textNode.nodeValue = value;
|
|
79
|
+
},
|
|
72
80
|
/**
|
|
73
81
|
*
|
|
74
82
|
* @param {*} children
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {ElementCreator} from "./ElementCreator";
|
|
2
|
-
import {createTextNode} from "./HtmlElementWrapper";
|
|
3
2
|
import TemplateBinding from "./TemplateBinding";
|
|
4
3
|
|
|
5
4
|
const cloneBindingsDataCache = new WeakMap();
|
|
@@ -65,9 +64,8 @@ const bindAttachMethods = function(node, bindDingData, data) {
|
|
|
65
64
|
|
|
66
65
|
|
|
67
66
|
const applyBindingTreePath = (root, target, data, path) => {
|
|
68
|
-
let newTarget = null;
|
|
69
67
|
if(path.fn) {
|
|
70
|
-
|
|
68
|
+
path.fn(data, target, root);
|
|
71
69
|
}
|
|
72
70
|
if(path.children) {
|
|
73
71
|
for(let i = 0, length = path.children.length; i < length; i++) {
|
|
@@ -76,7 +74,6 @@ const applyBindingTreePath = (root, target, data, path) => {
|
|
|
76
74
|
applyBindingTreePath(root, pathTargetNode, data, currentPath);
|
|
77
75
|
}
|
|
78
76
|
}
|
|
79
|
-
return newTarget;
|
|
80
77
|
};
|
|
81
78
|
|
|
82
79
|
export function TemplateCloner($fn) {
|
|
@@ -92,15 +89,10 @@ export function TemplateCloner($fn) {
|
|
|
92
89
|
const bindDingData = cloneBindingsDataCache.get(node);
|
|
93
90
|
if(node.nodeType === 3) {
|
|
94
91
|
if(bindDingData && bindDingData.value) {
|
|
95
|
-
currentPath.fn =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
targetNode.replaceWith(newNode);
|
|
101
|
-
return null;
|
|
102
|
-
};
|
|
103
|
-
return bindDingData.value(data);
|
|
92
|
+
currentPath.fn = bindDingData.value;
|
|
93
|
+
const textNode = node.cloneNode();
|
|
94
|
+
bindDingData.value(data, textNode);
|
|
95
|
+
return textNode;
|
|
104
96
|
}
|
|
105
97
|
return node.cloneNode(true);
|
|
106
98
|
}
|
|
@@ -137,11 +129,7 @@ export function TemplateCloner($fn) {
|
|
|
137
129
|
const cloneWithBindingPaths = (data) => {
|
|
138
130
|
let root = $node.cloneNode(true);
|
|
139
131
|
|
|
140
|
-
|
|
141
|
-
if(newRoot) {
|
|
142
|
-
root = newRoot;
|
|
143
|
-
}
|
|
144
|
-
|
|
132
|
+
applyBindingTreePath(root, root, data, $bindingTreePath);
|
|
145
133
|
return root;
|
|
146
134
|
};
|
|
147
135
|
|
|
@@ -176,13 +164,13 @@ export function TemplateCloner($fn) {
|
|
|
176
164
|
}
|
|
177
165
|
this.value = (callbackOrProperty) => {
|
|
178
166
|
if(typeof callbackOrProperty !== 'function') {
|
|
179
|
-
return createBinding(function(data) {
|
|
167
|
+
return createBinding(function(data, textNode) {
|
|
180
168
|
const firstArgument = data[0];
|
|
181
|
-
|
|
169
|
+
ElementCreator.bindTextNode(textNode, firstArgument[callbackOrProperty]);
|
|
182
170
|
}, 'value');
|
|
183
171
|
}
|
|
184
|
-
return createBinding(function(data) {
|
|
185
|
-
|
|
172
|
+
return createBinding(function(data, textNode) {
|
|
173
|
+
ElementCreator.bindTextNode(textNode, callbackOrProperty(...data));
|
|
186
174
|
}, 'value');
|
|
187
175
|
};
|
|
188
176
|
this.attr = (fn) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Validator from "../core/utils/validator";
|
|
2
|
+
import {Anchor} from "../../elements";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
*
|
|
@@ -8,22 +9,84 @@ import Validator from "../core/utils/validator";
|
|
|
8
9
|
export function RouterComponent(router, container) {
|
|
9
10
|
|
|
10
11
|
const $cache = new Map();
|
|
12
|
+
const $layoutCache = new WeakMap();
|
|
13
|
+
const $routeInstanceAnchors = new WeakMap();
|
|
14
|
+
let $currentLayout = null;
|
|
15
|
+
|
|
11
16
|
let $lastNodeInserted = null;
|
|
12
17
|
|
|
13
|
-
const
|
|
14
|
-
|
|
18
|
+
const getNodeAnchorForLayout = (node, path) => {
|
|
19
|
+
const existingAnchor = $routeInstanceAnchors.get(node);
|
|
20
|
+
if(existingAnchor) {
|
|
21
|
+
return existingAnchor;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let anchor = node;
|
|
25
|
+
if(!Validator.isAnchor(node)) {
|
|
26
|
+
anchor = Anchor(path);
|
|
27
|
+
anchor.appendChild(node);
|
|
28
|
+
}
|
|
29
|
+
$routeInstanceAnchors.set(node, anchor);
|
|
30
|
+
return anchor;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const removeLastNodeInserted = () => {
|
|
34
|
+
if(Validator.isAnchor($lastNodeInserted)) {
|
|
35
|
+
$lastNodeInserted.remove();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const cleanContainer = () => {
|
|
39
|
+
container.nodeValue = '';
|
|
40
|
+
removeLastNodeInserted();
|
|
41
|
+
|
|
42
|
+
if($currentLayout) {
|
|
43
|
+
$currentLayout.remove();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getNodeToInsert = (node) => {
|
|
15
48
|
let nodeToInsert = node;
|
|
16
|
-
const layout = route.layout();
|
|
17
49
|
if(Validator.isNDElement(node)) {
|
|
18
50
|
nodeToInsert = node.node();
|
|
19
51
|
}
|
|
20
|
-
|
|
21
|
-
|
|
52
|
+
return nodeToInsert;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const updateContainerByLayout = (layout, node, route, path) => {
|
|
56
|
+
let nodeToInsert = getNodeToInsert(node);
|
|
57
|
+
|
|
58
|
+
const cachedLayout = $layoutCache.get(nodeToInsert);
|
|
59
|
+
if(cachedLayout) {
|
|
60
|
+
if(cachedLayout === $currentLayout) {
|
|
61
|
+
const layoutAnchor = getNodeAnchorForLayout(nodeToInsert, path);
|
|
62
|
+
removeLastNodeInserted();
|
|
63
|
+
layoutAnchor.replaceContent(nodeToInsert);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
cleanContainer();
|
|
67
|
+
$currentLayout = cachedLayout;
|
|
68
|
+
const layoutAnchor = getNodeAnchorForLayout(nodeToInsert, path);
|
|
69
|
+
layoutAnchor.replaceContent(nodeToInsert);
|
|
70
|
+
container.appendChild($currentLayout);
|
|
22
71
|
return;
|
|
23
72
|
}
|
|
24
|
-
|
|
25
|
-
|
|
73
|
+
cleanContainer();
|
|
74
|
+
const anchor = getNodeAnchorForLayout(nodeToInsert, path);
|
|
75
|
+
|
|
76
|
+
$currentLayout = layout(anchor);
|
|
77
|
+
$layoutCache.set(nodeToInsert, $currentLayout);
|
|
78
|
+
container.appendChild($currentLayout);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const updateContainer = function(node, route, path) {
|
|
82
|
+
const layout = route.layout();
|
|
83
|
+
if(layout) {
|
|
84
|
+
updateContainerByLayout(layout, node, route, path);
|
|
85
|
+
return;
|
|
26
86
|
}
|
|
87
|
+
let nodeToInsert = getNodeToInsert(node);
|
|
88
|
+
|
|
89
|
+
cleanContainer();
|
|
27
90
|
container.appendChild(nodeToInsert);
|
|
28
91
|
$lastNodeInserted = node;
|
|
29
92
|
};
|
|
@@ -41,7 +104,7 @@ export function RouterComponent(router, container) {
|
|
|
41
104
|
const Component = route.component();
|
|
42
105
|
const node = Component({ params, query });
|
|
43
106
|
$cache.set(path, node);
|
|
44
|
-
updateContainer(node, route);
|
|
107
|
+
updateContainer(node, route, path);
|
|
45
108
|
};
|
|
46
109
|
|
|
47
110
|
router.subscribe(handleCurrentRouterState);
|