native-document 1.0.115 → 1.0.117

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.
@@ -528,21 +528,6 @@ var NativeDocument = (function (exports) {
528
528
  return this.shadow('closed', style);
529
529
  };
530
530
 
531
- /**
532
- * Attaches a template binding to the element by hydrating it with the specified method.
533
- *
534
- * @param {string} methodName - Name of the hydration method to call
535
- * @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
536
- * @returns {HTMLElement} The underlying HTML element
537
- * @example
538
- * const onClick = $binder.attach((event, data) => console.log(data));
539
- * element.nd.attach('onClick', onClick);
540
- */
541
- NDElement.prototype.attach = function(methodName, bindingHydrator) {
542
- bindingHydrator.$hydrate(this.$element, methodName);
543
- return this.$element;
544
- };
545
-
546
531
  /**
547
532
  * Extends the current NDElement instance with custom methods.
548
533
  * Methods are bound to the instance and available for chaining.
@@ -801,164 +786,6 @@ var NativeDocument = (function (exports) {
801
786
  };
802
787
  }
803
788
 
804
- function Anchor(name, isUniqueChild = false) {
805
- const anchorFragment = document.createDocumentFragment();
806
- anchorFragment.__Anchor__ = true;
807
-
808
- const anchorStart = document.createComment('Anchor Start : '+name);
809
- const anchorEnd = document.createComment('/ Anchor End '+name);
810
-
811
- anchorFragment.appendChild(anchorStart);
812
- anchorFragment.appendChild(anchorEnd);
813
-
814
- anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
815
- anchorFragment.nativeAppendChild = anchorFragment.appendChild;
816
- anchorFragment.nativeAppend = anchorFragment.append;
817
-
818
- const isParentUniqueChild = isUniqueChild
819
- ? () => true
820
- : (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
821
-
822
- const insertBefore = function(parent, child, target) {
823
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
824
- if(parent === anchorFragment) {
825
- parent.nativeInsertBefore(childElement, target);
826
- return;
827
- }
828
- if(isParentUniqueChild(parent) && target === anchorEnd) {
829
- parent.append(childElement, target);
830
- return;
831
- }
832
- parent.insertBefore(childElement, target);
833
- };
834
-
835
- anchorFragment.appendElement = function(child, before = null) {
836
- const parentNode = anchorStart.parentNode;
837
- const targetBefore = before || anchorEnd;
838
- if(parentNode === anchorFragment) {
839
- parentNode.nativeInsertBefore(child, targetBefore);
840
- return;
841
- }
842
- parentNode?.insertBefore(child, targetBefore);
843
- };
844
-
845
- anchorFragment.appendChild = function(child, before = null) {
846
- const parent = anchorEnd.parentNode;
847
- if(!parent) {
848
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
849
- return;
850
- }
851
- before = before ?? anchorEnd;
852
- insertBefore(parent, child, before);
853
- };
854
-
855
- anchorFragment.append = function(...args ) {
856
- return anchorFragment.appendChild(args);
857
- };
858
-
859
- anchorFragment.removeChildren = function() {
860
- const parent = anchorEnd.parentNode;
861
- if(parent === anchorFragment) {
862
- return;
863
- }
864
- if(isParentUniqueChild(parent)) {
865
- parent.replaceChildren(anchorStart, anchorEnd);
866
- return;
867
- }
868
-
869
- let itemToRemove = anchorStart.nextSibling, tempItem;
870
- while(itemToRemove && itemToRemove !== anchorEnd) {
871
- tempItem = itemToRemove.nextSibling;
872
- itemToRemove.remove();
873
- itemToRemove = tempItem;
874
- }
875
- };
876
-
877
- anchorFragment.remove = function() {
878
- const parent = anchorEnd.parentNode;
879
- if(parent === anchorFragment) {
880
- return;
881
- }
882
- if(isParentUniqueChild(parent)) {
883
- parent.replaceChildren(anchorStart, anchorEnd);
884
- return;
885
- }
886
- let itemToRemove = anchorStart.nextSibling, tempItem;
887
- while(itemToRemove && itemToRemove !== anchorEnd) {
888
- tempItem = itemToRemove.nextSibling;
889
- anchorFragment.nativeAppend(itemToRemove);
890
- itemToRemove = tempItem;
891
- }
892
- };
893
-
894
- anchorFragment.removeWithAnchors = function() {
895
- anchorFragment.removeChildren();
896
- anchorStart.remove();
897
- anchorEnd.remove();
898
- };
899
-
900
- anchorFragment.replaceContent = function(child) {
901
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
902
- const parent = anchorEnd.parentNode;
903
- if(!parent) {
904
- return;
905
- }
906
- if(isParentUniqueChild(parent)) {
907
- parent.replaceChildren(anchorStart, childElement, anchorEnd);
908
- return;
909
- }
910
- anchorFragment.removeChildren();
911
- parent.insertBefore(childElement, anchorEnd);
912
- };
913
-
914
- anchorFragment.setContent = anchorFragment.replaceContent;
915
-
916
- anchorFragment.insertBefore = function(child, anchor = null) {
917
- anchorFragment.appendChild(child, anchor);
918
- };
919
-
920
- anchorFragment.endElement = function() {
921
- return anchorEnd;
922
- };
923
-
924
- anchorFragment.startElement = function() {
925
- return anchorStart;
926
- };
927
- anchorFragment.restore = function() {
928
- anchorFragment.appendChild(anchorFragment);
929
- };
930
- anchorFragment.clear = anchorFragment.remove;
931
- anchorFragment.detach = anchorFragment.remove;
932
-
933
- anchorFragment.getByIndex = function(index) {
934
- let currentNode = anchorStart;
935
- for(let i = 0; i <= index; i++) {
936
- if(!currentNode.nextSibling) {
937
- return null;
938
- }
939
- currentNode = currentNode.nextSibling;
940
- }
941
- return currentNode !== anchorStart ? currentNode : null;
942
- };
943
-
944
- return anchorFragment;
945
- }
946
- /**
947
- *
948
- * @param {HTMLElement|DocumentFragment|Text|String|Array} children
949
- * @param {{ parent?: HTMLElement, name?: String}} configs
950
- * @returns {DocumentFragment}
951
- */
952
- function createPortal(children, { parent, name = 'unnamed' } = {}) {
953
- const anchor = Anchor('Portal '+name);
954
- anchor.appendChild(ElementCreator.getChild(children));
955
-
956
- (parent || document.body).appendChild(anchor);
957
- return anchor;
958
- }
959
-
960
- DocumentFragment.prototype.setAttribute = () => {};
961
-
962
789
  const BOOLEAN_ATTRIBUTES = new Set([
963
790
  'checked',
964
791
  'selected',
@@ -2647,7 +2474,6 @@ var NativeDocument = (function (exports) {
2647
2474
  this.$hydrate(element, attributeName);
2648
2475
  };
2649
2476
 
2650
- const $nodeCache = new Map();
2651
2477
  let $textNodeCache = null;
2652
2478
 
2653
2479
  const ElementCreator = {
@@ -2677,7 +2503,7 @@ var NativeDocument = (function (exports) {
2677
2503
  * @param {{$hydrate: Function}} item
2678
2504
  * @returns {Text}
2679
2505
  */
2680
- createHydratableNode(parent, item) {
2506
+ createHydratableNode: (parent, item) => {
2681
2507
  const text = ElementCreator.createTextNode();
2682
2508
  item.$hydrate(text);
2683
2509
  return text;
@@ -2689,7 +2515,7 @@ var NativeDocument = (function (exports) {
2689
2515
  * @param {*} value
2690
2516
  * @returns {Text}
2691
2517
  */
2692
- createStaticTextNode(parent, value) {
2518
+ createStaticTextNode: (parent, value) => {
2693
2519
  let text = ElementCreator.createTextNode();
2694
2520
  text.nodeValue = value;
2695
2521
  parent && parent.appendChild(text);
@@ -2701,15 +2527,10 @@ var NativeDocument = (function (exports) {
2701
2527
  * @returns {HTMLElement|DocumentFragment}
2702
2528
  */
2703
2529
  createElement: (name) => {
2704
- if(name) {
2705
- const cacheNode = $nodeCache.get(name);
2706
- if(cacheNode) {
2707
- return cacheNode.cloneNode();
2708
- }
2709
- const node = document.createElement(name);
2710
- $nodeCache.set(name, node);
2711
- return node.cloneNode();
2712
- }
2530
+ const node = document.createElement(name);
2531
+ return node.cloneNode();
2532
+ },
2533
+ createFragment: (name) => {
2713
2534
  return Anchor('Fragment');
2714
2535
  },
2715
2536
  bindTextNode: (textNode, value) => {
@@ -2725,12 +2546,12 @@ var NativeDocument = (function (exports) {
2725
2546
  * @param {*} children
2726
2547
  * @param {HTMLElement|DocumentFragment} parent
2727
2548
  */
2728
- processChildren(children, parent) {
2549
+ processChildren: (children, parent) => {
2729
2550
  if(children === null) return;
2730
2551
  {
2731
2552
  PluginsManager.emit('BeforeProcessChildren', parent);
2732
2553
  }
2733
- let child = this.getChild(children);
2554
+ let child = ElementCreator.getChild(children);
2734
2555
  if(child) {
2735
2556
  parent.appendChild(child);
2736
2557
  }
@@ -2777,6 +2598,164 @@ var NativeDocument = (function (exports) {
2777
2598
  processStyleAttribute: bindStyleAttribute,
2778
2599
  };
2779
2600
 
2601
+ function Anchor(name, isUniqueChild = false) {
2602
+ const anchorFragment = document.createDocumentFragment();
2603
+ anchorFragment.__Anchor__ = true;
2604
+
2605
+ const anchorStart = document.createComment('Anchor Start : '+name);
2606
+ const anchorEnd = document.createComment('/ Anchor End '+name);
2607
+
2608
+ anchorFragment.appendChild(anchorStart);
2609
+ anchorFragment.appendChild(anchorEnd);
2610
+
2611
+ anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
2612
+ anchorFragment.nativeAppendChild = anchorFragment.appendChild;
2613
+ anchorFragment.nativeAppend = anchorFragment.append;
2614
+
2615
+ const isParentUniqueChild = isUniqueChild
2616
+ ? () => true
2617
+ : (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
2618
+
2619
+ const insertBefore = function(parent, child, target) {
2620
+ const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
2621
+ if(parent === anchorFragment) {
2622
+ parent.nativeInsertBefore(childElement, target);
2623
+ return;
2624
+ }
2625
+ if(isParentUniqueChild(parent) && target === anchorEnd) {
2626
+ parent.append(childElement, target);
2627
+ return;
2628
+ }
2629
+ parent.insertBefore(childElement, target);
2630
+ };
2631
+
2632
+ anchorFragment.appendElement = function(child, before = null) {
2633
+ const parentNode = anchorStart.parentNode;
2634
+ const targetBefore = before || anchorEnd;
2635
+ if(parentNode === anchorFragment) {
2636
+ parentNode.nativeInsertBefore(child, targetBefore);
2637
+ return;
2638
+ }
2639
+ parentNode?.insertBefore(child, targetBefore);
2640
+ };
2641
+
2642
+ anchorFragment.appendChild = function(child, before = null) {
2643
+ const parent = anchorEnd.parentNode;
2644
+ if(!parent) {
2645
+ DebugManager.error('Anchor', 'Anchor : parent not found', child);
2646
+ return;
2647
+ }
2648
+ before = before ?? anchorEnd;
2649
+ insertBefore(parent, child, before);
2650
+ };
2651
+
2652
+ anchorFragment.append = function(...args ) {
2653
+ return anchorFragment.appendChild(args);
2654
+ };
2655
+
2656
+ anchorFragment.removeChildren = function() {
2657
+ const parent = anchorEnd.parentNode;
2658
+ if(parent === anchorFragment) {
2659
+ return;
2660
+ }
2661
+ if(isParentUniqueChild(parent)) {
2662
+ parent.replaceChildren(anchorStart, anchorEnd);
2663
+ return;
2664
+ }
2665
+
2666
+ let itemToRemove = anchorStart.nextSibling, tempItem;
2667
+ while(itemToRemove && itemToRemove !== anchorEnd) {
2668
+ tempItem = itemToRemove.nextSibling;
2669
+ itemToRemove.remove();
2670
+ itemToRemove = tempItem;
2671
+ }
2672
+ };
2673
+
2674
+ anchorFragment.remove = function() {
2675
+ const parent = anchorEnd.parentNode;
2676
+ if(parent === anchorFragment) {
2677
+ return;
2678
+ }
2679
+ if(isParentUniqueChild(parent)) {
2680
+ parent.replaceChildren(anchorStart, anchorEnd);
2681
+ return;
2682
+ }
2683
+ let itemToRemove = anchorStart.nextSibling, tempItem;
2684
+ while(itemToRemove && itemToRemove !== anchorEnd) {
2685
+ tempItem = itemToRemove.nextSibling;
2686
+ anchorFragment.nativeAppend(itemToRemove);
2687
+ itemToRemove = tempItem;
2688
+ }
2689
+ };
2690
+
2691
+ anchorFragment.removeWithAnchors = function() {
2692
+ anchorFragment.removeChildren();
2693
+ anchorStart.remove();
2694
+ anchorEnd.remove();
2695
+ };
2696
+
2697
+ anchorFragment.replaceContent = function(child) {
2698
+ const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
2699
+ const parent = anchorEnd.parentNode;
2700
+ if(!parent) {
2701
+ return;
2702
+ }
2703
+ if(isParentUniqueChild(parent)) {
2704
+ parent.replaceChildren(anchorStart, childElement, anchorEnd);
2705
+ return;
2706
+ }
2707
+ anchorFragment.removeChildren();
2708
+ parent.insertBefore(childElement, anchorEnd);
2709
+ };
2710
+
2711
+ anchorFragment.setContent = anchorFragment.replaceContent;
2712
+
2713
+ anchorFragment.insertBefore = function(child, anchor = null) {
2714
+ anchorFragment.appendChild(child, anchor);
2715
+ };
2716
+
2717
+ anchorFragment.endElement = function() {
2718
+ return anchorEnd;
2719
+ };
2720
+
2721
+ anchorFragment.startElement = function() {
2722
+ return anchorStart;
2723
+ };
2724
+ anchorFragment.restore = function() {
2725
+ anchorFragment.appendChild(anchorFragment);
2726
+ };
2727
+ anchorFragment.clear = anchorFragment.remove;
2728
+ anchorFragment.detach = anchorFragment.remove;
2729
+
2730
+ anchorFragment.getByIndex = function(index) {
2731
+ let currentNode = anchorStart;
2732
+ for(let i = 0; i <= index; i++) {
2733
+ if(!currentNode.nextSibling) {
2734
+ return null;
2735
+ }
2736
+ currentNode = currentNode.nextSibling;
2737
+ }
2738
+ return currentNode !== anchorStart ? currentNode : null;
2739
+ };
2740
+
2741
+ return anchorFragment;
2742
+ }
2743
+ /**
2744
+ *
2745
+ * @param {HTMLElement|DocumentFragment|Text|String|Array} children
2746
+ * @param {{ parent?: HTMLElement, name?: String}} configs
2747
+ * @returns {DocumentFragment}
2748
+ */
2749
+ function createPortal(children, { parent, name = 'unnamed' } = {}) {
2750
+ const anchor = Anchor('Portal '+name);
2751
+ anchor.appendChild(ElementCreator.getChild(children));
2752
+
2753
+ (parent || document.body).appendChild(anchor);
2754
+ return anchor;
2755
+ }
2756
+
2757
+ DocumentFragment.prototype.setAttribute = () => {};
2758
+
2780
2759
  const EVENTS = [
2781
2760
  "Click",
2782
2761
  "DblClick",
@@ -3180,7 +3159,10 @@ var NativeDocument = (function (exports) {
3180
3159
  }
3181
3160
 
3182
3161
  const normalizeComponentArgs = function(props, children = null) {
3183
- if(Array.isArray(props) || typeof props !== 'object' || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
3162
+ if(props && children) {
3163
+ return { props, children };
3164
+ }
3165
+ if(typeof props !== 'object' || Array.isArray(props) || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
3184
3166
  return { props: children, children: props }
3185
3167
  }
3186
3168
  return { props, children };
@@ -3191,22 +3173,20 @@ var NativeDocument = (function (exports) {
3191
3173
  * @param {*} value
3192
3174
  * @returns {Text}
3193
3175
  */
3194
- const createTextNode = function(value) {
3176
+ const createTextNode = (value) => {
3195
3177
  return (Validator.isObservable(value))
3196
3178
  ? ElementCreator.createObservableNode(null, value)
3197
3179
  : ElementCreator.createStaticTextNode(null, value);
3198
3180
  };
3199
3181
 
3200
3182
 
3201
- function createHtmlElement($tagName, customWrapper, _attributes, _children = null) {
3183
+ const createHtmlElement = (element, _attributes, _children = null) => {
3202
3184
  let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
3203
- let element = ElementCreator.createElement($tagName);
3204
- let finalElement = (customWrapper && typeof customWrapper === 'function') ? customWrapper(element) : element;
3205
3185
 
3206
- ElementCreator.processAttributes(finalElement, attributes);
3207
- ElementCreator.processChildren(children, finalElement);
3208
- return finalElement;
3209
- }
3186
+ ElementCreator.processAttributes(element, attributes);
3187
+ ElementCreator.processChildren(children, element);
3188
+ return element;
3189
+ };
3210
3190
 
3211
3191
  /**
3212
3192
  *
@@ -3215,341 +3195,233 @@ var NativeDocument = (function (exports) {
3215
3195
  * @returns {Function}
3216
3196
  */
3217
3197
  function HtmlElementWrapper(name, customWrapper = null) {
3218
- return createHtmlElement.bind(null, name, customWrapper);
3219
- }
3220
-
3221
- const cloneBindingsDataCache = new WeakMap();
3198
+ if(name) {
3199
+ if(customWrapper) {
3200
+ let node = null;
3201
+ let createElement = (attr, children) => {
3202
+ node = document.createElement(name);
3203
+ createElement = (attr, children) => {
3204
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children);
3205
+ };
3206
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children); };
3207
+
3208
+ return (attr, children) => createElement(attr, children)
3209
+ }
3210
+
3211
+ let node = null;
3212
+ let createElement = (attr, children) => {
3213
+ node = document.createElement(name);
3214
+ createElement = (attr, children) => {
3215
+ return createHtmlElement(node.cloneNode(), attr, children);
3216
+ };
3217
+ return createHtmlElement(node.cloneNode(), attr, children);
3218
+ };
3222
3219
 
3223
- const pathProcess = (target, path, data) => {
3224
- if(path.HYDRATE_TEXT) {
3225
- const value = path.value;
3226
- ElementCreator.bindTextNode(target, path.isString ? data[0][value] : value.apply(null, data));
3227
- return;
3228
- }
3229
- if(path.ATTACH_METHOD) {
3230
- const bindingData = path.bindingData;
3231
- for(let i = 0, length = bindingData._attachLength; i < length; i++) {
3232
- const method = bindingData.attach[i];
3233
- target.nd[method.methodName](function() {
3234
- method.fn.call(this, ...data, ...arguments);
3235
- });
3236
- }
3220
+ return (attr, children) => createElement(attr, children)
3237
3221
  }
3238
- if(path.HYDRATE_ATTRIBUTES) {
3239
- path.hydrator(target, path.bindingData, data);
3240
- }
3241
- };
3242
-
3243
- const buildAttributesCache = (bindDingData) => {
3244
- const cache = { };
3245
- if(bindDingData.attributes) cache.attributes = {};
3246
- if(bindDingData.classes) cache.class = {};
3247
- if(bindDingData.styles) cache.style = {};
3248
- bindDingData._cache = cache;
3249
- };
3250
-
3251
- const prepareBindingMetadata = (bindDingData) => {
3252
- const attributes = [];
3253
- const classAndStyles = [];
3222
+ return () => Anchor('');
3223
+ }
3254
3224
 
3255
- if(bindDingData.attributes) {
3256
- for (const attr in bindDingData.attributes) {
3257
- attributes.push({
3258
- name: attr,
3259
- value: bindDingData.attributes[attr]
3260
- });
3261
- }
3262
- }
3225
+ function NodeCloner($element) {
3226
+ this.$element = $element;
3227
+ this.$classes = null;
3228
+ this.$styles = null;
3229
+ this.$attrs = null;
3230
+ this.$ndMethods = null;
3231
+ }
3263
3232
 
3264
- if(bindDingData.classes) {
3265
- for (const className in bindDingData.classes) {
3266
- bindDingData._hasClassAttribute = true;
3267
- classAndStyles.push({
3268
- name: 'class',
3269
- key: className,
3270
- value: bindDingData.classes[className]
3271
- });
3272
- }
3273
- }
3274
3233
 
3275
- if(bindDingData.styles) {
3276
- for (const property in bindDingData.styles) {
3277
- bindDingData._hasStyleAttribute = true;
3278
- classAndStyles.push({
3279
- name: 'style',
3280
- key: property,
3281
- value: bindDingData.styles[property]
3282
- });
3283
- }
3234
+ /**
3235
+ * Attaches a template binding to the element by hydrating it with the specified method.
3236
+ *
3237
+ * @param {string} methodName - Name of the hydration method to call
3238
+ * @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
3239
+ * @returns {HTMLElement} The underlying HTML element
3240
+ * @example
3241
+ * const onClick = $binder.attach((event, data) => console.log(data));
3242
+ * element.nd.attach('onClick', onClick);
3243
+ */
3244
+ NDElement.prototype.attach = function(methodName, bindingHydrator) {
3245
+ if(typeof bindingHydrator === 'function') {
3246
+ const element = this.$element;
3247
+ element.nodeCloner = element.nodeCloner || new NodeCloner(element);
3248
+ element.nodeCloner.attach(methodName, bindingHydrator);
3249
+ return element;
3284
3250
  }
3285
-
3286
- bindDingData._flatAttributes = attributes;
3287
- bindDingData._flatAttributesLength = attributes.length;
3288
- bindDingData._flatDynamique = classAndStyles;
3289
- bindDingData._flatDynamiqueLength = classAndStyles.length;
3290
- bindDingData._attachLength = bindDingData.attach.length;
3251
+ bindingHydrator.$hydrate(this.$element, methodName);
3252
+ return this.$element;
3291
3253
  };
3292
3254
 
3255
+ NodeCloner.prototype.__$isNodeCloner = true;
3293
3256
 
3294
- const $hydrateFn = function(hydrateFunction, targetType, element, property) {
3295
- if(!cloneBindingsDataCache.has(element)) {
3296
- cloneBindingsDataCache.set(element, { attach: [] });
3257
+ const buildProperties = (cache, properties, data) => {
3258
+ for(const key in properties) {
3259
+ cache[key] = properties[key].apply(null, data);
3297
3260
  }
3298
- const hydrationState = cloneBindingsDataCache.get(element);
3261
+ return cache;
3262
+ };
3299
3263
 
3300
- if(targetType === 'value') {
3301
- hydrationState.value = hydrateFunction;
3264
+ NodeCloner.prototype.resolve = function() {
3265
+ if(this.$content) {
3302
3266
  return;
3303
3267
  }
3304
- if(targetType === 'attach') {
3305
- hydrationState.attach = hydrationState.attach || [];
3306
- hydrationState.attach.push({ methodName: property, fn: hydrateFunction});
3307
- return;
3308
- }
3309
- hydrationState[targetType] = hydrationState[targetType] || {};
3310
- hydrationState[targetType][property] = hydrateFunction;
3311
- };
3312
-
3313
- const bindAttachMethods = (node, bindDingData, data) => {
3314
- for(let i = 0, length = bindDingData._attachLength; i < length; i++) {
3315
- const method = bindDingData.attach[i];
3316
- node.nd[method.methodName](function() {
3317
- method.fn.call(this, ...data, ...arguments);
3268
+ const steps = [];
3269
+ if(this.$ndMethods) {
3270
+ steps.push((clonedNode, data) => {
3271
+ for(const methodName in this.$ndMethods) {
3272
+ clonedNode.nd[methodName](this.$ndMethods[methodName].bind(clonedNode, ...data));
3273
+ }
3318
3274
  });
3319
3275
  }
3320
- };
3321
-
3322
- const optimizeBindingData = (bindDingData) => {
3323
- buildAttributesCache(bindDingData);
3324
- prepareBindingMetadata(bindDingData);
3325
- };
3326
-
3327
-
3328
- const $applyBindingParents = [];
3329
- const hydrateClonedNode = (root, data, paths, pathSize) => {
3330
- const rootPath = paths[pathSize];
3331
- $applyBindingParents[rootPath.id] = root;
3332
- pathProcess(root, rootPath, data);
3333
-
3334
- let target = null, path = null;
3335
- for(let i = 0; i < pathSize; i++) {
3336
- path = paths[i];
3337
- target = $applyBindingParents[path.parentId].childNodes[path.index];
3338
- $applyBindingParents[path.id] = target;
3339
-
3340
- if(path.HYDRATE_TEXT) {
3341
- const value = path.value;
3342
- ElementCreator.bindTextNode(target, path.isString ? data[0][value] : value.apply(null, data));
3343
- continue;
3344
- }
3345
- if(path.ATTACH_METHOD) {
3346
- const bindingData = path.bindingData;
3347
- for(let i = 0, length = bindingData._attachLength; i < length; i++) {
3348
- const method = bindingData.attach[i];
3349
- target.nd[method.methodName](function() {
3350
- method.fn.call(this, ...data, ...arguments);
3351
- });
3352
- }
3353
- }
3354
- if(path.HYDRATE_ATTRIBUTES) {
3355
- path.hydrator(target, path.bindingData, data);
3356
- }
3276
+ if(this.$classes) {
3277
+ const cache = {};
3278
+ steps.push((clonedNode, data) => {
3279
+ ElementCreator.processClassAttribute(clonedNode, buildProperties(cache, this.$classes, data));
3280
+ });
3357
3281
  }
3358
-
3359
- for (let i = 0; i <= pathSize; i++) {
3360
- $applyBindingParents[i] = null;
3282
+ if(this.$styles) {
3283
+ const cache = {};
3284
+ steps.push((clonedNode, data) => {
3285
+ ElementCreator.processStyleAttribute(clonedNode, buildProperties(cache, this.$styles, data));
3286
+ });
3361
3287
  }
3362
- };
3363
-
3364
- const hydrateFull = (node, bindDingData, data) => {
3365
- const cacheAttributes = bindDingData._cache;
3366
-
3367
- for(let i = 0, length = bindDingData._flatAttributesLength; i < length; i++) {
3368
- const attr = bindDingData._flatAttributes[i];
3369
- cacheAttributes[attr.name] = attr.value.apply(null, data);
3288
+ if(this.$attrs) {
3289
+ const cache = {};
3290
+ steps.push((clonedNode, data) => {
3291
+ ElementCreator.processAttributes(clonedNode, buildProperties(cache, this.$attrs, data));
3292
+ });
3370
3293
  }
3371
3294
 
3372
- for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
3373
- const dyn = bindDingData._flatDynamique[i];
3374
- cacheAttributes[dyn.name][dyn.key] = dyn.value.apply(null, data);
3375
- }
3295
+ const stepsCount = steps.length;
3296
+ const $element = this.$element;
3376
3297
 
3377
- ElementCreator.processAttributesDirect(node, cacheAttributes);
3378
- return true;
3298
+ this.cloneNode = (data) => {
3299
+ const clonedNode = $element.cloneNode(false);
3300
+ for(let i = 0; i < stepsCount; i++) {
3301
+ steps[i](clonedNode, data);
3302
+ }
3303
+ return clonedNode;
3304
+ };
3379
3305
  };
3380
3306
 
3381
- const hydrateDynamic = (node, bindDingData, data) => {
3382
- const cacheAttributes = bindDingData._cache;
3383
-
3384
- for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
3385
- const dyn = bindDingData._flatDynamique[i];
3386
- cacheAttributes[dyn.name][dyn.key] = dyn.value.apply(null, data);
3387
- }
3388
-
3389
- ElementCreator.processClassAttribute(node, cacheAttributes.class);
3390
- ElementCreator.processStyleAttribute(node, cacheAttributes.style);
3391
- return true;
3307
+ NodeCloner.prototype.cloneNode = function(data) {
3308
+ return this.$element.cloneNode(false);
3392
3309
  };
3393
3310
 
3394
- const hydrateClassAttribute = (node, bindDingData, data) => {
3395
- const classAttributes = bindDingData._cache.class;
3396
-
3397
- for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
3398
- const dyn = bindDingData._flatDynamique[i];
3399
- classAttributes[dyn.key] = dyn.value.apply(null, data);
3400
- }
3401
-
3402
- ElementCreator.processClassAttribute(node, classAttributes);
3403
- return true;
3311
+ NodeCloner.prototype.attach = function(methodName, callback) {
3312
+ this.$ndMethods = this.$ndMethods || {};
3313
+ this.$ndMethods[methodName] = callback;
3314
+ return this;
3404
3315
  };
3405
3316
 
3406
- const hydrateStyleAttribute = (node, bindDingData, data) => {
3407
- const styleAttributes = bindDingData._cache;
3408
-
3409
- for(let i = 0, length = bindDingData._flatDynamiqueLength; i < length; i++) {
3410
- const dyn = bindDingData._flatDynamique[i];
3411
- styleAttributes[dyn.key] = dyn.value.apply(null, data);
3317
+ NodeCloner.prototype.text = function(value) {
3318
+ this.$content = value;
3319
+ if(typeof value === 'function') {
3320
+ this.cloneNode = (data) => createTextNode(value.apply(null, data));
3321
+ return this;
3412
3322
  }
3413
-
3414
- ElementCreator.processStyleAttribute(node, styleAttributes);
3415
- return true;
3323
+ this.cloneNode = (data) => createTextNode(data[0][value]);
3324
+ return this;
3416
3325
  };
3417
3326
 
3418
- const hydrateAttributes = (node, bindDingData, data) => {
3419
- const cacheAttributes = bindDingData._cache;
3420
-
3421
- for(let i = 0, length = bindDingData._flatAttributesLength; i < length; i++) {
3422
- const attr = bindDingData._flatAttributes[i];
3423
- cacheAttributes[attr.name] = attr.value.apply(null, data);
3327
+ NodeCloner.prototype.attr = function(attrName, value) {
3328
+ if(attrName === 'class') {
3329
+ this.$classes = this.$classes || {};
3330
+ this.$classes[value.property] = value.value;
3331
+ return this;
3424
3332
  }
3425
-
3426
- ElementCreator.processAttributesDirect(node, cacheAttributes);
3427
- return true;
3333
+ if(attrName === 'style') {
3334
+ this.$styles = this.$styles || {};
3335
+ this.$styles[value.property] = value.value;
3336
+ return this;
3337
+ }
3338
+ this.$attrs = this.$attrs || {};
3339
+ this.$attrs[attrName] = value.value;
3340
+ return this;
3428
3341
  };
3429
3342
 
3430
- const getHydrator = (bindDingData) => {
3431
- if(!bindDingData._cache) {
3432
- return noUpdate;
3433
- }
3434
- if(bindDingData._flatAttributesLength && bindDingData._flatDynamiqueLength) {
3435
- return hydrateFull;
3436
- }
3437
- if(bindDingData._flatAttributesLength) {
3438
- return hydrateAttributes;
3439
- }
3440
- if(bindDingData._hasClassAttribute && bindDingData._hasStyleAttribute) {
3441
- return hydrateDynamic;
3343
+ const $hydrateFn = function(value, targetType, element, property) {
3344
+ element.nodeCloner = element.nodeCloner || new NodeCloner(element);
3345
+ if(targetType === 'value') {
3346
+ element.nodeCloner.text(value);
3347
+ return;
3442
3348
  }
3443
- if(bindDingData._hasClassAttribute) {
3444
- return hydrateClassAttribute;
3349
+ if(targetType === 'attach') {
3350
+ element.nodeCloner.attach(property, value);
3351
+ return;
3445
3352
  }
3446
- return hydrateStyleAttribute;
3353
+ element.nodeCloner.attr(targetType, { property, value });
3447
3354
  };
3448
3355
 
3449
3356
  function TemplateCloner($fn) {
3450
3357
  let $node = null;
3451
- let $hasBindingData = false;
3452
-
3453
- let $bindingTreePathSize = 0;
3454
- const $bindingTreePath = [
3455
- {
3456
- id: 0,
3457
- parentId: null
3458
- }
3459
- ];
3460
-
3461
- let pathCounter = 0;
3462
- const clone = (node, data, currentPath) => {
3463
- const bindDingData = cloneBindingsDataCache.get(node);
3464
- if(bindDingData) {
3465
- optimizeBindingData(bindDingData);
3466
- }
3467
- if(node.nodeType === 3) {
3468
- if(bindDingData && bindDingData.value) {
3469
- const value = bindDingData.value;
3470
- const textNode = node.cloneNode();
3471
- currentPath.value = value;
3472
- currentPath.HYDRATE_TEXT = true;
3473
- currentPath.operation = true;
3474
- currentPath.isString = (typeof value === 'string');
3475
- ElementCreator.bindTextNode(textNode, (currentPath.isString ? data[0][value] : value.apply(null, data)));
3476
- return textNode;
3477
- }
3478
- return node.cloneNode(true);
3479
- }
3480
- const nodeCloned = node.cloneNode();
3481
- if(bindDingData) {
3482
- const hydrator = getHydrator(bindDingData);
3483
- hydrator(nodeCloned, bindDingData, data);
3484
- bindAttachMethods(nodeCloned, bindDingData, data);
3485
-
3486
- const hasAttributes = bindDingData.classes || bindDingData.styles || bindDingData.attributes;
3487
- const hasAttachMethods = bindDingData.attach.length;
3488
3358
 
3489
- currentPath.bindingData = bindDingData;
3490
- currentPath.hydrator = hydrator;
3491
-
3492
- if(hasAttributes) {
3493
- currentPath.HYDRATE_ATTRIBUTES = true;
3494
- currentPath.operation = true;
3359
+ const assignClonerToNode = ($node) => {
3360
+ const childNodes = $node.childNodes;
3361
+ let containDynamicNode = !!$node.nodeCloner;
3362
+ const childNodesLength = childNodes.length;
3363
+ for(let i = 0; i < childNodesLength; i++) {
3364
+ const child = childNodes[i];
3365
+ if(child.nodeCloner) {
3366
+ containDynamicNode = true;
3495
3367
  }
3496
- if(hasAttachMethods) {
3497
- currentPath.ATTACH_METHOD = true;
3498
- currentPath.operation = true;
3368
+ const localContainDynamicNode = assignClonerToNode(child);
3369
+ if(localContainDynamicNode) {
3370
+ containDynamicNode = true;
3499
3371
  }
3500
3372
  }
3501
- const childNodes = node.childNodes;
3502
- const parentId = currentPath.id;
3503
3373
 
3504
- for(let i = 0, length = childNodes.length; i < length; i++) {
3505
- const childNode = childNodes[i];
3506
- const path = { parentId, id: ++pathCounter, index: i };
3507
- const childNodeCloned = clone(childNode, data, path);
3508
- if(path.hasChildren || path.operation) {
3509
- $bindingTreePath.push(path);
3510
- currentPath.hasChildren = true;
3374
+ if(!containDynamicNode) {
3375
+ $node.dynamicCloneNode = $node.cloneNode.bind($node, true);
3376
+ } else {
3377
+ if($node.nodeCloner) {
3378
+ $node.nodeCloner.resolve();
3379
+ $node.dynamicCloneNode = (data) => {
3380
+ const clonedNode = $node.nodeCloner.cloneNode(data);
3381
+ for(let i = 0; i < childNodesLength; i++) {
3382
+ const child = childNodes[i].dynamicCloneNode(data);
3383
+ clonedNode.appendChild(child);
3384
+ }
3385
+ return clonedNode;
3386
+ };
3387
+ } else {
3388
+ $node.dynamicCloneNode = (data) => {
3389
+ const clonedNode = $node.cloneNode();
3390
+ for(let i = 0; i < childNodesLength; i++) {
3391
+ const child = childNodes[i].dynamicCloneNode(data);
3392
+ clonedNode.appendChild(child);
3393
+ }
3394
+ return clonedNode;
3395
+ };
3511
3396
  }
3512
- nodeCloned.appendChild(childNodeCloned);
3513
3397
  }
3514
- return nodeCloned;
3515
- };
3516
-
3517
- const cloneWithBindingPaths = (data) => {
3518
- let root = $node.cloneNode(true);
3519
3398
 
3520
- hydrateClonedNode(root, data, $bindingTreePath, $bindingTreePathSize);
3521
- return root;
3399
+ return containDynamicNode;
3522
3400
  };
3523
3401
 
3524
3402
  this.clone = (data) => {
3525
3403
  const binder = createTemplateCloner(this);
3526
3404
  $node = $fn(binder);
3527
- if(!$hasBindingData) {
3528
- this.clone = () => $node.cloneNode(true);
3529
- return $node.cloneNode(true);
3405
+ if(!$node.nodeCloner) {
3406
+ $node.nodeCloner = new NodeCloner($node);
3530
3407
  }
3531
-
3532
- const firstClone = clone($node, data, $bindingTreePath[0]);
3533
- $bindingTreePath.reverse();
3534
- $bindingTreePathSize = $bindingTreePath.length - 1;
3535
-
3536
- this.clone = cloneWithBindingPaths;
3537
- return firstClone;
3408
+ assignClonerToNode($node);
3409
+ this.clone = $node.dynamicCloneNode;
3410
+ return $node.dynamicCloneNode(data);
3538
3411
  };
3539
3412
 
3540
3413
 
3541
3414
  const createBinding = (hydrateFunction, targetType) => {
3542
3415
  return new TemplateBinding((element, property) => {
3543
- $hasBindingData = true;
3544
3416
  $hydrateFn(hydrateFunction, targetType, element, property);
3545
3417
  });
3546
3418
  };
3547
3419
 
3548
3420
  this.style = (fn) => {
3549
- return createBinding(fn, 'styles');
3421
+ return createBinding(fn, 'style');
3550
3422
  };
3551
3423
  this.class = (fn) => {
3552
- return createBinding(fn, 'classes');
3424
+ return createBinding(fn, 'class');
3553
3425
  };
3554
3426
  this.property = (propertyName) => {
3555
3427
  return this.value(propertyName);
@@ -3586,10 +3458,9 @@ var NativeDocument = (function (exports) {
3586
3458
  let wrapper = (args) => {
3587
3459
  $cache = new TemplateCloner(fn);
3588
3460
 
3589
- wrapper = (args) => {
3590
- return $cache.clone(args);
3591
- };
3592
- return $cache.clone(args);
3461
+ const node = $cache.clone(args);
3462
+ wrapper = $cache.clone;
3463
+ return node;
3593
3464
  };
3594
3465
 
3595
3466
  if(fn.length < 2) {