native-document 1.0.80 → 1.0.82
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 +22 -108
- package/dist/native-document.dev.js +177 -135
- 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/ObservableArray.js +7 -5
- package/src/core/data/ObservableItem.js +27 -10
- package/src/core/data/observable-helpers/computed.js +3 -2
- package/src/core/elements/anchor.js +3 -1
- package/src/core/elements/control/for-each-array.js +1 -1
- package/src/core/utils/plugins-manager.js +66 -62
- package/src/core/wrappers/ElementCreator.js +12 -6
- package/src/core/wrappers/HtmlElementWrapper.js +2 -7
- package/src/core/wrappers/NDElement.js +6 -3
- package/src/core/wrappers/TemplateCloner.js +45 -37
- package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -1
|
@@ -20,6 +20,7 @@ export default function ObservableItem(value, configs = null) {
|
|
|
20
20
|
this.$currentValue = value;
|
|
21
21
|
this.$isCleanedUp = false;
|
|
22
22
|
|
|
23
|
+
this.$firstListener = null;
|
|
23
24
|
this.$listeners = null;
|
|
24
25
|
this.$watchers = null;
|
|
25
26
|
|
|
@@ -31,8 +32,9 @@ export default function ObservableItem(value, configs = null) {
|
|
|
31
32
|
this.$initialValue = Validator.isObject(value) ? deepClone(value) : value;
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
if(process.env.NODE_ENV === 'development') {
|
|
36
|
+
PluginsManager.emit('CreateObservable', this);
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
Object.defineProperty(ObservableItem.prototype, '$value', {
|
|
@@ -55,7 +57,7 @@ ObservableItem.prototype.intercept = function(callback) {
|
|
|
55
57
|
};
|
|
56
58
|
|
|
57
59
|
ObservableItem.prototype.triggerFirstListener = function(operations) {
|
|
58
|
-
this.$
|
|
60
|
+
this.$firstListener(this.$currentValue, this.$previousValue, operations || {});
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
ObservableItem.prototype.triggerListeners = function(operations) {
|
|
@@ -104,22 +106,29 @@ ObservableItem.prototype.triggerWatchers = function() {
|
|
|
104
106
|
};
|
|
105
107
|
|
|
106
108
|
ObservableItem.prototype.triggerAll = function(operations) {
|
|
107
|
-
this.triggerListeners(operations);
|
|
108
109
|
this.triggerWatchers();
|
|
110
|
+
this.triggerListeners(operations);
|
|
109
111
|
};
|
|
110
112
|
|
|
111
113
|
ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations) {
|
|
112
|
-
this.triggerListeners(operations);
|
|
113
114
|
this.triggerWatchers();
|
|
115
|
+
this.triggerListeners(operations);
|
|
114
116
|
};
|
|
115
117
|
|
|
116
118
|
ObservableItem.prototype.assocTrigger = function() {
|
|
119
|
+
this.$firstListener = null;
|
|
117
120
|
if(this.$watchers?.size && this.$listeners?.length) {
|
|
118
121
|
this.trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
119
122
|
return;
|
|
120
123
|
}
|
|
121
124
|
if(this.$listeners?.length) {
|
|
122
|
-
|
|
125
|
+
if(this.$listeners.length === 1) {
|
|
126
|
+
this.$firstListener = this.$listeners[0];
|
|
127
|
+
this.trigger = this.triggerFirstListener
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.trigger = this.triggerListeners;
|
|
131
|
+
}
|
|
123
132
|
return;
|
|
124
133
|
}
|
|
125
134
|
if(this.$watchers?.size) {
|
|
@@ -150,10 +159,14 @@ ObservableItem.prototype.set = function(data) {
|
|
|
150
159
|
}
|
|
151
160
|
this.$previousValue = this.$currentValue;
|
|
152
161
|
this.$currentValue = newValue;
|
|
153
|
-
|
|
162
|
+
if(process.env.NODE_ENV === 'development') {
|
|
163
|
+
PluginsManager.emit('ObservableBeforeChange', this);
|
|
164
|
+
}
|
|
154
165
|
this.trigger();
|
|
155
166
|
this.$previousValue = null;
|
|
156
|
-
|
|
167
|
+
if(process.env.NODE_ENV === 'development') {
|
|
168
|
+
PluginsManager.emit('ObservableAfterChange', this);
|
|
169
|
+
}
|
|
157
170
|
};
|
|
158
171
|
|
|
159
172
|
ObservableItem.prototype.val = function() {
|
|
@@ -213,11 +226,15 @@ ObservableItem.prototype.subscribe = function(callback, target = null) {
|
|
|
213
226
|
|
|
214
227
|
this.$listeners.push(callback);
|
|
215
228
|
this.assocTrigger();
|
|
216
|
-
|
|
229
|
+
if(process.env.NODE_ENV === 'development') {
|
|
230
|
+
PluginsManager.emit('ObservableSubscribe', this, target);
|
|
231
|
+
}
|
|
217
232
|
return () => {
|
|
218
233
|
this.unsubscribe(callback);
|
|
219
234
|
this.assocTrigger();
|
|
220
|
-
|
|
235
|
+
if(process.env.NODE_ENV === 'development') {
|
|
236
|
+
PluginsManager.emit('ObservableUnsubscribe', this);
|
|
237
|
+
}
|
|
221
238
|
};
|
|
222
239
|
};
|
|
223
240
|
|
|
@@ -15,8 +15,9 @@ Observable.computed = function(callback, dependencies = []) {
|
|
|
15
15
|
const initialValue = callback();
|
|
16
16
|
const observable = new ObservableItem(initialValue);
|
|
17
17
|
const updatedValue = nextTick(() => observable.set(callback()));
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
if(process.env.NODE_ENV === 'development') {
|
|
19
|
+
PluginsManager.emit('CreateObservableComputed', observable, dependencies);
|
|
20
|
+
}
|
|
20
21
|
|
|
21
22
|
if(Validator.isFunction(dependencies)) {
|
|
22
23
|
if(!Validator.isObservable(dependencies.$observer)) {
|
|
@@ -1,77 +1,81 @@
|
|
|
1
1
|
import DebugManager from "./debug-manager";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let PluginsManager = null;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if(process.env.NODE_ENV === 'development') {
|
|
6
|
+
PluginsManager = (function() {
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return $pluginByEvents;
|
|
11
|
-
},
|
|
12
|
-
add(plugin, name){
|
|
13
|
-
if (!plugin || typeof plugin !== 'object') {
|
|
14
|
-
throw new Error(`Plugin ${name} must be an object`);
|
|
15
|
-
}
|
|
16
|
-
name = name || plugin.name;
|
|
17
|
-
if (!name || typeof name !== 'string') {
|
|
18
|
-
throw new Error(`Please, provide a valid plugin name`);
|
|
19
|
-
}
|
|
20
|
-
if($plugins.has(name)) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
8
|
+
const $plugins = new Map();
|
|
9
|
+
const $pluginByEvents = new Map();
|
|
23
10
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
11
|
+
return {
|
|
12
|
+
list() {
|
|
13
|
+
return $pluginByEvents;
|
|
14
|
+
},
|
|
15
|
+
add(plugin, name){
|
|
16
|
+
if (!plugin || typeof plugin !== 'object') {
|
|
17
|
+
throw new Error(`Plugin ${name} must be an object`);
|
|
18
|
+
}
|
|
19
|
+
name = name || plugin.name;
|
|
20
|
+
if (!name || typeof name !== 'string') {
|
|
21
|
+
throw new Error(`Please, provide a valid plugin name`);
|
|
22
|
+
}
|
|
23
|
+
if($plugins.has(name)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
plugin.$name = name;
|
|
28
|
+
$plugins.set(name ,plugin);
|
|
29
|
+
if(typeof plugin?.init === 'function') {
|
|
30
|
+
plugin.init();
|
|
31
|
+
}
|
|
32
|
+
for(const methodName in plugin) {
|
|
33
|
+
if(/^on[A-Z]/.test(methodName)) {
|
|
34
|
+
const eventName = methodName.replace(/^on/, '');
|
|
35
|
+
if(!$pluginByEvents.has(eventName)) {
|
|
36
|
+
$pluginByEvents.set(eventName, new Set());
|
|
37
|
+
}
|
|
38
|
+
$pluginByEvents.get(eventName).add(plugin);
|
|
34
39
|
}
|
|
35
|
-
$pluginByEvents.get(eventName).add(plugin);
|
|
36
40
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const plugin = $plugins.get(pluginName);
|
|
44
|
-
if(typeof plugin.cleanup === 'function') {
|
|
45
|
-
plugin.cleanup();
|
|
46
|
-
}
|
|
47
|
-
for(const [name, sets] of $pluginByEvents.entries() ) {
|
|
48
|
-
if(sets.has(plugin)) {
|
|
49
|
-
sets.delete(plugin);
|
|
41
|
+
},
|
|
42
|
+
remove(pluginName){
|
|
43
|
+
if(!$plugins.has(pluginName)) {
|
|
44
|
+
return;
|
|
50
45
|
}
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
const plugin = $plugins.get(pluginName);
|
|
47
|
+
if(typeof plugin.cleanup === 'function') {
|
|
48
|
+
plugin.cleanup();
|
|
53
49
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
for(const [name, sets] of $pluginByEvents.entries() ) {
|
|
51
|
+
if(sets.has(plugin)) {
|
|
52
|
+
sets.delete(plugin);
|
|
53
|
+
}
|
|
54
|
+
if(sets.size === 0) {
|
|
55
|
+
$pluginByEvents.delete(name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
$plugins.delete(pluginName);
|
|
59
|
+
},
|
|
60
|
+
emit(eventName, ...data) {
|
|
61
|
+
if(!$pluginByEvents.has(eventName)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const plugins = $pluginByEvents.get(eventName);
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
for(const plugin of plugins) {
|
|
67
|
+
const callback = plugin['on'+eventName];
|
|
68
|
+
if(typeof callback === 'function') {
|
|
69
|
+
try{
|
|
70
|
+
callback.call(plugin, ...data);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
DebugManager.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventName}`, error);
|
|
73
|
+
}
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
}
|
|
77
|
+
};
|
|
78
|
+
}());
|
|
79
|
+
}
|
|
76
80
|
|
|
77
81
|
export default PluginsManager;
|
|
@@ -59,8 +59,9 @@ export const ElementCreator = {
|
|
|
59
59
|
*/
|
|
60
60
|
createElement(name) {
|
|
61
61
|
if(name) {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const cacheNode = $nodeCache.get(name);
|
|
63
|
+
if(cacheNode) {
|
|
64
|
+
return cacheNode.cloneNode();
|
|
64
65
|
}
|
|
65
66
|
const node = document.createElement(name);
|
|
66
67
|
$nodeCache.set(name, node);
|
|
@@ -75,12 +76,16 @@ export const ElementCreator = {
|
|
|
75
76
|
*/
|
|
76
77
|
processChildren(children, parent) {
|
|
77
78
|
if(children === null) return;
|
|
78
|
-
|
|
79
|
+
if(process.env.NODE_ENV === 'development') {
|
|
80
|
+
PluginsManager.emit('BeforeProcessChildren', parent);
|
|
81
|
+
}
|
|
79
82
|
let child = this.getChild(children);
|
|
80
83
|
if(child) {
|
|
81
84
|
parent.appendChild(child);
|
|
82
85
|
}
|
|
83
|
-
|
|
86
|
+
if(process.env.NODE_ENV === 'development') {
|
|
87
|
+
PluginsManager.emit('AfterProcessChildren', parent);
|
|
88
|
+
}
|
|
84
89
|
},
|
|
85
90
|
getChild(child) {
|
|
86
91
|
if(child == null) {
|
|
@@ -103,7 +108,6 @@ export const ElementCreator = {
|
|
|
103
108
|
* @param {Object} attributes
|
|
104
109
|
*/
|
|
105
110
|
processAttributes(element, attributes) {
|
|
106
|
-
if(Validator.isFragment(element)) return;
|
|
107
111
|
if (attributes) {
|
|
108
112
|
AttributesWrapper(element, attributes);
|
|
109
113
|
}
|
|
@@ -116,7 +120,9 @@ export const ElementCreator = {
|
|
|
116
120
|
* @returns {HTMLElement|DocumentFragment}
|
|
117
121
|
*/
|
|
118
122
|
setup(element, attributes, customWrapper) {
|
|
119
|
-
|
|
123
|
+
if(process.env.NODE_ENV === 'development') {
|
|
124
|
+
PluginsManager.emit('Setup', element, attributes, customWrapper);
|
|
125
|
+
}
|
|
120
126
|
return element;
|
|
121
127
|
}
|
|
122
128
|
};
|
|
@@ -20,13 +20,8 @@ function createHtmlElement($tagName, customWrapper, _attributes, _children = nul
|
|
|
20
20
|
let element = ElementCreator.createElement($tagName);
|
|
21
21
|
let finalElement = (customWrapper && typeof customWrapper === 'function') ? customWrapper(element) : element;
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
if(children) {
|
|
27
|
-
ElementCreator.processChildren(children, finalElement);
|
|
28
|
-
}
|
|
29
|
-
|
|
23
|
+
ElementCreator.processAttributes(finalElement, attributes);
|
|
24
|
+
ElementCreator.processChildren(children, finalElement);
|
|
30
25
|
return ElementCreator.setup(finalElement, attributes, customWrapper);
|
|
31
26
|
}
|
|
32
27
|
|
|
@@ -6,7 +6,9 @@ import DebugManager from "../utils/debug-manager.js";
|
|
|
6
6
|
export function NDElement(element) {
|
|
7
7
|
this.$element = element;
|
|
8
8
|
this.$observer = null;
|
|
9
|
-
|
|
9
|
+
if(process.env.NODE_ENV === 'development') {
|
|
10
|
+
PluginsManager.emit('NDElementCreated', element, this);
|
|
11
|
+
}
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
NDElement.prototype.__$isNDElement = true;
|
|
@@ -175,8 +177,9 @@ NDElement.extend = function(methods) {
|
|
|
175
177
|
|
|
176
178
|
NDElement.prototype[name] = method;
|
|
177
179
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
if(process.env.NODE_ENV === 'development') {
|
|
181
|
+
PluginsManager.emit('NDElementExtended', methods);
|
|
182
|
+
}
|
|
180
183
|
|
|
181
184
|
return NDElement;
|
|
182
185
|
};
|
|
@@ -38,14 +38,6 @@ const bindAttributes = (node, bindDingData, data) => {
|
|
|
38
38
|
return null;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const findByPath = (root, path) => {
|
|
42
|
-
let target = root;
|
|
43
|
-
for (let i = 0, len = path.length; i < len; i++) {
|
|
44
|
-
target = target.childNodes[path[i]];
|
|
45
|
-
}
|
|
46
|
-
return target;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
41
|
const $hydrateFn = function(hydrateFunction, targetType, element, property) {
|
|
50
42
|
if(!cloneBindingsDataCache.has(element)) {
|
|
51
43
|
// { classes, styles, attributes, value, attach }
|
|
@@ -71,27 +63,43 @@ const bindAttachMethods = function(node, bindDingData, data) {
|
|
|
71
63
|
}
|
|
72
64
|
};
|
|
73
65
|
|
|
66
|
+
|
|
67
|
+
const applyBindingTreePath = (root, target, data, path) => {
|
|
68
|
+
let newTarget = null;
|
|
69
|
+
if(path.fn) {
|
|
70
|
+
newTarget = path.fn(data, target, root);
|
|
71
|
+
}
|
|
72
|
+
if(path.children) {
|
|
73
|
+
for(let i = 0, length = path.children.length; i < length; i++) {
|
|
74
|
+
const currentPath = path.children[i];
|
|
75
|
+
const pathTargetNode = target.childNodes[currentPath.index];
|
|
76
|
+
applyBindingTreePath(root, pathTargetNode, data, currentPath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return newTarget;
|
|
80
|
+
};
|
|
81
|
+
|
|
74
82
|
export function TemplateCloner($fn) {
|
|
75
83
|
let $node = null;
|
|
76
84
|
let $hasBindingData = false;
|
|
77
85
|
|
|
78
|
-
const $
|
|
86
|
+
const $bindingTreePath = {
|
|
87
|
+
fn: null,
|
|
88
|
+
children: [],
|
|
89
|
+
};
|
|
79
90
|
|
|
80
|
-
const clone = (node, data,
|
|
91
|
+
const clone = (node, data, currentPath) => {
|
|
81
92
|
const bindDingData = cloneBindingsDataCache.get(node);
|
|
82
93
|
if(node.nodeType === 3) {
|
|
83
94
|
if(bindDingData && bindDingData.value) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
targetNode.replaceWith(newNode);
|
|
89
|
-
if (targetNode === currentRoot) {
|
|
90
|
-
return newNode;
|
|
91
|
-
}
|
|
92
|
-
return null;
|
|
95
|
+
currentPath.fn = (data, targetNode, currentRoot) => {
|
|
96
|
+
const newNode = bindDingData.value(data);
|
|
97
|
+
if (targetNode === currentRoot) {
|
|
98
|
+
return newNode;
|
|
93
99
|
}
|
|
94
|
-
|
|
100
|
+
targetNode.replaceWith(newNode);
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
95
103
|
return bindDingData.value(data);
|
|
96
104
|
}
|
|
97
105
|
return node.cloneNode(true);
|
|
@@ -103,35 +111,35 @@ export function TemplateCloner($fn) {
|
|
|
103
111
|
if(bindDingData) {
|
|
104
112
|
bindAttributes(nodeCloned, bindDingData, data);
|
|
105
113
|
bindAttachMethods(nodeCloned, bindDingData, data);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
bindAttachMethods(targetNode, bindDingData, data);
|
|
111
|
-
}
|
|
112
|
-
})
|
|
114
|
+
currentPath.fn = (data, targetNode) => {
|
|
115
|
+
bindAttributes(targetNode, bindDingData, data);
|
|
116
|
+
bindAttachMethods(targetNode, bindDingData, data);
|
|
117
|
+
};
|
|
113
118
|
}
|
|
114
119
|
const childNodes = node.childNodes;
|
|
120
|
+
const bindingPathChildren = [];
|
|
115
121
|
for(let i = 0, length = childNodes.length; i < length; i++) {
|
|
116
122
|
const childNode = childNodes[i];
|
|
117
|
-
path
|
|
123
|
+
const path = { index: i, fn: null };
|
|
118
124
|
const childNodeCloned = clone(childNode, data, path);
|
|
119
|
-
path.
|
|
125
|
+
if(path.children || path.fn) {
|
|
126
|
+
bindingPathChildren.push(path);
|
|
127
|
+
}
|
|
120
128
|
nodeCloned.appendChild(childNodeCloned);
|
|
121
129
|
}
|
|
130
|
+
if(bindingPathChildren.length) {
|
|
131
|
+
currentPath.children = currentPath.children || [];
|
|
132
|
+
currentPath.children = bindingPathChildren;
|
|
133
|
+
}
|
|
122
134
|
return nodeCloned;
|
|
123
135
|
};
|
|
124
136
|
|
|
125
137
|
const cloneWithBindingPaths = (data) => {
|
|
126
138
|
let root = $node.cloneNode(true);
|
|
127
139
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const newRoot = binding.fn(data, target, root);
|
|
132
|
-
if(newRoot) {
|
|
133
|
-
root = newRoot;
|
|
134
|
-
}
|
|
140
|
+
const newRoot = applyBindingTreePath(root, root, data, $bindingTreePath);
|
|
141
|
+
if(newRoot) {
|
|
142
|
+
root = newRoot;
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
return root;
|
|
@@ -144,7 +152,7 @@ export function TemplateCloner($fn) {
|
|
|
144
152
|
return $node.cloneNode(true);
|
|
145
153
|
}
|
|
146
154
|
|
|
147
|
-
const firstClone = clone($node, data,
|
|
155
|
+
const firstClone = clone($node, data, $bindingTreePath);
|
|
148
156
|
this.clone = cloneWithBindingPaths;
|
|
149
157
|
return firstClone;
|
|
150
158
|
};
|
|
@@ -49,7 +49,9 @@ Array.prototype.toNdElement = function () {
|
|
|
49
49
|
|
|
50
50
|
Function.prototype.toNdElement = function () {
|
|
51
51
|
const child = this;
|
|
52
|
-
|
|
52
|
+
if(process.env.NODE_ENV === 'development') {
|
|
53
|
+
PluginsManager.emit('BeforeProcessComponent', child);
|
|
54
|
+
}
|
|
53
55
|
return ElementCreator.getChild(child());
|
|
54
56
|
};
|
|
55
57
|
|