native-document 1.0.87 → 1.0.89
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 +89 -95
- package/dist/native-document.dev.js +111 -130
- 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/data/ObservableChecker.js +4 -4
- package/src/core/data/ObservableItem.js +19 -14
- package/src/core/data/ObservableWhen.js +2 -2
- package/src/core/utils/callback-handler.js +21 -0
- package/src/core/wrappers/AttributesWrapper.js +49 -59
- package/src/core/wrappers/ElementCreator.js +8 -0
- package/src/core/wrappers/TemplateCloner.js +10 -22
- package/src/core/wrappers/prototypes/bind-class-extensions.js +7 -3
|
@@ -6,8 +6,8 @@ export const ObservableWhen = function(observer, value) {
|
|
|
6
6
|
|
|
7
7
|
ObservableWhen.prototype.__$isObservableWhen = true;
|
|
8
8
|
|
|
9
|
-
ObservableWhen.prototype.subscribe = function(callback) {
|
|
10
|
-
return this.$observer.on(this.$target, callback);
|
|
9
|
+
ObservableWhen.prototype.subscribe = function(callback, context = null) {
|
|
10
|
+
return this.$observer.on(this.$target, callback, context);
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
ObservableWhen.prototype.val = function() {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export function CallbackHandler(callback) {
|
|
4
|
+
|
|
5
|
+
if(!(this instanceof CallbackHandler)) {
|
|
6
|
+
return new CallbackHandler(callback);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const $contextSore = new WeakMap();
|
|
10
|
+
|
|
11
|
+
this.set = (target, context) => {
|
|
12
|
+
$contextSore.set(target, context);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
this.callback = function() {
|
|
16
|
+
const context = $contextSore.get(this);
|
|
17
|
+
if(context) {
|
|
18
|
+
callback(context, ...arguments);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -1,50 +1,30 @@
|
|
|
1
1
|
import Validator from "../utils/validator";
|
|
2
|
-
import NativeDocumentError from "../errors/NativeDocumentError";
|
|
3
2
|
import {BOOLEAN_ATTRIBUTES} from "./constants.js";
|
|
4
3
|
import {Observable} from "../data/Observable";
|
|
5
|
-
import './prototypes/bind-class-extensions';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export function toggleElementClass(element, className, shouldAdd) {
|
|
9
|
-
element.classes.toggle(className, shouldAdd);
|
|
10
|
-
}
|
|
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
4
|
|
|
5
|
+
export const handleElementAttributeClass = function(shouldAdd, _, __, context) {
|
|
6
|
+
context.element.classes.toggle(context.className, shouldAdd);
|
|
7
|
+
};
|
|
32
8
|
/**
|
|
33
9
|
*
|
|
34
10
|
* @param {HTMLElement} element
|
|
35
11
|
* @param {Object} data
|
|
36
12
|
*/
|
|
37
13
|
export function bindClassAttribute(element, data) {
|
|
38
|
-
|
|
14
|
+
const classNames = Object.keys(data);
|
|
15
|
+
|
|
16
|
+
for(let i = 0, length = classNames.length; i < length; i++) {
|
|
17
|
+
const className = classNames[i];
|
|
39
18
|
const value = data[className];
|
|
40
|
-
if(
|
|
19
|
+
if(value.__$isObservable) {
|
|
41
20
|
element.classes.toggle(className, value.val());
|
|
42
|
-
value.subscribe(
|
|
21
|
+
value.subscribe(handleElementAttributeClass, { element, className });
|
|
22
|
+
// value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
43
23
|
continue;
|
|
44
24
|
}
|
|
45
|
-
if(
|
|
25
|
+
if(value.__$isObservableWhen) {
|
|
46
26
|
element.classes.toggle(className, value.isMath());
|
|
47
|
-
value.subscribe(
|
|
27
|
+
value.subscribe(handleElementAttributeClass, { element, className });
|
|
48
28
|
continue;
|
|
49
29
|
}
|
|
50
30
|
if(value.$hydrate) {
|
|
@@ -53,7 +33,6 @@ export function bindClassAttribute(element, data) {
|
|
|
53
33
|
}
|
|
54
34
|
element.classes.toggle(className, value)
|
|
55
35
|
}
|
|
56
|
-
data = null;
|
|
57
36
|
}
|
|
58
37
|
|
|
59
38
|
/**
|
|
@@ -62,11 +41,13 @@ export function bindClassAttribute(element, data) {
|
|
|
62
41
|
* @param {Object} data
|
|
63
42
|
*/
|
|
64
43
|
export function bindStyleAttribute(element, data) {
|
|
65
|
-
|
|
44
|
+
const keys = Object.keys(data)
|
|
45
|
+
for(let i = 0, length = keys.length; i < length; i++) {
|
|
46
|
+
const styleName = keys[i];
|
|
66
47
|
const value = data[styleName];
|
|
67
|
-
if(
|
|
48
|
+
if(value.__$isObservable) {
|
|
68
49
|
element.style[styleName] = value.val();
|
|
69
|
-
value.subscribe(
|
|
50
|
+
value.subscribe((newValue) => element.style[styleName] = newValue);
|
|
70
51
|
continue;
|
|
71
52
|
}
|
|
72
53
|
element.style[styleName] = value;
|
|
@@ -80,18 +61,27 @@ export function bindStyleAttribute(element, data) {
|
|
|
80
61
|
* @param {boolean|number|Observable} value
|
|
81
62
|
*/
|
|
82
63
|
export function bindBooleanAttribute(element, attributeName, value) {
|
|
83
|
-
const
|
|
84
|
-
|
|
64
|
+
const isObservable = value.__$isObservable;
|
|
65
|
+
const defaultValue = isObservable? value.val() : value;
|
|
66
|
+
const isBoolValue = typeof defaultValue === "boolean";
|
|
67
|
+
if(isBoolValue) {
|
|
85
68
|
element[attributeName] = defaultValue;
|
|
86
69
|
}
|
|
87
70
|
else {
|
|
88
71
|
element[attributeName] = defaultValue === element.value;
|
|
89
72
|
}
|
|
90
|
-
if(
|
|
91
|
-
if(
|
|
92
|
-
|
|
73
|
+
if(isObservable) {
|
|
74
|
+
if(attributeName === 'checked') {
|
|
75
|
+
if(isBoolValue) {
|
|
76
|
+
element.addEventListener('input', () => value.set(element[attributeName]));
|
|
77
|
+
value.subscribe((newValue) => element[attributeName] = newValue);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
element.addEventListener('input', () => value.set(element.value));
|
|
81
|
+
value.subscribe((newValue) => element[attributeName] = (newValue === element.value));
|
|
82
|
+
return;
|
|
93
83
|
}
|
|
94
|
-
value.subscribe(
|
|
84
|
+
value.subscribe((newValue) => element[attributeName] = (newValue === element.value));
|
|
95
85
|
}
|
|
96
86
|
}
|
|
97
87
|
|
|
@@ -103,19 +93,15 @@ export function bindBooleanAttribute(element, attributeName, value) {
|
|
|
103
93
|
* @param {Observable} value
|
|
104
94
|
*/
|
|
105
95
|
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());
|
|
114
|
-
value.subscribe(applyValue);
|
|
115
|
-
|
|
116
96
|
if(attributeName === 'value') {
|
|
97
|
+
value.subscribe((newValue) => element.value = newValue);
|
|
98
|
+
element.value = value.val();
|
|
117
99
|
element.addEventListener('input', () => value.set(element.value));
|
|
100
|
+
return;
|
|
118
101
|
}
|
|
102
|
+
|
|
103
|
+
value.subscribe((newValue) => element.setAttribute(attributeName, newValue));
|
|
104
|
+
element.setAttribute(attributeName, value.val());
|
|
119
105
|
}
|
|
120
106
|
|
|
121
107
|
/**
|
|
@@ -125,15 +111,15 @@ export function bindAttributeWithObservable(element, attributeName, value) {
|
|
|
125
111
|
*/
|
|
126
112
|
export default function AttributesWrapper(element, attributes) {
|
|
127
113
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if(!Validator.isObject(attributes)) {
|
|
131
|
-
throw new NativeDocumentError('Attributes must be an object');
|
|
114
|
+
if(process.env.NODE_ENV === 'development') {
|
|
115
|
+
Validator.validateAttributes(attributes);
|
|
132
116
|
}
|
|
117
|
+
const attributeNames = Object.keys(attributes);
|
|
133
118
|
|
|
134
|
-
for(let
|
|
135
|
-
const
|
|
136
|
-
|
|
119
|
+
for(let i = 0, length = attributeNames.length; i < length; i++) {
|
|
120
|
+
const originalAttributeName = attributeNames[i];
|
|
121
|
+
const attributeName = originalAttributeName.toLowerCase();
|
|
122
|
+
let value = attributes[originalAttributeName];
|
|
137
123
|
if(value == null) {
|
|
138
124
|
continue;
|
|
139
125
|
}
|
|
@@ -156,6 +142,10 @@ export default function AttributesWrapper(element, attributes) {
|
|
|
156
142
|
continue;
|
|
157
143
|
}
|
|
158
144
|
|
|
145
|
+
if(attributeName === 'value') {
|
|
146
|
+
element.value = value;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
159
149
|
element.setAttribute(attributeName, value);
|
|
160
150
|
}
|
|
161
151
|
return element;
|
|
@@ -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,16 +1,20 @@
|
|
|
1
1
|
import ObservableItem from "../../../core/data/ObservableItem";
|
|
2
|
-
import {toggleElementClass} from "../AttributesWrapper";
|
|
3
2
|
import {ObservableWhen} from "../../data/ObservableWhen";
|
|
4
3
|
import TemplateBinding from "../../../core/wrappers/TemplateBinding";
|
|
5
4
|
|
|
5
|
+
|
|
6
|
+
export const handleElementAttributeClass = function(shouldAdd, _, __, context) {
|
|
7
|
+
context.element.classes.toggle(context.className, shouldAdd);
|
|
8
|
+
};
|
|
9
|
+
|
|
6
10
|
ObservableItem.prototype.bindNdClass = function(element, className) {
|
|
7
11
|
element.classes.toggle(className, this.val());
|
|
8
|
-
this.subscribe(
|
|
12
|
+
this.subscribe(handleElementAttributeClass, { element, className });
|
|
9
13
|
};
|
|
10
14
|
|
|
11
15
|
ObservableWhen.prototype.bindNdClass = function(element, className) {
|
|
12
16
|
element.classes.toggle(className, this.isMath());
|
|
13
|
-
this.subscribe(
|
|
17
|
+
this.subscribe(handleElementAttributeClass, { element, className });
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
TemplateBinding.prototype.bindNdClass = function(element, className) {
|