native-document 1.0.34 → 1.0.36

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.
@@ -165,10 +165,11 @@ var NativeDocument = (function (exports) {
165
165
  }
166
166
  for(const methodName in plugin) {
167
167
  if(/^on[A-Z]/.test(methodName)) {
168
- if(!$pluginByEvents.has(methodName)) {
169
- $pluginByEvents.set(methodName, new Set());
168
+ const eventName = methodName.replace(/^on/, '');
169
+ if(!$pluginByEvents.has(eventName)) {
170
+ $pluginByEvents.set(eventName, new Set());
170
171
  }
171
- $pluginByEvents.get(methodName).add(plugin);
172
+ $pluginByEvents.get(eventName).add(plugin);
172
173
  }
173
174
  }
174
175
  },
@@ -190,20 +191,19 @@ var NativeDocument = (function (exports) {
190
191
  }
191
192
  $plugins.delete(pluginName);
192
193
  },
193
- emit(event, ...data) {
194
- const eventMethodName = 'on'+event;
195
- if(!$pluginByEvents.has(eventMethodName)) {
194
+ emit(eventName, ...data) {
195
+ if(!$pluginByEvents.has(eventName)) {
196
196
  return;
197
197
  }
198
- const plugins = $pluginByEvents.get(eventMethodName);
198
+ const plugins = $pluginByEvents.get(eventName);
199
199
 
200
200
  for(const plugin of plugins) {
201
- const callback = plugin[eventMethodName];
201
+ const callback = plugin[eventName];
202
202
  if(typeof callback === 'function') {
203
203
  try{
204
204
  callback.call(plugin, ...data);
205
205
  } catch (error) {
206
- DebugManager$1.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventMethodName}`, error);
206
+ DebugManager$1.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventName}`, error);
207
207
  }
208
208
  }
209
209
  }
@@ -217,7 +217,7 @@ var NativeDocument = (function (exports) {
217
217
  * @class ObservableItem
218
218
  */
219
219
  function ObservableItem(value) {
220
- this.$previousValue = value;
220
+ this.$previousValue = null;
221
221
  this.$currentValue = value;
222
222
  this.$isCleanedUp = false;
223
223
 
@@ -241,19 +241,33 @@ var NativeDocument = (function (exports) {
241
241
  ObservableItem.prototype.__$isObservable = true;
242
242
 
243
243
  const noneTrigger = function() {};
244
+ ObservableItem.prototype.triggerFirstListener = function(operations) {
245
+ this.$listeners[0](this.$currentValue, this.$previousValue, operations || {});
246
+ };
244
247
  ObservableItem.prototype.triggerListeners = function(operations) {
245
248
  const $listeners = this.$listeners;
246
249
  const $previousValue = this.$previousValue;
247
250
  const $currentValue = this.$currentValue;
248
251
 
249
- operations = operations || {};
250
- if($listeners?.length) {
251
- for(let i = 0, length = $listeners.length; i < length; i++) {
252
- $listeners[i]($currentValue, $previousValue, operations);
253
- }
252
+ operations = operations || DEFAULT_OPERATIONS;
253
+ for(let i = 0, length = $listeners.length; i < length; i++) {
254
+ $listeners[i]($currentValue, $previousValue, operations);
254
255
  }
255
256
  };
256
257
 
258
+ const handleWatcherCallback = function(callbacks, value) {
259
+ if(typeof callbacks === "function") {
260
+ callbacks(value);
261
+ return;
262
+ }
263
+ if (callbacks.set) {
264
+ callbacks.set(value);
265
+ return;
266
+ }
267
+ callbacks.forEach(callback => {
268
+ callback.set ? callback.set(value) : callback(value);
269
+ });
270
+ };
257
271
  ObservableItem.prototype.triggerWatchers = function() {
258
272
  if(!this.$watchers) {
259
273
  return;
@@ -265,28 +279,11 @@ var NativeDocument = (function (exports) {
265
279
 
266
280
  if($watchers.has($currentValue)) {
267
281
  const $currentValueCallbacks = $watchers.get($currentValue);
268
- if(typeof $currentValueCallbacks === "function") {
269
- $currentValueCallbacks(true);
270
- } else if ($currentValueCallbacks.set) {
271
- $currentValueCallbacks.set(true);
272
- }
273
- else {
274
- $currentValueCallbacks.forEach(callback => {
275
- callback.set ? callback.set(true) : callback(true);
276
- });
277
- }
282
+ handleWatcherCallback($currentValueCallbacks, true);
278
283
  }
279
284
  if($watchers.has($previousValue)) {
280
285
  const $previousValueCallbacks = $watchers.get($previousValue);
281
- if(typeof $previousValueCallbacks === "function") {
282
- $previousValueCallbacks(false);
283
- } else if($previousValueCallbacks.set) {
284
- $previousValueCallbacks.set(false);
285
- } else {
286
- $previousValueCallbacks.forEach(callback => {
287
- callback.set ? callback.set(false) : callback(false);
288
- });
289
- }
286
+ handleWatcherCallback($previousValueCallbacks, false);
290
287
  }
291
288
  };
292
289
 
@@ -295,13 +292,18 @@ var NativeDocument = (function (exports) {
295
292
  this.triggerWatchers();
296
293
  };
297
294
 
295
+ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations) {
296
+ this.triggerListeners(operations);
297
+ this.triggerWatchers();
298
+ };
299
+
298
300
  ObservableItem.prototype.assocTrigger = function() {
299
301
  if(this.$watchers?.size && this.$listeners?.length) {
300
- this.trigger = this.triggerAll;
302
+ this.trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
301
303
  return;
302
304
  }
303
305
  if(this.$listeners?.length) {
304
- this.trigger = this.triggerListeners;
306
+ this.trigger = (this.$listeners.length === 1) ? this.triggerFirstListener : this.triggerListeners;
305
307
  return;
306
308
  }
307
309
  if(this.$watchers?.size) {
@@ -461,7 +463,7 @@ var NativeDocument = (function (exports) {
461
463
  if(!Validator.isObject(item)) {
462
464
  return item;
463
465
  }
464
- return item[key] ?? defaultKey;
466
+ return item[key]?.val?.() ?? item[key] ?? defaultKey;
465
467
  };
466
468
 
467
469
  const trim = function(str, char) {
@@ -633,35 +635,7 @@ var NativeDocument = (function (exports) {
633
635
  }
634
636
  NDElement.prototype.__$isNDElement = true;
635
637
 
636
- for(const event of EVENTS) {
637
- const eventName = event.toLowerCase();
638
- NDElement.prototype['on'+event] = function(callback) {
639
- this.$element.addEventListener(eventName, callback);
640
- return this;
641
- };
642
- NDElement.prototype['onPrevent'+event] = function(callback) {
643
- this.$element.addEventListener(eventName, function(event) {
644
- event.preventDefault();
645
- callback && callback(event);
646
- });
647
- return this;
648
- };
649
- NDElement.prototype['onStop'+event] = function(callback) {
650
- this.$element.addEventListener(eventName, function(event) {
651
- event.stopPropagation();
652
- callback && callback(event);
653
- });
654
- return this;
655
- };
656
- NDElement.prototype['onPreventStop'+event] = function(callback) {
657
- this.$element.addEventListener(eventName, function(event) {
658
- event.stopPropagation();
659
- event.preventDefault();
660
- callback && callback(event);
661
- });
662
- return this;
663
- };
664
- }
638
+
665
639
 
666
640
  NDElement.prototype.valueOf = function() {
667
641
  return this.$element;
@@ -717,20 +691,26 @@ var NativeDocument = (function (exports) {
717
691
 
718
692
  NDElement.prototype.node = NDElement.prototype.htmlElement;
719
693
 
720
- NDElement.prototype.attach = function(methodName, bindingHydrator) {
721
- bindingHydrator.$hydrate(this.$element, methodName);
694
+ NDElement.prototype.attach = function(bindingHydrator) {
695
+ bindingHydrator.$hydrate(this.$element);
722
696
  return this.$element;
723
697
  };
724
698
 
699
+ const COMMON_NODE_TYPES = {
700
+ ELEMENT: 1,
701
+ TEXT: 3,
702
+ DOCUMENT_FRAGMENT: 11
703
+ };
704
+
725
705
  const Validator = {
726
706
  isObservable(value) {
727
- return value instanceof ObservableItem || value instanceof ObservableChecker || value?.__$isObservable;
707
+ return value?.__$isObservable || value instanceof ObservableItem || value instanceof ObservableChecker;
728
708
  },
729
709
  isProxy(value) {
730
710
  return value?.__isProxy__
731
711
  },
732
712
  isObservableChecker(value) {
733
- return value instanceof ObservableChecker || value?.__$isObservableChecker;
713
+ return value?.__$isObservableChecker || value instanceof ObservableChecker;
734
714
  },
735
715
  isArray(value) {
736
716
  return Array.isArray(value);
@@ -754,13 +734,17 @@ var NativeDocument = (function (exports) {
754
734
  return typeof value === 'object';
755
735
  },
756
736
  isJson(value) {
757
- return typeof value === 'object' && value !== null && value.constructor.name === 'Object' && !Array.isArray(value);
737
+ return typeof value === 'object' && value !== null && !Array.isArray(value) && value.constructor.name === 'Object';
758
738
  },
759
739
  isElement(value) {
760
- return value instanceof HTMLElement || value instanceof DocumentFragment || value instanceof Text;
740
+ return value && (
741
+ value.nodeType === COMMON_NODE_TYPES.ELEMENT ||
742
+ value.nodeType === COMMON_NODE_TYPES.TEXT ||
743
+ value.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT
744
+ );
761
745
  },
762
746
  isFragment(value) {
763
- return value instanceof DocumentFragment;
747
+ return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
764
748
  },
765
749
  isStringOrObservable(value) {
766
750
  return this.isString(value) || this.isObservable(value);
@@ -773,7 +757,7 @@ var NativeDocument = (function (exports) {
773
757
  ['string', 'number', 'boolean'].includes(typeof child);
774
758
  },
775
759
  isNDElement(child) {
776
- return child instanceof NDElement || child?.constructor?.__$isNDElement;
760
+ return child?.__$isNDElement || child instanceof NDElement;
777
761
  },
778
762
  isValidChildren(children) {
779
763
  if (!Array.isArray(children)) {
@@ -818,7 +802,16 @@ var NativeDocument = (function (exports) {
818
802
  }
819
803
  return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
820
804
  },
821
- validateAttributes(attributes) {
805
+ validateAttributes(attributes) {},
806
+
807
+ validateEventCallback(callback) {
808
+ if (typeof callback !== 'function') {
809
+ throw new NativeDocumentError('Event callback must be a function');
810
+ }
811
+ }
812
+ };
813
+ {
814
+ Validator.validateAttributes = function(attributes) {
822
815
  if (!attributes || typeof attributes !== 'object') {
823
816
  return attributes;
824
817
  }
@@ -831,14 +824,8 @@ var NativeDocument = (function (exports) {
831
824
  }
832
825
 
833
826
  return attributes;
834
- },
835
-
836
- validateEventCallback(callback) {
837
- if (typeof callback !== 'function') {
838
- throw new NativeDocumentError('Event callback must be a function');
839
- }
840
- }
841
- };
827
+ };
828
+ }
842
829
 
843
830
  function Anchor(name, isUniqueChild = false) {
844
831
  const element = document.createDocumentFragment();
@@ -852,13 +839,15 @@ var NativeDocument = (function (exports) {
852
839
  element.nativeInsertBefore = element.insertBefore;
853
840
  element.nativeAppendChild = element.appendChild;
854
841
 
842
+ const isParentUniqueChild = (parent) => (isUniqueChild || (parent.firstChild === anchorStart && parent.lastChild === anchorEnd));
843
+
855
844
  const insertBefore = function(parent, child, target) {
856
845
  const element = Validator.isElement(child) ? child : ElementCreator.getChild(child);
857
846
  if(parent === element) {
858
847
  parent.nativeInsertBefore(element, target);
859
848
  return;
860
849
  }
861
- if(isUniqueChild || target === anchorEnd) {
850
+ if(isParentUniqueChild(parent) || target === anchorEnd) {
862
851
  parent.append(element, target);
863
852
  return;
864
853
  }
@@ -866,17 +855,13 @@ var NativeDocument = (function (exports) {
866
855
  };
867
856
 
868
857
  element.appendElement = function(child, before = null) {
869
- if(isUniqueChild) {
870
- (before && before !== anchorEnd)
871
- ? anchorEnd.parentNode.insertBefore(child, anchorEnd)
872
- : anchorEnd.parentNode.append(child, anchorEnd);
873
- return;
874
- }
875
- if(anchorEnd.parentNode === element) {
876
- anchorEnd.parentNode.nativeInsertBefore(child, before || anchorEnd);
858
+ const parentNode = anchorStart.parentNode;
859
+ const targetBefore = before || anchorEnd;
860
+ if(parentNode === element) {
861
+ parentNode.nativeInsertBefore(child, targetBefore);
877
862
  return;
878
863
  }
879
- anchorEnd.parentNode?.insertBefore(child, before || anchorEnd);
864
+ parentNode?.insertBefore(child, targetBefore);
880
865
  };
881
866
 
882
867
  element.appendChild = function(child, before = null) {
@@ -894,7 +879,7 @@ var NativeDocument = (function (exports) {
894
879
  if(parent === element) {
895
880
  return;
896
881
  }
897
- if(isUniqueChild || (parent.firstChild === anchorStart && parent.lastChild === anchorEnd)) {
882
+ if(isParentUniqueChild(parent)) {
898
883
  parent.replaceChildren(anchorStart, anchorEnd);
899
884
  return;
900
885
  }
@@ -913,7 +898,7 @@ var NativeDocument = (function (exports) {
913
898
  if(parent === element) {
914
899
  return;
915
900
  }
916
- if(isUniqueChild) {
901
+ if(isParentUniqueChild(parent)) {
917
902
  parent.replaceChildren(anchorEnd, anchorEnd);
918
903
  return;
919
904
  }
@@ -936,7 +921,7 @@ var NativeDocument = (function (exports) {
936
921
  if(!parent) {
937
922
  return;
938
923
  }
939
- if(isUniqueChild || (parent.firstChild === anchorStart && parent.lastChild === anchorEnd)) {
924
+ if(isParentUniqueChild(parent)) {
940
925
  parent.replaceChildren(anchorStart, child, anchorEnd);
941
926
  return;
942
927
  }
@@ -955,10 +940,22 @@ var NativeDocument = (function (exports) {
955
940
  element.endElement = function() {
956
941
  return anchorEnd;
957
942
  };
943
+
958
944
  element.startElement = function() {
959
945
  return anchorStart;
960
946
  };
961
947
 
948
+ element.getByIndex = function(index) {
949
+ let currentNode = anchorStart;
950
+ for(let i = 0; i <= index; i++) {
951
+ if(!currentNode.nextSibling) {
952
+ return null;
953
+ }
954
+ currentNode = currentNode.nextSibling;
955
+ }
956
+ return currentNode !== anchorStart ? currentNode : null;
957
+ };
958
+
962
959
  return element;
963
960
  }
964
961
 
@@ -1013,6 +1010,26 @@ var NativeDocument = (function (exports) {
1013
1010
  setInterval(() => MemoryManager.cleanObservables(threshold), interval);
1014
1011
  };
1015
1012
 
1013
+ function toggleElementClass(element, className, shouldAdd) {
1014
+ element.classes.toggle(className, shouldAdd);
1015
+ }
1016
+ function toggleElementStyle(element, styleName, newValue) {
1017
+ element.style[styleName] = newValue;
1018
+ }
1019
+ function updateInputFromObserver(element, attributeName, newValue) {
1020
+ if(Validator.isBoolean(newValue)) {
1021
+ element[attributeName] = newValue;
1022
+ return;
1023
+ }
1024
+ element[attributeName] = newValue === element.value;
1025
+ }
1026
+ function updateObserverFromInput(element, attributeName, defaultValue, value) {
1027
+ if(Validator.isBoolean(defaultValue)) {
1028
+ value.set(element[attributeName]);
1029
+ return;
1030
+ }
1031
+ value.set(element.value);
1032
+ }
1016
1033
  /**
1017
1034
  *
1018
1035
  * @param {HTMLElement} element
@@ -1022,23 +1039,22 @@ var NativeDocument = (function (exports) {
1022
1039
  for(let className in data) {
1023
1040
  const value = data[className];
1024
1041
  if(Validator.isObservable(value)) {
1025
- element.classList.toggle(className, value.val());
1026
- value.subscribe(newValue => element.classList.toggle(className, newValue));
1042
+ element.classes.toggle(className, value.val());
1043
+ value.subscribe(toggleElementClass.bind(null, element, className));
1027
1044
  continue;
1028
1045
  }
1029
1046
  if(value.$observer) {
1030
- element.classList.toggle(className, value.$observer.val() === value.$target);
1031
- value.$observer.on(value.$target, function(isTargetValue) {
1032
- element.classList.toggle(className, isTargetValue);
1033
- });
1047
+ element.classes.toggle(className, value.$observer.val() === value.$target);
1048
+ value.$observer.on(value.$target, toggleElementClass.bind(null, element, className));
1034
1049
  continue;
1035
1050
  }
1036
1051
  if(value.$hydrate) {
1037
1052
  value.$hydrate(element, className);
1038
1053
  continue;
1039
1054
  }
1040
- element.classList.toggle(className, value);
1055
+ element.classes.toggle(className, value);
1041
1056
  }
1057
+ data = null;
1042
1058
  }
1043
1059
 
1044
1060
  /**
@@ -1051,9 +1067,7 @@ var NativeDocument = (function (exports) {
1051
1067
  const value = data[styleName];
1052
1068
  if(Validator.isObservable(value)) {
1053
1069
  element.style[styleName] = value.val();
1054
- value.subscribe(newValue => {
1055
- element.style[styleName] = newValue;
1056
- });
1070
+ value.subscribe(toggleElementStyle.bind(null, element, styleName));
1057
1071
  continue;
1058
1072
  }
1059
1073
  element.style[styleName] = value;
@@ -1076,21 +1090,9 @@ var NativeDocument = (function (exports) {
1076
1090
  }
1077
1091
  if(Validator.isObservable(value)) {
1078
1092
  if(['checked'].includes(attributeName)) {
1079
- element.addEventListener('input', () => {
1080
- if(Validator.isBoolean(defaultValue)) {
1081
- value.set(element[attributeName]);
1082
- return;
1083
- }
1084
- value.set(element.value);
1085
- });
1093
+ element.addEventListener('input', updateObserverFromInput.bind(null, element, attributeName, defaultValue));
1086
1094
  }
1087
- value.subscribe(newValue => {
1088
- if(Validator.isBoolean(newValue)) {
1089
- element[attributeName] = newValue;
1090
- return;
1091
- }
1092
- element[attributeName] = newValue === element.value;
1093
- });
1095
+ value.subscribe(updateInputFromObserver.bind(null, element, attributeName));
1094
1096
  }
1095
1097
  }
1096
1098
 
@@ -1144,11 +1146,11 @@ var NativeDocument = (function (exports) {
1144
1146
  return value.map(item => Validator.isObservable(item) ? item.val() : item).join(' ') || ' ';
1145
1147
  }, observables);
1146
1148
  }
1147
- if(attributeName === 'class' && Validator.isJson(value)) {
1149
+ if(attributeName === 'class' && Validator.isObject(value)) {
1148
1150
  bindClassAttribute(element, value);
1149
1151
  continue;
1150
1152
  }
1151
- if(attributeName === 'style' && Validator.isJson(value)) {
1153
+ if(attributeName === 'style' && Validator.isObject(value)) {
1152
1154
  bindStyleAttribute(element, value);
1153
1155
  continue;
1154
1156
  }
@@ -1160,6 +1162,10 @@ var NativeDocument = (function (exports) {
1160
1162
  bindAttributeWithObservable(element, attributeName, value);
1161
1163
  continue;
1162
1164
  }
1165
+ if(value.$hydrate) {
1166
+ value.$hydrate(element, attributeName);
1167
+ continue;
1168
+ }
1163
1169
  element.setAttribute(attributeName, value);
1164
1170
 
1165
1171
  }
@@ -1236,14 +1242,19 @@ var NativeDocument = (function (exports) {
1236
1242
  */
1237
1243
  processChildren(children, parent) {
1238
1244
  if(children === null) return;
1239
- const childrenArray = Array.isArray(children) ? children : [children];
1240
-
1241
1245
  PluginsManager.emit('BeforeProcessChildren', parent);
1242
-
1243
- for(let i = 0, length = childrenArray.length; i < length; i++) {
1244
- let child = this.getChild(childrenArray[i]);
1245
- if (child === null) continue;
1246
- parent.appendChild(child);
1246
+ if(!Array.isArray(children)) {
1247
+ let child = this.getChild(children);
1248
+ if(child) {
1249
+ parent.appendChild(child);
1250
+ }
1251
+ }
1252
+ else {
1253
+ for(let i = 0, length = children.length; i < length; i++) {
1254
+ let child = this.getChild(children[i]);
1255
+ if (child === null) continue;
1256
+ parent.appendChild(child);
1257
+ }
1247
1258
  }
1248
1259
 
1249
1260
  PluginsManager.emit('AfterProcessChildren', parent);
@@ -1310,13 +1321,60 @@ var NativeDocument = (function (exports) {
1310
1321
  Object.defineProperty(HTMLElement.prototype, 'nd', {
1311
1322
  configurable: true,
1312
1323
  get() {
1313
- if(this.$nd) {
1314
- return this.$nd;
1324
+ return new NDElement(this);
1325
+ }
1326
+ });
1327
+
1328
+ const classListMethods = {
1329
+ getClasses() {
1330
+ return this.$element.className?.split(' ').filter(Boolean);
1331
+ },
1332
+ add(value) {
1333
+ const classes = this.getClasses();
1334
+ if(classes.indexOf(value) >= 0) {
1335
+ return;
1336
+ }
1337
+ classes.push(value);
1338
+ this.$element.className = classes.join(' ');
1339
+ },
1340
+ remove(value) {
1341
+ const classes = this.getClasses();
1342
+ const index = classes.indexOf(value);
1343
+ if(index < 0) {
1344
+ return;
1345
+ }
1346
+ classes.splice(index, 1);
1347
+ this.$element.className = classes.join(' ');
1348
+ },
1349
+ toggle(value, force = undefined) {
1350
+ const classes = this.getClasses();
1351
+ const index = classes.indexOf(value);
1352
+ if(index >= 0) {
1353
+ if(force === true) {
1354
+ return;
1355
+ }
1356
+ classes.splice(index, 1);
1315
1357
  }
1358
+ else {
1359
+ if(force === false) {
1360
+ return;
1361
+ }
1362
+ classes.push(value);
1363
+ }
1364
+ this.$element.className = classes.join(' ');
1365
+ },
1366
+ contains(value) {
1367
+ return this.getClasses().indexOf(value) >= 0;
1368
+ }
1369
+ };
1316
1370
 
1317
- this.$nd = new NDElement(this);
1318
- this.$nd.nd = this.$nd;
1319
- return this.$nd;
1371
+ Object.defineProperty(HTMLElement.prototype, 'classes', {
1372
+ configurable: true,
1373
+ get() {
1374
+ return {
1375
+ $element: this,
1376
+ ...classListMethods
1377
+ };
1320
1378
  }
1321
1379
  });
1322
1380
 
@@ -1452,13 +1510,17 @@ var NativeDocument = (function (exports) {
1452
1510
  };
1453
1511
 
1454
1512
 
1455
- function createHtmlElement($tagName, _attributes, _children = null, customWrapper) {
1456
- const { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
1457
- const element = ElementCreator.createElement($tagName);
1458
- const finalElement = (typeof customWrapper === 'function') ? customWrapper(element) : element;
1513
+ function createHtmlElement($tagName, customWrapper, _attributes, _children = null) {
1514
+ let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
1515
+ let element = ElementCreator.createElement($tagName);
1516
+ let finalElement = (customWrapper && typeof customWrapper === 'function') ? customWrapper(element) : element;
1459
1517
 
1460
- ElementCreator.processAttributes(finalElement, attributes);
1461
- ElementCreator.processChildren(children, finalElement);
1518
+ if(attributes) {
1519
+ ElementCreator.processAttributes(finalElement, attributes);
1520
+ }
1521
+ if(children) {
1522
+ ElementCreator.processChildren(children, finalElement);
1523
+ }
1462
1524
 
1463
1525
  return ElementCreator.setup(finalElement, attributes, customWrapper);
1464
1526
  }
@@ -1470,24 +1532,23 @@ var NativeDocument = (function (exports) {
1470
1532
  * @returns {Function}
1471
1533
  */
1472
1534
  function HtmlElementWrapper(name, customWrapper) {
1473
- return (_attributes, _children = null) => createHtmlElement(name.toLowerCase(), _attributes, _children, customWrapper);
1535
+ return createHtmlElement.bind(null, name.toLowerCase(), customWrapper);
1474
1536
  }
1475
1537
 
1476
1538
  const cloneBindingsDataCache = new WeakMap();
1477
1539
 
1478
1540
 
1479
1541
  const bindAttributes = (node, bindDingData, data) => {
1480
- if(!bindDingData) {
1481
- return null;
1482
- }
1483
- const attributes = { };
1542
+ let attributes = null;
1484
1543
  if(bindDingData.attributes) {
1544
+ attributes = attributes || {};
1485
1545
  for (const attr in bindDingData.attributes) {
1486
1546
  attributes[attr] = bindDingData.attributes[attr](...data);
1487
1547
  }
1488
1548
  }
1489
1549
 
1490
1550
  if(bindDingData.classes) {
1551
+ attributes = attributes || {};
1491
1552
  attributes.class = {};
1492
1553
  for (const className in bindDingData.classes) {
1493
1554
  attributes.class[className] = bindDingData.classes[className](...data);
@@ -1495,30 +1556,27 @@ var NativeDocument = (function (exports) {
1495
1556
  }
1496
1557
 
1497
1558
  if(bindDingData.styles) {
1559
+ attributes = attributes || {};
1498
1560
  attributes.style = {};
1499
1561
  for (const property in bindDingData.styles) {
1500
1562
  attributes.style[property] = bindDingData.styles[property](...data);
1501
1563
  }
1502
1564
  }
1503
1565
 
1504
- if(Object.keys(attributes)) {
1566
+ if(attributes) {
1505
1567
  ElementCreator.processAttributes(node, attributes);
1506
- return attributes;
1568
+ return true;
1507
1569
  }
1508
1570
 
1509
1571
  return null;
1510
1572
  };
1511
1573
 
1512
1574
 
1513
- const bindAttachesMethods = function(node, bindDingData, data) {
1514
- if(!bindDingData?.attaches) {
1575
+ const bindAttachMethods = function(node, bindDingData, data) {
1576
+ if(!bindDingData.attach) {
1515
1577
  return null;
1516
1578
  }
1517
- for(const methodName in bindDingData.attaches) {
1518
- node.nd[methodName](function(...args) {
1519
- bindDingData.attaches[methodName].call(this, ...[...args, ...data]);
1520
- });
1521
- }
1579
+ bindDingData.attach(node, ...data);
1522
1580
  };
1523
1581
 
1524
1582
  function TemplateCloner($fn) {
@@ -1526,18 +1584,20 @@ var NativeDocument = (function (exports) {
1526
1584
 
1527
1585
  const clone = (node, data) => {
1528
1586
  const bindDingData = cloneBindingsDataCache.get(node);
1529
- if(node instanceof Text) {
1530
- if(bindDingData?.value) {
1587
+ if(node.nodeType === 3) {
1588
+ if(bindDingData && bindDingData.value) {
1531
1589
  return bindDingData.value(data);
1532
1590
  }
1533
1591
  return node.cloneNode(true);
1534
1592
  }
1535
1593
  const nodeCloned = node.cloneNode();
1536
- bindAttributes(nodeCloned, bindDingData, data);
1537
- bindAttachesMethods(nodeCloned, bindDingData, data);
1538
-
1539
- for(let i = 0, length = node.childNodes.length; i < length; i++) {
1540
- const childNode = node.childNodes[i];
1594
+ if(bindDingData) {
1595
+ bindAttributes(nodeCloned, bindDingData, data);
1596
+ bindAttachMethods(nodeCloned, bindDingData, data);
1597
+ }
1598
+ const childNodes = node.childNodes;
1599
+ for(let i = 0, length = childNodes.length; i < length; i++) {
1600
+ const childNode = childNodes[i];
1541
1601
  const childNodeCloned = clone(childNode, data);
1542
1602
  nodeCloned.appendChild(childNodeCloned);
1543
1603
  }
@@ -1551,21 +1611,27 @@ var NativeDocument = (function (exports) {
1551
1611
  return clone($node, data);
1552
1612
  };
1553
1613
 
1614
+ const $hydrateFn = function(hydrateFunction, target, element, property) {
1615
+ if(!cloneBindingsDataCache.has(element)) {
1616
+ // { classes, styles, attributes, value, attach }
1617
+ cloneBindingsDataCache.set(element, {});
1618
+ }
1619
+ const hydrationState = cloneBindingsDataCache.get(element);
1620
+ if(target === 'value') {
1621
+ hydrationState.value = hydrateFunction;
1622
+ return;
1623
+ }
1624
+ if(target === 'attach') {
1625
+ hydrationState.attach = hydrateFunction;
1626
+ return;
1627
+ }
1628
+ hydrationState[target] = hydrationState[target] || {};
1629
+ hydrationState[target][property] = hydrateFunction;
1630
+ };
1631
+
1554
1632
  const createBinding = (hydrateFunction, target) => {
1555
1633
  return {
1556
- $hydrate : function(element, property) {
1557
- if(!cloneBindingsDataCache.has(element)) {
1558
- // { classes, styles, attributes, value, attaches }
1559
- cloneBindingsDataCache.set(element, {});
1560
- }
1561
- const hydrationState = cloneBindingsDataCache.get(element);
1562
- if(target === 'value') {
1563
- hydrationState.value = hydrateFunction;
1564
- return;
1565
- }
1566
- hydrationState[target] = hydrationState[target] || {};
1567
- hydrationState[target][property] = hydrateFunction;
1568
- }
1634
+ $hydrate : (element, property) => $hydrateFn(hydrateFunction, target, element, property),
1569
1635
  }
1570
1636
  };
1571
1637
 
@@ -1575,29 +1641,46 @@ var NativeDocument = (function (exports) {
1575
1641
  this.class = (fn) => {
1576
1642
  return createBinding(fn, 'classes');
1577
1643
  };
1578
- this.value = (fn) => {
1644
+ this.property = (propertyName) => {
1645
+ return this.value(propertyName);
1646
+ };
1647
+ this.value = (callbackOrProperty) => {
1648
+ if(typeof callbackOrProperty !== 'function') {
1649
+ return createBinding(function(data) {
1650
+ const firstArgument = data[0];
1651
+ return createTextNode(firstArgument[callbackOrProperty]);
1652
+ }, 'value');
1653
+ }
1579
1654
  return createBinding(function(data) {
1580
- return createTextNode(fn(...data));
1655
+ return createTextNode(callbackOrProperty(...data));
1581
1656
  }, 'value');
1582
1657
  };
1583
1658
  this.attr = (fn) => {
1584
1659
  return createBinding(fn, 'attributes');
1585
1660
  };
1586
1661
  this.attach = (fn) => {
1587
- return createBinding(fn, 'attaches');
1662
+ return createBinding(fn, 'attach');
1588
1663
  };
1589
1664
  }
1590
1665
 
1591
1666
  function useCache(fn) {
1592
1667
  let $cache = null;
1593
1668
 
1594
- return function(...args) {
1669
+ const wrapper = function(args) {
1595
1670
  if(!$cache) {
1596
1671
  $cache = new TemplateCloner(fn);
1597
1672
  }
1598
-
1599
1673
  return $cache.clone(args);
1600
1674
  };
1675
+
1676
+ if(fn.length < 2) {
1677
+ return function(...args) {
1678
+ return wrapper(args);
1679
+ };
1680
+ }
1681
+ return function(_, __, ...args) {
1682
+ return wrapper([_, __, ...args]);
1683
+ };
1601
1684
  }
1602
1685
 
1603
1686
  Function.prototype.args = function(...args) {
@@ -1657,6 +1740,118 @@ var NativeDocument = (function (exports) {
1657
1740
  });
1658
1741
  };
1659
1742
 
1743
+ (function() {
1744
+ const DelegatedEventsCallbackStore = {};
1745
+
1746
+ const addCallbackToCallbacksStore = function(element, eventName, callback) {
1747
+ if(!element) return;
1748
+ if(!DelegatedEventsCallbackStore[eventName]) {
1749
+ const eventStore = new WeakMap();
1750
+ DelegatedEventsCallbackStore[eventName] = eventStore;
1751
+ eventStore.set(element, callback);
1752
+ return;
1753
+ }
1754
+ const eventStore = DelegatedEventsCallbackStore[eventName];
1755
+
1756
+ if(!eventStore.has(element)) {
1757
+ eventStore.set(element, callback);
1758
+ return;
1759
+ }
1760
+ const existingCallbacks = eventStore.get(element);
1761
+ if(!Validator.isArray(existingCallbacks)) {
1762
+ eventStore.set(element, [store[eventName], callback]);
1763
+ return;
1764
+ }
1765
+ existingCallbacks.push(callback);
1766
+ };
1767
+
1768
+ const handleDelegatedCallbacks = function(container, eventName) {
1769
+ container.addEventListener(eventName, (event) => {
1770
+ const eventStore = DelegatedEventsCallbackStore[eventName];
1771
+ if(!eventStore) {
1772
+ return;
1773
+ }
1774
+ let target = event.target;
1775
+ while(target && target !== container) {
1776
+ const callback = eventStore.get(target);
1777
+ if(!callback) {
1778
+ target = target.parentElement;
1779
+ continue;
1780
+ }
1781
+
1782
+ if(Validator.isFunction(callback)) {
1783
+ callback.call(target, event);
1784
+ }
1785
+ else {
1786
+ for(let i = 0; i < callback.length; i++) {
1787
+ callback[i].call(target, event);
1788
+ }
1789
+ }
1790
+ return;
1791
+ }
1792
+ });
1793
+ };
1794
+
1795
+
1796
+ const preventDefaultWrapper = function(element, eventName, callback) {
1797
+ element.addEventListener(eventName, (event) => {
1798
+ event.preventDefault();
1799
+ callback && callback.call(element, event);
1800
+ });
1801
+ return this;
1802
+ };
1803
+ const stopPropagationWrapper = function(element, eventName, callback) {
1804
+ element.addEventListener(eventName, (event) => {
1805
+ event.stopPropagation();
1806
+ callback && callback.call(element, event);
1807
+ });
1808
+ return this;
1809
+ };
1810
+ const preventDefaultAndStopPropagationWrapper = function(element, eventName, callback) {
1811
+ element.addEventListener(eventName, (event) => {
1812
+ event.stopPropagation();
1813
+ event.preventDefault();
1814
+ callback && callback.call(element, event);
1815
+ });
1816
+ return this;
1817
+ };
1818
+ const captureEventWrapper = function(element, eventName, directHandler) {
1819
+ if(directHandler) {
1820
+ element.addEventListener(eventName, directHandler);
1821
+ return this;
1822
+ }
1823
+ handleDelegatedCallbacks(element, eventName);
1824
+ return this;
1825
+ };
1826
+
1827
+ for(const event of EVENTS) {
1828
+ const eventName = event.toLowerCase();
1829
+ NDElement.prototype['on'+event] = function(callback) {
1830
+ this.$element.addEventListener(eventName, callback);
1831
+ return this;
1832
+ };
1833
+ NDElement.prototype['onPrevent'+event] = function(callback) {
1834
+ return preventDefaultWrapper(this.$element, eventName, callback);
1835
+ };
1836
+ NDElement.prototype['onStop'+event] = function(callback) {
1837
+ return stopPropagationWrapper(this.$element, eventName, callback);
1838
+ };
1839
+ NDElement.prototype['onPreventStop'+event] = function(callback) {
1840
+ return preventDefaultAndStopPropagationWrapper(this.$element, eventName, callback);
1841
+ };
1842
+
1843
+ NDElement.prototype['when'+event] = function(callback) {
1844
+ addCallbackToCallbacksStore(this.$element, eventName, callback);
1845
+ return this;
1846
+ };
1847
+
1848
+ NDElement.prototype['capture'+event] = function(directHandler) {
1849
+ captureEventWrapper(this.$element, eventName, directHandler);
1850
+ return this;
1851
+ };
1852
+ }
1853
+ }());
1854
+
1660
1855
  const cssPropertyAccumulator = function(initialValue = {}) {
1661
1856
  let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
1662
1857
  const isArray = Validator.isArray(data);
@@ -1769,9 +1964,9 @@ var NativeDocument = (function (exports) {
1769
1964
  return observer.val().length;
1770
1965
  };
1771
1966
 
1772
- const overrideMethods = ['map', 'filter', 'reduce', 'some', 'every', 'find', 'findIndex', 'concat'];
1967
+ const overrideMethods = ['map', 'filter', 'reduce', 'some', 'every', 'find', 'findIndex', 'concat', 'includes', 'indexOf'];
1773
1968
  overrideMethods.forEach((method) => {
1774
- observer[method] = function(...args) {
1969
+ observer[method] = (...args) => {
1775
1970
  return observer.val()[method](...args);
1776
1971
  };
1777
1972
  });
@@ -1801,13 +1996,13 @@ var NativeDocument = (function (exports) {
1801
1996
 
1802
1997
  /**
1803
1998
  *
1804
- * @param {Object} value
1999
+ * @param {Object} initialValue
1805
2000
  * @returns {Proxy}
1806
2001
  */
1807
- Observable.init = function(value) {
2002
+ Observable.init = function(initialValue) {
1808
2003
  const data = {};
1809
- for(const key in value) {
1810
- const itemValue = value[key];
2004
+ for(const key in initialValue) {
2005
+ const itemValue = initialValue[key];
1811
2006
  if(Validator.isJson(itemValue)) {
1812
2007
  data[key] = Observable.init(itemValue);
1813
2008
  continue;
@@ -1836,8 +2031,11 @@ var NativeDocument = (function (exports) {
1836
2031
  const $clone = function() {
1837
2032
 
1838
2033
  };
2034
+ const $updateWith = function(values) {
2035
+ Observable.update(proxy, values);
2036
+ };
1839
2037
 
1840
- return new Proxy(data, {
2038
+ const proxy = new Proxy(data, {
1841
2039
  get(target, property) {
1842
2040
  if(property === '__isProxy__') {
1843
2041
  return true;
@@ -1848,6 +2046,12 @@ var NativeDocument = (function (exports) {
1848
2046
  if(property === '$clone') {
1849
2047
  return $clone;
1850
2048
  }
2049
+ if(property === '$observables') {
2050
+ return Object.values(target);
2051
+ }
2052
+ if(property === '$updateWith') {
2053
+ return $updateWith;
2054
+ }
1851
2055
  if(target[property] !== undefined) {
1852
2056
  return target[property];
1853
2057
  }
@@ -1855,10 +2059,25 @@ var NativeDocument = (function (exports) {
1855
2059
  },
1856
2060
  set(target, prop, newValue) {
1857
2061
  if(target[prop] !== undefined) {
1858
- target[prop].set(newValue);
2062
+ Validator.isObservable(newValue)
2063
+ ? target[prop].set(newValue.val())
2064
+ : target[prop].set(newValue);
2065
+ return true;
1859
2066
  }
2067
+ return true;
1860
2068
  }
1861
- })
2069
+ });
2070
+
2071
+ return proxy;
2072
+ };
2073
+
2074
+ /**
2075
+ *
2076
+ * @param {any[]} data
2077
+ * @return Proxy[]
2078
+ */
2079
+ Observable.arrayOfObject = function(data) {
2080
+ return data.map(item => Observable.object(item));
1862
2081
  };
1863
2082
 
1864
2083
  /**
@@ -1886,13 +2105,16 @@ var NativeDocument = (function (exports) {
1886
2105
 
1887
2106
 
1888
2107
  Observable.update = function($target, data) {
2108
+ if(Validator.isProxy(data)) {
2109
+ data = data.$value;
2110
+ }
1889
2111
  for(const key in data) {
1890
2112
  const targetItem = $target[key];
1891
2113
  const newValue = data[key];
1892
2114
 
1893
2115
  if(Validator.isObservable(targetItem)) {
1894
2116
  if(Validator.isArray(newValue)) {
1895
- Observable.update(targetItem, newValue);
2117
+ targetItem.set([...newValue]);
1896
2118
  continue;
1897
2119
  }
1898
2120
  targetItem.set(newValue);
@@ -1930,7 +2152,15 @@ var NativeDocument = (function (exports) {
1930
2152
  return observable;
1931
2153
  }
1932
2154
 
1933
- dependencies.forEach(dependency => dependency.subscribe(updatedValue));
2155
+ dependencies.forEach(dependency => {
2156
+ if(Validator.isProxy(dependency)) {
2157
+ dependency.$observables.forEach((observable) => {
2158
+ observable.subscribe(updatedValue);
2159
+ });
2160
+ return;
2161
+ }
2162
+ dependency.subscribe(updatedValue);
2163
+ });
1934
2164
 
1935
2165
  return observable;
1936
2166
  };
@@ -2012,10 +2242,11 @@ var NativeDocument = (function (exports) {
2012
2242
  *
2013
2243
  * @param {Array|Object|ObservableItem} data
2014
2244
  * @param {Function} callback
2015
- * @param {?Function} key
2245
+ * @param {?Function|?string} key
2246
+ * @param {{shouldKeepItemsInCache: boolean}?} configs
2016
2247
  * @returns {DocumentFragment}
2017
2248
  */
2018
- function ForEach(data, callback, key) {
2249
+ function ForEach(data, callback, key, { shouldKeepItemsInCache = false } = {}) {
2019
2250
  const element = new Anchor('ForEach');
2020
2251
  const blockEnd = element.endElement();
2021
2252
  element.startElement();
@@ -2030,6 +2261,9 @@ var NativeDocument = (function (exports) {
2030
2261
  };
2031
2262
 
2032
2263
  const cleanCache = (parent) => {
2264
+ if(shouldKeepItemsInCache) {
2265
+ return;
2266
+ }
2033
2267
  for(const [keyId, cacheItem] of cache.entries()) {
2034
2268
  if(keyIds.has(keyId)) {
2035
2269
  continue;
@@ -2062,6 +2296,9 @@ var NativeDocument = (function (exports) {
2062
2296
  try {
2063
2297
  const indexObserver = callback.length >= 2 ? Observable(indexKey) : null;
2064
2298
  let child = ElementCreator.getChild(callback(item, indexObserver));
2299
+ if(!child || Validator.isFragment(child)) {
2300
+ throw new NativeDocumentError("ForEachArray child can't be null or undefined!");
2301
+ }
2065
2302
  cache.set(keyId, { keyId, isNew: true, child: new WeakRef(child), indexObserver});
2066
2303
  } catch (e) {
2067
2304
  DebugManager$1.error('ForEach', `Error creating element for key ${keyId}` , e);
@@ -2113,7 +2350,7 @@ var NativeDocument = (function (exports) {
2113
2350
  keyIds.clear();
2114
2351
  if(Array.isArray(items)) {
2115
2352
  for(let i = 0, length = items.length; i < length; i++) {
2116
- const keyId= handleContentItem(items[i], i);
2353
+ const keyId = handleContentItem(items[i], i);
2117
2354
  keyIds.add(keyId);
2118
2355
  }
2119
2356
  } else {
@@ -2191,14 +2428,12 @@ var NativeDocument = (function (exports) {
2191
2428
  if(!cacheItem) {
2192
2429
  return;
2193
2430
  }
2194
- const child = cacheItem.child;
2195
- cacheItem.indexObserver?.deref()?.cleanup();
2196
- cacheItem.child = null;
2197
- cacheItem.indexObserver = null;
2198
2431
  if(removeChild) {
2432
+ const child = cacheItem.child;
2199
2433
  child?.remove();
2200
2434
  cache.delete(cacheItem.keyId);
2201
2435
  }
2436
+ cacheItem.indexObserver?.deref()?.cleanup();
2202
2437
  };
2203
2438
 
2204
2439
  const removeCacheItemByKey = (keyId, removeChild = true) => {
@@ -2206,6 +2441,13 @@ var NativeDocument = (function (exports) {
2206
2441
  };
2207
2442
 
2208
2443
  const cleanCache = () => {
2444
+ if(configs.shouldKeepItemsInCache) {
2445
+ return;
2446
+ }
2447
+ if(!isIndexRequired) {
2448
+ cache.clear();
2449
+ return;
2450
+ }
2209
2451
  for (const [keyId, cacheItem] of cache.entries()) {
2210
2452
  removeCacheItem(cacheItem, false);
2211
2453
  }
@@ -2227,6 +2469,9 @@ var NativeDocument = (function (exports) {
2227
2469
 
2228
2470
  const indexObserver = isIndexRequired ? Observable(indexKey) : null;
2229
2471
  let child = ElementCreator.getChild(callback(item, indexObserver));
2472
+ if(!child || Validator.isFragment(child)) {
2473
+ throw new NativeDocumentError("ForEachArray child can't be null or undefined!");
2474
+ }
2230
2475
  cache.set(keyId, {
2231
2476
  keyId,
2232
2477
  child: child,
@@ -2269,12 +2514,12 @@ var NativeDocument = (function (exports) {
2269
2514
  toFragment(items, startIndexFrom = 0){
2270
2515
  const fragment = document.createDocumentFragment();
2271
2516
  for(let i = 0, length = items.length; i < length; i++) {
2272
- fragment.append(buildItem(items[i], lastNumberOfItems));
2517
+ fragment.appendChild(buildItem(items[i], lastNumberOfItems));
2273
2518
  lastNumberOfItems++;
2274
2519
  }
2275
2520
  return fragment;
2276
2521
  },
2277
- add(items, delay = 0) {
2522
+ add(items, delay = 2) {
2278
2523
  const fragment = Actions.toFragment(items);
2279
2524
  setTimeout(() => {
2280
2525
  element.appendElement(fragment);
@@ -2301,7 +2546,7 @@ var NativeDocument = (function (exports) {
2301
2546
  },
2302
2547
  clear,
2303
2548
  merge(items) {
2304
- Actions.add(items, 0);
2549
+ Actions.add(items);
2305
2550
  },
2306
2551
  push(items) {
2307
2552
  let delay = 0;
@@ -2408,7 +2653,9 @@ var NativeDocument = (function (exports) {
2408
2653
  updateIndexObservers(items, 0);
2409
2654
  };
2410
2655
 
2411
- buildContent(data.val(), null, {action: null});
2656
+ if(data.val().length) {
2657
+ buildContent(data.val(), null, {action: null});
2658
+ }
2412
2659
  if(Validator.isObservable(data)) {
2413
2660
  data.subscribe(buildContent);
2414
2661
  }
@@ -2421,10 +2668,10 @@ var NativeDocument = (function (exports) {
2421
2668
  *
2422
2669
  * @param {ObservableItem|ObservableChecker} condition
2423
2670
  * @param {*} child
2424
- * @param {string|null} comment
2671
+ * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} comment
2425
2672
  * @returns {DocumentFragment}
2426
2673
  */
2427
- const ShowIf = function(condition, child, comment = null) {
2674
+ const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
2428
2675
  if(!(Validator.isObservable(condition))) {
2429
2676
  return DebugManager$1.warn('ShowIf', "ShowIf : condition must be an Observable / "+comment, condition);
2430
2677
  }
@@ -2432,10 +2679,13 @@ var NativeDocument = (function (exports) {
2432
2679
 
2433
2680
  let childElement = null;
2434
2681
  const getChildElement = () => {
2435
- if(childElement) {
2682
+ if(childElement && shouldKeepInCache) {
2436
2683
  return childElement;
2437
2684
  }
2438
2685
  childElement = ElementCreator.getChild(child);
2686
+ if(Validator.isFragment(childElement)) {
2687
+ childElement = Array.from(childElement.children);
2688
+ }
2439
2689
  return childElement;
2440
2690
  };
2441
2691
 
@@ -2507,6 +2757,9 @@ var NativeDocument = (function (exports) {
2507
2757
  return null;
2508
2758
  }
2509
2759
  item = ElementCreator.getChild(item);
2760
+ if(Validator.isFragment(item)) {
2761
+ item = Array.from(item.children);
2762
+ }
2510
2763
  shouldKeepInCache && cache.set(key, item);
2511
2764
  return item;
2512
2765
  };