vasille 2.0.3 → 2.2.0

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 +939 -1009
  3. package/cdn/es5.js +1048 -1029
  4. package/flow-typed/vasille.js +2641 -832
  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 +78 -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 +338 -684
  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 +7 -6
  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 +40 -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 +97 -422
  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,40 @@ 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
+ compose(input) {
1753
+ // empty
1754
+ }
1755
+ runFunctional(f, ...args) {
1756
+ stack(this);
1757
+ // yet another ts bug
1758
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1759
+ // @ts-ignore
1760
+ const result = f(...args);
1761
+ unstack();
1762
+ return result;
1763
+ }
1764
+ runOnDestroy(func) {
1765
+ this.$.onDestroy = func;
1766
+ }
1767
+ destroy() {
1768
+ super.destroy();
1769
+ this.$.destroy();
1417
1770
  this.$ = null;
1418
1771
  }
1419
1772
  }
@@ -1430,7 +1783,7 @@ window.Reactive = Reactive;
1430
1783
  class FragmentPrivate extends ReactivePrivate {
1431
1784
  constructor() {
1432
1785
  super();
1433
- this.$seal();
1786
+ this.seal();
1434
1787
  }
1435
1788
  /**
1436
1789
  * Pre-initializes the base of a fragment
@@ -1444,10 +1797,10 @@ class FragmentPrivate extends ReactivePrivate {
1444
1797
  /**
1445
1798
  * Unlinks all bindings
1446
1799
  */
1447
- $destroy() {
1800
+ destroy() {
1448
1801
  this.next = null;
1449
1802
  this.prev = null;
1450
- super.$destroy();
1803
+ super.destroy();
1451
1804
  }
1452
1805
  }
1453
1806
  /**
@@ -1457,16 +1810,17 @@ class FragmentPrivate extends ReactivePrivate {
1457
1810
  class Fragment extends Reactive {
1458
1811
  /**
1459
1812
  * Constructs a Vasille Node
1813
+ * @param input
1460
1814
  * @param $ {FragmentPrivate}
1461
1815
  */
1462
- constructor($) {
1463
- super();
1816
+ constructor(input, $) {
1817
+ super(input, $ || new FragmentPrivate);
1464
1818
  /**
1465
1819
  * The children list
1466
1820
  * @type Array
1467
1821
  */
1468
- this.$children = [];
1469
- this.$ = $ || new FragmentPrivate;
1822
+ this.children = new Set;
1823
+ this.lastChild = null;
1470
1824
  }
1471
1825
  /**
1472
1826
  * Gets the app of node
@@ -1480,43 +1834,16 @@ class Fragment extends Reactive {
1480
1834
  * @param parent {Fragment} parent of node
1481
1835
  * @param data {*} additional data
1482
1836
  */
1483
- $preinit(app, parent, data) {
1837
+ preinit(app, parent, data) {
1484
1838
  const $ = this.$;
1485
1839
  $.preinit(app, parent);
1486
1840
  }
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
1501
- }
1502
- /** To be overloaded: mounted event handler */
1503
- $mounted() {
1504
- // empty
1841
+ compose(input) {
1842
+ super.compose(input);
1843
+ input.slot && input.slot(this);
1505
1844
  }
1506
1845
  /** 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() {
1846
+ ready() {
1520
1847
  // empty
1521
1848
  }
1522
1849
  /**
@@ -1524,27 +1851,23 @@ class Fragment extends Reactive {
1524
1851
  * @param node {Fragment} A node to push
1525
1852
  * @protected
1526
1853
  */
1527
- $$pushNode(node) {
1528
- let lastChild = null;
1529
- if (this.$children.length) {
1530
- lastChild = this.$children[this.$children.length - 1];
1531
- }
1532
- if (lastChild) {
1533
- lastChild.$.next = node;
1854
+ pushNode(node) {
1855
+ if (this.lastChild) {
1856
+ this.lastChild.$.next = node;
1534
1857
  }
1535
- node.$.prev = lastChild;
1536
- node.$.parent = this;
1537
- this.$children.push(node);
1858
+ node.$.prev = this.lastChild;
1859
+ this.lastChild = node;
1860
+ this.children.add(node);
1538
1861
  }
1539
1862
  /**
1540
1863
  * Find first node in element if so exists
1541
1864
  * @return {?Element}
1542
1865
  * @protected
1543
1866
  */
1544
- $$findFirstChild() {
1867
+ findFirstChild() {
1545
1868
  let first;
1546
- this.$children.forEach(child => {
1547
- first = first || child.$$findFirstChild();
1869
+ this.children.forEach(child => {
1870
+ first = first || child.findFirstChild();
1548
1871
  });
1549
1872
  return first;
1550
1873
  }
@@ -1552,30 +1875,30 @@ class Fragment extends Reactive {
1552
1875
  * Append a node to end of element
1553
1876
  * @param node {Node} node to insert
1554
1877
  */
1555
- $$appendNode(node) {
1878
+ appendNode(node) {
1556
1879
  const $ = this.$;
1557
1880
  if ($.next) {
1558
- $.next.$$insertAdjacent(node);
1881
+ $.next.insertAdjacent(node);
1559
1882
  }
1560
1883
  else {
1561
- $.parent.$$appendNode(node);
1884
+ $.parent.appendNode(node);
1562
1885
  }
1563
1886
  }
1564
1887
  /**
1565
1888
  * Insert a node as a sibling of this
1566
1889
  * @param node {Node} node to insert
1567
1890
  */
1568
- $$insertAdjacent(node) {
1569
- const child = this.$$findFirstChild();
1891
+ insertAdjacent(node) {
1892
+ const child = this.findFirstChild();
1570
1893
  const $ = this.$;
1571
1894
  if (child) {
1572
- $.app.$run.insertBefore(child, node);
1895
+ child.parentElement.insertBefore(node, child);
1573
1896
  }
1574
1897
  else if ($.next) {
1575
- $.next.$$insertAdjacent(node);
1898
+ $.next.insertAdjacent(node);
1576
1899
  }
1577
1900
  else {
1578
- $.parent.$$appendNode(node);
1901
+ $.parent.appendNode(node);
1579
1902
  }
1580
1903
  }
1581
1904
  /**
@@ -1583,60 +1906,49 @@ class Fragment extends Reactive {
1583
1906
  * @param text {String | IValue} A text fragment string
1584
1907
  * @param cb {function (TextNode)} Callback if previous is slot name
1585
1908
  */
1586
- $text(text, cb) {
1909
+ text(text, cb) {
1587
1910
  const $ = this.$;
1588
1911
  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;
1912
+ node.preinit($.app, this, text);
1913
+ this.pushNode(node);
1914
+ cb && cb(node);
1598
1915
  }
1599
- $debug(text) {
1600
- if (this.$.app.$debugUi) {
1916
+ debug(text) {
1917
+ if (this.$.app.debugUi) {
1601
1918
  const node = new DebugNode();
1602
- node.$preinit(this.$.app, this, text);
1603
- this.$$pushNode(node);
1919
+ node.preinit(this.$.app, this, text);
1920
+ this.pushNode(node);
1604
1921
  }
1605
- return this;
1606
1922
  }
1607
- $tag(tagName, cb) {
1923
+ /**
1924
+ * Defines a tag element
1925
+ * @param tagName {String} the tag name
1926
+ * @param input
1927
+ * @param cb {function(Tag, *)} callback
1928
+ */
1929
+ tag(tagName, input, cb) {
1608
1930
  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;
1931
+ const node = new Tag(input);
1932
+ input.slot = cb || input.slot;
1933
+ node.preinit($.app, this, tagName);
1934
+ node.init();
1935
+ this.pushNode(node);
1936
+ node.ready();
1937
+ return node.node;
1620
1938
  }
1621
1939
  /**
1622
1940
  * Defines a custom element
1623
1941
  * @param node {Fragment} vasille element to insert
1624
1942
  * @param callback {function($ : *)}
1625
- * @param callback1 {function($ : *)}
1626
1943
  */
1627
- $create(node, callback, callback1) {
1944
+ create(node, callback) {
1628
1945
  const $ = this.$;
1629
1946
  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;
1947
+ node.preinit($.app, this);
1948
+ node.input.slot = callback || node.input.slot;
1949
+ this.pushNode(node);
1950
+ node.init();
1951
+ node.ready();
1640
1952
  }
1641
1953
  /**
1642
1954
  * Defines an if node
@@ -1644,32 +1956,29 @@ class Fragment extends Reactive {
1644
1956
  * @param cb {function(Fragment)} callback to run on true
1645
1957
  * @return {this}
1646
1958
  */
1647
- $if(cond, cb) {
1648
- return this.$switch({ cond, cb });
1959
+ if(cond, cb) {
1960
+ const node = new SwitchedNode();
1961
+ node.preinit(this.$.app, this);
1962
+ node.init();
1963
+ this.pushNode(node);
1964
+ node.addCase(this.case(cond, cb));
1965
+ node.ready();
1649
1966
  }
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 });
1967
+ else(cb) {
1968
+ if (this.lastChild instanceof SwitchedNode) {
1969
+ this.lastChild.addCase(this.default(cb));
1970
+ }
1971
+ else {
1972
+ throw userError('wrong `else` function use', 'logic-error');
1973
+ }
1658
1974
  }
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;
1975
+ elif(cond, cb) {
1976
+ if (this.lastChild instanceof SwitchedNode) {
1977
+ this.lastChild.addCase(this.case(cond, cb));
1978
+ }
1979
+ else {
1980
+ throw userError('wrong `elif` function use', 'logic-error');
1981
+ }
1673
1982
  }
1674
1983
  /**
1675
1984
  * Create a case for switch
@@ -1677,22 +1986,48 @@ class Fragment extends Reactive {
1677
1986
  * @param cb {function(Fragment) : void}
1678
1987
  * @return {{cond : IValue, cb : (function(Fragment) : void)}}
1679
1988
  */
1680
- $case(cond, cb) {
1989
+ case(cond, cb) {
1681
1990
  return { cond, cb };
1682
1991
  }
1683
1992
  /**
1684
1993
  * @param cb {(function(Fragment) : void)}
1685
1994
  * @return {{cond : IValue, cb : (function(Fragment) : void)}}
1686
1995
  */
1687
- $default(cb) {
1996
+ default(cb) {
1688
1997
  return { cond: trueIValue, cb };
1689
1998
  }
1690
- $destroy() {
1691
- for (const child of this.$children) {
1692
- child.$destroy();
1999
+ insertBefore(node) {
2000
+ const $ = this.$;
2001
+ node.$.prev = $.prev;
2002
+ node.$.next = this;
2003
+ if ($.prev) {
2004
+ $.prev.$.next = node;
2005
+ }
2006
+ $.prev = node;
2007
+ }
2008
+ insertAfter(node) {
2009
+ const $ = this.$;
2010
+ node.$.prev = this;
2011
+ node.$.next = $.next;
2012
+ $.next = node;
2013
+ }
2014
+ remove() {
2015
+ const $ = this.$;
2016
+ if ($.next) {
2017
+ $.next.$.prev = $.prev;
2018
+ }
2019
+ if ($.prev) {
2020
+ $.prev.$.next = $.next;
2021
+ }
2022
+ }
2023
+ destroy() {
2024
+ this.children.forEach(child => child.destroy());
2025
+ this.children.clear();
2026
+ this.lastChild = null;
2027
+ if (this.$.parent.lastChild === this) {
2028
+ this.$.parent.lastChild = this.$.prev;
1693
2029
  }
1694
- this.$children.splice(0);
1695
- super.$destroy();
2030
+ super.destroy();
1696
2031
  }
1697
2032
  }
1698
2033
  const trueIValue = new Reference(true);
@@ -1704,26 +2039,28 @@ const trueIValue = new Reference(true);
1704
2039
  class TextNodePrivate extends FragmentPrivate {
1705
2040
  constructor() {
1706
2041
  super();
1707
- this.$seal();
2042
+ this.seal();
1708
2043
  }
1709
2044
  /**
1710
2045
  * Pre-initializes a text node
1711
2046
  * @param app {AppNode} the app node
2047
+ * @param parent
1712
2048
  * @param text {IValue}
1713
2049
  */
1714
2050
  preinitText(app, parent, text) {
1715
2051
  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);
2052
+ this.node = document.createTextNode(text instanceof IValue ? text.$ : text);
2053
+ if (text instanceof IValue) {
2054
+ this.bindings.add(new Expression((v) => {
2055
+ this.node.replaceData(0, -1, v);
2056
+ }, true, text));
2057
+ }
1721
2058
  }
1722
2059
  /**
1723
2060
  * Clear node data
1724
2061
  */
1725
- $destroy() {
1726
- super.$destroy();
2062
+ destroy() {
2063
+ super.destroy();
1727
2064
  }
1728
2065
  }
1729
2066
  /**
@@ -1732,25 +2069,25 @@ class TextNodePrivate extends FragmentPrivate {
1732
2069
  * @extends Fragment
1733
2070
  */
1734
2071
  class TextNode extends Fragment {
1735
- constructor() {
1736
- super();
1737
- this.$ = new TextNodePrivate();
1738
- this.$seal();
2072
+ constructor($ = new TextNodePrivate()) {
2073
+ super({}, $);
2074
+ this.seal();
1739
2075
  }
1740
- $preinit(app, parent, text) {
2076
+ preinit(app, parent, text) {
1741
2077
  const $ = this.$;
1742
2078
  if (!text) {
1743
2079
  throw internalError('wrong TextNode::$preninit call');
1744
2080
  }
1745
2081
  $.preinitText(app, parent, text);
2082
+ $.parent.appendNode($.node);
1746
2083
  }
1747
- $$findFirstChild() {
2084
+ findFirstChild() {
1748
2085
  return this.$.node;
1749
2086
  }
1750
- $destroy() {
2087
+ destroy() {
1751
2088
  this.$.node.remove();
1752
- this.$.$destroy();
1753
- super.$destroy();
2089
+ this.$.destroy();
2090
+ super.destroy();
1754
2091
  }
1755
2092
  }
1756
2093
  /**
@@ -1766,10 +2103,10 @@ class INodePrivate extends FragmentPrivate {
1766
2103
  * @type {boolean}
1767
2104
  */
1768
2105
  this.unmounted = false;
1769
- this.$seal();
2106
+ this.seal();
1770
2107
  }
1771
- $destroy() {
1772
- super.$destroy();
2108
+ destroy() {
2109
+ super.destroy();
1773
2110
  }
1774
2111
  }
1775
2112
  /**
@@ -1780,11 +2117,12 @@ class INodePrivate extends FragmentPrivate {
1780
2117
  class INode extends Fragment {
1781
2118
  /**
1782
2119
  * Constructs a base node
2120
+ * @param input
1783
2121
  * @param $ {?INodePrivate}
1784
2122
  */
1785
- constructor($) {
1786
- super($ || new INodePrivate);
1787
- this.$seal();
2123
+ constructor(input, $) {
2124
+ super(input, $ || new INodePrivate);
2125
+ this.seal();
1788
2126
  }
1789
2127
  /**
1790
2128
  * Get the bound node
@@ -1792,78 +2130,55 @@ class INode extends Fragment {
1792
2130
  get node() {
1793
2131
  return this.$.node;
1794
2132
  }
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
2133
  /**
1817
2134
  * Bind attribute value
1818
2135
  * @param name {String} name of attribute
1819
2136
  * @param value {IValue} value
1820
2137
  */
1821
- $attr(name, value) {
2138
+ attr(name, value) {
1822
2139
  const $ = this.$;
1823
2140
  const attr = new AttributeBinding(this, name, value);
1824
2141
  $.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
2142
  }
1833
2143
  /**
1834
2144
  * Set attribute value
1835
2145
  * @param name {string} name of attribute
1836
2146
  * @param value {string} value
1837
2147
  */
1838
- $setAttr(name, value) {
1839
- this.$.app.$run.setAttribute(this.$.node, name, value);
2148
+ setAttr(name, value) {
2149
+ if (typeof value === 'boolean') {
2150
+ if (value) {
2151
+ this.$.node.setAttribute(name, "");
2152
+ }
2153
+ }
2154
+ else {
2155
+ this.$.node.setAttribute(name, `${value}`);
2156
+ }
1840
2157
  return this;
1841
2158
  }
1842
2159
  /**
1843
2160
  * Adds a CSS class
1844
2161
  * @param cl {string} Class name
1845
2162
  */
1846
- $addClass(cl) {
1847
- this.$.app.$run.addClass(this.$.node, cl);
2163
+ addClass(cl) {
2164
+ this.$.node.classList.add(cl);
1848
2165
  return this;
1849
2166
  }
1850
2167
  /**
1851
2168
  * Adds some CSS classes
1852
2169
  * @param cls {...string} classes names
1853
2170
  */
1854
- $addClasses(...cls) {
1855
- cls.forEach(cl => {
1856
- this.$.app.$run.addClass(this.$.node, cl);
1857
- });
2171
+ removeClasse(cl) {
2172
+ this.$.node.classList.remove(cl);
1858
2173
  return this;
1859
2174
  }
1860
2175
  /**
1861
2176
  * Bind a CSS class
1862
2177
  * @param className {IValue}
1863
2178
  */
1864
- $bindClass(className) {
2179
+ bindClass(className) {
1865
2180
  const $ = this.$;
1866
- $.bindings.add(new ClassBinding(this, "", className));
2181
+ $.bindings.add(new DynamicalClassBinding(this, className));
1867
2182
  return this;
1868
2183
  }
1869
2184
  /**
@@ -1871,8 +2186,8 @@ class INode extends Fragment {
1871
2186
  * @param cond {IValue} condition
1872
2187
  * @param className {string} class name
1873
2188
  */
1874
- $floatingClass(cond, className) {
1875
- this.$.bindings.add(new ClassBinding(this, className, cond));
2189
+ floatingClass(cond, className) {
2190
+ this.$.bindings.add(new StaticClassBinding(this, className, cond));
1876
2191
  return this;
1877
2192
  }
1878
2193
  /**
@@ -1880,7 +2195,7 @@ class INode extends Fragment {
1880
2195
  * @param name {String} name of style attribute
1881
2196
  * @param value {IValue} value
1882
2197
  */
1883
- $style(name, value) {
2198
+ style(name, value) {
1884
2199
  const $ = this.$;
1885
2200
  if ($.node instanceof HTMLElement) {
1886
2201
  $.bindings.add(new StyleBinding(this, name, value));
@@ -1890,28 +2205,17 @@ class INode extends Fragment {
1890
2205
  }
1891
2206
  return this;
1892
2207
  }
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
2208
  /**
1905
2209
  * Sets a style property value
1906
2210
  * @param prop {string} Property name
1907
2211
  * @param value {string} Property value
1908
2212
  */
1909
- $setStyle(prop, value) {
2213
+ setStyle(prop, value) {
1910
2214
  if (this.$.node instanceof HTMLElement) {
1911
- this.$.app.$run.setStyle(this.$.node, prop, value);
2215
+ this.$.node.style.setProperty(prop, value);
1912
2216
  }
1913
2217
  else {
1914
- throw userError("Style can be setted for HTML elements only", "non-html-element");
2218
+ throw userError("Style can be set for HTML elements only", "non-html-element");
1915
2219
  }
1916
2220
  return this;
1917
2221
  }
@@ -1921,403 +2225,24 @@ class INode extends Fragment {
1921
2225
  * @param handler {function (Event)} Event handler
1922
2226
  * @param options {Object | boolean} addEventListener options
1923
2227
  */
1924
- $listen(name, handler, options) {
2228
+ listen(name, handler, options) {
1925
2229
  this.$.node.addEventListener(name, handler, options);
1926
2230
  return this;
1927
2231
  }
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);
2232
+ insertAdjacent(node) {
2233
+ this.$.node.parentNode.insertBefore(node, this.$.node);
1948
2234
  }
1949
2235
  /**
1950
- * @param handler {function (MouseEvent)}
1951
- * @param options {Object | boolean}
2236
+ * A v-show & ngShow alternative
2237
+ * @param cond {IValue} show condition
1952
2238
  */
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) {
2239
+ bindShow(cond) {
2315
2240
  const $ = this.$;
2316
2241
  const node = $.node;
2317
2242
  if (node instanceof HTMLElement) {
2318
2243
  let lastDisplay = node.style.display;
2319
2244
  const htmlNode = node;
2320
- return this.$bindAlive(cond, () => {
2245
+ return this.bindAlive(cond, () => {
2321
2246
  lastDisplay = htmlNode.style.display;
2322
2247
  htmlNode.style.display = 'none';
2323
2248
  }, () => {
@@ -2332,19 +2257,105 @@ class INode extends Fragment {
2332
2257
  * bind HTML
2333
2258
  * @param value {IValue}
2334
2259
  */
2335
- $html(value) {
2260
+ bindDomApi(name, value) {
2336
2261
  const $ = this.$;
2337
2262
  const node = $.node;
2338
2263
  if (node instanceof HTMLElement) {
2339
- node.innerHTML = value.$;
2340
- this.$watch((v) => {
2341
- node.innerHTML = v;
2264
+ node[name] = value.$;
2265
+ this.watch((v) => {
2266
+ node[name] = v;
2342
2267
  }, value);
2343
2268
  }
2344
2269
  else {
2345
2270
  throw userError("HTML can be bound for HTML nodes only", "dom-error");
2346
2271
  }
2347
2272
  }
2273
+ applyOptions(options) {
2274
+ options["v:attr"] && Object.keys(options["v:attr"]).forEach(name => {
2275
+ const value = options["v:attr"][name];
2276
+ if (value instanceof IValue) {
2277
+ this.attr(name, value);
2278
+ }
2279
+ else {
2280
+ this.setAttr(name, value);
2281
+ }
2282
+ });
2283
+ if (options.class) {
2284
+ const handleClass = (name, value) => {
2285
+ if (value instanceof IValue) {
2286
+ this.floatingClass(value, name);
2287
+ }
2288
+ else if (value && name !== '$') {
2289
+ this.addClass(name);
2290
+ }
2291
+ else {
2292
+ this.removeClasse(name);
2293
+ }
2294
+ };
2295
+ if (Array.isArray(options.class)) {
2296
+ options.class.forEach(item => {
2297
+ if (item instanceof IValue) {
2298
+ this.bindClass(item);
2299
+ }
2300
+ else if (typeof item == "string") {
2301
+ this.addClass(item);
2302
+ }
2303
+ else {
2304
+ Reflect.ownKeys(item).forEach((name) => {
2305
+ handleClass(name, item[name]);
2306
+ });
2307
+ }
2308
+ });
2309
+ }
2310
+ else {
2311
+ options.class.$.forEach(item => {
2312
+ this.bindClass(item);
2313
+ });
2314
+ Reflect.ownKeys(options.class).forEach((name) => {
2315
+ handleClass(name, options.class[name]);
2316
+ });
2317
+ }
2318
+ }
2319
+ options.style && Object.keys(options.style).forEach(name => {
2320
+ const value = options.style[name];
2321
+ if (value instanceof IValue) {
2322
+ this.style(name, value);
2323
+ }
2324
+ else if (typeof value === "string") {
2325
+ this.setStyle(name, value);
2326
+ }
2327
+ else {
2328
+ if (value[0] instanceof IValue) {
2329
+ this.style(name, this.expr((v) => v + value[1], value[0]));
2330
+ }
2331
+ else {
2332
+ this.setStyle(name, value[0] + value[1]);
2333
+ }
2334
+ }
2335
+ });
2336
+ options["v:events"] && Object.keys(options["v:events"]).forEach(name => {
2337
+ this.listen(name, options["v:events"][name]);
2338
+ });
2339
+ if (options["v:bind"]) {
2340
+ const inode = this.node;
2341
+ Reflect.ownKeys(options["v:bind"]).forEach((k) => {
2342
+ const value = options["v:bind"][k];
2343
+ if (k === 'value' && (inode instanceof HTMLInputElement || inode instanceof HTMLTextAreaElement)) {
2344
+ inode.oninput = () => value.$ = inode.value;
2345
+ }
2346
+ else if (k === 'checked' && inode instanceof HTMLInputElement) {
2347
+ inode.oninput = () => value.$ = inode.checked;
2348
+ }
2349
+ else if (k === 'volume' && inode instanceof HTMLMediaElement) {
2350
+ inode.onvolumechange = () => value.$ = inode.volume;
2351
+ }
2352
+ this.bindDomApi(k, value);
2353
+ });
2354
+ }
2355
+ options["v:set"] && Object.keys(options["v:set"]).forEach(key => {
2356
+ this.node[key] = options["v:set"][key];
2357
+ });
2358
+ }
2348
2359
  }
2349
2360
  /**
2350
2361
  * Represents an Vasille.js HTML element node
@@ -2352,11 +2363,11 @@ class INode extends Fragment {
2352
2363
  * @extends INode
2353
2364
  */
2354
2365
  class Tag extends INode {
2355
- constructor() {
2356
- super();
2357
- this.$seal();
2366
+ constructor(input) {
2367
+ super(input);
2368
+ this.seal();
2358
2369
  }
2359
- $preinit(app, parent, tagName) {
2370
+ preinit(app, parent, tagName) {
2360
2371
  if (!tagName || typeof tagName !== "string") {
2361
2372
  throw internalError('wrong Tag::$preinit call');
2362
2373
  }
@@ -2364,55 +2375,52 @@ class Tag extends INode {
2364
2375
  const $ = this.$;
2365
2376
  $.preinit(app, parent);
2366
2377
  $.node = node;
2367
- $.parent.$$appendNode(node);
2378
+ $.parent.appendNode(node);
2379
+ }
2380
+ compose(input) {
2381
+ input.slot && input.slot(this);
2368
2382
  }
2369
- $$findFirstChild() {
2383
+ findFirstChild() {
2370
2384
  return this.$.unmounted ? null : this.$.node;
2371
2385
  }
2372
- $$insertAdjacent(node) {
2386
+ insertAdjacent(node) {
2373
2387
  if (this.$.unmounted) {
2374
2388
  if (this.$.next) {
2375
- this.$.next.$$insertAdjacent(node);
2389
+ this.$.next.insertAdjacent(node);
2376
2390
  }
2377
2391
  else {
2378
- this.$.parent.$$appendNode(node);
2392
+ this.$.parent.appendNode(node);
2379
2393
  }
2380
2394
  }
2381
2395
  else {
2382
- super.$$insertAdjacent(node);
2396
+ super.insertAdjacent(node);
2383
2397
  }
2384
2398
  }
2385
- $$appendNode(node) {
2386
- const $ = this.$;
2387
- $.app.$run.appendChild($.node, node);
2399
+ appendNode(node) {
2400
+ this.$.node.appendChild(node);
2388
2401
  }
2389
2402
  /**
2390
2403
  * Mount/Unmount a node
2391
2404
  * @param cond {IValue} show condition
2392
2405
  */
2393
- $bindMount(cond) {
2406
+ bindMount(cond) {
2394
2407
  const $ = this.$;
2395
- return this.$bindAlive(cond, () => {
2408
+ this.bindAlive(cond, () => {
2396
2409
  $.node.remove();
2397
2410
  $.unmounted = true;
2398
2411
  }, () => {
2399
- if (!$.unmounted)
2400
- return;
2401
- if ($.next) {
2402
- $.next.$$insertAdjacent($.node);
2412
+ if ($.unmounted) {
2413
+ this.insertAdjacent($.node);
2414
+ $.unmounted = false;
2403
2415
  }
2404
- else {
2405
- $.parent.$$appendNode($.node);
2406
- }
2407
- $.unmounted = false;
2408
2416
  });
2409
2417
  }
2410
2418
  /**
2411
2419
  * Runs GC
2412
2420
  */
2413
- $destroy() {
2421
+ destroy() {
2414
2422
  this.node.remove();
2415
- super.$destroy();
2423
+ super.destroy();
2416
2424
  }
2417
2425
  }
2418
2426
  /**
@@ -2421,22 +2429,22 @@ class Tag extends INode {
2421
2429
  * @extends INode
2422
2430
  */
2423
2431
  class Extension extends INode {
2424
- $preinit(app, parent) {
2425
- if (parent instanceof INode) {
2426
- const $ = this.$;
2427
- $.preinit(app, parent);
2428
- $.node = parent.node;
2432
+ preinit(app, parent) {
2433
+ const $ = this.$;
2434
+ let it = parent;
2435
+ while (it && !(it instanceof INode)) {
2436
+ it = it.parent;
2429
2437
  }
2430
- else {
2431
- throw internalError("A extension node can be encapsulated only in a tag/extension/component");
2438
+ if (it && it instanceof INode) {
2439
+ $.node = it.node;
2440
+ }
2441
+ $.preinit(app, parent);
2442
+ if (!it) {
2443
+ throw userError("A extension node can be encapsulated only in a tag/extension/component", "virtual-dom");
2432
2444
  }
2433
2445
  }
2434
- constructor($) {
2435
- super($);
2436
- this.$seal();
2437
- }
2438
- $destroy() {
2439
- super.$destroy();
2446
+ destroy() {
2447
+ super.destroy();
2440
2448
  }
2441
2449
  }
2442
2450
  /**
@@ -2445,45 +2453,49 @@ class Extension extends INode {
2445
2453
  * @extends Extension
2446
2454
  */
2447
2455
  class Component extends Extension {
2448
- constructor() {
2449
- super();
2450
- this.$seal();
2451
- }
2452
- $mounted() {
2453
- super.$mounted();
2454
- if (this.$children.length !== 1) {
2455
- throw userError("UserNode must have a child only", "dom-error");
2456
+ ready() {
2457
+ super.ready();
2458
+ if (this.children.size !== 1) {
2459
+ throw userError("Component must have a child only", "dom-error");
2456
2460
  }
2457
- const child = this.$children[0];
2461
+ const child = this.lastChild;
2458
2462
  if (child instanceof Tag || child instanceof Component) {
2459
2463
  const $ = this.$;
2460
2464
  $.node = child.node;
2461
2465
  }
2462
2466
  else {
2463
- throw userError("UserNode child must be Tag or Component", "dom-error");
2467
+ throw userError("Component child must be Tag or Component", "dom-error");
2464
2468
  }
2465
2469
  }
2470
+ preinit(app, parent) {
2471
+ this.$.preinit(app, parent);
2472
+ }
2466
2473
  }
2467
2474
  /**
2468
2475
  * Private part of switch node
2469
2476
  * @class SwitchedNodePrivate
2470
2477
  * @extends INodePrivate
2471
2478
  */
2472
- class SwitchedNodePrivate extends INodePrivate {
2479
+ class SwitchedNodePrivate extends FragmentPrivate {
2473
2480
  constructor() {
2474
2481
  super();
2475
- this.$seal();
2482
+ /**
2483
+ * Array of possible cases
2484
+ * @type {Array<{cond : IValue<boolean>, cb : function(Fragment)}>}
2485
+ */
2486
+ this.cases = [];
2487
+ this.seal();
2476
2488
  }
2477
2489
  /**
2478
2490
  * Runs GC
2479
2491
  */
2480
- $destroy() {
2492
+ destroy() {
2481
2493
  this.cases.forEach(c => {
2482
2494
  delete c.cond;
2483
2495
  delete c.cb;
2484
2496
  });
2485
2497
  this.cases.splice(0);
2486
- super.$destroy();
2498
+ super.destroy();
2487
2499
  }
2488
2500
  }
2489
2501
  /**
@@ -2494,7 +2506,7 @@ class SwitchedNode extends Fragment {
2494
2506
  * Constructs a switch node and define a sync function
2495
2507
  */
2496
2508
  constructor() {
2497
- super(new SwitchedNodePrivate);
2509
+ super({}, new SwitchedNodePrivate);
2498
2510
  this.$.sync = () => {
2499
2511
  const $ = this.$;
2500
2512
  let i = 0;
@@ -2506,10 +2518,10 @@ class SwitchedNode extends Fragment {
2506
2518
  if (i === $.index) {
2507
2519
  return;
2508
2520
  }
2509
- if ($.fragment) {
2510
- $.fragment.$destroy();
2511
- this.$children.splice(0);
2512
- $.fragment = null;
2521
+ if (this.lastChild) {
2522
+ this.lastChild.destroy();
2523
+ this.children.clear();
2524
+ this.lastChild = null;
2513
2525
  }
2514
2526
  if (i !== $.cases.length) {
2515
2527
  $.index = i;
@@ -2519,43 +2531,38 @@ class SwitchedNode extends Fragment {
2519
2531
  $.index = -1;
2520
2532
  }
2521
2533
  };
2522
- this.$seal();
2534
+ this.seal();
2523
2535
  }
2524
- /**
2525
- * Set up switch cases
2526
- * @param cases {{ cond : IValue, cb : function(Fragment) }}
2527
- */
2528
- setCases(cases) {
2529
- const $ = this.$;
2530
- $.cases = [...cases];
2536
+ addCase(case_) {
2537
+ this.$.cases.push(case_);
2538
+ case_.cond.on(this.$.sync);
2539
+ this.$.sync();
2531
2540
  }
2532
2541
  /**
2533
2542
  * Creates a child node
2534
2543
  * @param cb {function(Fragment)} Call-back
2535
2544
  */
2536
2545
  createChild(cb) {
2537
- const node = new Fragment();
2538
- node.$preinit(this.$.app, this);
2539
- node.$init();
2540
- node.$ready();
2541
- this.$.fragment = node;
2542
- this.$children.push(node);
2546
+ const node = new Fragment({});
2547
+ node.preinit(this.$.app, this);
2548
+ node.init();
2549
+ this.lastChild = node;
2550
+ this.children.add(node);
2543
2551
  cb(node);
2544
2552
  }
2545
- $ready() {
2553
+ ready() {
2546
2554
  const $ = this.$;
2547
- super.$ready();
2548
2555
  $.cases.forEach(c => {
2549
2556
  c.cond.on($.sync);
2550
2557
  });
2551
2558
  $.sync();
2552
2559
  }
2553
- $destroy() {
2560
+ destroy() {
2554
2561
  const $ = this.$;
2555
2562
  $.cases.forEach(c => {
2556
2563
  c.cond.off($.sync);
2557
2564
  });
2558
- super.$destroy();
2565
+ super.destroy();
2559
2566
  }
2560
2567
  }
2561
2568
  /**
@@ -2564,7 +2571,7 @@ class SwitchedNode extends Fragment {
2564
2571
  class DebugPrivate extends FragmentPrivate {
2565
2572
  constructor() {
2566
2573
  super();
2567
- this.$seal();
2574
+ this.seal();
2568
2575
  }
2569
2576
  /**
2570
2577
  * Pre-initializes a text node
@@ -2578,14 +2585,14 @@ class DebugPrivate extends FragmentPrivate {
2578
2585
  this.bindings.add(new Expression((v) => {
2579
2586
  this.node.replaceData(0, -1, v);
2580
2587
  }, true, text));
2581
- this.parent.$$appendNode(this.node);
2588
+ this.parent.appendNode(this.node);
2582
2589
  }
2583
2590
  /**
2584
2591
  * Clear node data
2585
2592
  */
2586
- $destroy() {
2593
+ destroy() {
2587
2594
  this.node.remove();
2588
- super.$destroy();
2595
+ super.destroy();
2589
2596
  }
2590
2597
  }
2591
2598
  /**
@@ -2595,15 +2602,15 @@ class DebugPrivate extends FragmentPrivate {
2595
2602
  */
2596
2603
  class DebugNode extends Fragment {
2597
2604
  constructor() {
2598
- super();
2605
+ super({});
2599
2606
  /**
2600
2607
  * private data
2601
2608
  * @type {DebugNode}
2602
2609
  */
2603
2610
  this.$ = new DebugPrivate();
2604
- this.$seal();
2611
+ this.seal();
2605
2612
  }
2606
- $preinit(app, parent, text) {
2613
+ preinit(app, parent, text) {
2607
2614
  const $ = this.$;
2608
2615
  if (!text) {
2609
2616
  throw internalError('wrong DebugNode::$preninit call');
@@ -2613,9 +2620,9 @@ class DebugNode extends Fragment {
2613
2620
  /**
2614
2621
  * Runs garbage collector
2615
2622
  */
2616
- $destroy() {
2617
- this.$.$destroy();
2618
- super.$destroy();
2623
+ destroy() {
2624
+ this.$.destroy();
2625
+ super.destroy();
2619
2626
  }
2620
2627
  }
2621
2628
 
@@ -2629,6 +2636,7 @@ window.Tag = Tag;
2629
2636
  window.Extension = Extension;
2630
2637
  window.Component = Component;
2631
2638
  window.SwitchedNodePrivate = SwitchedNodePrivate;
2639
+ window.SwitchedNode = SwitchedNode;
2632
2640
  window.DebugPrivate = DebugPrivate;
2633
2641
  window.DebugNode = DebugNode;
2634
2642
 
@@ -2640,12 +2648,12 @@ window.DebugNode = DebugNode;
2640
2648
  */
2641
2649
  class AppNode extends INode {
2642
2650
  /**
2643
- * @param options {Object} Application options
2651
+ * @param input
2644
2652
  */
2645
- constructor(options) {
2646
- super();
2647
- this.$run = (options === null || options === void 0 ? void 0 : options.executor) || ((options === null || options === void 0 ? void 0 : options.freezeUi) === false ? timeoutExecutor : instantExecutor);
2648
- this.$debugUi = (options === null || options === void 0 ? void 0 : options.debugUi) || false;
2653
+ constructor(input) {
2654
+ super(input);
2655
+ this.debugUi = input.debugUi || false;
2656
+ this.seal();
2649
2657
  }
2650
2658
  }
2651
2659
  /**
@@ -2657,22 +2665,33 @@ class App extends AppNode {
2657
2665
  /**
2658
2666
  * Constructs an app node
2659
2667
  * @param node {Element} The root of application
2660
- * @param options {Object} Application options
2668
+ * @param input
2661
2669
  */
2662
- constructor(node, options) {
2663
- super(options);
2670
+ constructor(node, input) {
2671
+ super(input);
2664
2672
  this.$.node = node;
2665
- this.$preinit(this, this);
2666
- this.$seal();
2673
+ this.preinit(this, this);
2674
+ this.init();
2675
+ this.seal();
2667
2676
  }
2668
- $$appendNode(node) {
2669
- const $ = this.$;
2670
- $.app.$run.appendChild($.node, node);
2677
+ appendNode(node) {
2678
+ this.$.node.appendChild(node);
2679
+ }
2680
+ }
2681
+ class Portal extends AppNode {
2682
+ constructor(input) {
2683
+ super(input);
2684
+ this.$.node = input.node;
2685
+ this.seal();
2686
+ }
2687
+ appendNode(node) {
2688
+ this.$.node.appendChild(node);
2671
2689
  }
2672
2690
  }
2673
2691
 
2674
2692
  window.AppNode = AppNode;
2675
2693
  window.App = App;
2694
+ window.Portal = Portal;
2676
2695
 
2677
2696
  // ./lib/node/interceptor.js
2678
2697
  /**
@@ -2722,8 +2741,8 @@ class Interceptor extends Destroyable {
2722
2741
  signal.unsubscribe(handler);
2723
2742
  });
2724
2743
  }
2725
- $destroy() {
2726
- super.$destroy();
2744
+ destroy() {
2745
+ super.destroy();
2727
2746
  this.signals.forEach(signal => {
2728
2747
  this.handlers.forEach(handler => {
2729
2748
  signal.unsubscribe(handler);
@@ -2750,7 +2769,7 @@ class InterceptorNode extends Fragment {
2750
2769
  */
2751
2770
  this.slot = new Slot;
2752
2771
  }
2753
- $compose() {
2772
+ compose() {
2754
2773
  this.slot.release(this, this.interceptor);
2755
2774
  }
2756
2775
  }
@@ -2772,22 +2791,21 @@ class AttributeBinding extends Binding {
2772
2791
  * @param value {IValue} value to bind
2773
2792
  */
2774
2793
  constructor(node, name, value) {
2775
- super(node, name, value);
2776
- }
2777
- /**
2778
- * Generates a function which updates the attribute value
2779
- * @param name {String} The name of attribute
2780
- * @returns {Function} a function which will update attribute value
2781
- */
2782
- bound(name) {
2783
- return function (node, value) {
2794
+ super(value);
2795
+ this.init((value) => {
2784
2796
  if (value) {
2785
- node.app.$run.setAttribute(node.node, name, value);
2797
+ if (typeof value === 'boolean') {
2798
+ node.node.setAttribute(name, "");
2799
+ }
2800
+ else {
2801
+ node.node.setAttribute(name, `${value}`);
2802
+ }
2786
2803
  }
2787
2804
  else {
2788
- node.app.$run.removeAttribute(node.node, name);
2805
+ node.node.removeAttribute(name);
2789
2806
  }
2790
- };
2807
+ });
2808
+ this.seal();
2791
2809
  }
2792
2810
  }
2793
2811
 
@@ -2807,77 +2825,64 @@ class StyleBinding extends Binding {
2807
2825
  * @param value {IValue} the value to bind
2808
2826
  */
2809
2827
  constructor(node, name, value) {
2810
- super(node, name, value);
2811
- }
2812
- /**
2813
- * Generates a function to update style property value
2814
- * @param name {string}
2815
- * @returns {Function} a function to update style property
2816
- */
2817
- bound(name) {
2818
- return function (node, value) {
2828
+ super(value);
2829
+ this.init((value) => {
2819
2830
  if (node.node instanceof HTMLElement) {
2820
- node.app.$run.setStyle(node.node, name, value);
2831
+ node.node.style.setProperty(name, value);
2821
2832
  }
2822
- };
2833
+ });
2834
+ this.seal();
2823
2835
  }
2824
2836
  }
2825
2837
 
2826
2838
  window.StyleBinding = StyleBinding;
2827
2839
 
2828
2840
  // ./lib/binding/class.js
2829
- /**
2830
- * Represents a HTML class binding description
2831
- * @class ClassBinding
2832
- * @extends Binding
2833
- */
2834
- class ClassBinding extends Binding {
2835
- /**
2836
- * Constructs an HTML class binding description
2837
- * @param node {INode} the vasille node
2838
- * @param name {String} the name of class
2839
- * @param value {IValue} the value to bind
2840
- */
2841
+ function addClass(node, cl) {
2842
+ node.node.classList.add(cl);
2843
+ }
2844
+ function removeClass(node, cl) {
2845
+ node.node.classList.remove(cl);
2846
+ }
2847
+ class StaticClassBinding extends Binding {
2841
2848
  constructor(node, name, value) {
2842
- super(node, name, value);
2843
- this.$seal();
2844
- }
2845
- /**
2846
- * Generates a function which updates the html class value
2847
- * @param name {String} The name of attribute
2848
- * @returns {Function} a function which will update attribute value
2849
- */
2850
- bound(name) {
2851
- let current = null;
2852
- function addClass(node, cl) {
2853
- node.app.$run.addClass(node.node, cl);
2854
- }
2855
- function removeClass(node, cl) {
2856
- node.app.$run.removeClass(node.node, cl);
2857
- }
2858
- return (node, value) => {
2859
- if (value !== current) {
2860
- if (typeof current === "string" && current !== "") {
2861
- removeClass(node, current);
2849
+ super(value);
2850
+ this.current = false;
2851
+ this.init((value) => {
2852
+ if (value !== this.current) {
2853
+ if (value) {
2854
+ addClass(node, name);
2862
2855
  }
2863
- if (typeof value === "boolean") {
2864
- if (value) {
2865
- addClass(node, name);
2866
- }
2867
- else {
2868
- removeClass(node, name);
2869
- }
2856
+ else {
2857
+ removeClass(node, name);
2870
2858
  }
2871
- else if (typeof value === "string" && value !== "") {
2859
+ this.current = value;
2860
+ }
2861
+ });
2862
+ this.seal();
2863
+ }
2864
+ }
2865
+ class DynamicalClassBinding extends Binding {
2866
+ constructor(node, value) {
2867
+ super(value);
2868
+ this.current = "";
2869
+ this.init((value) => {
2870
+ if (this.current != value) {
2871
+ if (this.current.length) {
2872
+ removeClass(node, this.current);
2873
+ }
2874
+ if (value.length) {
2872
2875
  addClass(node, value);
2873
2876
  }
2874
- current = value;
2877
+ this.current = value;
2875
2878
  }
2876
- };
2879
+ });
2880
+ this.seal();
2877
2881
  }
2878
2882
  }
2879
2883
 
2880
- window.ClassBinding = ClassBinding;
2884
+ window.StaticClassBinding = StaticClassBinding;
2885
+ window.DynamicalClassBinding = DynamicalClassBinding;
2881
2886
 
2882
2887
  // ./lib/views/repeat-node.js
2883
2888
  /**
@@ -2893,11 +2898,11 @@ class RepeatNodePrivate extends INodePrivate {
2893
2898
  * @type {Map}
2894
2899
  */
2895
2900
  this.nodes = new Map();
2896
- this.$seal();
2901
+ this.seal();
2897
2902
  }
2898
- $destroy() {
2903
+ destroy() {
2899
2904
  this.nodes.clear();
2900
- super.$destroy();
2905
+ super.destroy();
2901
2906
  }
2902
2907
  }
2903
2908
  /**
@@ -2906,80 +2911,42 @@ class RepeatNodePrivate extends INodePrivate {
2906
2911
  * @extends Fragment
2907
2912
  */
2908
2913
  class RepeatNode extends Fragment {
2909
- constructor($) {
2910
- super($ || new RepeatNodePrivate);
2914
+ constructor(input, $) {
2915
+ super(input, $);
2911
2916
  /**
2912
2917
  * If false will use timeout executor, otherwise the app executor
2913
2918
  */
2914
2919
  this.freezeUi = true;
2915
- this.slot = new Slot;
2916
2920
  }
2917
- createChild(id, item, before) {
2918
- // TODO: Refactor: remove @ts-ignore
2919
- const node = new Fragment();
2920
- // eslint-disable-next-line
2921
- // @ts-ignore
2922
- const $ = node.$;
2921
+ createChild(opts, id, item, before) {
2922
+ const node = new Fragment({});
2923
2923
  this.destroyChild(id, item);
2924
2924
  if (before) {
2925
- $.next = before;
2926
- // eslint-disable-next-line
2927
- // @ts-ignore
2928
- $.prev = before.$.prev;
2929
- // eslint-disable-next-line
2930
- // @ts-ignore
2931
- before.$.prev = node;
2932
- if ($.prev) {
2933
- // eslint-disable-next-line
2934
- // @ts-ignore
2935
- $.prev.$.next = node;
2936
- }
2937
- this.$children.splice(this.$children.indexOf(before), 0, node);
2925
+ this.children.add(node);
2926
+ before.insertBefore(node);
2938
2927
  }
2939
2928
  else {
2940
- const lastChild = this.$children[this.$children.length - 1];
2929
+ const lastChild = this.lastChild;
2941
2930
  if (lastChild) {
2942
- // eslint-disable-next-line
2943
- // @ts-ignore
2944
- lastChild.$.next = node;
2931
+ lastChild.insertAfter(node);
2945
2932
  }
2946
- $.prev = lastChild;
2947
- this.$children.push(node);
2948
- }
2949
- node.$preinit(this.$.app, this);
2950
- node.$init();
2951
- const callback = () => {
2952
- this.slot.release(node, item, id);
2953
- node.$ready();
2954
- };
2955
- if (this.freezeUi) {
2956
- this.$.app.$run.callCallback(callback);
2957
- }
2958
- else {
2959
- timeoutExecutor.callCallback(callback);
2933
+ this.children.add(node);
2960
2934
  }
2935
+ this.lastChild = node;
2936
+ node.preinit(this.$.app, this);
2937
+ node.init();
2938
+ opts.slot && opts.slot(node, item, id);
2939
+ node.ready();
2961
2940
  this.$.nodes.set(id, node);
2962
2941
  }
2963
2942
  destroyChild(id, item) {
2964
2943
  const $ = this.$;
2965
2944
  const child = $.nodes.get(id);
2966
2945
  if (child) {
2967
- // eslint-disable-next-line
2968
- // @ts-ignore
2969
- const $ = child.$;
2970
- if ($.prev) {
2971
- // eslint-disable-next-line
2972
- // @ts-ignore
2973
- $.prev.$.next = $.next;
2974
- }
2975
- if ($.next) {
2976
- // eslint-disable-next-line
2977
- // @ts-ignore
2978
- $.next.$.prev = $.prev;
2979
- }
2980
- child.$destroy();
2946
+ child.remove();
2947
+ child.destroy();
2981
2948
  this.$.nodes.delete(id);
2982
- this.$children.splice(this.$children.indexOf(child), 1);
2949
+ this.children.delete(child);
2983
2950
  }
2984
2951
  }
2985
2952
  }
@@ -3000,7 +2967,7 @@ class RepeaterPrivate extends RepeatNodePrivate {
3000
2967
  * Current count of child nodes
3001
2968
  */
3002
2969
  this.currentCount = 0;
3003
- this.$seal();
2970
+ this.seal();
3004
2971
  }
3005
2972
  }
3006
2973
  /**
@@ -3015,7 +2982,7 @@ class Repeater extends RepeatNode {
3015
2982
  * The count of children
3016
2983
  */
3017
2984
  this.count = new Reference(0);
3018
- this.$seal();
2985
+ this.seal();
3019
2986
  }
3020
2987
  /**
3021
2988
  * Changes the children count
@@ -3034,18 +3001,18 @@ class Repeater extends RepeatNode {
3034
3001
  }
3035
3002
  $.currentCount = number;
3036
3003
  }
3037
- $created() {
3004
+ created() {
3038
3005
  const $ = this.$;
3039
- super.$created();
3006
+ super.created();
3040
3007
  $.updateHandler = this.changeCount.bind(this);
3041
3008
  this.count.on($.updateHandler);
3042
3009
  }
3043
- $ready() {
3010
+ ready() {
3044
3011
  this.changeCount(this.count.$);
3045
3012
  }
3046
- $destroy() {
3013
+ destroy() {
3047
3014
  const $ = this.$;
3048
- super.$destroy();
3015
+ super.destroy();
3049
3016
  this.count.off($.updateHandler);
3050
3017
  }
3051
3018
  }
@@ -3062,7 +3029,7 @@ window.Repeater = Repeater;
3062
3029
  class BaseViewPrivate extends RepeatNodePrivate {
3063
3030
  constructor() {
3064
3031
  super();
3065
- this.$seal();
3032
+ this.seal();
3066
3033
  }
3067
3034
  }
3068
3035
  /**
@@ -3072,34 +3039,23 @@ class BaseViewPrivate extends RepeatNodePrivate {
3072
3039
  * @implements IModel
3073
3040
  */
3074
3041
  class BaseView extends RepeatNode {
3075
- constructor($1) {
3076
- super($1 || new BaseViewPrivate);
3042
+ constructor(input, $) {
3043
+ super(input, $ || new BaseViewPrivate);
3044
+ }
3045
+ compose(input) {
3077
3046
  const $ = this.$;
3078
3047
  $.addHandler = (id, item) => {
3079
- this.createChild(id, item);
3048
+ this.createChild(input, id, item);
3080
3049
  };
3081
3050
  $.removeHandler = (id, item) => {
3082
3051
  this.destroyChild(id, item);
3083
3052
  };
3084
- this.$seal();
3085
- }
3086
- /**
3087
- * Handle ready event
3088
- */
3089
- $ready() {
3090
- const $ = this.$;
3091
- this.model.listener.onAdd($.addHandler);
3092
- this.model.listener.onRemove($.removeHandler);
3093
- super.$ready();
3094
- }
3095
- /**
3096
- * Handles destroy event
3097
- */
3098
- $destroy() {
3099
- const $ = this.$;
3100
- this.model.listener.offAdd($.addHandler);
3101
- this.model.listener.offRemove($.removeHandler);
3102
- super.$destroy();
3053
+ input.model.listener.onAdd($.addHandler);
3054
+ input.model.listener.onRemove($.removeHandler);
3055
+ this.runOnDestroy(() => {
3056
+ input.model.listener.offAdd($.addHandler);
3057
+ input.model.listener.offRemove($.removeHandler);
3058
+ });
3103
3059
  }
3104
3060
  }
3105
3061
 
@@ -3113,18 +3069,14 @@ window.BaseView = BaseView;
3113
3069
  * @extends BaseView
3114
3070
  */
3115
3071
  class ArrayView extends BaseView {
3116
- constructor(model) {
3117
- super();
3118
- this.model = model;
3119
- }
3120
- createChild(id, item, before) {
3121
- super.createChild(item, item, before || this.$.nodes.get(id));
3072
+ createChild(input, id, item, before) {
3073
+ super.createChild(input, item, item, before || this.$.nodes.get(id));
3122
3074
  }
3123
- $ready() {
3124
- this.model.forEach(item => {
3125
- this.createChild(item, item);
3075
+ compose(input) {
3076
+ super.compose(input);
3077
+ input.model.forEach(item => {
3078
+ this.createChild(input, item, item);
3126
3079
  });
3127
- super.$ready();
3128
3080
  }
3129
3081
  }
3130
3082
 
@@ -3137,23 +3089,16 @@ window.ArrayView = ArrayView;
3137
3089
  * @extends Fragment
3138
3090
  */
3139
3091
  class Watch extends Fragment {
3140
- constructor() {
3141
- super();
3142
- this.slot = new Slot;
3143
- this.model = this.$ref(null);
3144
- this.$seal();
3145
- }
3146
- $createWatchers() {
3147
- this.$watch((value) => {
3148
- this.$children.forEach(child => {
3149
- child.$destroy();
3092
+ compose(input) {
3093
+ this.watch((value) => {
3094
+ this.children.forEach(child => {
3095
+ child.destroy();
3150
3096
  });
3151
- this.$children.splice(0);
3152
- this.slot.release(this, value);
3153
- }, this.model);
3154
- }
3155
- $compose() {
3156
- this.slot.release(this, this.model.$);
3097
+ this.children.clear();
3098
+ this.lastChild = null;
3099
+ input.slot && input.slot(this, value);
3100
+ }, input.model);
3101
+ input.slot(this, input.model.$);
3157
3102
  }
3158
3103
  }
3159
3104
 
@@ -3166,16 +3111,13 @@ window.Watch = Watch;
3166
3111
  * @extends BaseView
3167
3112
  */
3168
3113
  class ObjectView extends BaseView {
3169
- constructor(model) {
3170
- super();
3171
- this.model = model;
3172
- }
3173
- $ready() {
3174
- const obj = this.model;
3114
+ compose(input) {
3115
+ super.compose(input);
3116
+ const obj = input.model.proxy();
3175
3117
  for (const key in obj) {
3176
- this.createChild(key, obj[key]);
3118
+ this.createChild(input, key, obj[key]);
3177
3119
  }
3178
- super.$ready();
3120
+ super.ready();
3179
3121
  }
3180
3122
  }
3181
3123
 
@@ -3188,16 +3130,11 @@ window.ObjectView = ObjectView;
3188
3130
  * @extends BaseView
3189
3131
  */
3190
3132
  class MapView extends BaseView {
3191
- constructor(model) {
3192
- super();
3193
- this.model = model;
3194
- }
3195
- $ready() {
3196
- const map = this.model;
3197
- map.forEach((value, key) => {
3198
- this.createChild(key, value);
3133
+ compose(input) {
3134
+ super.compose(input);
3135
+ input.model.forEach((value, key) => {
3136
+ this.createChild(input, key, value);
3199
3137
  });
3200
- super.$ready();
3201
3138
  }
3202
3139
  }
3203
3140
 
@@ -3210,19 +3147,12 @@ window.MapView = MapView;
3210
3147
  * @extends BaseView
3211
3148
  */
3212
3149
  class SetView extends BaseView {
3213
- constructor(model) {
3214
- super();
3215
- this.model = model;
3216
- }
3217
- $ready() {
3218
- const $ = this.$;
3219
- const set = this.model;
3150
+ compose(input) {
3151
+ super.compose(input);
3152
+ const set = input.model;
3220
3153
  set.forEach(item => {
3221
- $.app.$run.callCallback(() => {
3222
- this.createChild(item, item);
3223
- });
3154
+ this.createChild(input, item, item);
3224
3155
  });
3225
- super.$ready();
3226
3156
  }
3227
3157
  }
3228
3158