vasille 2.0.4 → 2.2.1

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.
Files changed (79) hide show
  1. package/README.md +7 -3
  2. package/cdn/es2015.js +947 -1006
  3. package/cdn/es5.js +1053 -1023
  4. package/flow-typed/vasille.js +2646 -838
  5. package/lib/binding/attribute.js +11 -12
  6. package/lib/binding/binding.js +9 -19
  7. package/lib/binding/class.js +34 -42
  8. package/lib/binding/style.js +5 -11
  9. package/lib/core/core.js +84 -32
  10. package/lib/core/destroyable.js +2 -2
  11. package/lib/core/ivalue.js +15 -13
  12. package/lib/functional/components.js +17 -0
  13. package/lib/functional/merge.js +41 -0
  14. package/lib/functional/models.js +26 -0
  15. package/lib/functional/options.js +1 -0
  16. package/lib/functional/reactivity.js +33 -0
  17. package/lib/functional/stack.js +127 -0
  18. package/lib/index.js +2 -7
  19. package/lib/models/array-model.js +9 -0
  20. package/lib/models/object-model.js +28 -14
  21. package/lib/node/app.js +23 -14
  22. package/lib/node/interceptor.js +3 -3
  23. package/lib/node/node.js +340 -681
  24. package/lib/node/watch.js +9 -17
  25. package/lib/spec/html.js +1 -0
  26. package/lib/spec/react.js +1 -0
  27. package/lib/spec/svg.js +1 -0
  28. package/lib/v/index.js +23 -0
  29. package/lib/value/expression.js +11 -8
  30. package/lib/value/mirror.js +6 -8
  31. package/lib/value/reference.js +3 -7
  32. package/lib/views/array-view.js +6 -10
  33. package/lib/views/base-view.js +12 -23
  34. package/lib/views/map-view.js +4 -9
  35. package/lib/views/object-view.js +5 -8
  36. package/lib/views/repeat-node.js +20 -60
  37. package/lib/views/repeater.js +7 -7
  38. package/lib/views/set-view.js +4 -11
  39. package/package.json +3 -1
  40. package/types/binding/attribute.d.ts +2 -8
  41. package/types/binding/binding.d.ts +4 -13
  42. package/types/binding/class.d.ts +7 -19
  43. package/types/binding/style.d.ts +0 -6
  44. package/types/core/core.d.ts +42 -54
  45. package/types/core/destroyable.d.ts +2 -2
  46. package/types/core/ivalue.d.ts +13 -11
  47. package/types/functional/components.d.ts +4 -0
  48. package/types/functional/merge.d.ts +1 -0
  49. package/types/functional/models.d.ts +10 -0
  50. package/types/functional/options.d.ts +23 -0
  51. package/types/functional/reactivity.d.ts +11 -0
  52. package/types/functional/stack.d.ts +24 -0
  53. package/types/index.d.ts +3 -7
  54. package/types/models/array-model.d.ts +3 -2
  55. package/types/models/map-model.d.ts +2 -2
  56. package/types/models/model.d.ts +3 -1
  57. package/types/models/object-model.d.ts +4 -2
  58. package/types/models/set-model.d.ts +2 -2
  59. package/types/node/app.d.ts +21 -19
  60. package/types/node/node.d.ts +99 -423
  61. package/types/node/watch.d.ts +9 -15
  62. package/types/spec/html.d.ts +975 -0
  63. package/types/spec/react.d.ts +4 -0
  64. package/types/spec/svg.d.ts +314 -0
  65. package/types/v/index.d.ts +32 -0
  66. package/types/value/expression.d.ts +7 -20
  67. package/types/value/mirror.d.ts +3 -3
  68. package/types/value/reference.d.ts +5 -5
  69. package/types/views/array-view.d.ts +3 -4
  70. package/types/views/base-view.d.ts +9 -17
  71. package/types/views/map-view.d.ts +2 -3
  72. package/types/views/object-view.d.ts +2 -3
  73. package/types/views/repeat-node.d.ts +8 -9
  74. package/types/views/set-view.d.ts +2 -3
  75. package/types/core/executor.d.ts +0 -87
  76. package/types/core/signal.d.ts +0 -35
  77. package/types/core/slot.d.ts +0 -45
  78. package/types/node/interceptor.d.ts +0 -50
  79. package/types/views/repeater.d.ts +0 -38
package/cdn/es2015.js CHANGED
@@ -1,4 +1,24 @@
1
1
  (function(){
2
+ // ./lib/v/index.js
3
+
4
+ const v = Object.assign(Object.assign({ ref(value) {
5
+ return current.ref(value);
6
+ }, expr: expr, of: valueOf, sv: setValue, alwaysFalse: new Reference(false), app,
7
+ component,
8
+ fragment,
9
+ extension,
10
+ text,
11
+ tag,
12
+ create }, vx), { merge,
13
+ destructor() {
14
+ return current.destroy.bind(current);
15
+ },
16
+ runOnDestroy(callback) {
17
+ current.runOnDestroy(callback);
18
+ } });
19
+
20
+ window.v = v;
21
+
2
22
  // ./lib/models/model.js
3
23
 
4
24
 
@@ -149,13 +169,14 @@ class ObjectModel extends Object {
149
169
  */
150
170
  constructor(obj = {}) {
151
171
  super();
172
+ this.container = Object.create(null);
152
173
  Object.defineProperty(this, 'listener', {
153
174
  value: new Listener,
154
175
  writable: false,
155
176
  configurable: false
156
177
  });
157
178
  for (const i in obj) {
158
- Object.defineProperty(this, i, {
179
+ Object.defineProperty(this.container, i, {
159
180
  value: obj[i],
160
181
  configurable: true,
161
182
  writable: true,
@@ -170,8 +191,7 @@ class ObjectModel extends Object {
170
191
  * @return {*}
171
192
  */
172
193
  get(key) {
173
- const ts = this;
174
- return ts[key];
194
+ return this.container[key];
175
195
  }
176
196
  /**
177
197
  * Sets an object property value
@@ -180,21 +200,19 @@ class ObjectModel extends Object {
180
200
  * @return {ObjectModel} a pointer to this
181
201
  */
182
202
  set(key, v) {
183
- const ts = this;
184
- // eslint-disable-next-line no-prototype-builtins
185
- if (ts.hasOwnProperty(key)) {
186
- this.listener.emitRemoved(key, ts[key]);
187
- ts[key] = v;
203
+ if (Reflect.has(this.container, key)) {
204
+ this.listener.emitRemoved(key, this.container[key]);
205
+ this.container[key] = v;
188
206
  }
189
207
  else {
190
- Object.defineProperty(ts, key, {
208
+ Object.defineProperty(this.container, key, {
191
209
  value: v,
192
210
  configurable: true,
193
211
  writable: true,
194
212
  enumerable: true
195
213
  });
196
214
  }
197
- this.listener.emitAdded(key, ts[key]);
215
+ this.listener.emitAdded(key, this.container[key]);
198
216
  return this;
199
217
  }
200
218
  /**
@@ -202,12 +220,28 @@ class ObjectModel extends Object {
202
220
  * @param key {string} property name
203
221
  */
204
222
  delete(key) {
205
- const ts = this;
206
- if (ts[key]) {
207
- this.listener.emitRemoved(key, ts[key]);
208
- delete ts[key];
223
+ if (this.container[key]) {
224
+ this.listener.emitRemoved(key, this.container[key]);
225
+ delete this.container[key];
209
226
  }
210
227
  }
228
+ proxy() {
229
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
230
+ const ts = this;
231
+ return new Proxy(this.container, {
232
+ get(target, p) {
233
+ return ts.get(p);
234
+ },
235
+ set(target, p, value) {
236
+ ts.set(p, value);
237
+ return true;
238
+ },
239
+ deleteProperty(target, p) {
240
+ ts.delete(p);
241
+ return true;
242
+ }
243
+ });
244
+ }
211
245
  enableReactivity() {
212
246
  this.listener.enableReactivity();
213
247
  }
@@ -373,6 +407,15 @@ class ArrayModel extends Array {
373
407
  super.push(data[i]);
374
408
  }
375
409
  }
410
+ // proxy
411
+ proxy() {
412
+ return new Proxy(this, {
413
+ set(target, p, value) {
414
+ target.splice(parseInt(p), 1, value);
415
+ return true;
416
+ }
417
+ });
418
+ }
376
419
  /* Array members */
377
420
  /**
378
421
  * Gets the last item of array
@@ -563,6 +606,266 @@ class ArrayModel extends Array {
563
606
 
564
607
  window.ArrayModel = ArrayModel;
565
608
 
609
+ // ./lib/functional/merge.js
610
+ function merge(main, ...targets) {
611
+ function refactorClass(obj) {
612
+ if (Array.isArray(obj.class)) {
613
+ const out = {
614
+ $: []
615
+ };
616
+ obj.class.forEach(item => {
617
+ if (item instanceof IValue) {
618
+ out.$.push(item);
619
+ }
620
+ else if (typeof item === 'string') {
621
+ out[item] = true;
622
+ }
623
+ else if (typeof item === 'object') {
624
+ Object.assign(out, item);
625
+ }
626
+ });
627
+ obj.class = out;
628
+ }
629
+ }
630
+ refactorClass(main);
631
+ targets.forEach(target => {
632
+ Reflect.ownKeys(target).forEach((prop) => {
633
+ if (!Reflect.has(main, prop)) {
634
+ main[prop] = target[prop];
635
+ }
636
+ else if (typeof main[prop] === 'object' && typeof target[prop] === 'object') {
637
+ if (prop === 'class') {
638
+ refactorClass(target);
639
+ }
640
+ if (prop === '$' && Array.isArray(main[prop]) && Array.isArray(target[prop])) {
641
+ main.$.push(...target.$);
642
+ }
643
+ else {
644
+ merge(main[prop], target[prop]);
645
+ }
646
+ }
647
+ });
648
+ });
649
+ }
650
+
651
+ window.merge = merge;
652
+
653
+ // ./lib/functional/stack.js
654
+ function app(renderer) {
655
+ return (node, opts) => {
656
+ return new App(node, opts).runFunctional(renderer, opts);
657
+ };
658
+ }
659
+ function component(renderer) {
660
+ return (opts, callback) => {
661
+ const component = new Component(opts);
662
+ if (!(current instanceof Fragment))
663
+ throw userError('missing parent node', 'out-of-context');
664
+ let ret;
665
+ if (callback)
666
+ opts.slot = callback;
667
+ current.create(component, node => {
668
+ ret = node.runFunctional(renderer, opts);
669
+ });
670
+ return ret;
671
+ };
672
+ }
673
+ function fragment(renderer) {
674
+ return (opts, callback) => {
675
+ const frag = new Fragment(opts);
676
+ if (!(current instanceof Fragment))
677
+ throw userError('missing parent node', 'out-of-context');
678
+ if (callback)
679
+ opts.slot = callback;
680
+ current.create(frag);
681
+ return frag.runFunctional(renderer, opts);
682
+ };
683
+ }
684
+ function extension(renderer) {
685
+ return (opts, callback) => {
686
+ const ext = new Extension(opts);
687
+ if (!(current instanceof Fragment))
688
+ throw userError('missing parent node', 'out-of-context');
689
+ if (callback)
690
+ opts.slot = callback;
691
+ current.create(ext);
692
+ return ext.runFunctional(renderer, opts);
693
+ };
694
+ }
695
+ function tag(name, opts, callback) {
696
+ if (!(current instanceof Fragment))
697
+ throw userError('missing parent node', 'out-of-context');
698
+ return {
699
+ node: current.tag(name, opts, (node) => {
700
+ callback && node.runFunctional(callback);
701
+ })
702
+ };
703
+ }
704
+ function create(node, callback) {
705
+ if (!(current instanceof Fragment))
706
+ throw userError('missing current node', 'out-of-context');
707
+ current.create(node, (node, ...args) => {
708
+ callback && node.runFunctional(callback, ...args);
709
+ });
710
+ return node;
711
+ }
712
+ const vx = {
713
+ if(condition, callback) {
714
+ if (current instanceof Fragment) {
715
+ current.if(condition, node => node.runFunctional(callback));
716
+ }
717
+ else {
718
+ throw userError("wrong use of `v.if` function", "logic-error");
719
+ }
720
+ },
721
+ else(callback) {
722
+ if (current instanceof Fragment) {
723
+ current.else(node => node.runFunctional(callback));
724
+ }
725
+ else {
726
+ throw userError("wrong use of `v.else` function", "logic-error");
727
+ }
728
+ },
729
+ elif(condition, callback) {
730
+ if (current instanceof Fragment) {
731
+ current.elif(condition, node => node.runFunctional(callback));
732
+ }
733
+ else {
734
+ throw userError("wrong use of `v.elif` function", "logic-error");
735
+ }
736
+ },
737
+ for(model, callback) {
738
+ if (model instanceof ArrayModel) {
739
+ // for arrays T & K are the same type
740
+ create(new ArrayView({ model }), callback);
741
+ }
742
+ else if (model instanceof MapModel) {
743
+ create(new MapView({ model }), callback);
744
+ }
745
+ else if (model instanceof SetModel) {
746
+ // for sets T & K are the same type
747
+ create(new SetView({ model }), callback);
748
+ }
749
+ else if (model instanceof ObjectModel) {
750
+ // for objects K is always string
751
+ create(new ObjectView({ model }), callback);
752
+ }
753
+ else {
754
+ throw userError("wrong use of `v.for` function", 'wrong-model');
755
+ }
756
+ },
757
+ watch(model, callback) {
758
+ const opts = { model };
759
+ create(new Watch(opts), callback);
760
+ },
761
+ nextTick(callback) {
762
+ const node = current;
763
+ window.setTimeout(() => {
764
+ node.runFunctional(callback);
765
+ }, 0);
766
+ }
767
+ };
768
+
769
+ window.app = app;
770
+ window.component = component;
771
+ window.fragment = fragment;
772
+ window.extension = extension;
773
+ window.tag = tag;
774
+ window.create = create;
775
+ window.vx = vx;
776
+
777
+ // ./lib/functional/models.js
778
+ function arrayModel(arr = []) {
779
+ if (!current)
780
+ throw userError('missing parent node', 'out-of-context');
781
+ return current.register(new ArrayModel(arr)).proxy();
782
+ }
783
+ function mapModel(map = []) {
784
+ if (!current)
785
+ throw userError('missing parent node', 'out-of-context');
786
+ return current.register(new MapModel(map));
787
+ }
788
+ function setModel(arr = []) {
789
+ if (!current)
790
+ throw userError('missing parent node', 'out-of-context');
791
+ return current.register(new SetModel(arr));
792
+ }
793
+ function objectModel(obj = {}) {
794
+ if (!current)
795
+ throw userError('missing parent node', 'out-of-context');
796
+ return current.register(new ObjectModel(obj));
797
+ }
798
+
799
+ window.arrayModel = arrayModel;
800
+ window.mapModel = mapModel;
801
+ window.setModel = setModel;
802
+ window.objectModel = objectModel;
803
+
804
+ // ./lib/functional/options.js
805
+
806
+
807
+
808
+ // ./lib/functional/reactivity.js
809
+ function ref(value) {
810
+ const ref = current.ref(value);
811
+ return [ref, (value) => ref.$ = value];
812
+ }
813
+ function mirror(value) {
814
+ return current.mirror(value);
815
+ }
816
+ function forward(value) {
817
+ return current.forward(value);
818
+ }
819
+ function point(value) {
820
+ return current.point(value);
821
+ }
822
+ function expr(func, ...values) {
823
+ return current.expr(func, ...values);
824
+ }
825
+ function watch(func, ...values) {
826
+ current.watch(func, ...values);
827
+ }
828
+ function valueOf(value) {
829
+ return value.$;
830
+ }
831
+ function setValue(ref, value) {
832
+ if (ref instanceof Pointer && value instanceof IValue) {
833
+ ref.point(value);
834
+ }
835
+ else {
836
+ ref.$ = value instanceof IValue ? value.$ : value;
837
+ }
838
+ }
839
+
840
+ window.ref = ref;
841
+ window.mirror = mirror;
842
+ window.forward = forward;
843
+ window.point = point;
844
+ window.expr = expr;
845
+ window.watch = watch;
846
+ window.valueOf = valueOf;
847
+ window.setValue = setValue;
848
+
849
+ // ./lib/functional/components.js
850
+ function text(text) {
851
+ if (!(current instanceof Fragment))
852
+ throw userError('missing parent node', 'out-of-context');
853
+ ;
854
+ current.text(text);
855
+ }
856
+ function debug(text) {
857
+ if (!(current instanceof Fragment))
858
+ throw userError('missing parent node', 'out-of-context');
859
+ current.debug(text);
860
+ }
861
+ function predefine(slot, predefined) {
862
+ return slot || predefined;
863
+ }
864
+
865
+ window.text = text;
866
+ window.debug = debug;
867
+ window.predefine = predefine;
868
+
566
869
  // ./lib/core/signal.js
567
870
  /**
568
871
  * Signal is an event generator
@@ -862,7 +1165,7 @@ class Destroyable {
862
1165
  * Make object fields non configurable
863
1166
  * @protected
864
1167
  */
865
- $seal() {
1168
+ seal() {
866
1169
  const $ = this;
867
1170
  Object.keys($).forEach(i => {
868
1171
  // eslint-disable-next-line no-prototype-builtins
@@ -894,7 +1197,7 @@ class Destroyable {
894
1197
  /**
895
1198
  * Garbage collector method
896
1199
  */
897
- $destroy() {
1200
+ destroy() {
898
1201
  // nothing here
899
1202
  }
900
1203
  }
@@ -902,12 +1205,26 @@ class Destroyable {
902
1205
  window.Destroyable = Destroyable;
903
1206
 
904
1207
  // ./lib/core/ivalue.js
1208
+ class Switchable extends Destroyable {
1209
+ /**
1210
+ * Enable update handlers triggering
1211
+ */
1212
+ enable() {
1213
+ throw notOverwritten();
1214
+ }
1215
+ /**
1216
+ * disable update handlers triggering
1217
+ */
1218
+ disable() {
1219
+ throw notOverwritten();
1220
+ }
1221
+ }
905
1222
  /**
906
1223
  * Interface which describes a value
907
1224
  * @class IValue
908
1225
  * @extends Destroyable
909
1226
  */
910
- class IValue extends Destroyable {
1227
+ class IValue extends Switchable {
911
1228
  /**
912
1229
  * @param isEnabled {boolean} initial is enabled state
913
1230
  */
@@ -943,26 +1260,27 @@ class IValue extends Destroyable {
943
1260
  off(handler) {
944
1261
  throw notOverwritten();
945
1262
  }
946
- /**
947
- * Enable update handlers triggering
948
- */
949
- enable() {
950
- throw notOverwritten();
951
- }
952
- /**
953
- * disable update handlers triggering
954
- */
955
- disable() {
956
- throw notOverwritten();
957
- }
958
1263
  }
959
1264
 
1265
+ window.Switchable = Switchable;
960
1266
  window.IValue = IValue;
961
1267
 
962
1268
  // ./lib/index.js
963
1269
 
964
1270
 
965
1271
 
1272
+ // ./lib/spec/svg.js
1273
+
1274
+
1275
+
1276
+ // ./lib/spec/react.js
1277
+
1278
+
1279
+
1280
+ // ./lib/spec/html.js
1281
+
1282
+
1283
+
966
1284
  // ./lib/value/expression.js
967
1285
  /**
968
1286
  * Bind some values to one expression
@@ -970,13 +1288,18 @@ window.IValue = IValue;
970
1288
  * @extends IValue
971
1289
  */
972
1290
  class Expression extends IValue {
973
- constructor(func, link, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1291
+ /**
1292
+ * Creates a function bounded to N values
1293
+ * @param func {Function} the function to bound
1294
+ * @param values
1295
+ * @param link {Boolean} links immediately if true
1296
+ */
1297
+ constructor(func, link, ...values) {
974
1298
  super(false);
975
1299
  /**
976
1300
  * Expression will link different handler for each value of list
977
1301
  */
978
1302
  this.linkedFunc = [];
979
- const values = [v1, v2, v3, v4, v5, v6, v7, v8, v9].filter(v => v instanceof IValue);
980
1303
  const handler = (i) => {
981
1304
  if (i != null) {
982
1305
  this.valuesCache[i] = this.values[i].$;
@@ -985,14 +1308,12 @@ class Expression extends IValue {
985
1308
  };
986
1309
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
987
1310
  // @ts-ignore
988
- this.valuesCache = values.map(iValue => iValue.$);
1311
+ this.valuesCache = values.map(item => item.$);
989
1312
  this.sync = new Reference(func.apply(this, this.valuesCache));
990
1313
  let i = 0;
991
1314
  values.forEach(() => {
992
1315
  this.linkedFunc.push(handler.bind(this, Number(i++)));
993
1316
  });
994
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
995
- // @ts-ignore
996
1317
  this.values = values;
997
1318
  this.func = handler;
998
1319
  if (link) {
@@ -1001,7 +1322,7 @@ class Expression extends IValue {
1001
1322
  else {
1002
1323
  handler();
1003
1324
  }
1004
- this.$seal();
1325
+ this.seal();
1005
1326
  }
1006
1327
  get $() {
1007
1328
  return this.sync.$;
@@ -1037,12 +1358,12 @@ class Expression extends IValue {
1037
1358
  }
1038
1359
  return this;
1039
1360
  }
1040
- $destroy() {
1361
+ destroy() {
1041
1362
  this.disable();
1042
1363
  this.values.splice(0);
1043
1364
  this.valuesCache.splice(0);
1044
1365
  this.linkedFunc.splice(0);
1045
- super.$destroy();
1366
+ super.destroy();
1046
1367
  }
1047
1368
  }
1048
1369
 
@@ -1062,7 +1383,7 @@ class Reference extends IValue {
1062
1383
  super(true);
1063
1384
  this.value = value;
1064
1385
  this.onchange = new Set;
1065
- this.$seal();
1386
+ this.seal();
1066
1387
  }
1067
1388
  get $() {
1068
1389
  return this.value;
@@ -1084,22 +1405,18 @@ class Reference extends IValue {
1084
1405
  });
1085
1406
  this.isEnabled = true;
1086
1407
  }
1087
- return this;
1088
1408
  }
1089
1409
  disable() {
1090
1410
  this.isEnabled = false;
1091
- return this;
1092
1411
  }
1093
1412
  on(handler) {
1094
1413
  this.onchange.add(handler);
1095
- return this;
1096
1414
  }
1097
1415
  off(handler) {
1098
1416
  this.onchange.delete(handler);
1099
- return this;
1100
1417
  }
1101
- $destroy() {
1102
- super.$destroy();
1418
+ destroy() {
1419
+ super.destroy();
1103
1420
  this.onchange.clear();
1104
1421
  }
1105
1422
  }
@@ -1127,7 +1444,7 @@ class Mirror extends Reference {
1127
1444
  this.pointedValue = value;
1128
1445
  this.forwardOnly = forwardOnly;
1129
1446
  value.on(this.handler);
1130
- this.$seal();
1447
+ this.seal();
1131
1448
  }
1132
1449
  get $() {
1133
1450
  // this is a ts bug
@@ -1136,13 +1453,13 @@ class Mirror extends Reference {
1136
1453
  return super.$;
1137
1454
  }
1138
1455
  set $(v) {
1456
+ if (!this.forwardOnly) {
1457
+ this.pointedValue.$ = v;
1458
+ }
1139
1459
  // this is a ts bug
1140
1460
  // eslint-disable-next-line
1141
1461
  // @ts-ignore
1142
1462
  super.$ = v;
1143
- if (!this.forwardOnly) {
1144
- this.pointedValue.$ = v;
1145
- }
1146
1463
  }
1147
1464
  enable() {
1148
1465
  if (!this.isEnabled) {
@@ -1150,18 +1467,16 @@ class Mirror extends Reference {
1150
1467
  this.pointedValue.on(this.handler);
1151
1468
  this.$ = this.pointedValue.$;
1152
1469
  }
1153
- return this;
1154
1470
  }
1155
1471
  disable() {
1156
1472
  if (this.isEnabled) {
1157
1473
  this.pointedValue.off(this.handler);
1158
1474
  this.isEnabled = false;
1159
1475
  }
1160
- return this;
1161
1476
  }
1162
- $destroy() {
1477
+ destroy() {
1163
1478
  this.disable();
1164
- super.$destroy();
1479
+ super.destroy();
1165
1480
  }
1166
1481
  }
1167
1482
 
@@ -1205,39 +1520,39 @@ window.Pointer = Pointer;
1205
1520
  class Binding extends Destroyable {
1206
1521
  /**
1207
1522
  * Constructs a common binding logic
1208
- * @param node {INode} the vasille node
1209
- * @param name {String} the name of property/attribute/class
1210
1523
  * @param value {IValue} the value to bind
1211
1524
  */
1212
- constructor(node, name, value) {
1525
+ constructor(value) {
1213
1526
  super();
1214
- this.updateFunc = this.bound(name).bind(null, node);
1215
1527
  this.binding = value;
1216
- this.binding.on(this.updateFunc);
1217
- this.updateFunc(this.binding.$);
1218
- this.$seal();
1528
+ this.seal();
1219
1529
  }
1220
- /**
1221
- * Is a virtual function to get the specific bind function
1222
- * @param name {String} the name of attribute/property
1223
- * @returns {Function} a function to update attribute/property value
1224
- * @throws Always throws and must be overloaded in child class
1225
- */
1226
- bound(name) {
1227
- throw notOverwritten();
1530
+ init(bounded) {
1531
+ this.func = bounded;
1532
+ this.binding.on(this.func);
1533
+ this.func(this.binding.$);
1228
1534
  }
1229
1535
  /**
1230
1536
  * Just clear bindings
1231
1537
  */
1232
- $destroy() {
1233
- this.binding.off(this.updateFunc);
1234
- super.$destroy();
1538
+ destroy() {
1539
+ this.binding.off(this.func);
1540
+ super.destroy();
1235
1541
  }
1236
1542
  }
1237
1543
 
1238
1544
  window.Binding = Binding;
1239
1545
 
1240
1546
  // ./lib/core/core.js
1547
+
1548
+ const currentStack = [];
1549
+ function stack(node) {
1550
+ currentStack.push(current);
1551
+ current = node;
1552
+ }
1553
+ function unstack() {
1554
+ current = currentStack.pop();
1555
+ }
1241
1556
  /**
1242
1557
  * Private stuff of a reactive object
1243
1558
  * @class ReactivePrivate
@@ -1270,16 +1585,18 @@ class ReactivePrivate extends Destroyable {
1270
1585
  * @type {boolean}
1271
1586
  */
1272
1587
  this.frozen = false;
1273
- this.$seal();
1588
+ this.seal();
1274
1589
  }
1275
- $destroy() {
1276
- var _a;
1277
- this.watch.forEach(value => value.$destroy());
1590
+ destroy() {
1591
+ this.watch.forEach(value => value.destroy());
1278
1592
  this.watch.clear();
1279
- this.bindings.forEach(binding => binding.$destroy());
1593
+ this.bindings.forEach(binding => binding.destroy());
1280
1594
  this.bindings.clear();
1281
- (_a = this.freezeExpr) === null || _a === void 0 ? void 0 : _a.$destroy();
1282
- super.$destroy();
1595
+ this.models.forEach(model => model.disableReactivity());
1596
+ this.models.clear();
1597
+ this.freezeExpr && this.freezeExpr.destroy();
1598
+ this.onDestroy && this.onDestroy();
1599
+ super.destroy();
1283
1600
  }
1284
1601
  }
1285
1602
  /**
@@ -1288,15 +1605,23 @@ class ReactivePrivate extends Destroyable {
1288
1605
  * @extends Destroyable
1289
1606
  */
1290
1607
  class Reactive extends Destroyable {
1291
- constructor($) {
1608
+ constructor(input, $) {
1292
1609
  super();
1610
+ this.input = input;
1293
1611
  this.$ = $ || new ReactivePrivate;
1612
+ this.seal();
1613
+ }
1614
+ /**
1615
+ * Get parent node
1616
+ */
1617
+ get parent() {
1618
+ return this.$.parent;
1294
1619
  }
1295
1620
  /**
1296
1621
  * Create a reference
1297
1622
  * @param value {*} value to reference
1298
1623
  */
1299
- $ref(value) {
1624
+ ref(value) {
1300
1625
  const $ = this.$;
1301
1626
  const ref = new Reference(value);
1302
1627
  $.watch.add(ref);
@@ -1306,7 +1631,7 @@ class Reactive extends Destroyable {
1306
1631
  * Create a mirror
1307
1632
  * @param value {IValue} value to mirror
1308
1633
  */
1309
- $mirror(value) {
1634
+ mirror(value) {
1310
1635
  const mirror = new Mirror(value, false);
1311
1636
  this.$.watch.add(mirror);
1312
1637
  return mirror;
@@ -1315,7 +1640,7 @@ class Reactive extends Destroyable {
1315
1640
  * Create a forward-only mirror
1316
1641
  * @param value {IValue} value to mirror
1317
1642
  */
1318
- $forward(value) {
1643
+ forward(value) {
1319
1644
  const mirror = new Mirror(value, true);
1320
1645
  this.$.watch.add(mirror);
1321
1646
  return mirror;
@@ -1325,14 +1650,9 @@ class Reactive extends Destroyable {
1325
1650
  * @param value {*} default value to point
1326
1651
  * @param forwardOnly {boolean} forward only sync
1327
1652
  */
1328
- $point(value, forwardOnly = false) {
1653
+ point(value, forwardOnly = false) {
1329
1654
  const $ = this.$;
1330
- const ref = value instanceof IValue ? value : new Reference(value);
1331
- const pointer = new Pointer(ref, forwardOnly);
1332
- // when value is an ivalue will be equal to ref
1333
- if (value !== ref) {
1334
- $.watch.add(ref);
1335
- }
1655
+ const pointer = new Pointer(value, forwardOnly);
1336
1656
  $.watch.add(pointer);
1337
1657
  return pointer;
1338
1658
  }
@@ -1340,16 +1660,27 @@ class Reactive extends Destroyable {
1340
1660
  * Register a model
1341
1661
  * @param model
1342
1662
  */
1343
- $register(model) {
1663
+ register(model) {
1344
1664
  this.$.models.add(model);
1345
1665
  return model;
1346
1666
  }
1347
- $watch(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1667
+ /**
1668
+ * Creates a watcher
1669
+ * @param func {function} function to run on any argument change
1670
+ * @param values
1671
+ */
1672
+ watch(func, ...values) {
1348
1673
  const $ = this.$;
1349
- $.watch.add(new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9));
1674
+ $.watch.add(new Expression(func, !this.$.frozen, ...values));
1350
1675
  }
1351
- $bind(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1352
- const res = new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1676
+ /**
1677
+ * Creates a computed value
1678
+ * @param func {function} function to run on any argument change
1679
+ * @param values
1680
+ * @return {IValue} the created ivalue
1681
+ */
1682
+ expr(func, ...values) {
1683
+ const res = new Expression(func, !this.$.frozen, ...values);
1353
1684
  const $ = this.$;
1354
1685
  $.watch.add(res);
1355
1686
  return res;
@@ -1357,7 +1688,7 @@ class Reactive extends Destroyable {
1357
1688
  /**
1358
1689
  * Enable reactivity of fields
1359
1690
  */
1360
- $enable() {
1691
+ enable() {
1361
1692
  const $ = this.$;
1362
1693
  if (!$.enabled) {
1363
1694
  $.watch.forEach(watcher => {
@@ -1372,7 +1703,7 @@ class Reactive extends Destroyable {
1372
1703
  /**
1373
1704
  * Disable reactivity of fields
1374
1705
  */
1375
- $disable() {
1706
+ disable() {
1376
1707
  const $ = this.$;
1377
1708
  if ($.enabled) {
1378
1709
  $.watch.forEach(watcher => {
@@ -1390,7 +1721,7 @@ class Reactive extends Destroyable {
1390
1721
  * @param onOff {function} on show feedback
1391
1722
  * @param onOn {function} on hide feedback
1392
1723
  */
1393
- $bindAlive(cond, onOff, onOn) {
1724
+ bindAlive(cond, onOff, onOn) {
1394
1725
  const $ = this.$;
1395
1726
  if ($.freezeExpr) {
1396
1727
  throw wrongBinding("this component already have a freeze state");
@@ -1402,18 +1733,46 @@ class Reactive extends Destroyable {
1402
1733
  $.frozen = !cond;
1403
1734
  if (cond) {
1404
1735
  onOn === null || onOn === void 0 ? void 0 : onOn();
1405
- this.$enable();
1736
+ this.enable();
1406
1737
  }
1407
1738
  else {
1408
1739
  onOff === null || onOff === void 0 ? void 0 : onOff();
1409
- this.$disable();
1740
+ this.disable();
1410
1741
  }
1411
1742
  }, true, cond);
1412
1743
  return this;
1413
1744
  }
1414
- $destroy() {
1415
- super.$destroy();
1416
- this.$.$destroy();
1745
+ init() {
1746
+ this.applyOptions(this.input);
1747
+ this.compose(this.input);
1748
+ }
1749
+ applyOptions(input) {
1750
+ // empty
1751
+ }
1752
+ applyOptionsNow() {
1753
+ this.applyOptions(this.input);
1754
+ }
1755
+ compose(input) {
1756
+ // empty
1757
+ }
1758
+ composeNow() {
1759
+ this.compose(this.input);
1760
+ }
1761
+ runFunctional(f, ...args) {
1762
+ stack(this);
1763
+ // yet another ts bug
1764
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1765
+ // @ts-ignore
1766
+ const result = f(...args);
1767
+ unstack();
1768
+ return result;
1769
+ }
1770
+ runOnDestroy(func) {
1771
+ this.$.onDestroy = func;
1772
+ }
1773
+ destroy() {
1774
+ super.destroy();
1775
+ this.$.destroy();
1417
1776
  this.$ = null;
1418
1777
  }
1419
1778
  }
@@ -1430,7 +1789,7 @@ window.Reactive = Reactive;
1430
1789
  class FragmentPrivate extends ReactivePrivate {
1431
1790
  constructor() {
1432
1791
  super();
1433
- this.$seal();
1792
+ this.seal();
1434
1793
  }
1435
1794
  /**
1436
1795
  * Pre-initializes the base of a fragment
@@ -1444,10 +1803,10 @@ class FragmentPrivate extends ReactivePrivate {
1444
1803
  /**
1445
1804
  * Unlinks all bindings
1446
1805
  */
1447
- $destroy() {
1806
+ destroy() {
1448
1807
  this.next = null;
1449
1808
  this.prev = null;
1450
- super.$destroy();
1809
+ super.destroy();
1451
1810
  }
1452
1811
  }
1453
1812
  /**
@@ -1457,16 +1816,17 @@ class FragmentPrivate extends ReactivePrivate {
1457
1816
  class Fragment extends Reactive {
1458
1817
  /**
1459
1818
  * Constructs a Vasille Node
1819
+ * @param input
1460
1820
  * @param $ {FragmentPrivate}
1461
1821
  */
1462
- constructor($) {
1463
- super();
1822
+ constructor(input, $) {
1823
+ super(input, $ || new FragmentPrivate);
1464
1824
  /**
1465
1825
  * The children list
1466
1826
  * @type Array
1467
1827
  */
1468
- this.$children = [];
1469
- this.$ = $ || new FragmentPrivate;
1828
+ this.children = new Set;
1829
+ this.lastChild = null;
1470
1830
  }
1471
1831
  /**
1472
1832
  * Gets the app of node
@@ -1480,43 +1840,20 @@ class Fragment extends Reactive {
1480
1840
  * @param parent {Fragment} parent of node
1481
1841
  * @param data {*} additional data
1482
1842
  */
1483
- $preinit(app, parent, data) {
1843
+ preinit(app, parent, data) {
1484
1844
  const $ = this.$;
1485
1845
  $.preinit(app, parent);
1486
1846
  }
1487
- /**
1488
- * Initialize node
1489
- */
1490
- $init() {
1491
- this.$createSignals();
1492
- this.$createWatchers();
1493
- this.$created();
1494
- this.$compose();
1495
- this.$mounted();
1496
- return this;
1497
- }
1498
- /** To be overloaded: created event handler */
1499
- $created() {
1500
- // empty
1847
+ init() {
1848
+ super.init();
1849
+ this.ready();
1501
1850
  }
1502
- /** To be overloaded: mounted event handler */
1503
- $mounted() {
1504
- // empty
1851
+ compose(input) {
1852
+ super.compose(input);
1853
+ input.slot && input.slot(this);
1505
1854
  }
1506
1855
  /** To be overloaded: ready event handler */
1507
- $ready() {
1508
- // empty
1509
- }
1510
- /** To be overloaded: signals creation milestone */
1511
- $createSignals() {
1512
- // empty
1513
- }
1514
- /** To be overloaded: watchers creation milestone */
1515
- $createWatchers() {
1516
- // empty
1517
- }
1518
- /** To be overloaded: DOM creation milestone */
1519
- $compose() {
1856
+ ready() {
1520
1857
  // empty
1521
1858
  }
1522
1859
  /**
@@ -1524,27 +1861,23 @@ class Fragment extends Reactive {
1524
1861
  * @param node {Fragment} A node to push
1525
1862
  * @protected
1526
1863
  */
1527
- $$pushNode(node) {
1528
- let lastChild = null;
1529
- if (this.$children.length) {
1530
- lastChild = this.$children[this.$children.length - 1];
1864
+ pushNode(node) {
1865
+ if (this.lastChild) {
1866
+ this.lastChild.$.next = node;
1531
1867
  }
1532
- if (lastChild) {
1533
- lastChild.$.next = node;
1534
- }
1535
- node.$.prev = lastChild;
1536
- node.$.parent = this;
1537
- this.$children.push(node);
1868
+ node.$.prev = this.lastChild;
1869
+ this.lastChild = node;
1870
+ this.children.add(node);
1538
1871
  }
1539
1872
  /**
1540
1873
  * Find first node in element if so exists
1541
1874
  * @return {?Element}
1542
1875
  * @protected
1543
1876
  */
1544
- $$findFirstChild() {
1877
+ findFirstChild() {
1545
1878
  let first;
1546
- this.$children.forEach(child => {
1547
- first = first || child.$$findFirstChild();
1879
+ this.children.forEach(child => {
1880
+ first = first || child.findFirstChild();
1548
1881
  });
1549
1882
  return first;
1550
1883
  }
@@ -1552,30 +1885,30 @@ class Fragment extends Reactive {
1552
1885
  * Append a node to end of element
1553
1886
  * @param node {Node} node to insert
1554
1887
  */
1555
- $$appendNode(node) {
1888
+ appendNode(node) {
1556
1889
  const $ = this.$;
1557
1890
  if ($.next) {
1558
- $.next.$$insertAdjacent(node);
1891
+ $.next.insertAdjacent(node);
1559
1892
  }
1560
1893
  else {
1561
- $.parent.$$appendNode(node);
1894
+ $.parent.appendNode(node);
1562
1895
  }
1563
1896
  }
1564
1897
  /**
1565
1898
  * Insert a node as a sibling of this
1566
1899
  * @param node {Node} node to insert
1567
1900
  */
1568
- $$insertAdjacent(node) {
1569
- const child = this.$$findFirstChild();
1901
+ insertAdjacent(node) {
1902
+ const child = this.findFirstChild();
1570
1903
  const $ = this.$;
1571
1904
  if (child) {
1572
- $.app.$run.insertBefore(child, node);
1905
+ child.parentElement.insertBefore(node, child);
1573
1906
  }
1574
1907
  else if ($.next) {
1575
- $.next.$$insertAdjacent(node);
1908
+ $.next.insertAdjacent(node);
1576
1909
  }
1577
1910
  else {
1578
- $.parent.$$appendNode(node);
1911
+ $.parent.appendNode(node);
1579
1912
  }
1580
1913
  }
1581
1914
  /**
@@ -1583,60 +1916,48 @@ class Fragment extends Reactive {
1583
1916
  * @param text {String | IValue} A text fragment string
1584
1917
  * @param cb {function (TextNode)} Callback if previous is slot name
1585
1918
  */
1586
- $text(text, cb) {
1919
+ text(text, cb) {
1587
1920
  const $ = this.$;
1588
1921
  const node = new TextNode();
1589
- const textValue = text instanceof IValue ? text : this.$ref(text);
1590
- node.$preinit($.app, this, textValue);
1591
- this.$$pushNode(node);
1592
- if (cb) {
1593
- $.app.$run.callCallback(() => {
1594
- cb(node);
1595
- });
1596
- }
1597
- return this;
1922
+ node.preinit($.app, this, text);
1923
+ this.pushNode(node);
1924
+ cb && cb(node);
1598
1925
  }
1599
- $debug(text) {
1600
- if (this.$.app.$debugUi) {
1926
+ debug(text) {
1927
+ if (this.$.app.debugUi) {
1601
1928
  const node = new DebugNode();
1602
- node.$preinit(this.$.app, this, text);
1603
- this.$$pushNode(node);
1929
+ node.preinit(this.$.app, this, text);
1930
+ this.pushNode(node);
1604
1931
  }
1605
- return this;
1606
1932
  }
1607
- $tag(tagName, cb) {
1933
+ /**
1934
+ * Defines a tag element
1935
+ * @param tagName {String} the tag name
1936
+ * @param input
1937
+ * @param cb {function(Tag, *)} callback
1938
+ */
1939
+ tag(tagName, input, cb) {
1608
1940
  const $ = this.$;
1609
- const node = new Tag();
1610
- node.$preinit($.app, this, tagName);
1611
- node.$init();
1612
- this.$$pushNode(node);
1613
- $.app.$run.callCallback(() => {
1614
- if (cb) {
1615
- cb(node, node.node);
1616
- }
1617
- node.$ready();
1618
- });
1619
- return this;
1941
+ const node = new Tag(input);
1942
+ input.slot = cb || input.slot;
1943
+ node.preinit($.app, this, tagName);
1944
+ node.init();
1945
+ this.pushNode(node);
1946
+ node.ready();
1947
+ return node.node;
1620
1948
  }
1621
1949
  /**
1622
1950
  * Defines a custom element
1623
1951
  * @param node {Fragment} vasille element to insert
1624
1952
  * @param callback {function($ : *)}
1625
- * @param callback1 {function($ : *)}
1626
1953
  */
1627
- $create(node, callback, callback1) {
1954
+ create(node, callback) {
1628
1955
  const $ = this.$;
1629
1956
  node.$.parent = this;
1630
- node.$preinit($.app, this);
1631
- if (callback) {
1632
- callback(node);
1633
- }
1634
- if (callback1) {
1635
- callback1(node);
1636
- }
1637
- this.$$pushNode(node);
1638
- node.$init().$ready();
1639
- return this;
1957
+ node.preinit($.app, this);
1958
+ node.input.slot = callback || node.input.slot;
1959
+ this.pushNode(node);
1960
+ node.init();
1640
1961
  }
1641
1962
  /**
1642
1963
  * Defines an if node
@@ -1644,32 +1965,29 @@ class Fragment extends Reactive {
1644
1965
  * @param cb {function(Fragment)} callback to run on true
1645
1966
  * @return {this}
1646
1967
  */
1647
- $if(cond, cb) {
1648
- return this.$switch({ cond, cb });
1968
+ if(cond, cb) {
1969
+ const node = new SwitchedNode();
1970
+ node.preinit(this.$.app, this);
1971
+ node.init();
1972
+ this.pushNode(node);
1973
+ node.addCase(this.case(cond, cb));
1974
+ node.ready();
1649
1975
  }
1650
- /**
1651
- * Defines a if-else node
1652
- * @param ifCond {IValue} `if` condition
1653
- * @param ifCb {function(Fragment)} Call-back to create `if` child nodes
1654
- * @param elseCb {function(Fragment)} Call-back to create `else` child nodes
1655
- */
1656
- $if_else(ifCond, ifCb, elseCb) {
1657
- return this.$switch({ cond: ifCond, cb: ifCb }, { cond: trueIValue, cb: elseCb });
1976
+ else(cb) {
1977
+ if (this.lastChild instanceof SwitchedNode) {
1978
+ this.lastChild.addCase(this.default(cb));
1979
+ }
1980
+ else {
1981
+ throw userError('wrong `else` function use', 'logic-error');
1982
+ }
1658
1983
  }
1659
- /**
1660
- * Defines a switch nodes: Will break after first true condition
1661
- * @param cases {...{ cond : IValue, cb : function(Fragment) }} cases
1662
- * @return {INode}
1663
- */
1664
- $switch(...cases) {
1665
- const $ = this.$;
1666
- const node = new SwitchedNode();
1667
- node.$preinit($.app, this);
1668
- node.$init();
1669
- this.$$pushNode(node);
1670
- node.setCases(cases);
1671
- node.$ready();
1672
- return this;
1984
+ elif(cond, cb) {
1985
+ if (this.lastChild instanceof SwitchedNode) {
1986
+ this.lastChild.addCase(this.case(cond, cb));
1987
+ }
1988
+ else {
1989
+ throw userError('wrong `elif` function use', 'logic-error');
1990
+ }
1673
1991
  }
1674
1992
  /**
1675
1993
  * Create a case for switch
@@ -1677,22 +1995,48 @@ class Fragment extends Reactive {
1677
1995
  * @param cb {function(Fragment) : void}
1678
1996
  * @return {{cond : IValue, cb : (function(Fragment) : void)}}
1679
1997
  */
1680
- $case(cond, cb) {
1998
+ case(cond, cb) {
1681
1999
  return { cond, cb };
1682
2000
  }
1683
2001
  /**
1684
2002
  * @param cb {(function(Fragment) : void)}
1685
2003
  * @return {{cond : IValue, cb : (function(Fragment) : void)}}
1686
2004
  */
1687
- $default(cb) {
2005
+ default(cb) {
1688
2006
  return { cond: trueIValue, cb };
1689
2007
  }
1690
- $destroy() {
1691
- for (const child of this.$children) {
1692
- child.$destroy();
2008
+ insertBefore(node) {
2009
+ const $ = this.$;
2010
+ node.$.prev = $.prev;
2011
+ node.$.next = this;
2012
+ if ($.prev) {
2013
+ $.prev.$.next = node;
2014
+ }
2015
+ $.prev = node;
2016
+ }
2017
+ insertAfter(node) {
2018
+ const $ = this.$;
2019
+ node.$.prev = this;
2020
+ node.$.next = $.next;
2021
+ $.next = node;
2022
+ }
2023
+ remove() {
2024
+ const $ = this.$;
2025
+ if ($.next) {
2026
+ $.next.$.prev = $.prev;
2027
+ }
2028
+ if ($.prev) {
2029
+ $.prev.$.next = $.next;
2030
+ }
2031
+ }
2032
+ destroy() {
2033
+ this.children.forEach(child => child.destroy());
2034
+ this.children.clear();
2035
+ this.lastChild = null;
2036
+ if (this.$.parent.lastChild === this) {
2037
+ this.$.parent.lastChild = this.$.prev;
1693
2038
  }
1694
- this.$children.splice(0);
1695
- super.$destroy();
2039
+ super.destroy();
1696
2040
  }
1697
2041
  }
1698
2042
  const trueIValue = new Reference(true);
@@ -1704,26 +2048,28 @@ const trueIValue = new Reference(true);
1704
2048
  class TextNodePrivate extends FragmentPrivate {
1705
2049
  constructor() {
1706
2050
  super();
1707
- this.$seal();
2051
+ this.seal();
1708
2052
  }
1709
2053
  /**
1710
2054
  * Pre-initializes a text node
1711
2055
  * @param app {AppNode} the app node
2056
+ * @param parent
1712
2057
  * @param text {IValue}
1713
2058
  */
1714
2059
  preinitText(app, parent, text) {
1715
2060
  super.preinit(app, parent);
1716
- this.node = document.createTextNode(text.$);
1717
- this.bindings.add(new Expression((v) => {
1718
- this.node.replaceData(0, -1, v);
1719
- }, true, text));
1720
- this.parent.$$appendNode(this.node);
2061
+ this.node = document.createTextNode(text instanceof IValue ? text.$ : text);
2062
+ if (text instanceof IValue) {
2063
+ this.bindings.add(new Expression((v) => {
2064
+ this.node.replaceData(0, -1, v);
2065
+ }, true, text));
2066
+ }
1721
2067
  }
1722
2068
  /**
1723
2069
  * Clear node data
1724
2070
  */
1725
- $destroy() {
1726
- super.$destroy();
2071
+ destroy() {
2072
+ super.destroy();
1727
2073
  }
1728
2074
  }
1729
2075
  /**
@@ -1732,25 +2078,25 @@ class TextNodePrivate extends FragmentPrivate {
1732
2078
  * @extends Fragment
1733
2079
  */
1734
2080
  class TextNode extends Fragment {
1735
- constructor() {
1736
- super();
1737
- this.$ = new TextNodePrivate();
1738
- this.$seal();
2081
+ constructor($ = new TextNodePrivate()) {
2082
+ super({}, $);
2083
+ this.seal();
1739
2084
  }
1740
- $preinit(app, parent, text) {
2085
+ preinit(app, parent, text) {
1741
2086
  const $ = this.$;
1742
2087
  if (!text) {
1743
2088
  throw internalError('wrong TextNode::$preninit call');
1744
2089
  }
1745
2090
  $.preinitText(app, parent, text);
2091
+ $.parent.appendNode($.node);
1746
2092
  }
1747
- $$findFirstChild() {
2093
+ findFirstChild() {
1748
2094
  return this.$.node;
1749
2095
  }
1750
- $destroy() {
2096
+ destroy() {
1751
2097
  this.$.node.remove();
1752
- this.$.$destroy();
1753
- super.$destroy();
2098
+ this.$.destroy();
2099
+ super.destroy();
1754
2100
  }
1755
2101
  }
1756
2102
  /**
@@ -1766,10 +2112,10 @@ class INodePrivate extends FragmentPrivate {
1766
2112
  * @type {boolean}
1767
2113
  */
1768
2114
  this.unmounted = false;
1769
- this.$seal();
2115
+ this.seal();
1770
2116
  }
1771
- $destroy() {
1772
- super.$destroy();
2117
+ destroy() {
2118
+ super.destroy();
1773
2119
  }
1774
2120
  }
1775
2121
  /**
@@ -1780,11 +2126,12 @@ class INodePrivate extends FragmentPrivate {
1780
2126
  class INode extends Fragment {
1781
2127
  /**
1782
2128
  * Constructs a base node
2129
+ * @param input
1783
2130
  * @param $ {?INodePrivate}
1784
2131
  */
1785
- constructor($) {
1786
- super($ || new INodePrivate);
1787
- this.$seal();
2132
+ constructor(input, $) {
2133
+ super(input, $ || new INodePrivate);
2134
+ this.seal();
1788
2135
  }
1789
2136
  /**
1790
2137
  * Get the bound node
@@ -1792,78 +2139,55 @@ class INode extends Fragment {
1792
2139
  get node() {
1793
2140
  return this.$.node;
1794
2141
  }
1795
- /**
1796
- * Initialize node
1797
- */
1798
- $init() {
1799
- this.$createSignals();
1800
- this.$createWatchers();
1801
- this.$createAttrs();
1802
- this.$createStyle();
1803
- this.$created();
1804
- this.$compose();
1805
- this.$mounted();
1806
- return this;
1807
- }
1808
- /** To be overloaded: attributes creation milestone */
1809
- $createAttrs() {
1810
- // empty
1811
- }
1812
- /** To be overloaded: $style attributes creation milestone */
1813
- $createStyle() {
1814
- // empty
1815
- }
1816
2142
  /**
1817
2143
  * Bind attribute value
1818
2144
  * @param name {String} name of attribute
1819
2145
  * @param value {IValue} value
1820
2146
  */
1821
- $attr(name, value) {
2147
+ attr(name, value) {
1822
2148
  const $ = this.$;
1823
2149
  const attr = new AttributeBinding(this, name, value);
1824
2150
  $.bindings.add(attr);
1825
- return this;
1826
- }
1827
- $bindAttr(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1828
- const $ = this.$;
1829
- const expr = this.$bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1830
- $.bindings.add(new AttributeBinding(this, name, expr));
1831
- return this;
1832
2151
  }
1833
2152
  /**
1834
2153
  * Set attribute value
1835
2154
  * @param name {string} name of attribute
1836
2155
  * @param value {string} value
1837
2156
  */
1838
- $setAttr(name, value) {
1839
- this.$.app.$run.setAttribute(this.$.node, name, value);
2157
+ setAttr(name, value) {
2158
+ if (typeof value === 'boolean') {
2159
+ if (value) {
2160
+ this.$.node.setAttribute(name, "");
2161
+ }
2162
+ }
2163
+ else {
2164
+ this.$.node.setAttribute(name, `${value}`);
2165
+ }
1840
2166
  return this;
1841
2167
  }
1842
2168
  /**
1843
2169
  * Adds a CSS class
1844
2170
  * @param cl {string} Class name
1845
2171
  */
1846
- $addClass(cl) {
1847
- this.$.app.$run.addClass(this.$.node, cl);
2172
+ addClass(cl) {
2173
+ this.$.node.classList.add(cl);
1848
2174
  return this;
1849
2175
  }
1850
2176
  /**
1851
2177
  * Adds some CSS classes
1852
2178
  * @param cls {...string} classes names
1853
2179
  */
1854
- $addClasses(...cls) {
1855
- cls.forEach(cl => {
1856
- this.$.app.$run.addClass(this.$.node, cl);
1857
- });
2180
+ removeClasse(cl) {
2181
+ this.$.node.classList.remove(cl);
1858
2182
  return this;
1859
2183
  }
1860
2184
  /**
1861
2185
  * Bind a CSS class
1862
2186
  * @param className {IValue}
1863
2187
  */
1864
- $bindClass(className) {
2188
+ bindClass(className) {
1865
2189
  const $ = this.$;
1866
- $.bindings.add(new ClassBinding(this, "", className));
2190
+ $.bindings.add(new DynamicalClassBinding(this, className));
1867
2191
  return this;
1868
2192
  }
1869
2193
  /**
@@ -1871,8 +2195,8 @@ class INode extends Fragment {
1871
2195
  * @param cond {IValue} condition
1872
2196
  * @param className {string} class name
1873
2197
  */
1874
- $floatingClass(cond, className) {
1875
- this.$.bindings.add(new ClassBinding(this, className, cond));
2198
+ floatingClass(cond, className) {
2199
+ this.$.bindings.add(new StaticClassBinding(this, className, cond));
1876
2200
  return this;
1877
2201
  }
1878
2202
  /**
@@ -1880,7 +2204,7 @@ class INode extends Fragment {
1880
2204
  * @param name {String} name of style attribute
1881
2205
  * @param value {IValue} value
1882
2206
  */
1883
- $style(name, value) {
2207
+ style(name, value) {
1884
2208
  const $ = this.$;
1885
2209
  if ($.node instanceof HTMLElement) {
1886
2210
  $.bindings.add(new StyleBinding(this, name, value));
@@ -1890,28 +2214,17 @@ class INode extends Fragment {
1890
2214
  }
1891
2215
  return this;
1892
2216
  }
1893
- $bindStyle(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1894
- const $ = this.$;
1895
- const expr = this.$bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1896
- if ($.node instanceof HTMLElement) {
1897
- $.bindings.add(new StyleBinding(this, name, expr));
1898
- }
1899
- else {
1900
- throw userError('style can be applied to HTML elements only', 'non-html-element');
1901
- }
1902
- return this;
1903
- }
1904
2217
  /**
1905
2218
  * Sets a style property value
1906
2219
  * @param prop {string} Property name
1907
2220
  * @param value {string} Property value
1908
2221
  */
1909
- $setStyle(prop, value) {
2222
+ setStyle(prop, value) {
1910
2223
  if (this.$.node instanceof HTMLElement) {
1911
- this.$.app.$run.setStyle(this.$.node, prop, value);
2224
+ this.$.node.style.setProperty(prop, value);
1912
2225
  }
1913
2226
  else {
1914
- throw userError("Style can be setted for HTML elements only", "non-html-element");
2227
+ throw userError("Style can be set for HTML elements only", "non-html-element");
1915
2228
  }
1916
2229
  return this;
1917
2230
  }
@@ -1921,403 +2234,24 @@ class INode extends Fragment {
1921
2234
  * @param handler {function (Event)} Event handler
1922
2235
  * @param options {Object | boolean} addEventListener options
1923
2236
  */
1924
- $listen(name, handler, options) {
2237
+ listen(name, handler, options) {
1925
2238
  this.$.node.addEventListener(name, handler, options);
1926
2239
  return this;
1927
2240
  }
1928
- /**
1929
- * @param handler {function (MouseEvent)}
1930
- * @param options {Object | boolean}
1931
- */
1932
- $oncontextmenu(handler, options) {
1933
- return this.$listen("contextmenu", handler, options);
1934
- }
1935
- /**
1936
- * @param handler {function (MouseEvent)}
1937
- * @param options {Object | boolean}
1938
- */
1939
- $onmousedown(handler, options) {
1940
- return this.$listen("mousedown", handler, options);
1941
- }
1942
- /**
1943
- * @param handler {function (MouseEvent)}
1944
- * @param options {Object | boolean}
1945
- */
1946
- $onmouseenter(handler, options) {
1947
- return this.$listen("mouseenter", handler, options);
2241
+ insertAdjacent(node) {
2242
+ this.$.node.parentNode.insertBefore(node, this.$.node);
1948
2243
  }
1949
2244
  /**
1950
- * @param handler {function (MouseEvent)}
1951
- * @param options {Object | boolean}
2245
+ * A v-show & ngShow alternative
2246
+ * @param cond {IValue} show condition
1952
2247
  */
1953
- $onmouseleave(handler, options) {
1954
- return this.$listen("mouseleave", handler, options);
1955
- }
1956
- /**
1957
- * @param handler {function (MouseEvent)}
1958
- * @param options {Object | boolean}
1959
- */
1960
- $onmousemove(handler, options) {
1961
- return this.$listen("mousemove", handler, options);
1962
- }
1963
- /**
1964
- * @param handler {function (MouseEvent)}
1965
- * @param options {Object | boolean}
1966
- */
1967
- $onmouseout(handler, options) {
1968
- return this.$listen("mouseout", handler, options);
1969
- }
1970
- /**
1971
- * @param handler {function (MouseEvent)}
1972
- * @param options {Object | boolean}
1973
- */
1974
- $onmouseover(handler, options) {
1975
- return this.$listen("mouseover", handler, options);
1976
- }
1977
- /**
1978
- * @param handler {function (MouseEvent)}
1979
- * @param options {Object | boolean}
1980
- */
1981
- $onmouseup(handler, options) {
1982
- return this.$listen("mouseup", handler, options);
1983
- }
1984
- /**
1985
- * @param handler {function (MouseEvent)}
1986
- * @param options {Object | boolean}
1987
- */
1988
- $onclick(handler, options) {
1989
- return this.$listen("click", handler, options);
1990
- }
1991
- /**
1992
- * @param handler {function (MouseEvent)}
1993
- * @param options {Object | boolean}
1994
- */
1995
- $ondblclick(handler, options) {
1996
- return this.$listen("dblclick", handler, options);
1997
- }
1998
- /**
1999
- * @param handler {function (FocusEvent)}
2000
- * @param options {Object | boolean}
2001
- */
2002
- $onblur(handler, options) {
2003
- return this.$listen("blur", handler, options);
2004
- }
2005
- /**
2006
- * @param handler {function (FocusEvent)}
2007
- * @param options {Object | boolean}
2008
- */
2009
- $onfocus(handler, options) {
2010
- return this.$listen("focus", handler, options);
2011
- }
2012
- /**
2013
- * @param handler {function (FocusEvent)}
2014
- * @param options {Object | boolean}
2015
- */
2016
- $onfocusin(handler, options) {
2017
- return this.$listen("focusin", handler, options);
2018
- }
2019
- /**
2020
- * @param handler {function (FocusEvent)}
2021
- * @param options {Object | boolean}
2022
- */
2023
- $onfocusout(handler, options) {
2024
- return this.$listen("focusout", handler, options);
2025
- }
2026
- /**
2027
- * @param handler {function (KeyboardEvent)}
2028
- * @param options {Object | boolean}
2029
- */
2030
- $onkeydown(handler, options) {
2031
- return this.$listen("keydown", handler, options);
2032
- }
2033
- /**
2034
- * @param handler {function (KeyboardEvent)}
2035
- * @param options {Object | boolean}
2036
- */
2037
- $onkeyup(handler, options) {
2038
- return this.$listen("keyup", handler, options);
2039
- }
2040
- /**
2041
- * @param handler {function (KeyboardEvent)}
2042
- * @param options {Object | boolean}
2043
- */
2044
- $onkeypress(handler, options) {
2045
- return this.$listen("keypress", handler, options);
2046
- }
2047
- /**
2048
- * @param handler {function (TouchEvent)}
2049
- * @param options {Object | boolean}
2050
- */
2051
- $ontouchstart(handler, options) {
2052
- return this.$listen("touchstart", handler, options);
2053
- }
2054
- /**
2055
- * @param handler {function (TouchEvent)}
2056
- * @param options {Object | boolean}
2057
- */
2058
- $ontouchmove(handler, options) {
2059
- return this.$listen("touchmove", handler, options);
2060
- }
2061
- /**
2062
- * @param handler {function (TouchEvent)}
2063
- * @param options {Object | boolean}
2064
- */
2065
- $ontouchend(handler, options) {
2066
- return this.$listen("touchend", handler, options);
2067
- }
2068
- /**
2069
- * @param handler {function (TouchEvent)}
2070
- * @param options {Object | boolean}
2071
- */
2072
- $ontouchcancel(handler, options) {
2073
- return this.$listen("touchcancel", handler, options);
2074
- }
2075
- /**
2076
- * @param handler {function (WheelEvent)}
2077
- * @param options {Object | boolean}
2078
- */
2079
- $onwheel(handler, options) {
2080
- return this.$listen("wheel", handler, options);
2081
- }
2082
- /**
2083
- * @param handler {function (ProgressEvent)}
2084
- * @param options {Object | boolean}
2085
- */
2086
- $onabort(handler, options) {
2087
- return this.$listen("abort", handler, options);
2088
- }
2089
- /**
2090
- * @param handler {function (ProgressEvent)}
2091
- * @param options {Object | boolean}
2092
- */
2093
- $onerror(handler, options) {
2094
- return this.$listen("error", handler, options);
2095
- }
2096
- /**
2097
- * @param handler {function (ProgressEvent)}
2098
- * @param options {Object | boolean}
2099
- */
2100
- $onload(handler, options) {
2101
- return this.$listen("load", handler, options);
2102
- }
2103
- /**
2104
- * @param handler {function (ProgressEvent)}
2105
- * @param options {Object | boolean}
2106
- */
2107
- $onloadend(handler, options) {
2108
- return this.$listen("loadend", handler, options);
2109
- }
2110
- /**
2111
- * @param handler {function (ProgressEvent)}
2112
- * @param options {Object | boolean}
2113
- */
2114
- $onloadstart(handler, options) {
2115
- return this.$listen("loadstart", handler, options);
2116
- }
2117
- /**
2118
- * @param handler {function (ProgressEvent)}
2119
- * @param options {Object | boolean}
2120
- */
2121
- $onprogress(handler, options) {
2122
- return this.$listen("progress", handler, options);
2123
- }
2124
- /**
2125
- * @param handler {function (ProgressEvent)}
2126
- * @param options {Object | boolean}
2127
- */
2128
- $ontimeout(handler, options) {
2129
- return this.$listen("timeout", handler, options);
2130
- }
2131
- /**
2132
- * @param handler {function (DragEvent)}
2133
- * @param options {Object | boolean}
2134
- */
2135
- $ondrag(handler, options) {
2136
- return this.$listen("drag", handler, options);
2137
- }
2138
- /**
2139
- * @param handler {function (DragEvent)}
2140
- * @param options {Object | boolean}
2141
- */
2142
- $ondragend(handler, options) {
2143
- return this.$listen("dragend", handler, options);
2144
- }
2145
- /**
2146
- * @param handler {function (DragEvent)}
2147
- * @param options {Object | boolean}
2148
- */
2149
- $ondragenter(handler, options) {
2150
- return this.$listen("dragenter", handler, options);
2151
- }
2152
- /**
2153
- * @param handler {function (DragEvent)}
2154
- * @param options {Object | boolean}
2155
- */
2156
- $ondragexit(handler, options) {
2157
- return this.$listen("dragexit", handler, options);
2158
- }
2159
- /**
2160
- * @param handler {function (DragEvent)}
2161
- * @param options {Object | boolean}
2162
- */
2163
- $ondragleave(handler, options) {
2164
- return this.$listen("dragleave", handler, options);
2165
- }
2166
- /**
2167
- * @param handler {function (DragEvent)}
2168
- * @param options {Object | boolean}
2169
- */
2170
- $ondragover(handler, options) {
2171
- return this.$listen("dragover", handler, options);
2172
- }
2173
- /**
2174
- * @param handler {function (DragEvent)}
2175
- * @param options {Object | boolean}
2176
- */
2177
- $ondragstart(handler, options) {
2178
- return this.$listen("dragstart", handler, options);
2179
- }
2180
- /**
2181
- * @param handler {function (DragEvent)}
2182
- * @param options {Object | boolean}
2183
- */
2184
- $ondrop(handler, options) {
2185
- return this.$listen("drop", handler, options);
2186
- }
2187
- /**
2188
- * @param handler {function (PointerEvent)}
2189
- * @param options {Object | boolean}
2190
- */
2191
- $onpointerover(handler, options) {
2192
- return this.$listen("pointerover", handler, options);
2193
- }
2194
- /**
2195
- * @param handler {function (PointerEvent)}
2196
- * @param options {Object | boolean}
2197
- */
2198
- $onpointerenter(handler, options) {
2199
- return this.$listen("pointerenter", handler, options);
2200
- }
2201
- /**
2202
- * @param handler {function (PointerEvent)}
2203
- * @param options {Object | boolean}
2204
- */
2205
- $onpointerdown(handler, options) {
2206
- return this.$listen("pointerdown", handler, options);
2207
- }
2208
- /**
2209
- * @param handler {function (PointerEvent)}
2210
- * @param options {Object | boolean}
2211
- */
2212
- $onpointermove(handler, options) {
2213
- return this.$listen("pointermove", handler, options);
2214
- }
2215
- /**
2216
- * @param handler {function (PointerEvent)}
2217
- * @param options {Object | boolean}
2218
- */
2219
- $onpointerup(handler, options) {
2220
- return this.$listen("pointerup", handler, options);
2221
- }
2222
- /**
2223
- * @param handler {function (PointerEvent)}
2224
- * @param options {Object | boolean}
2225
- */
2226
- $onpointercancel(handler, options) {
2227
- return this.$listen("pointercancel", handler, options);
2228
- }
2229
- /**
2230
- * @param handler {function (PointerEvent)}
2231
- * @param options {Object | boolean}
2232
- */
2233
- $onpointerout(handler, options) {
2234
- return this.$listen("pointerout", handler, options);
2235
- }
2236
- /**
2237
- * @param handler {function (PointerEvent)}
2238
- * @param options {Object | boolean}
2239
- */
2240
- $onpointerleave(handler, options) {
2241
- return this.$listen("pointerleave", handler, options);
2242
- }
2243
- /**
2244
- * @param handler {function (PointerEvent)}
2245
- * @param options {Object | boolean}
2246
- */
2247
- $ongotpointercapture(handler, options) {
2248
- return this.$listen("gotpointercapture", handler, options);
2249
- }
2250
- /**
2251
- * @param handler {function (PointerEvent)}
2252
- * @param options {Object | boolean}
2253
- */
2254
- $onlostpointercapture(handler, options) {
2255
- return this.$listen("lostpointercapture", handler, options);
2256
- }
2257
- /**
2258
- * @param handler {function (AnimationEvent)}
2259
- * @param options {Object | boolean}
2260
- */
2261
- $onanimationstart(handler, options) {
2262
- return this.$listen("animationstart", handler, options);
2263
- }
2264
- /**
2265
- * @param handler {function (AnimationEvent)}
2266
- * @param options {Object | boolean}
2267
- */
2268
- $onanimationend(handler, options) {
2269
- return this.$listen("animationend", handler, options);
2270
- }
2271
- /**
2272
- * @param handler {function (AnimationEvent)}
2273
- * @param options {Object | boolean}
2274
- */
2275
- $onanimationiteraton(handler, options) {
2276
- return this.$listen("animationiteration", handler, options);
2277
- }
2278
- /**
2279
- * @param handler {function (ClipboardEvent)}
2280
- * @param options {Object | boolean}
2281
- */
2282
- $onclipboardchange(handler, options) {
2283
- return this.$listen("clipboardchange", handler, options);
2284
- }
2285
- /**
2286
- * @param handler {function (ClipboardEvent)}
2287
- * @param options {Object | boolean}
2288
- */
2289
- $oncut(handler, options) {
2290
- return this.$listen("cut", handler, options);
2291
- }
2292
- /**
2293
- * @param handler {function (ClipboardEvent)}
2294
- * @param options {Object | boolean}
2295
- */
2296
- $oncopy(handler, options) {
2297
- return this.$listen("copy", handler, options);
2298
- }
2299
- /**
2300
- * @param handler {function (ClipboardEvent)}
2301
- * @param options {Object | boolean}
2302
- */
2303
- $onpaste(handler, options) {
2304
- return this.$listen("paste", handler, options);
2305
- }
2306
- $$insertAdjacent(node) {
2307
- const $ = this.$;
2308
- $.app.$run.insertBefore($.node, node);
2309
- }
2310
- /**
2311
- * A v-show & ngShow alternative
2312
- * @param cond {IValue} show condition
2313
- */
2314
- $bindShow(cond) {
2248
+ bindShow(cond) {
2315
2249
  const $ = this.$;
2316
2250
  const node = $.node;
2317
2251
  if (node instanceof HTMLElement) {
2318
2252
  let lastDisplay = node.style.display;
2319
2253
  const htmlNode = node;
2320
- return this.$bindAlive(cond, () => {
2254
+ return this.bindAlive(cond, () => {
2321
2255
  lastDisplay = htmlNode.style.display;
2322
2256
  htmlNode.style.display = 'none';
2323
2257
  }, () => {
@@ -2332,19 +2266,105 @@ class INode extends Fragment {
2332
2266
  * bind HTML
2333
2267
  * @param value {IValue}
2334
2268
  */
2335
- $html(value) {
2269
+ bindDomApi(name, value) {
2336
2270
  const $ = this.$;
2337
2271
  const node = $.node;
2338
2272
  if (node instanceof HTMLElement) {
2339
- node.innerHTML = value.$;
2340
- this.$watch((v) => {
2341
- node.innerHTML = v;
2273
+ node[name] = value.$;
2274
+ this.watch((v) => {
2275
+ node[name] = v;
2342
2276
  }, value);
2343
2277
  }
2344
2278
  else {
2345
2279
  throw userError("HTML can be bound for HTML nodes only", "dom-error");
2346
2280
  }
2347
2281
  }
2282
+ applyOptions(options) {
2283
+ options["v:attr"] && Object.keys(options["v:attr"]).forEach(name => {
2284
+ const value = options["v:attr"][name];
2285
+ if (value instanceof IValue) {
2286
+ this.attr(name, value);
2287
+ }
2288
+ else {
2289
+ this.setAttr(name, value);
2290
+ }
2291
+ });
2292
+ if (options.class) {
2293
+ const handleClass = (name, value) => {
2294
+ if (value instanceof IValue) {
2295
+ this.floatingClass(value, name);
2296
+ }
2297
+ else if (value && name !== '$') {
2298
+ this.addClass(name);
2299
+ }
2300
+ else {
2301
+ this.removeClasse(name);
2302
+ }
2303
+ };
2304
+ if (Array.isArray(options.class)) {
2305
+ options.class.forEach(item => {
2306
+ if (item instanceof IValue) {
2307
+ this.bindClass(item);
2308
+ }
2309
+ else if (typeof item == "string") {
2310
+ this.addClass(item);
2311
+ }
2312
+ else {
2313
+ Reflect.ownKeys(item).forEach((name) => {
2314
+ handleClass(name, item[name]);
2315
+ });
2316
+ }
2317
+ });
2318
+ }
2319
+ else {
2320
+ options.class.$.forEach(item => {
2321
+ this.bindClass(item);
2322
+ });
2323
+ Reflect.ownKeys(options.class).forEach((name) => {
2324
+ handleClass(name, options.class[name]);
2325
+ });
2326
+ }
2327
+ }
2328
+ options.style && Object.keys(options.style).forEach(name => {
2329
+ const value = options.style[name];
2330
+ if (value instanceof IValue) {
2331
+ this.style(name, value);
2332
+ }
2333
+ else if (typeof value === "string") {
2334
+ this.setStyle(name, value);
2335
+ }
2336
+ else {
2337
+ if (value[0] instanceof IValue) {
2338
+ this.style(name, this.expr((v) => v + value[1], value[0]));
2339
+ }
2340
+ else {
2341
+ this.setStyle(name, value[0] + value[1]);
2342
+ }
2343
+ }
2344
+ });
2345
+ options["v:events"] && Object.keys(options["v:events"]).forEach(name => {
2346
+ this.listen(name, options["v:events"][name]);
2347
+ });
2348
+ if (options["v:bind"]) {
2349
+ const inode = this.node;
2350
+ Reflect.ownKeys(options["v:bind"]).forEach((k) => {
2351
+ const value = options["v:bind"][k];
2352
+ if (k === 'value' && (inode instanceof HTMLInputElement || inode instanceof HTMLTextAreaElement)) {
2353
+ inode.oninput = () => value.$ = inode.value;
2354
+ }
2355
+ else if (k === 'checked' && inode instanceof HTMLInputElement) {
2356
+ inode.oninput = () => value.$ = inode.checked;
2357
+ }
2358
+ else if (k === 'volume' && inode instanceof HTMLMediaElement) {
2359
+ inode.onvolumechange = () => value.$ = inode.volume;
2360
+ }
2361
+ this.bindDomApi(k, value);
2362
+ });
2363
+ }
2364
+ options["v:set"] && Object.keys(options["v:set"]).forEach(key => {
2365
+ this.node[key] = options["v:set"][key];
2366
+ });
2367
+ }
2348
2368
  }
2349
2369
  /**
2350
2370
  * Represents an Vasille.js HTML element node
@@ -2352,11 +2372,11 @@ class INode extends Fragment {
2352
2372
  * @extends INode
2353
2373
  */
2354
2374
  class Tag extends INode {
2355
- constructor() {
2356
- super();
2357
- this.$seal();
2375
+ constructor(input) {
2376
+ super(input);
2377
+ this.seal();
2358
2378
  }
2359
- $preinit(app, parent, tagName) {
2379
+ preinit(app, parent, tagName) {
2360
2380
  if (!tagName || typeof tagName !== "string") {
2361
2381
  throw internalError('wrong Tag::$preinit call');
2362
2382
  }
@@ -2364,55 +2384,52 @@ class Tag extends INode {
2364
2384
  const $ = this.$;
2365
2385
  $.preinit(app, parent);
2366
2386
  $.node = node;
2367
- $.parent.$$appendNode(node);
2387
+ $.parent.appendNode(node);
2368
2388
  }
2369
- $$findFirstChild() {
2389
+ compose(input) {
2390
+ input.slot && input.slot(this);
2391
+ }
2392
+ findFirstChild() {
2370
2393
  return this.$.unmounted ? null : this.$.node;
2371
2394
  }
2372
- $$insertAdjacent(node) {
2395
+ insertAdjacent(node) {
2373
2396
  if (this.$.unmounted) {
2374
2397
  if (this.$.next) {
2375
- this.$.next.$$insertAdjacent(node);
2398
+ this.$.next.insertAdjacent(node);
2376
2399
  }
2377
2400
  else {
2378
- this.$.parent.$$appendNode(node);
2401
+ this.$.parent.appendNode(node);
2379
2402
  }
2380
2403
  }
2381
2404
  else {
2382
- super.$$insertAdjacent(node);
2405
+ super.insertAdjacent(node);
2383
2406
  }
2384
2407
  }
2385
- $$appendNode(node) {
2386
- const $ = this.$;
2387
- $.app.$run.appendChild($.node, node);
2408
+ appendNode(node) {
2409
+ this.$.node.appendChild(node);
2388
2410
  }
2389
2411
  /**
2390
2412
  * Mount/Unmount a node
2391
2413
  * @param cond {IValue} show condition
2392
2414
  */
2393
- $bindMount(cond) {
2415
+ bindMount(cond) {
2394
2416
  const $ = this.$;
2395
- return this.$bindAlive(cond, () => {
2417
+ this.bindAlive(cond, () => {
2396
2418
  $.node.remove();
2397
2419
  $.unmounted = true;
2398
2420
  }, () => {
2399
- if (!$.unmounted)
2400
- return;
2401
- if ($.next) {
2402
- $.next.$$insertAdjacent($.node);
2403
- }
2404
- else {
2405
- $.parent.$$appendNode($.node);
2421
+ if ($.unmounted) {
2422
+ this.insertAdjacent($.node);
2423
+ $.unmounted = false;
2406
2424
  }
2407
- $.unmounted = false;
2408
2425
  });
2409
2426
  }
2410
2427
  /**
2411
2428
  * Runs GC
2412
2429
  */
2413
- $destroy() {
2430
+ destroy() {
2414
2431
  this.node.remove();
2415
- super.$destroy();
2432
+ super.destroy();
2416
2433
  }
2417
2434
  }
2418
2435
  /**
@@ -2421,22 +2438,22 @@ class Tag extends INode {
2421
2438
  * @extends INode
2422
2439
  */
2423
2440
  class Extension extends INode {
2424
- $preinit(app, parent) {
2425
- if (parent instanceof INode) {
2426
- const $ = this.$;
2427
- $.preinit(app, parent);
2428
- $.node = parent.node;
2441
+ preinit(app, parent) {
2442
+ const $ = this.$;
2443
+ let it = parent;
2444
+ while (it && !(it instanceof INode)) {
2445
+ it = it.parent;
2429
2446
  }
2430
- else {
2447
+ if (it && it instanceof INode) {
2448
+ $.node = it.node;
2449
+ }
2450
+ $.preinit(app, parent);
2451
+ if (!it) {
2431
2452
  throw userError("A extension node can be encapsulated only in a tag/extension/component", "virtual-dom");
2432
2453
  }
2433
2454
  }
2434
- constructor($) {
2435
- super($);
2436
- this.$seal();
2437
- }
2438
- $destroy() {
2439
- super.$destroy();
2455
+ destroy() {
2456
+ super.destroy();
2440
2457
  }
2441
2458
  }
2442
2459
  /**
@@ -2445,16 +2462,17 @@ class Extension extends INode {
2445
2462
  * @extends Extension
2446
2463
  */
2447
2464
  class Component extends Extension {
2448
- constructor() {
2449
- super();
2450
- this.$seal();
2451
- }
2452
- $mounted() {
2453
- super.$mounted();
2454
- if (this.$children.length !== 1) {
2465
+ init() {
2466
+ super.composeNow();
2467
+ this.ready();
2468
+ super.applyOptionsNow();
2469
+ }
2470
+ ready() {
2471
+ super.ready();
2472
+ if (this.children.size !== 1) {
2455
2473
  throw userError("Component must have a child only", "dom-error");
2456
2474
  }
2457
- const child = this.$children[0];
2475
+ const child = this.lastChild;
2458
2476
  if (child instanceof Tag || child instanceof Component) {
2459
2477
  const $ = this.$;
2460
2478
  $.node = child.node;
@@ -2463,7 +2481,7 @@ class Component extends Extension {
2463
2481
  throw userError("Component child must be Tag or Component", "dom-error");
2464
2482
  }
2465
2483
  }
2466
- $preinit(app, parent) {
2484
+ preinit(app, parent) {
2467
2485
  this.$.preinit(app, parent);
2468
2486
  }
2469
2487
  }
@@ -2472,21 +2490,26 @@ class Component extends Extension {
2472
2490
  * @class SwitchedNodePrivate
2473
2491
  * @extends INodePrivate
2474
2492
  */
2475
- class SwitchedNodePrivate extends INodePrivate {
2493
+ class SwitchedNodePrivate extends FragmentPrivate {
2476
2494
  constructor() {
2477
2495
  super();
2478
- this.$seal();
2496
+ /**
2497
+ * Array of possible cases
2498
+ * @type {Array<{cond : IValue<boolean>, cb : function(Fragment)}>}
2499
+ */
2500
+ this.cases = [];
2501
+ this.seal();
2479
2502
  }
2480
2503
  /**
2481
2504
  * Runs GC
2482
2505
  */
2483
- $destroy() {
2506
+ destroy() {
2484
2507
  this.cases.forEach(c => {
2485
2508
  delete c.cond;
2486
2509
  delete c.cb;
2487
2510
  });
2488
2511
  this.cases.splice(0);
2489
- super.$destroy();
2512
+ super.destroy();
2490
2513
  }
2491
2514
  }
2492
2515
  /**
@@ -2497,7 +2520,7 @@ class SwitchedNode extends Fragment {
2497
2520
  * Constructs a switch node and define a sync function
2498
2521
  */
2499
2522
  constructor() {
2500
- super(new SwitchedNodePrivate);
2523
+ super({}, new SwitchedNodePrivate);
2501
2524
  this.$.sync = () => {
2502
2525
  const $ = this.$;
2503
2526
  let i = 0;
@@ -2509,10 +2532,10 @@ class SwitchedNode extends Fragment {
2509
2532
  if (i === $.index) {
2510
2533
  return;
2511
2534
  }
2512
- if ($.fragment) {
2513
- $.fragment.$destroy();
2514
- this.$children.splice(0);
2515
- $.fragment = null;
2535
+ if (this.lastChild) {
2536
+ this.lastChild.destroy();
2537
+ this.children.clear();
2538
+ this.lastChild = null;
2516
2539
  }
2517
2540
  if (i !== $.cases.length) {
2518
2541
  $.index = i;
@@ -2522,43 +2545,38 @@ class SwitchedNode extends Fragment {
2522
2545
  $.index = -1;
2523
2546
  }
2524
2547
  };
2525
- this.$seal();
2548
+ this.seal();
2526
2549
  }
2527
- /**
2528
- * Set up switch cases
2529
- * @param cases {{ cond : IValue, cb : function(Fragment) }}
2530
- */
2531
- setCases(cases) {
2532
- const $ = this.$;
2533
- $.cases = [...cases];
2550
+ addCase(case_) {
2551
+ this.$.cases.push(case_);
2552
+ case_.cond.on(this.$.sync);
2553
+ this.$.sync();
2534
2554
  }
2535
2555
  /**
2536
2556
  * Creates a child node
2537
2557
  * @param cb {function(Fragment)} Call-back
2538
2558
  */
2539
2559
  createChild(cb) {
2540
- const node = new Fragment();
2541
- node.$preinit(this.$.app, this);
2542
- node.$init();
2543
- node.$ready();
2544
- this.$.fragment = node;
2545
- this.$children.push(node);
2560
+ const node = new Fragment({});
2561
+ node.preinit(this.$.app, this);
2562
+ node.init();
2563
+ this.lastChild = node;
2564
+ this.children.add(node);
2546
2565
  cb(node);
2547
2566
  }
2548
- $ready() {
2567
+ ready() {
2549
2568
  const $ = this.$;
2550
- super.$ready();
2551
2569
  $.cases.forEach(c => {
2552
2570
  c.cond.on($.sync);
2553
2571
  });
2554
2572
  $.sync();
2555
2573
  }
2556
- $destroy() {
2574
+ destroy() {
2557
2575
  const $ = this.$;
2558
2576
  $.cases.forEach(c => {
2559
2577
  c.cond.off($.sync);
2560
2578
  });
2561
- super.$destroy();
2579
+ super.destroy();
2562
2580
  }
2563
2581
  }
2564
2582
  /**
@@ -2567,7 +2585,7 @@ class SwitchedNode extends Fragment {
2567
2585
  class DebugPrivate extends FragmentPrivate {
2568
2586
  constructor() {
2569
2587
  super();
2570
- this.$seal();
2588
+ this.seal();
2571
2589
  }
2572
2590
  /**
2573
2591
  * Pre-initializes a text node
@@ -2581,14 +2599,14 @@ class DebugPrivate extends FragmentPrivate {
2581
2599
  this.bindings.add(new Expression((v) => {
2582
2600
  this.node.replaceData(0, -1, v);
2583
2601
  }, true, text));
2584
- this.parent.$$appendNode(this.node);
2602
+ this.parent.appendNode(this.node);
2585
2603
  }
2586
2604
  /**
2587
2605
  * Clear node data
2588
2606
  */
2589
- $destroy() {
2607
+ destroy() {
2590
2608
  this.node.remove();
2591
- super.$destroy();
2609
+ super.destroy();
2592
2610
  }
2593
2611
  }
2594
2612
  /**
@@ -2598,15 +2616,15 @@ class DebugPrivate extends FragmentPrivate {
2598
2616
  */
2599
2617
  class DebugNode extends Fragment {
2600
2618
  constructor() {
2601
- super();
2619
+ super({});
2602
2620
  /**
2603
2621
  * private data
2604
2622
  * @type {DebugNode}
2605
2623
  */
2606
2624
  this.$ = new DebugPrivate();
2607
- this.$seal();
2625
+ this.seal();
2608
2626
  }
2609
- $preinit(app, parent, text) {
2627
+ preinit(app, parent, text) {
2610
2628
  const $ = this.$;
2611
2629
  if (!text) {
2612
2630
  throw internalError('wrong DebugNode::$preninit call');
@@ -2616,9 +2634,9 @@ class DebugNode extends Fragment {
2616
2634
  /**
2617
2635
  * Runs garbage collector
2618
2636
  */
2619
- $destroy() {
2620
- this.$.$destroy();
2621
- super.$destroy();
2637
+ destroy() {
2638
+ this.$.destroy();
2639
+ super.destroy();
2622
2640
  }
2623
2641
  }
2624
2642
 
@@ -2632,6 +2650,7 @@ window.Tag = Tag;
2632
2650
  window.Extension = Extension;
2633
2651
  window.Component = Component;
2634
2652
  window.SwitchedNodePrivate = SwitchedNodePrivate;
2653
+ window.SwitchedNode = SwitchedNode;
2635
2654
  window.DebugPrivate = DebugPrivate;
2636
2655
  window.DebugNode = DebugNode;
2637
2656
 
@@ -2643,12 +2662,12 @@ window.DebugNode = DebugNode;
2643
2662
  */
2644
2663
  class AppNode extends INode {
2645
2664
  /**
2646
- * @param options {Object} Application options
2665
+ * @param input
2647
2666
  */
2648
- constructor(options) {
2649
- super();
2650
- this.$run = (options === null || options === void 0 ? void 0 : options.executor) || ((options === null || options === void 0 ? void 0 : options.freezeUi) === false ? timeoutExecutor : instantExecutor);
2651
- this.$debugUi = (options === null || options === void 0 ? void 0 : options.debugUi) || false;
2667
+ constructor(input) {
2668
+ super(input);
2669
+ this.debugUi = input.debugUi || false;
2670
+ this.seal();
2652
2671
  }
2653
2672
  }
2654
2673
  /**
@@ -2660,22 +2679,33 @@ class App extends AppNode {
2660
2679
  /**
2661
2680
  * Constructs an app node
2662
2681
  * @param node {Element} The root of application
2663
- * @param options {Object} Application options
2682
+ * @param input
2664
2683
  */
2665
- constructor(node, options) {
2666
- super(options);
2684
+ constructor(node, input) {
2685
+ super(input);
2667
2686
  this.$.node = node;
2668
- this.$preinit(this, this);
2669
- this.$seal();
2687
+ this.preinit(this, this);
2688
+ this.init();
2689
+ this.seal();
2670
2690
  }
2671
- $$appendNode(node) {
2672
- const $ = this.$;
2673
- $.app.$run.appendChild($.node, node);
2691
+ appendNode(node) {
2692
+ this.$.node.appendChild(node);
2693
+ }
2694
+ }
2695
+ class Portal extends AppNode {
2696
+ constructor(input) {
2697
+ super(input);
2698
+ this.$.node = input.node;
2699
+ this.seal();
2700
+ }
2701
+ appendNode(node) {
2702
+ this.$.node.appendChild(node);
2674
2703
  }
2675
2704
  }
2676
2705
 
2677
2706
  window.AppNode = AppNode;
2678
2707
  window.App = App;
2708
+ window.Portal = Portal;
2679
2709
 
2680
2710
  // ./lib/node/interceptor.js
2681
2711
  /**
@@ -2725,8 +2755,8 @@ class Interceptor extends Destroyable {
2725
2755
  signal.unsubscribe(handler);
2726
2756
  });
2727
2757
  }
2728
- $destroy() {
2729
- super.$destroy();
2758
+ destroy() {
2759
+ super.destroy();
2730
2760
  this.signals.forEach(signal => {
2731
2761
  this.handlers.forEach(handler => {
2732
2762
  signal.unsubscribe(handler);
@@ -2753,7 +2783,7 @@ class InterceptorNode extends Fragment {
2753
2783
  */
2754
2784
  this.slot = new Slot;
2755
2785
  }
2756
- $compose() {
2786
+ compose() {
2757
2787
  this.slot.release(this, this.interceptor);
2758
2788
  }
2759
2789
  }
@@ -2775,22 +2805,21 @@ class AttributeBinding extends Binding {
2775
2805
  * @param value {IValue} value to bind
2776
2806
  */
2777
2807
  constructor(node, name, value) {
2778
- super(node, name, value);
2779
- }
2780
- /**
2781
- * Generates a function which updates the attribute value
2782
- * @param name {String} The name of attribute
2783
- * @returns {Function} a function which will update attribute value
2784
- */
2785
- bound(name) {
2786
- return function (node, value) {
2808
+ super(value);
2809
+ this.init((value) => {
2787
2810
  if (value) {
2788
- node.app.$run.setAttribute(node.node, name, value);
2811
+ if (typeof value === 'boolean') {
2812
+ node.node.setAttribute(name, "");
2813
+ }
2814
+ else {
2815
+ node.node.setAttribute(name, `${value}`);
2816
+ }
2789
2817
  }
2790
2818
  else {
2791
- node.app.$run.removeAttribute(node.node, name);
2819
+ node.node.removeAttribute(name);
2792
2820
  }
2793
- };
2821
+ });
2822
+ this.seal();
2794
2823
  }
2795
2824
  }
2796
2825
 
@@ -2810,77 +2839,64 @@ class StyleBinding extends Binding {
2810
2839
  * @param value {IValue} the value to bind
2811
2840
  */
2812
2841
  constructor(node, name, value) {
2813
- super(node, name, value);
2814
- }
2815
- /**
2816
- * Generates a function to update style property value
2817
- * @param name {string}
2818
- * @returns {Function} a function to update style property
2819
- */
2820
- bound(name) {
2821
- return function (node, value) {
2842
+ super(value);
2843
+ this.init((value) => {
2822
2844
  if (node.node instanceof HTMLElement) {
2823
- node.app.$run.setStyle(node.node, name, value);
2845
+ node.node.style.setProperty(name, value);
2824
2846
  }
2825
- };
2847
+ });
2848
+ this.seal();
2826
2849
  }
2827
2850
  }
2828
2851
 
2829
2852
  window.StyleBinding = StyleBinding;
2830
2853
 
2831
2854
  // ./lib/binding/class.js
2832
- /**
2833
- * Represents a HTML class binding description
2834
- * @class ClassBinding
2835
- * @extends Binding
2836
- */
2837
- class ClassBinding extends Binding {
2838
- /**
2839
- * Constructs an HTML class binding description
2840
- * @param node {INode} the vasille node
2841
- * @param name {String} the name of class
2842
- * @param value {IValue} the value to bind
2843
- */
2855
+ function addClass(node, cl) {
2856
+ node.node.classList.add(cl);
2857
+ }
2858
+ function removeClass(node, cl) {
2859
+ node.node.classList.remove(cl);
2860
+ }
2861
+ class StaticClassBinding extends Binding {
2844
2862
  constructor(node, name, value) {
2845
- super(node, name, value);
2846
- this.$seal();
2847
- }
2848
- /**
2849
- * Generates a function which updates the html class value
2850
- * @param name {String} The name of attribute
2851
- * @returns {Function} a function which will update attribute value
2852
- */
2853
- bound(name) {
2854
- let current = null;
2855
- function addClass(node, cl) {
2856
- node.app.$run.addClass(node.node, cl);
2857
- }
2858
- function removeClass(node, cl) {
2859
- node.app.$run.removeClass(node.node, cl);
2860
- }
2861
- return (node, value) => {
2862
- if (value !== current) {
2863
- if (typeof current === "string" && current !== "") {
2864
- removeClass(node, current);
2863
+ super(value);
2864
+ this.current = false;
2865
+ this.init((value) => {
2866
+ if (value !== this.current) {
2867
+ if (value) {
2868
+ addClass(node, name);
2865
2869
  }
2866
- if (typeof value === "boolean") {
2867
- if (value) {
2868
- addClass(node, name);
2869
- }
2870
- else {
2871
- removeClass(node, name);
2872
- }
2870
+ else {
2871
+ removeClass(node, name);
2873
2872
  }
2874
- else if (typeof value === "string" && value !== "") {
2873
+ this.current = value;
2874
+ }
2875
+ });
2876
+ this.seal();
2877
+ }
2878
+ }
2879
+ class DynamicalClassBinding extends Binding {
2880
+ constructor(node, value) {
2881
+ super(value);
2882
+ this.current = "";
2883
+ this.init((value) => {
2884
+ if (this.current != value) {
2885
+ if (this.current.length) {
2886
+ removeClass(node, this.current);
2887
+ }
2888
+ if (value.length) {
2875
2889
  addClass(node, value);
2876
2890
  }
2877
- current = value;
2891
+ this.current = value;
2878
2892
  }
2879
- };
2893
+ });
2894
+ this.seal();
2880
2895
  }
2881
2896
  }
2882
2897
 
2883
- window.ClassBinding = ClassBinding;
2898
+ window.StaticClassBinding = StaticClassBinding;
2899
+ window.DynamicalClassBinding = DynamicalClassBinding;
2884
2900
 
2885
2901
  // ./lib/views/repeat-node.js
2886
2902
  /**
@@ -2896,11 +2912,11 @@ class RepeatNodePrivate extends INodePrivate {
2896
2912
  * @type {Map}
2897
2913
  */
2898
2914
  this.nodes = new Map();
2899
- this.$seal();
2915
+ this.seal();
2900
2916
  }
2901
- $destroy() {
2917
+ destroy() {
2902
2918
  this.nodes.clear();
2903
- super.$destroy();
2919
+ super.destroy();
2904
2920
  }
2905
2921
  }
2906
2922
  /**
@@ -2909,80 +2925,42 @@ class RepeatNodePrivate extends INodePrivate {
2909
2925
  * @extends Fragment
2910
2926
  */
2911
2927
  class RepeatNode extends Fragment {
2912
- constructor($) {
2913
- super($ || new RepeatNodePrivate);
2928
+ constructor(input, $) {
2929
+ super(input, $);
2914
2930
  /**
2915
2931
  * If false will use timeout executor, otherwise the app executor
2916
2932
  */
2917
2933
  this.freezeUi = true;
2918
- this.slot = new Slot;
2919
2934
  }
2920
- createChild(id, item, before) {
2921
- // TODO: Refactor: remove @ts-ignore
2922
- const node = new Fragment();
2923
- // eslint-disable-next-line
2924
- // @ts-ignore
2925
- const $ = node.$;
2935
+ createChild(opts, id, item, before) {
2936
+ const node = new Fragment({});
2926
2937
  this.destroyChild(id, item);
2927
2938
  if (before) {
2928
- $.next = before;
2929
- // eslint-disable-next-line
2930
- // @ts-ignore
2931
- $.prev = before.$.prev;
2932
- // eslint-disable-next-line
2933
- // @ts-ignore
2934
- before.$.prev = node;
2935
- if ($.prev) {
2936
- // eslint-disable-next-line
2937
- // @ts-ignore
2938
- $.prev.$.next = node;
2939
- }
2940
- this.$children.splice(this.$children.indexOf(before), 0, node);
2939
+ this.children.add(node);
2940
+ before.insertBefore(node);
2941
2941
  }
2942
2942
  else {
2943
- const lastChild = this.$children[this.$children.length - 1];
2943
+ const lastChild = this.lastChild;
2944
2944
  if (lastChild) {
2945
- // eslint-disable-next-line
2946
- // @ts-ignore
2947
- lastChild.$.next = node;
2945
+ lastChild.insertAfter(node);
2948
2946
  }
2949
- $.prev = lastChild;
2950
- this.$children.push(node);
2951
- }
2952
- node.$preinit(this.$.app, this);
2953
- node.$init();
2954
- const callback = () => {
2955
- this.slot.release(node, item, id);
2956
- node.$ready();
2957
- };
2958
- if (this.freezeUi) {
2959
- this.$.app.$run.callCallback(callback);
2960
- }
2961
- else {
2962
- timeoutExecutor.callCallback(callback);
2947
+ this.children.add(node);
2963
2948
  }
2949
+ this.lastChild = node;
2950
+ node.preinit(this.$.app, this);
2951
+ node.init();
2952
+ opts.slot && opts.slot(node, item, id);
2953
+ node.ready();
2964
2954
  this.$.nodes.set(id, node);
2965
2955
  }
2966
2956
  destroyChild(id, item) {
2967
2957
  const $ = this.$;
2968
2958
  const child = $.nodes.get(id);
2969
2959
  if (child) {
2970
- // eslint-disable-next-line
2971
- // @ts-ignore
2972
- const $ = child.$;
2973
- if ($.prev) {
2974
- // eslint-disable-next-line
2975
- // @ts-ignore
2976
- $.prev.$.next = $.next;
2977
- }
2978
- if ($.next) {
2979
- // eslint-disable-next-line
2980
- // @ts-ignore
2981
- $.next.$.prev = $.prev;
2982
- }
2983
- child.$destroy();
2960
+ child.remove();
2961
+ child.destroy();
2984
2962
  this.$.nodes.delete(id);
2985
- this.$children.splice(this.$children.indexOf(child), 1);
2963
+ this.children.delete(child);
2986
2964
  }
2987
2965
  }
2988
2966
  }
@@ -3003,7 +2981,7 @@ class RepeaterPrivate extends RepeatNodePrivate {
3003
2981
  * Current count of child nodes
3004
2982
  */
3005
2983
  this.currentCount = 0;
3006
- this.$seal();
2984
+ this.seal();
3007
2985
  }
3008
2986
  }
3009
2987
  /**
@@ -3018,7 +2996,7 @@ class Repeater extends RepeatNode {
3018
2996
  * The count of children
3019
2997
  */
3020
2998
  this.count = new Reference(0);
3021
- this.$seal();
2999
+ this.seal();
3022
3000
  }
3023
3001
  /**
3024
3002
  * Changes the children count
@@ -3037,18 +3015,18 @@ class Repeater extends RepeatNode {
3037
3015
  }
3038
3016
  $.currentCount = number;
3039
3017
  }
3040
- $created() {
3018
+ created() {
3041
3019
  const $ = this.$;
3042
- super.$created();
3020
+ super.created();
3043
3021
  $.updateHandler = this.changeCount.bind(this);
3044
3022
  this.count.on($.updateHandler);
3045
3023
  }
3046
- $ready() {
3024
+ ready() {
3047
3025
  this.changeCount(this.count.$);
3048
3026
  }
3049
- $destroy() {
3027
+ destroy() {
3050
3028
  const $ = this.$;
3051
- super.$destroy();
3029
+ super.destroy();
3052
3030
  this.count.off($.updateHandler);
3053
3031
  }
3054
3032
  }
@@ -3065,7 +3043,7 @@ window.Repeater = Repeater;
3065
3043
  class BaseViewPrivate extends RepeatNodePrivate {
3066
3044
  constructor() {
3067
3045
  super();
3068
- this.$seal();
3046
+ this.seal();
3069
3047
  }
3070
3048
  }
3071
3049
  /**
@@ -3075,34 +3053,23 @@ class BaseViewPrivate extends RepeatNodePrivate {
3075
3053
  * @implements IModel
3076
3054
  */
3077
3055
  class BaseView extends RepeatNode {
3078
- constructor($1) {
3079
- super($1 || new BaseViewPrivate);
3056
+ constructor(input, $) {
3057
+ super(input, $ || new BaseViewPrivate);
3058
+ }
3059
+ compose(input) {
3080
3060
  const $ = this.$;
3081
3061
  $.addHandler = (id, item) => {
3082
- this.createChild(id, item);
3062
+ this.createChild(input, id, item);
3083
3063
  };
3084
3064
  $.removeHandler = (id, item) => {
3085
3065
  this.destroyChild(id, item);
3086
3066
  };
3087
- this.$seal();
3088
- }
3089
- /**
3090
- * Handle ready event
3091
- */
3092
- $ready() {
3093
- const $ = this.$;
3094
- this.model.listener.onAdd($.addHandler);
3095
- this.model.listener.onRemove($.removeHandler);
3096
- super.$ready();
3097
- }
3098
- /**
3099
- * Handles destroy event
3100
- */
3101
- $destroy() {
3102
- const $ = this.$;
3103
- this.model.listener.offAdd($.addHandler);
3104
- this.model.listener.offRemove($.removeHandler);
3105
- super.$destroy();
3067
+ input.model.listener.onAdd($.addHandler);
3068
+ input.model.listener.onRemove($.removeHandler);
3069
+ this.runOnDestroy(() => {
3070
+ input.model.listener.offAdd($.addHandler);
3071
+ input.model.listener.offRemove($.removeHandler);
3072
+ });
3106
3073
  }
3107
3074
  }
3108
3075
 
@@ -3116,18 +3083,14 @@ window.BaseView = BaseView;
3116
3083
  * @extends BaseView
3117
3084
  */
3118
3085
  class ArrayView extends BaseView {
3119
- constructor(model) {
3120
- super();
3121
- this.model = model;
3122
- }
3123
- createChild(id, item, before) {
3124
- super.createChild(item, item, before || this.$.nodes.get(id));
3086
+ createChild(input, id, item, before) {
3087
+ super.createChild(input, item, item, before || this.$.nodes.get(id));
3125
3088
  }
3126
- $ready() {
3127
- this.model.forEach(item => {
3128
- this.createChild(item, item);
3089
+ compose(input) {
3090
+ super.compose(input);
3091
+ input.model.forEach(item => {
3092
+ this.createChild(input, item, item);
3129
3093
  });
3130
- super.$ready();
3131
3094
  }
3132
3095
  }
3133
3096
 
@@ -3140,23 +3103,16 @@ window.ArrayView = ArrayView;
3140
3103
  * @extends Fragment
3141
3104
  */
3142
3105
  class Watch extends Fragment {
3143
- constructor() {
3144
- super();
3145
- this.slot = new Slot;
3146
- this.model = this.$ref(null);
3147
- this.$seal();
3148
- }
3149
- $createWatchers() {
3150
- this.$watch((value) => {
3151
- this.$children.forEach(child => {
3152
- child.$destroy();
3106
+ compose(input) {
3107
+ this.watch((value) => {
3108
+ this.children.forEach(child => {
3109
+ child.destroy();
3153
3110
  });
3154
- this.$children.splice(0);
3155
- this.slot.release(this, value);
3156
- }, this.model);
3157
- }
3158
- $compose() {
3159
- this.slot.release(this, this.model.$);
3111
+ this.children.clear();
3112
+ this.lastChild = null;
3113
+ input.slot && input.slot(this, value);
3114
+ }, input.model);
3115
+ input.slot(this, input.model.$);
3160
3116
  }
3161
3117
  }
3162
3118
 
@@ -3169,16 +3125,13 @@ window.Watch = Watch;
3169
3125
  * @extends BaseView
3170
3126
  */
3171
3127
  class ObjectView extends BaseView {
3172
- constructor(model) {
3173
- super();
3174
- this.model = model;
3175
- }
3176
- $ready() {
3177
- const obj = this.model;
3128
+ compose(input) {
3129
+ super.compose(input);
3130
+ const obj = input.model.proxy();
3178
3131
  for (const key in obj) {
3179
- this.createChild(key, obj[key]);
3132
+ this.createChild(input, key, obj[key]);
3180
3133
  }
3181
- super.$ready();
3134
+ super.ready();
3182
3135
  }
3183
3136
  }
3184
3137
 
@@ -3191,16 +3144,11 @@ window.ObjectView = ObjectView;
3191
3144
  * @extends BaseView
3192
3145
  */
3193
3146
  class MapView extends BaseView {
3194
- constructor(model) {
3195
- super();
3196
- this.model = model;
3197
- }
3198
- $ready() {
3199
- const map = this.model;
3200
- map.forEach((value, key) => {
3201
- this.createChild(key, value);
3147
+ compose(input) {
3148
+ super.compose(input);
3149
+ input.model.forEach((value, key) => {
3150
+ this.createChild(input, key, value);
3202
3151
  });
3203
- super.$ready();
3204
3152
  }
3205
3153
  }
3206
3154
 
@@ -3213,19 +3161,12 @@ window.MapView = MapView;
3213
3161
  * @extends BaseView
3214
3162
  */
3215
3163
  class SetView extends BaseView {
3216
- constructor(model) {
3217
- super();
3218
- this.model = model;
3219
- }
3220
- $ready() {
3221
- const $ = this.$;
3222
- const set = this.model;
3164
+ compose(input) {
3165
+ super.compose(input);
3166
+ const set = input.model;
3223
3167
  set.forEach(item => {
3224
- $.app.$run.callCallback(() => {
3225
- this.createChild(item, item);
3226
- });
3168
+ this.createChild(input, item, item);
3227
3169
  });
3228
- super.$ready();
3229
3170
  }
3230
3171
  }
3231
3172