native-document 1.0.109 → 1.0.110

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.109",
3
+ "version": "1.0.110",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  import Anchor from "../elements/anchor";
2
2
  import Validator from "../utils/validator";
3
- import AttributesWrapper from "./AttributesWrapper";
3
+ import AttributesWrapper, { bindClassAttribute, bindStyleAttribute } from "./AttributesWrapper";
4
4
  import PluginsManager from "../utils/plugins-manager";
5
5
  import './prototypes/nd-element-extensions';
6
6
  import './prototypes/nd-element.transition.extensions';
@@ -124,5 +124,13 @@ export const ElementCreator = {
124
124
  if (attributes) {
125
125
  AttributesWrapper(element, attributes);
126
126
  }
127
- }
127
+ },
128
+ /**
129
+ *
130
+ * @param {HTMLElement} element
131
+ * @param {Object} attributes
132
+ */
133
+ processAttributesDirect: AttributesWrapper,
134
+ processClassAttribute: bindClassAttribute,
135
+ processStyleAttribute: bindStyleAttribute,
128
136
  };
@@ -3,6 +3,12 @@ import TemplateBinding from "./TemplateBinding";
3
3
 
4
4
  const cloneBindingsDataCache = new WeakMap();
5
5
 
6
+ const OPERATIONS = {
7
+ HYDRATE_TEXT: 1,
8
+ ATTACH_METHOD: 2,
9
+ HYDRATE_ATTRIBUTES: 3,
10
+ HYDRATE_FULL: 4,
11
+ };
6
12
 
7
13
  const hydrateFull = (node, bindDingData, data) => {
8
14
  const cacheAttributes = bindDingData._cache;
@@ -29,7 +35,32 @@ const hydrateDynamic = (node, bindDingData, data) => {
29
35
  cacheAttributes[dyn.name][dyn.key] = dyn.value.apply(null, data);
30
36
  }
31
37
 
32
- ElementCreator.processAttributesDirect(node, cacheAttributes);
38
+ ElementCreator.processClassAttribute(node, cacheAttributes.class);
39
+ ElementCreator.processStyleAttribute(node, cacheAttributes.style);
40
+ return true;
41
+ };
42
+
43
+ const hydrateClassAttribute = (node, bindDingData, data) => {
44
+ const classAttributes = bindDingData._cache.class;
45
+
46
+ for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
47
+ const dyn = bindDingData._flatDynamique[i];
48
+ classAttributes[dyn.key] = dyn.value.apply(null, data);
49
+ }
50
+
51
+ ElementCreator.processClassAttribute(node, classAttributes);
52
+ return true;
53
+ };
54
+
55
+ const hydrateStyleAttribute = (node, bindDingData, data) => {
56
+ const styleAttributes = bindDingData._cache;
57
+
58
+ for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
59
+ const dyn = bindDingData._flatDynamique[i];
60
+ styleAttributes[dyn.key] = dyn.value.apply(null, data);
61
+ }
62
+
63
+ ElementCreator.processStyleAttribute(node, styleAttributes);
33
64
  return true;
34
65
  };
35
66
 
@@ -55,7 +86,13 @@ const getHydrator = (bindDingData) => {
55
86
  if(bindDingData._flatAttributesLength) {
56
87
  return hydrateAttributes;
57
88
  }
58
- return hydrateDynamic;
89
+ if(bindDingData._hasClassAttribute && bindDingData._hasStyleAttribute) {
90
+ return hydrateDynamic;
91
+ }
92
+ if(bindDingData._hasClassAttribute) {
93
+ return hydrateClassAttribute;
94
+ }
95
+ return hydrateStyleAttribute;
59
96
  };
60
97
 
61
98
  const $hydrateFn = function(hydrateFunction, targetType, element, property) {
@@ -81,29 +118,50 @@ const bindAttachMethods = (node, bindDingData, data) => {
81
118
  for(let i = 0, length = bindDingData._attachLength; i < length; i++) {
82
119
  const method = bindDingData.attach[i];
83
120
  node.nd[method.methodName](function() {
84
- method.fn.call(this, ...arguments, ...data);
121
+ method.fn.call(this, ...data, ...arguments);
85
122
  });
86
123
  }
87
124
  };
88
125
 
89
126
 
90
127
  const $applyBindingParents = [];
128
+ const pathProcess = (target, path, data) => {
129
+ if(path.operation === OPERATIONS.HYDRATE_TEXT) {
130
+ const value = path.value;
131
+ ElementCreator.bindTextNode(target, path.isString ? data[0][value] : value.apply(null, data));
132
+ return;
133
+ }
134
+ if(path.operation === OPERATIONS.ATTACH_METHOD || path.operation === OPERATIONS.HYDRATE_FULL) {
135
+ const bindingData = path.bindingData;
136
+ for(let i = 0, length = bindingData._attachLength; i < length; i++) {
137
+ const method = bindingData.attach[i];
138
+ target.nd[method.methodName](function() {
139
+ method.fn.call(this, ...data, ...arguments);
140
+ });
141
+ }
142
+ }
143
+ if(path.operation === OPERATIONS.HYDRATE_ATTRIBUTES || path.operation === OPERATIONS.HYDRATE_FULL) {
144
+ path.hydrator(target, path.bindingData, data);
145
+ }
146
+ };
147
+
91
148
  const applyBindingTreePath = (root, data, paths, pathSize) => {
92
- const rootPath = paths.at(-1);
149
+ const rootPath = paths[pathSize];
93
150
  $applyBindingParents[rootPath.id] = root;
94
- const rootPathFn = rootPath.fn;
95
- rootPathFn(data, root, root);
96
-
151
+ pathProcess(root, rootPath, data);
97
152
 
153
+ let target = null, path = null;
98
154
  for(let i = 0; i < pathSize; i++) {
99
- const path = paths[i];
100
- const target = $applyBindingParents[path.parentId].childNodes[path.index];
101
-
155
+ path = paths[i];
156
+ target = $applyBindingParents[path.parentId].childNodes[path.index];
102
157
  $applyBindingParents[path.id] = target;
103
- const pathFn = path.fn;
104
- pathFn(data, target, root);
158
+
159
+ pathProcess(target, path, data);
160
+ }
161
+
162
+ for (let i = 0; i <= pathSize; i++) {
163
+ $applyBindingParents[i] = null;
105
164
  }
106
- $applyBindingParents.length = 0;
107
165
  };
108
166
  const buildAttributesCache = (bindDingData) => {
109
167
  const cache = { };
@@ -128,6 +186,7 @@ const prepareBindingMetadata = (bindDingData) => {
128
186
 
129
187
  if(bindDingData.classes) {
130
188
  for (const className in bindDingData.classes) {
189
+ bindDingData._hasClassAttribute = true;
131
190
  classAndStyles.push({
132
191
  name: 'class',
133
192
  key: className,
@@ -138,6 +197,7 @@ const prepareBindingMetadata = (bindDingData) => {
138
197
 
139
198
  if(bindDingData.styles) {
140
199
  for (const property in bindDingData.styles) {
200
+ bindDingData._hasStyleAttribute = true;
141
201
  classAndStyles.push({
142
202
  name: 'style',
143
203
  key: property,
@@ -154,9 +214,6 @@ const prepareBindingMetadata = (bindDingData) => {
154
214
  };
155
215
 
156
216
  const optimizeBindingData = (bindDingData) => {
157
- if(!bindDingData) {
158
- return;
159
- }
160
217
  buildAttributesCache(bindDingData);
161
218
  prepareBindingMetadata(bindDingData);
162
219
  };
@@ -170,24 +227,24 @@ export function TemplateCloner($fn) {
170
227
  const $bindingTreePath = [
171
228
  {
172
229
  id: 0,
173
- parentId: null,
174
- fn: noUpdate,
230
+ parentId: null
175
231
  }
176
232
  ];
177
233
 
178
234
  let pathCounter = 0;
179
235
  const clone = (node, data, currentPath) => {
180
236
  const bindDingData = cloneBindingsDataCache.get(node);
181
- optimizeBindingData(bindDingData);
237
+ if(bindDingData) {
238
+ optimizeBindingData(bindDingData);
239
+ }
182
240
  if(node.nodeType === 3) {
183
241
  if(bindDingData && bindDingData.value) {
184
- currentPath.fn = bindDingData.value;
242
+ const value = bindDingData.value;
185
243
  const textNode = node.cloneNode();
186
- if(typeof bindDingData.value === 'string') {
187
- ElementCreator.bindTextNode(textNode, data[0][bindDingData.value]);
188
- return textNode;
189
- }
190
- bindDingData.value(data, textNode);
244
+ currentPath.value = value;
245
+ currentPath.operation = OPERATIONS.HYDRATE_TEXT;
246
+ currentPath.isString = (typeof value === 'string');
247
+ ElementCreator.bindTextNode(textNode, (currentPath.isString ? data[0][value] : value.apply(null, data)));
191
248
  return textNode;
192
249
  }
193
250
  return node.cloneNode(true);
@@ -201,22 +258,17 @@ export function TemplateCloner($fn) {
201
258
  const hasAttributes = bindDingData.classes || bindDingData.styles || bindDingData.attributes;
202
259
  const hasAttachMethods = bindDingData.attach.length;
203
260
 
204
- currentPath.fn = noUpdate;
261
+ currentPath.bindingData = bindDingData;
262
+ currentPath.hydrator = hydrator;
263
+
205
264
  if(hasAttributes && hasAttachMethods) {
206
- currentPath.fn = (data, targetNode) => {
207
- hydrator(targetNode, bindDingData, data);
208
- bindAttachMethods(targetNode, bindDingData, data);
209
- };
265
+ currentPath.operation = OPERATIONS.HYDRATE_FULL;
210
266
  }
211
267
  else if(hasAttributes) {
212
- currentPath.fn = (data, targetNode) => {
213
- hydrator(targetNode, bindDingData, data);
214
- };
268
+ currentPath.operation = OPERATIONS.HYDRATE_ATTRIBUTES;
215
269
  }
216
270
  else if(hasAttachMethods) {
217
- currentPath.fn = (data, targetNode) => {
218
- bindAttachMethods(targetNode, bindDingData, data);
219
- };
271
+ currentPath.operation = OPERATIONS.ATTACH_METHOD;
220
272
  }
221
273
  }
222
274
  const childNodes = node.childNodes;
@@ -224,9 +276,9 @@ export function TemplateCloner($fn) {
224
276
 
225
277
  for(let i = 0, length = childNodes.length; i < length; i++) {
226
278
  const childNode = childNodes[i];
227
- const path = { parentId, id: ++pathCounter, index: i, fn: noUpdate };
279
+ const path = { parentId, id: ++pathCounter, index: i };
228
280
  const childNodeCloned = clone(childNode, data, path);
229
- if(path.hasChildren || path.fn !== noUpdate) {
281
+ if(path.hasChildren || path.operation) {
230
282
  $bindingTreePath.push(path);
231
283
  currentPath.hasChildren = true;
232
284
  }
@@ -243,7 +295,8 @@ export function TemplateCloner($fn) {
243
295
  };
244
296
 
245
297
  this.clone = (data) => {
246
- $node = $fn(this);
298
+ const binder = createTemplateCloner(this);
299
+ $node = $fn(binder);
247
300
  if(!$hasBindingData) {
248
301
  this.clone = () => $node.cloneNode(true);
249
302
  return $node.cloneNode(true);
@@ -275,14 +328,7 @@ export function TemplateCloner($fn) {
275
328
  return this.value(propertyName);
276
329
  }
277
330
  this.value = (callbackOrProperty) => {
278
- if(typeof callbackOrProperty !== 'function') {
279
- return createBinding((data, textNode) => {
280
- ElementCreator.bindTextNode(textNode, data[0][callbackOrProperty]);
281
- }, 'value');
282
- }
283
- return createBinding((data, textNode) => {
284
- ElementCreator.bindTextNode(textNode, callbackOrProperty(...data));
285
- }, 'value');
331
+ return createBinding(callbackOrProperty, 'value');
286
332
  };
287
333
  this.text = this.value;
288
334
  this.attr = (fn) => {
@@ -295,11 +341,24 @@ export function TemplateCloner($fn) {
295
341
 
296
342
  }
297
343
 
344
+ function createTemplateCloner($binder) {
345
+ return new Proxy($binder, {
346
+ get(target, prop) {
347
+ if(prop in target) {
348
+ return target[prop];
349
+ }
350
+ if (typeof prop === 'symbol') return target[prop];
351
+ return target.value(prop);
352
+ }
353
+ });
354
+ }
355
+
298
356
  export function useCache(fn) {
299
357
  let $cache = null;
300
358
 
301
359
  let wrapper = function(args) {
302
360
  $cache = new TemplateCloner(fn);
361
+
303
362
  wrapper = function(args) {
304
363
  return $cache.clone(args);
305
364
  };