vasille 2.0.5 → 2.2.2

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 (74) hide show
  1. package/README.md +4 -0
  2. package/cdn/es2015.js +827 -827
  3. package/cdn/es5.js +909 -829
  4. package/flow-typed/vasille.js +2647 -835
  5. package/lib/binding/attribute.js +8 -3
  6. package/lib/binding/binding.js +5 -5
  7. package/lib/binding/class.js +4 -4
  8. package/lib/binding/style.js +2 -2
  9. package/lib/core/core.js +73 -17
  10. package/lib/core/destroyable.js +2 -2
  11. package/lib/core/ivalue.js +4 -4
  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 +21 -12
  22. package/lib/node/node.js +229 -573
  23. package/lib/node/watch.js +6 -14
  24. package/lib/spec/html.js +1 -0
  25. package/lib/spec/react.js +1 -0
  26. package/lib/spec/svg.js +1 -0
  27. package/lib/v/index.js +23 -0
  28. package/lib/value/expression.js +21 -18
  29. package/lib/value/mirror.js +15 -15
  30. package/lib/value/pointer.js +5 -5
  31. package/lib/value/reference.js +18 -18
  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 +4 -7
  36. package/lib/views/repeat-node.js +10 -22
  37. package/lib/views/set-view.js +4 -11
  38. package/package.json +3 -1
  39. package/types/binding/attribute.d.ts +2 -2
  40. package/types/binding/binding.d.ts +1 -1
  41. package/types/core/core.d.ts +31 -43
  42. package/types/core/destroyable.d.ts +2 -2
  43. package/types/core/ivalue.d.ts +4 -4
  44. package/types/functional/components.d.ts +4 -0
  45. package/types/functional/merge.d.ts +1 -0
  46. package/types/functional/models.d.ts +10 -0
  47. package/types/functional/options.d.ts +23 -0
  48. package/types/functional/reactivity.d.ts +11 -0
  49. package/types/functional/stack.d.ts +24 -0
  50. package/types/index.d.ts +3 -7
  51. package/types/models/array-model.d.ts +1 -0
  52. package/types/models/object-model.d.ts +2 -0
  53. package/types/node/app.d.ts +19 -17
  54. package/types/node/node.d.ts +67 -388
  55. package/types/node/watch.d.ts +9 -15
  56. package/types/spec/html.d.ts +975 -0
  57. package/types/spec/react.d.ts +4 -0
  58. package/types/spec/svg.d.ts +314 -0
  59. package/types/v/index.d.ts +36 -0
  60. package/types/value/expression.d.ts +11 -24
  61. package/types/value/mirror.d.ts +6 -6
  62. package/types/value/pointer.d.ts +1 -1
  63. package/types/value/reference.d.ts +7 -7
  64. package/types/views/array-view.d.ts +3 -4
  65. package/types/views/base-view.d.ts +8 -16
  66. package/types/views/map-view.d.ts +2 -3
  67. package/types/views/object-view.d.ts +2 -3
  68. package/types/views/repeat-node.d.ts +8 -9
  69. package/types/views/set-view.d.ts +2 -3
  70. package/types/core/executor.d.ts +0 -87
  71. package/types/core/signal.d.ts +0 -35
  72. package/types/core/slot.d.ts +0 -45
  73. package/types/node/interceptor.d.ts +0 -50
  74. package/types/views/repeater.d.ts +0 -38
package/cdn/es2015.js CHANGED
@@ -149,13 +149,14 @@ class ObjectModel extends Object {
149
149
  */
150
150
  constructor(obj = {}) {
151
151
  super();
152
+ this.container = Object.create(null);
152
153
  Object.defineProperty(this, 'listener', {
153
154
  value: new Listener,
154
155
  writable: false,
155
156
  configurable: false
156
157
  });
157
158
  for (const i in obj) {
158
- Object.defineProperty(this, i, {
159
+ Object.defineProperty(this.container, i, {
159
160
  value: obj[i],
160
161
  configurable: true,
161
162
  writable: true,
@@ -170,8 +171,7 @@ class ObjectModel extends Object {
170
171
  * @return {*}
171
172
  */
172
173
  get(key) {
173
- const ts = this;
174
- return ts[key];
174
+ return this.container[key];
175
175
  }
176
176
  /**
177
177
  * Sets an object property value
@@ -180,21 +180,19 @@ class ObjectModel extends Object {
180
180
  * @return {ObjectModel} a pointer to this
181
181
  */
182
182
  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;
183
+ if (Reflect.has(this.container, key)) {
184
+ this.listener.emitRemoved(key, this.container[key]);
185
+ this.container[key] = v;
188
186
  }
189
187
  else {
190
- Object.defineProperty(ts, key, {
188
+ Object.defineProperty(this.container, key, {
191
189
  value: v,
192
190
  configurable: true,
193
191
  writable: true,
194
192
  enumerable: true
195
193
  });
196
194
  }
197
- this.listener.emitAdded(key, ts[key]);
195
+ this.listener.emitAdded(key, this.container[key]);
198
196
  return this;
199
197
  }
200
198
  /**
@@ -202,12 +200,28 @@ class ObjectModel extends Object {
202
200
  * @param key {string} property name
203
201
  */
204
202
  delete(key) {
205
- const ts = this;
206
- if (ts[key]) {
207
- this.listener.emitRemoved(key, ts[key]);
208
- delete ts[key];
203
+ if (this.container[key]) {
204
+ this.listener.emitRemoved(key, this.container[key]);
205
+ delete this.container[key];
209
206
  }
210
207
  }
208
+ proxy() {
209
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
210
+ const ts = this;
211
+ return new Proxy(this.container, {
212
+ get(target, p) {
213
+ return ts.get(p);
214
+ },
215
+ set(target, p, value) {
216
+ ts.set(p, value);
217
+ return true;
218
+ },
219
+ deleteProperty(target, p) {
220
+ ts.delete(p);
221
+ return true;
222
+ }
223
+ });
224
+ }
211
225
  enableReactivity() {
212
226
  this.listener.enableReactivity();
213
227
  }
@@ -373,6 +387,15 @@ class ArrayModel extends Array {
373
387
  super.push(data[i]);
374
388
  }
375
389
  }
390
+ // proxy
391
+ proxy() {
392
+ return new Proxy(this, {
393
+ set(target, p, value) {
394
+ target.splice(parseInt(p), 1, value);
395
+ return true;
396
+ }
397
+ });
398
+ }
376
399
  /* Array members */
377
400
  /**
378
401
  * Gets the last item of array
@@ -862,7 +885,7 @@ class Destroyable {
862
885
  * Make object fields non configurable
863
886
  * @protected
864
887
  */
865
- seal() {
888
+ $seal() {
866
889
  const $ = this;
867
890
  Object.keys($).forEach(i => {
868
891
  // eslint-disable-next-line no-prototype-builtins
@@ -894,7 +917,7 @@ class Destroyable {
894
917
  /**
895
918
  * Garbage collector method
896
919
  */
897
- destroy() {
920
+ $destroy() {
898
921
  // nothing here
899
922
  }
900
923
  }
@@ -906,13 +929,13 @@ class Switchable extends Destroyable {
906
929
  /**
907
930
  * Enable update handlers triggering
908
931
  */
909
- enable() {
932
+ $enable() {
910
933
  throw notOverwritten();
911
934
  }
912
935
  /**
913
936
  * disable update handlers triggering
914
937
  */
915
- disable() {
938
+ $disable() {
916
939
  throw notOverwritten();
917
940
  }
918
941
  }
@@ -947,14 +970,14 @@ class IValue extends Switchable {
947
970
  * Add a new handler to value change
948
971
  * @param handler {function(value : *)} the handler to add
949
972
  */
950
- on(handler) {
973
+ $on(handler) {
951
974
  throw notOverwritten();
952
975
  }
953
976
  /**
954
977
  * Removes a handler of value change
955
978
  * @param handler {function(value : *)} the handler to remove
956
979
  */
957
- off(handler) {
980
+ $off(handler) {
958
981
  throw notOverwritten();
959
982
  }
960
983
  }
@@ -966,6 +989,18 @@ window.IValue = IValue;
966
989
 
967
990
 
968
991
 
992
+ // ./lib/spec/svg.js
993
+
994
+
995
+
996
+ // ./lib/spec/react.js
997
+
998
+
999
+
1000
+ // ./lib/spec/html.js
1001
+
1002
+
1003
+
969
1004
  // ./lib/value/expression.js
970
1005
  /**
971
1006
  * Bind some values to one expression
@@ -973,13 +1008,18 @@ window.IValue = IValue;
973
1008
  * @extends IValue
974
1009
  */
975
1010
  class Expression extends IValue {
976
- constructor(func, link, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1011
+ /**
1012
+ * Creates a function bounded to N values
1013
+ * @param func {Function} the function to bound
1014
+ * @param values
1015
+ * @param link {Boolean} links immediately if true
1016
+ */
1017
+ constructor(func, link, ...values) {
977
1018
  super(false);
978
1019
  /**
979
1020
  * Expression will link different handler for each value of list
980
1021
  */
981
1022
  this.linkedFunc = [];
982
- const values = [v1, v2, v3, v4, v5, v6, v7, v8, v9].filter(v => v instanceof IValue);
983
1023
  const handler = (i) => {
984
1024
  if (i != null) {
985
1025
  this.valuesCache[i] = this.values[i].$;
@@ -988,23 +1028,21 @@ class Expression extends IValue {
988
1028
  };
989
1029
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
990
1030
  // @ts-ignore
991
- this.valuesCache = values.map(iValue => iValue.$);
1031
+ this.valuesCache = values.map(item => item.$);
992
1032
  this.sync = new Reference(func.apply(this, this.valuesCache));
993
1033
  let i = 0;
994
1034
  values.forEach(() => {
995
1035
  this.linkedFunc.push(handler.bind(this, Number(i++)));
996
1036
  });
997
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
998
- // @ts-ignore
999
1037
  this.values = values;
1000
1038
  this.func = handler;
1001
1039
  if (link) {
1002
- this.enable();
1040
+ this.$enable();
1003
1041
  }
1004
1042
  else {
1005
1043
  handler();
1006
1044
  }
1007
- this.seal();
1045
+ this.$seal();
1008
1046
  }
1009
1047
  get $() {
1010
1048
  return this.sync.$;
@@ -1012,18 +1050,18 @@ class Expression extends IValue {
1012
1050
  set $(value) {
1013
1051
  this.sync.$ = value;
1014
1052
  }
1015
- on(handler) {
1016
- this.sync.on(handler);
1053
+ $on(handler) {
1054
+ this.sync.$on(handler);
1017
1055
  return this;
1018
1056
  }
1019
- off(handler) {
1020
- this.sync.off(handler);
1057
+ $off(handler) {
1058
+ this.sync.$off(handler);
1021
1059
  return this;
1022
1060
  }
1023
- enable() {
1061
+ $enable() {
1024
1062
  if (!this.isEnabled) {
1025
1063
  for (let i = 0; i < this.values.length; i++) {
1026
- this.values[i].on(this.linkedFunc[i]);
1064
+ this.values[i].$on(this.linkedFunc[i]);
1027
1065
  this.valuesCache[i] = this.values[i].$;
1028
1066
  }
1029
1067
  this.func();
@@ -1031,21 +1069,21 @@ class Expression extends IValue {
1031
1069
  }
1032
1070
  return this;
1033
1071
  }
1034
- disable() {
1072
+ $disable() {
1035
1073
  if (this.isEnabled) {
1036
1074
  for (let i = 0; i < this.values.length; i++) {
1037
- this.values[i].off(this.linkedFunc[i]);
1075
+ this.values[i].$off(this.linkedFunc[i]);
1038
1076
  }
1039
1077
  this.isEnabled = false;
1040
1078
  }
1041
1079
  return this;
1042
1080
  }
1043
- destroy() {
1044
- this.disable();
1081
+ $destroy() {
1082
+ this.$disable();
1045
1083
  this.values.splice(0);
1046
1084
  this.valuesCache.splice(0);
1047
1085
  this.linkedFunc.splice(0);
1048
- super.destroy();
1086
+ super.$destroy();
1049
1087
  }
1050
1088
  }
1051
1089
 
@@ -1063,43 +1101,43 @@ class Reference extends IValue {
1063
1101
  */
1064
1102
  constructor(value) {
1065
1103
  super(true);
1066
- this.value = value;
1067
- this.onchange = new Set;
1068
- this.seal();
1104
+ this.$value = value;
1105
+ this.$onchange = new Set;
1106
+ this.$seal();
1069
1107
  }
1070
1108
  get $() {
1071
- return this.value;
1109
+ return this.$value;
1072
1110
  }
1073
1111
  set $(value) {
1074
- if (this.value !== value) {
1075
- this.value = value;
1112
+ if (this.$value !== value) {
1113
+ this.$value = value;
1076
1114
  if (this.isEnabled) {
1077
- this.onchange.forEach(handler => {
1115
+ this.$onchange.forEach(handler => {
1078
1116
  handler(value);
1079
1117
  });
1080
1118
  }
1081
1119
  }
1082
1120
  }
1083
- enable() {
1121
+ $enable() {
1084
1122
  if (!this.isEnabled) {
1085
- this.onchange.forEach(handler => {
1086
- handler(this.value);
1123
+ this.$onchange.forEach(handler => {
1124
+ handler(this.$value);
1087
1125
  });
1088
1126
  this.isEnabled = true;
1089
1127
  }
1090
1128
  }
1091
- disable() {
1129
+ $disable() {
1092
1130
  this.isEnabled = false;
1093
1131
  }
1094
- on(handler) {
1095
- this.onchange.add(handler);
1132
+ $on(handler) {
1133
+ this.$onchange.add(handler);
1096
1134
  }
1097
- off(handler) {
1098
- this.onchange.delete(handler);
1135
+ $off(handler) {
1136
+ this.$onchange.delete(handler);
1099
1137
  }
1100
- destroy() {
1101
- super.destroy();
1102
- this.onchange.clear();
1138
+ $destroy() {
1139
+ super.$destroy();
1140
+ this.$onchange.clear();
1103
1141
  }
1104
1142
  }
1105
1143
 
@@ -1120,13 +1158,13 @@ class Mirror extends Reference {
1120
1158
  */
1121
1159
  constructor(value, forwardOnly = false) {
1122
1160
  super(value.$);
1123
- this.handler = (v) => {
1161
+ this.$handler = (v) => {
1124
1162
  this.$ = v;
1125
1163
  };
1126
- this.pointedValue = value;
1127
- this.forwardOnly = forwardOnly;
1128
- value.on(this.handler);
1129
- this.seal();
1164
+ this.$pointedValue = value;
1165
+ this.$forwardOnly = forwardOnly;
1166
+ value.$on(this.$handler);
1167
+ this.$seal();
1130
1168
  }
1131
1169
  get $() {
1132
1170
  // this is a ts bug
@@ -1135,30 +1173,30 @@ class Mirror extends Reference {
1135
1173
  return super.$;
1136
1174
  }
1137
1175
  set $(v) {
1138
- if (!this.forwardOnly) {
1139
- this.pointedValue.$ = v;
1176
+ if (!this.$forwardOnly) {
1177
+ this.$pointedValue.$ = v;
1140
1178
  }
1141
1179
  // this is a ts bug
1142
1180
  // eslint-disable-next-line
1143
1181
  // @ts-ignore
1144
1182
  super.$ = v;
1145
1183
  }
1146
- enable() {
1184
+ $enable() {
1147
1185
  if (!this.isEnabled) {
1148
1186
  this.isEnabled = true;
1149
- this.pointedValue.on(this.handler);
1150
- this.$ = this.pointedValue.$;
1187
+ this.$pointedValue.$on(this.$handler);
1188
+ this.$ = this.$pointedValue.$;
1151
1189
  }
1152
1190
  }
1153
- disable() {
1191
+ $disable() {
1154
1192
  if (this.isEnabled) {
1155
- this.pointedValue.off(this.handler);
1193
+ this.$pointedValue.$off(this.$handler);
1156
1194
  this.isEnabled = false;
1157
1195
  }
1158
1196
  }
1159
- destroy() {
1160
- this.disable();
1161
- super.destroy();
1197
+ $destroy() {
1198
+ this.$disable();
1199
+ super.$destroy();
1162
1200
  }
1163
1201
  }
1164
1202
 
@@ -1182,11 +1220,11 @@ class Pointer extends Mirror {
1182
1220
  * Point a new ivalue
1183
1221
  * @param value {IValue} value to point
1184
1222
  */
1185
- point(value) {
1186
- if (this.pointedValue !== value) {
1187
- this.disable();
1188
- this.pointedValue = value;
1189
- this.enable();
1223
+ set $$(value) {
1224
+ if (this.$pointedValue !== value) {
1225
+ this.$disable();
1226
+ this.$pointedValue = value;
1227
+ this.$enable();
1190
1228
  }
1191
1229
  }
1192
1230
  }
@@ -1207,25 +1245,34 @@ class Binding extends Destroyable {
1207
1245
  constructor(value) {
1208
1246
  super();
1209
1247
  this.binding = value;
1210
- this.seal();
1248
+ this.$seal();
1211
1249
  }
1212
1250
  init(bounded) {
1213
1251
  this.func = bounded;
1214
- this.binding.on(this.func);
1252
+ this.binding.$on(this.func);
1215
1253
  this.func(this.binding.$);
1216
1254
  }
1217
1255
  /**
1218
1256
  * Just clear bindings
1219
1257
  */
1220
- destroy() {
1221
- this.binding.off(this.func);
1222
- super.destroy();
1258
+ $destroy() {
1259
+ this.binding.$off(this.func);
1260
+ super.$destroy();
1223
1261
  }
1224
1262
  }
1225
1263
 
1226
1264
  window.Binding = Binding;
1227
1265
 
1228
1266
  // ./lib/core/core.js
1267
+
1268
+ const currentStack = [];
1269
+ function stack(node) {
1270
+ currentStack.push(current);
1271
+ current = node;
1272
+ }
1273
+ function unstack() {
1274
+ current = currentStack.pop();
1275
+ }
1229
1276
  /**
1230
1277
  * Private stuff of a reactive object
1231
1278
  * @class ReactivePrivate
@@ -1258,18 +1305,18 @@ class ReactivePrivate extends Destroyable {
1258
1305
  * @type {boolean}
1259
1306
  */
1260
1307
  this.frozen = false;
1261
- this.seal();
1308
+ this.$seal();
1262
1309
  }
1263
- destroy() {
1264
- var _a;
1265
- this.watch.forEach(value => value.destroy());
1310
+ $destroy() {
1311
+ this.watch.forEach(value => value.$destroy());
1266
1312
  this.watch.clear();
1267
- this.bindings.forEach(binding => binding.destroy());
1313
+ this.bindings.forEach(binding => binding.$destroy());
1268
1314
  this.bindings.clear();
1269
1315
  this.models.forEach(model => model.disableReactivity());
1270
1316
  this.models.clear();
1271
- (_a = this.freezeExpr) === null || _a === void 0 ? void 0 : _a.destroy();
1272
- super.destroy();
1317
+ this.freezeExpr && this.freezeExpr.$destroy();
1318
+ this.onDestroy && this.onDestroy();
1319
+ super.$destroy();
1273
1320
  }
1274
1321
  }
1275
1322
  /**
@@ -1278,9 +1325,17 @@ class ReactivePrivate extends Destroyable {
1278
1325
  * @extends Destroyable
1279
1326
  */
1280
1327
  class Reactive extends Destroyable {
1281
- constructor($) {
1328
+ constructor(input, $) {
1282
1329
  super();
1330
+ this.input = input;
1283
1331
  this.$ = $ || new ReactivePrivate;
1332
+ this.$seal();
1333
+ }
1334
+ /**
1335
+ * Get parent node
1336
+ */
1337
+ get parent() {
1338
+ return this.$.parent;
1284
1339
  }
1285
1340
  /**
1286
1341
  * Create a reference
@@ -1329,12 +1384,23 @@ class Reactive extends Destroyable {
1329
1384
  this.$.models.add(model);
1330
1385
  return model;
1331
1386
  }
1332
- watch(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1387
+ /**
1388
+ * Creates a watcher
1389
+ * @param func {function} function to run on any argument change
1390
+ * @param values
1391
+ */
1392
+ watch(func, ...values) {
1333
1393
  const $ = this.$;
1334
- $.watch.add(new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9));
1394
+ $.watch.add(new Expression(func, !this.$.frozen, ...values));
1335
1395
  }
1336
- bind(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1337
- const res = new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1396
+ /**
1397
+ * Creates a computed value
1398
+ * @param func {function} function to run on any argument change
1399
+ * @param values
1400
+ * @return {IValue} the created ivalue
1401
+ */
1402
+ expr(func, ...values) {
1403
+ const res = new Expression(func, !this.$.frozen, ...values);
1338
1404
  const $ = this.$;
1339
1405
  $.watch.add(res);
1340
1406
  return res;
@@ -1346,7 +1412,7 @@ class Reactive extends Destroyable {
1346
1412
  const $ = this.$;
1347
1413
  if (!$.enabled) {
1348
1414
  $.watch.forEach(watcher => {
1349
- watcher.enable();
1415
+ watcher.$enable();
1350
1416
  });
1351
1417
  $.models.forEach(model => {
1352
1418
  model.enableReactivity();
@@ -1361,7 +1427,7 @@ class Reactive extends Destroyable {
1361
1427
  const $ = this.$;
1362
1428
  if ($.enabled) {
1363
1429
  $.watch.forEach(watcher => {
1364
- watcher.disable();
1430
+ watcher.$disable();
1365
1431
  });
1366
1432
  $.models.forEach(model => {
1367
1433
  model.disableReactivity();
@@ -1396,9 +1462,37 @@ class Reactive extends Destroyable {
1396
1462
  }, true, cond);
1397
1463
  return this;
1398
1464
  }
1399
- destroy() {
1400
- super.destroy();
1401
- this.$.destroy();
1465
+ init() {
1466
+ this.applyOptions(this.input);
1467
+ this.compose(this.input);
1468
+ }
1469
+ applyOptions(input) {
1470
+ // empty
1471
+ }
1472
+ applyOptionsNow() {
1473
+ this.applyOptions(this.input);
1474
+ }
1475
+ compose(input) {
1476
+ // empty
1477
+ }
1478
+ composeNow() {
1479
+ this.compose(this.input);
1480
+ }
1481
+ runFunctional(f, ...args) {
1482
+ stack(this);
1483
+ // yet another ts bug
1484
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1485
+ // @ts-ignore
1486
+ const result = f(...args);
1487
+ unstack();
1488
+ return result;
1489
+ }
1490
+ runOnDestroy(func) {
1491
+ this.$.onDestroy = func;
1492
+ }
1493
+ $destroy() {
1494
+ super.$destroy();
1495
+ this.$.$destroy();
1402
1496
  this.$ = null;
1403
1497
  }
1404
1498
  }
@@ -1415,7 +1509,7 @@ window.Reactive = Reactive;
1415
1509
  class FragmentPrivate extends ReactivePrivate {
1416
1510
  constructor() {
1417
1511
  super();
1418
- this.seal();
1512
+ this.$seal();
1419
1513
  }
1420
1514
  /**
1421
1515
  * Pre-initializes the base of a fragment
@@ -1429,10 +1523,10 @@ class FragmentPrivate extends ReactivePrivate {
1429
1523
  /**
1430
1524
  * Unlinks all bindings
1431
1525
  */
1432
- destroy() {
1526
+ $destroy() {
1433
1527
  this.next = null;
1434
1528
  this.prev = null;
1435
- super.destroy();
1529
+ super.$destroy();
1436
1530
  }
1437
1531
  }
1438
1532
  /**
@@ -1442,10 +1536,11 @@ class FragmentPrivate extends ReactivePrivate {
1442
1536
  class Fragment extends Reactive {
1443
1537
  /**
1444
1538
  * Constructs a Vasille Node
1539
+ * @param input
1445
1540
  * @param $ {FragmentPrivate}
1446
1541
  */
1447
- constructor($) {
1448
- super($ || new FragmentPrivate);
1542
+ constructor(input, $) {
1543
+ super(input, $ || new FragmentPrivate);
1449
1544
  /**
1450
1545
  * The children list
1451
1546
  * @type Array
@@ -1469,36 +1564,18 @@ class Fragment extends Reactive {
1469
1564
  const $ = this.$;
1470
1565
  $.preinit(app, parent);
1471
1566
  }
1472
- /**
1473
- * Initialize node
1474
- */
1475
1567
  init() {
1476
- this.createWatchers();
1477
- this.created();
1478
- this.compose();
1479
- this.mounted();
1480
- return this;
1568
+ super.init();
1569
+ this.ready();
1481
1570
  }
1482
- /** To be overloaded: created event handler */
1483
- created() {
1484
- // empty
1485
- }
1486
- /** To be overloaded: mounted event handler */
1487
- mounted() {
1488
- // empty
1571
+ compose(input) {
1572
+ super.compose(input);
1573
+ input.slot && input.slot(this);
1489
1574
  }
1490
1575
  /** To be overloaded: ready event handler */
1491
1576
  ready() {
1492
1577
  // empty
1493
1578
  }
1494
- /** To be overloaded: watchers creation milestone */
1495
- createWatchers() {
1496
- // empty
1497
- }
1498
- /** To be overloaded: DOM creation milestone */
1499
- compose() {
1500
- // empty
1501
- }
1502
1579
  /**
1503
1580
  * Pushes a node to children immediately
1504
1581
  * @param node {Fragment} A node to push
@@ -1545,7 +1622,7 @@ class Fragment extends Reactive {
1545
1622
  const child = this.findFirstChild();
1546
1623
  const $ = this.$;
1547
1624
  if (child) {
1548
- $.app.run.insertBefore(child, node);
1625
+ child.parentElement.insertBefore(node, child);
1549
1626
  }
1550
1627
  else if ($.next) {
1551
1628
  $.next.insertAdjacent(node);
@@ -1562,14 +1639,9 @@ class Fragment extends Reactive {
1562
1639
  text(text, cb) {
1563
1640
  const $ = this.$;
1564
1641
  const node = new TextNode();
1565
- const textValue = text instanceof IValue ? text : this.ref(text);
1566
- node.preinit($.app, this, textValue);
1642
+ node.preinit($.app, this, text);
1567
1643
  this.pushNode(node);
1568
- if (cb) {
1569
- $.app.run.callCallback(() => {
1570
- cb(node);
1571
- });
1572
- }
1644
+ cb && cb(node);
1573
1645
  }
1574
1646
  debug(text) {
1575
1647
  if (this.$.app.debugUi) {
@@ -1577,39 +1649,35 @@ class Fragment extends Reactive {
1577
1649
  node.preinit(this.$.app, this, text);
1578
1650
  this.pushNode(node);
1579
1651
  }
1580
- return this;
1581
1652
  }
1582
- tag(tagName, cb) {
1653
+ /**
1654
+ * Defines a tag element
1655
+ * @param tagName {String} the tag name
1656
+ * @param input
1657
+ * @param cb {function(Tag, *)} callback
1658
+ */
1659
+ tag(tagName, input, cb) {
1583
1660
  const $ = this.$;
1584
- const node = new Tag();
1661
+ const node = new Tag(input);
1662
+ input.slot = cb || input.slot;
1585
1663
  node.preinit($.app, this, tagName);
1586
1664
  node.init();
1587
1665
  this.pushNode(node);
1588
- $.app.run.callCallback(() => {
1589
- if (cb) {
1590
- cb(node, node.node);
1591
- }
1592
- node.ready();
1593
- });
1666
+ node.ready();
1667
+ return node.node;
1594
1668
  }
1595
1669
  /**
1596
1670
  * Defines a custom element
1597
1671
  * @param node {Fragment} vasille element to insert
1598
1672
  * @param callback {function($ : *)}
1599
- * @param callback1 {function($ : *)}
1600
1673
  */
1601
- create(node, callback, callback1) {
1674
+ create(node, callback) {
1602
1675
  const $ = this.$;
1603
1676
  node.$.parent = this;
1604
1677
  node.preinit($.app, this);
1605
- if (callback) {
1606
- callback(node);
1607
- }
1608
- if (callback1) {
1609
- callback1(node);
1610
- }
1678
+ node.input.slot = callback || node.input.slot;
1611
1679
  this.pushNode(node);
1612
- node.init().ready();
1680
+ node.init();
1613
1681
  }
1614
1682
  /**
1615
1683
  * Defines an if node
@@ -1618,31 +1686,28 @@ class Fragment extends Reactive {
1618
1686
  * @return {this}
1619
1687
  */
1620
1688
  if(cond, cb) {
1621
- return this.switch({ cond, cb });
1622
- }
1623
- /**
1624
- * Defines a if-else node
1625
- * @param ifCond {IValue} `if` condition
1626
- * @param ifCb {function(Fragment)} Call-back to create `if` child nodes
1627
- * @param elseCb {function(Fragment)} Call-back to create `else` child nodes
1628
- */
1629
- if_else(ifCond, ifCb, elseCb) {
1630
- return this.switch({ cond: ifCond, cb: ifCb }, { cond: trueIValue, cb: elseCb });
1631
- }
1632
- /**
1633
- * Defines a switch nodes: Will break after first true condition
1634
- * @param cases {...{ cond : IValue, cb : function(Fragment) }} cases
1635
- * @return {INode}
1636
- */
1637
- switch(...cases) {
1638
- const $ = this.$;
1639
1689
  const node = new SwitchedNode();
1640
- node.preinit($.app, this);
1690
+ node.preinit(this.$.app, this);
1641
1691
  node.init();
1642
1692
  this.pushNode(node);
1643
- node.setCases(cases);
1693
+ node.addCase(this.case(cond, cb));
1644
1694
  node.ready();
1645
- return this;
1695
+ }
1696
+ else(cb) {
1697
+ if (this.lastChild instanceof SwitchedNode) {
1698
+ this.lastChild.addCase(this.default(cb));
1699
+ }
1700
+ else {
1701
+ throw userError('wrong `else` function use', 'logic-error');
1702
+ }
1703
+ }
1704
+ elif(cond, cb) {
1705
+ if (this.lastChild instanceof SwitchedNode) {
1706
+ this.lastChild.addCase(this.case(cond, cb));
1707
+ }
1708
+ else {
1709
+ throw userError('wrong `elif` function use', 'logic-error');
1710
+ }
1646
1711
  }
1647
1712
  /**
1648
1713
  * Create a case for switch
@@ -1684,14 +1749,14 @@ class Fragment extends Reactive {
1684
1749
  $.prev.$.next = $.next;
1685
1750
  }
1686
1751
  }
1687
- destroy() {
1688
- this.children.forEach(child => child.destroy());
1752
+ $destroy() {
1753
+ this.children.forEach(child => child.$destroy());
1689
1754
  this.children.clear();
1690
1755
  this.lastChild = null;
1691
1756
  if (this.$.parent.lastChild === this) {
1692
1757
  this.$.parent.lastChild = this.$.prev;
1693
1758
  }
1694
- super.destroy();
1759
+ super.$destroy();
1695
1760
  }
1696
1761
  }
1697
1762
  const trueIValue = new Reference(true);
@@ -1703,25 +1768,28 @@ const trueIValue = new Reference(true);
1703
1768
  class TextNodePrivate extends FragmentPrivate {
1704
1769
  constructor() {
1705
1770
  super();
1706
- this.seal();
1771
+ this.$seal();
1707
1772
  }
1708
1773
  /**
1709
1774
  * Pre-initializes a text node
1710
1775
  * @param app {AppNode} the app node
1776
+ * @param parent
1711
1777
  * @param text {IValue}
1712
1778
  */
1713
1779
  preinitText(app, parent, text) {
1714
1780
  super.preinit(app, parent);
1715
- this.node = document.createTextNode(text.$);
1716
- this.bindings.add(new Expression((v) => {
1717
- this.node.replaceData(0, -1, v);
1718
- }, true, text));
1781
+ this.node = document.createTextNode(text instanceof IValue ? text.$ : text);
1782
+ if (text instanceof IValue) {
1783
+ this.bindings.add(new Expression((v) => {
1784
+ this.node.replaceData(0, -1, v);
1785
+ }, true, text));
1786
+ }
1719
1787
  }
1720
1788
  /**
1721
1789
  * Clear node data
1722
1790
  */
1723
- destroy() {
1724
- super.destroy();
1791
+ $destroy() {
1792
+ super.$destroy();
1725
1793
  }
1726
1794
  }
1727
1795
  /**
@@ -1731,8 +1799,8 @@ class TextNodePrivate extends FragmentPrivate {
1731
1799
  */
1732
1800
  class TextNode extends Fragment {
1733
1801
  constructor($ = new TextNodePrivate()) {
1734
- super($);
1735
- this.seal();
1802
+ super({}, $);
1803
+ this.$seal();
1736
1804
  }
1737
1805
  preinit(app, parent, text) {
1738
1806
  const $ = this.$;
@@ -1745,10 +1813,10 @@ class TextNode extends Fragment {
1745
1813
  findFirstChild() {
1746
1814
  return this.$.node;
1747
1815
  }
1748
- destroy() {
1816
+ $destroy() {
1749
1817
  this.$.node.remove();
1750
- this.$.destroy();
1751
- super.destroy();
1818
+ this.$.$destroy();
1819
+ super.$destroy();
1752
1820
  }
1753
1821
  }
1754
1822
  /**
@@ -1764,10 +1832,10 @@ class INodePrivate extends FragmentPrivate {
1764
1832
  * @type {boolean}
1765
1833
  */
1766
1834
  this.unmounted = false;
1767
- this.seal();
1835
+ this.$seal();
1768
1836
  }
1769
- destroy() {
1770
- super.destroy();
1837
+ $destroy() {
1838
+ super.$destroy();
1771
1839
  }
1772
1840
  }
1773
1841
  /**
@@ -1778,11 +1846,12 @@ class INodePrivate extends FragmentPrivate {
1778
1846
  class INode extends Fragment {
1779
1847
  /**
1780
1848
  * Constructs a base node
1849
+ * @param input
1781
1850
  * @param $ {?INodePrivate}
1782
1851
  */
1783
- constructor($) {
1784
- super($ || new INodePrivate);
1785
- this.seal();
1852
+ constructor(input, $) {
1853
+ super(input, $ || new INodePrivate);
1854
+ this.$seal();
1786
1855
  }
1787
1856
  /**
1788
1857
  * Get the bound node
@@ -1790,26 +1859,6 @@ class INode extends Fragment {
1790
1859
  get node() {
1791
1860
  return this.$.node;
1792
1861
  }
1793
- /**
1794
- * Initialize node
1795
- */
1796
- init() {
1797
- this.createWatchers();
1798
- this.createAttrs();
1799
- this.createStyle();
1800
- this.created();
1801
- this.compose();
1802
- this.mounted();
1803
- return this;
1804
- }
1805
- /** To be overloaded: attributes creation milestone */
1806
- createAttrs() {
1807
- // empty
1808
- }
1809
- /** To be overloaded: $style attributes creation milestone */
1810
- createStyle() {
1811
- // empty
1812
- }
1813
1862
  /**
1814
1863
  * Bind attribute value
1815
1864
  * @param name {String} name of attribute
@@ -1820,18 +1869,20 @@ class INode extends Fragment {
1820
1869
  const attr = new AttributeBinding(this, name, value);
1821
1870
  $.bindings.add(attr);
1822
1871
  }
1823
- bindAttr(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1824
- const $ = this.$;
1825
- const expr = this.bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1826
- $.bindings.add(new AttributeBinding(this, name, expr));
1827
- }
1828
1872
  /**
1829
1873
  * Set attribute value
1830
1874
  * @param name {string} name of attribute
1831
1875
  * @param value {string} value
1832
1876
  */
1833
1877
  setAttr(name, value) {
1834
- this.$.app.run.setAttribute(this.$.node, name, value);
1878
+ if (typeof value === 'boolean') {
1879
+ if (value) {
1880
+ this.$.node.setAttribute(name, "");
1881
+ }
1882
+ }
1883
+ else {
1884
+ this.$.node.setAttribute(name, `${value}`);
1885
+ }
1835
1886
  return this;
1836
1887
  }
1837
1888
  /**
@@ -1839,17 +1890,15 @@ class INode extends Fragment {
1839
1890
  * @param cl {string} Class name
1840
1891
  */
1841
1892
  addClass(cl) {
1842
- this.$.app.run.addClass(this.$.node, cl);
1893
+ this.$.node.classList.add(cl);
1843
1894
  return this;
1844
1895
  }
1845
1896
  /**
1846
1897
  * Adds some CSS classes
1847
1898
  * @param cls {...string} classes names
1848
1899
  */
1849
- addClasses(...cls) {
1850
- cls.forEach(cl => {
1851
- this.$.app.run.addClass(this.$.node, cl);
1852
- });
1900
+ removeClasse(cl) {
1901
+ this.$.node.classList.remove(cl);
1853
1902
  return this;
1854
1903
  }
1855
1904
  /**
@@ -1885,17 +1934,6 @@ class INode extends Fragment {
1885
1934
  }
1886
1935
  return this;
1887
1936
  }
1888
- bindStyle(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
1889
- const $ = this.$;
1890
- const expr = this.bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
1891
- if ($.node instanceof HTMLElement) {
1892
- $.bindings.add(new StyleBinding(this, name, expr));
1893
- }
1894
- else {
1895
- throw userError('style can be applied to HTML elements only', 'non-html-element');
1896
- }
1897
- return this;
1898
- }
1899
1937
  /**
1900
1938
  * Sets a style property value
1901
1939
  * @param prop {string} Property name
@@ -1903,10 +1941,10 @@ class INode extends Fragment {
1903
1941
  */
1904
1942
  setStyle(prop, value) {
1905
1943
  if (this.$.node instanceof HTMLElement) {
1906
- this.$.app.run.setStyle(this.$.node, prop, value);
1944
+ this.$.node.style.setProperty(prop, value);
1907
1945
  }
1908
1946
  else {
1909
- throw userError("Style can be setted for HTML elements only", "non-html-element");
1947
+ throw userError("Style can be set for HTML elements only", "non-html-element");
1910
1948
  }
1911
1949
  return this;
1912
1950
  }
@@ -1920,446 +1958,156 @@ class INode extends Fragment {
1920
1958
  this.$.node.addEventListener(name, handler, options);
1921
1959
  return this;
1922
1960
  }
1923
- /**
1924
- * @param handler {function (MouseEvent)}
1925
- * @param options {Object | boolean}
1926
- */
1927
- oncontextmenu(handler, options) {
1928
- return this.listen("contextmenu", handler, options);
1961
+ insertAdjacent(node) {
1962
+ this.$.node.parentNode.insertBefore(node, this.$.node);
1929
1963
  }
1930
1964
  /**
1931
- * @param handler {function (MouseEvent)}
1932
- * @param options {Object | boolean}
1965
+ * A v-show & ngShow alternative
1966
+ * @param cond {IValue} show condition
1933
1967
  */
1934
- onmousedown(handler, options) {
1935
- return this.listen("mousedown", handler, options);
1968
+ bindShow(cond) {
1969
+ const $ = this.$;
1970
+ const node = $.node;
1971
+ if (node instanceof HTMLElement) {
1972
+ let lastDisplay = node.style.display;
1973
+ const htmlNode = node;
1974
+ return this.bindAlive(cond, () => {
1975
+ lastDisplay = htmlNode.style.display;
1976
+ htmlNode.style.display = 'none';
1977
+ }, () => {
1978
+ htmlNode.style.display = lastDisplay;
1979
+ });
1980
+ }
1981
+ else {
1982
+ throw userError('the element must be a html element', 'bind-show');
1983
+ }
1936
1984
  }
1937
1985
  /**
1938
- * @param handler {function (MouseEvent)}
1939
- * @param options {Object | boolean}
1986
+ * bind HTML
1987
+ * @param value {IValue}
1940
1988
  */
1941
- onmouseenter(handler, options) {
1942
- return this.listen("mouseenter", handler, options);
1989
+ bindDomApi(name, value) {
1990
+ const $ = this.$;
1991
+ const node = $.node;
1992
+ if (node instanceof HTMLElement) {
1993
+ node[name] = value.$;
1994
+ this.watch((v) => {
1995
+ node[name] = v;
1996
+ }, value);
1997
+ }
1998
+ else {
1999
+ throw userError("HTML can be bound for HTML nodes only", "dom-error");
2000
+ }
1943
2001
  }
1944
- /**
1945
- * @param handler {function (MouseEvent)}
1946
- * @param options {Object | boolean}
1947
- */
1948
- onmouseleave(handler, options) {
1949
- return this.listen("mouseleave", handler, options);
2002
+ applyOptions(options) {
2003
+ options["v:attr"] && Object.keys(options["v:attr"]).forEach(name => {
2004
+ const value = options["v:attr"][name];
2005
+ if (value instanceof IValue) {
2006
+ this.attr(name, value);
2007
+ }
2008
+ else {
2009
+ this.setAttr(name, value);
2010
+ }
2011
+ });
2012
+ if (options.class) {
2013
+ const handleClass = (name, value) => {
2014
+ if (value instanceof IValue) {
2015
+ this.floatingClass(value, name);
2016
+ }
2017
+ else if (value && name !== '$') {
2018
+ this.addClass(name);
2019
+ }
2020
+ else {
2021
+ this.removeClasse(name);
2022
+ }
2023
+ };
2024
+ if (Array.isArray(options.class)) {
2025
+ options.class.forEach(item => {
2026
+ if (item instanceof IValue) {
2027
+ this.bindClass(item);
2028
+ }
2029
+ else if (typeof item == "string") {
2030
+ this.addClass(item);
2031
+ }
2032
+ else {
2033
+ Reflect.ownKeys(item).forEach((name) => {
2034
+ handleClass(name, item[name]);
2035
+ });
2036
+ }
2037
+ });
2038
+ }
2039
+ else {
2040
+ options.class.$.forEach(item => {
2041
+ this.bindClass(item);
2042
+ });
2043
+ Reflect.ownKeys(options.class).forEach((name) => {
2044
+ handleClass(name, options.class[name]);
2045
+ });
2046
+ }
2047
+ }
2048
+ options.style && Object.keys(options.style).forEach(name => {
2049
+ const value = options.style[name];
2050
+ if (value instanceof IValue) {
2051
+ this.style(name, value);
2052
+ }
2053
+ else if (typeof value === "string") {
2054
+ this.setStyle(name, value);
2055
+ }
2056
+ else {
2057
+ if (value[0] instanceof IValue) {
2058
+ this.style(name, this.expr((v) => v + value[1], value[0]));
2059
+ }
2060
+ else {
2061
+ this.setStyle(name, value[0] + value[1]);
2062
+ }
2063
+ }
2064
+ });
2065
+ options["v:events"] && Object.keys(options["v:events"]).forEach(name => {
2066
+ this.listen(name, options["v:events"][name]);
2067
+ });
2068
+ if (options["v:bind"]) {
2069
+ const inode = this.node;
2070
+ Reflect.ownKeys(options["v:bind"]).forEach((k) => {
2071
+ const value = options["v:bind"][k];
2072
+ if (k === 'value' && (inode instanceof HTMLInputElement || inode instanceof HTMLTextAreaElement)) {
2073
+ inode.oninput = () => value.$ = inode.value;
2074
+ }
2075
+ else if (k === 'checked' && inode instanceof HTMLInputElement) {
2076
+ inode.oninput = () => value.$ = inode.checked;
2077
+ }
2078
+ else if (k === 'volume' && inode instanceof HTMLMediaElement) {
2079
+ inode.onvolumechange = () => value.$ = inode.volume;
2080
+ }
2081
+ this.bindDomApi(k, value);
2082
+ });
2083
+ }
2084
+ options["v:set"] && Object.keys(options["v:set"]).forEach(key => {
2085
+ this.node[key] = options["v:set"][key];
2086
+ });
1950
2087
  }
1951
- /**
1952
- * @param handler {function (MouseEvent)}
1953
- * @param options {Object | boolean}
1954
- */
1955
- onmousemove(handler, options) {
1956
- return this.listen("mousemove", handler, options);
2088
+ }
2089
+ /**
2090
+ * Represents an Vasille.js HTML element node
2091
+ * @class Tag
2092
+ * @extends INode
2093
+ */
2094
+ class Tag extends INode {
2095
+ constructor(input) {
2096
+ super(input);
2097
+ this.$seal();
1957
2098
  }
1958
- /**
1959
- * @param handler {function (MouseEvent)}
1960
- * @param options {Object | boolean}
1961
- */
1962
- onmouseout(handler, options) {
1963
- return this.listen("mouseout", handler, options);
2099
+ preinit(app, parent, tagName) {
2100
+ if (!tagName || typeof tagName !== "string") {
2101
+ throw internalError('wrong Tag::$preinit call');
2102
+ }
2103
+ const node = document.createElement(tagName);
2104
+ const $ = this.$;
2105
+ $.preinit(app, parent);
2106
+ $.node = node;
2107
+ $.parent.appendNode(node);
1964
2108
  }
1965
- /**
1966
- * @param handler {function (MouseEvent)}
1967
- * @param options {Object | boolean}
1968
- */
1969
- onmouseover(handler, options) {
1970
- return this.listen("mouseover", handler, options);
1971
- }
1972
- /**
1973
- * @param handler {function (MouseEvent)}
1974
- * @param options {Object | boolean}
1975
- */
1976
- onmouseup(handler, options) {
1977
- return this.listen("mouseup", handler, options);
1978
- }
1979
- /**
1980
- * @param handler {function (MouseEvent)}
1981
- * @param options {Object | boolean}
1982
- */
1983
- onclick(handler, options) {
1984
- return this.listen("click", handler, options);
1985
- }
1986
- /**
1987
- * @param handler {function (MouseEvent)}
1988
- * @param options {Object | boolean}
1989
- */
1990
- ondblclick(handler, options) {
1991
- return this.listen("dblclick", handler, options);
1992
- }
1993
- /**
1994
- * @param handler {function (FocusEvent)}
1995
- * @param options {Object | boolean}
1996
- */
1997
- onblur(handler, options) {
1998
- return this.listen("blur", handler, options);
1999
- }
2000
- /**
2001
- * @param handler {function (FocusEvent)}
2002
- * @param options {Object | boolean}
2003
- */
2004
- onfocus(handler, options) {
2005
- return this.listen("focus", handler, options);
2006
- }
2007
- /**
2008
- * @param handler {function (FocusEvent)}
2009
- * @param options {Object | boolean}
2010
- */
2011
- onfocusin(handler, options) {
2012
- return this.listen("focusin", handler, options);
2013
- }
2014
- /**
2015
- * @param handler {function (FocusEvent)}
2016
- * @param options {Object | boolean}
2017
- */
2018
- onfocusout(handler, options) {
2019
- return this.listen("focusout", handler, options);
2020
- }
2021
- /**
2022
- * @param handler {function (KeyboardEvent)}
2023
- * @param options {Object | boolean}
2024
- */
2025
- onkeydown(handler, options) {
2026
- return this.listen("keydown", handler, options);
2027
- }
2028
- /**
2029
- * @param handler {function (KeyboardEvent)}
2030
- * @param options {Object | boolean}
2031
- */
2032
- onkeyup(handler, options) {
2033
- return this.listen("keyup", handler, options);
2034
- }
2035
- /**
2036
- * @param handler {function (KeyboardEvent)}
2037
- * @param options {Object | boolean}
2038
- */
2039
- onkeypress(handler, options) {
2040
- return this.listen("keypress", handler, options);
2041
- }
2042
- /**
2043
- * @param handler {function (TouchEvent)}
2044
- * @param options {Object | boolean}
2045
- */
2046
- ontouchstart(handler, options) {
2047
- return this.listen("touchstart", handler, options);
2048
- }
2049
- /**
2050
- * @param handler {function (TouchEvent)}
2051
- * @param options {Object | boolean}
2052
- */
2053
- ontouchmove(handler, options) {
2054
- return this.listen("touchmove", handler, options);
2055
- }
2056
- /**
2057
- * @param handler {function (TouchEvent)}
2058
- * @param options {Object | boolean}
2059
- */
2060
- ontouchend(handler, options) {
2061
- return this.listen("touchend", handler, options);
2062
- }
2063
- /**
2064
- * @param handler {function (TouchEvent)}
2065
- * @param options {Object | boolean}
2066
- */
2067
- ontouchcancel(handler, options) {
2068
- return this.listen("touchcancel", handler, options);
2069
- }
2070
- /**
2071
- * @param handler {function (WheelEvent)}
2072
- * @param options {Object | boolean}
2073
- */
2074
- onwheel(handler, options) {
2075
- return this.listen("wheel", handler, options);
2076
- }
2077
- /**
2078
- * @param handler {function (ProgressEvent)}
2079
- * @param options {Object | boolean}
2080
- */
2081
- onabort(handler, options) {
2082
- return this.listen("abort", handler, options);
2083
- }
2084
- /**
2085
- * @param handler {function (ProgressEvent)}
2086
- * @param options {Object | boolean}
2087
- */
2088
- onerror(handler, options) {
2089
- return this.listen("error", handler, options);
2090
- }
2091
- /**
2092
- * @param handler {function (ProgressEvent)}
2093
- * @param options {Object | boolean}
2094
- */
2095
- onload(handler, options) {
2096
- return this.listen("load", handler, options);
2097
- }
2098
- /**
2099
- * @param handler {function (ProgressEvent)}
2100
- * @param options {Object | boolean}
2101
- */
2102
- onloadend(handler, options) {
2103
- return this.listen("loadend", handler, options);
2104
- }
2105
- /**
2106
- * @param handler {function (ProgressEvent)}
2107
- * @param options {Object | boolean}
2108
- */
2109
- onloadstart(handler, options) {
2110
- return this.listen("loadstart", handler, options);
2111
- }
2112
- /**
2113
- * @param handler {function (ProgressEvent)}
2114
- * @param options {Object | boolean}
2115
- */
2116
- onprogress(handler, options) {
2117
- return this.listen("progress", handler, options);
2118
- }
2119
- /**
2120
- * @param handler {function (ProgressEvent)}
2121
- * @param options {Object | boolean}
2122
- */
2123
- ontimeout(handler, options) {
2124
- return this.listen("timeout", handler, options);
2125
- }
2126
- /**
2127
- * @param handler {function (DragEvent)}
2128
- * @param options {Object | boolean}
2129
- */
2130
- ondrag(handler, options) {
2131
- return this.listen("drag", handler, options);
2132
- }
2133
- /**
2134
- * @param handler {function (DragEvent)}
2135
- * @param options {Object | boolean}
2136
- */
2137
- ondragend(handler, options) {
2138
- return this.listen("dragend", handler, options);
2139
- }
2140
- /**
2141
- * @param handler {function (DragEvent)}
2142
- * @param options {Object | boolean}
2143
- */
2144
- ondragenter(handler, options) {
2145
- return this.listen("dragenter", handler, options);
2146
- }
2147
- /**
2148
- * @param handler {function (DragEvent)}
2149
- * @param options {Object | boolean}
2150
- */
2151
- ondragexit(handler, options) {
2152
- return this.listen("dragexit", handler, options);
2153
- }
2154
- /**
2155
- * @param handler {function (DragEvent)}
2156
- * @param options {Object | boolean}
2157
- */
2158
- ondragleave(handler, options) {
2159
- return this.listen("dragleave", handler, options);
2160
- }
2161
- /**
2162
- * @param handler {function (DragEvent)}
2163
- * @param options {Object | boolean}
2164
- */
2165
- ondragover(handler, options) {
2166
- return this.listen("dragover", handler, options);
2167
- }
2168
- /**
2169
- * @param handler {function (DragEvent)}
2170
- * @param options {Object | boolean}
2171
- */
2172
- ondragstart(handler, options) {
2173
- return this.listen("dragstart", handler, options);
2174
- }
2175
- /**
2176
- * @param handler {function (DragEvent)}
2177
- * @param options {Object | boolean}
2178
- */
2179
- ondrop(handler, options) {
2180
- return this.listen("drop", handler, options);
2181
- }
2182
- /**
2183
- * @param handler {function (PointerEvent)}
2184
- * @param options {Object | boolean}
2185
- */
2186
- onpointerover(handler, options) {
2187
- return this.listen("pointerover", handler, options);
2188
- }
2189
- /**
2190
- * @param handler {function (PointerEvent)}
2191
- * @param options {Object | boolean}
2192
- */
2193
- onpointerenter(handler, options) {
2194
- return this.listen("pointerenter", handler, options);
2195
- }
2196
- /**
2197
- * @param handler {function (PointerEvent)}
2198
- * @param options {Object | boolean}
2199
- */
2200
- onpointerdown(handler, options) {
2201
- return this.listen("pointerdown", handler, options);
2202
- }
2203
- /**
2204
- * @param handler {function (PointerEvent)}
2205
- * @param options {Object | boolean}
2206
- */
2207
- onpointermove(handler, options) {
2208
- return this.listen("pointermove", handler, options);
2209
- }
2210
- /**
2211
- * @param handler {function (PointerEvent)}
2212
- * @param options {Object | boolean}
2213
- */
2214
- onpointerup(handler, options) {
2215
- return this.listen("pointerup", handler, options);
2216
- }
2217
- /**
2218
- * @param handler {function (PointerEvent)}
2219
- * @param options {Object | boolean}
2220
- */
2221
- onpointercancel(handler, options) {
2222
- return this.listen("pointercancel", handler, options);
2223
- }
2224
- /**
2225
- * @param handler {function (PointerEvent)}
2226
- * @param options {Object | boolean}
2227
- */
2228
- onpointerout(handler, options) {
2229
- return this.listen("pointerout", handler, options);
2230
- }
2231
- /**
2232
- * @param handler {function (PointerEvent)}
2233
- * @param options {Object | boolean}
2234
- */
2235
- onpointerleave(handler, options) {
2236
- return this.listen("pointerleave", handler, options);
2237
- }
2238
- /**
2239
- * @param handler {function (PointerEvent)}
2240
- * @param options {Object | boolean}
2241
- */
2242
- ongotpointercapture(handler, options) {
2243
- return this.listen("gotpointercapture", handler, options);
2244
- }
2245
- /**
2246
- * @param handler {function (PointerEvent)}
2247
- * @param options {Object | boolean}
2248
- */
2249
- onlostpointercapture(handler, options) {
2250
- return this.listen("lostpointercapture", handler, options);
2251
- }
2252
- /**
2253
- * @param handler {function (AnimationEvent)}
2254
- * @param options {Object | boolean}
2255
- */
2256
- onanimationstart(handler, options) {
2257
- return this.listen("animationstart", handler, options);
2258
- }
2259
- /**
2260
- * @param handler {function (AnimationEvent)}
2261
- * @param options {Object | boolean}
2262
- */
2263
- onanimationend(handler, options) {
2264
- return this.listen("animationend", handler, options);
2265
- }
2266
- /**
2267
- * @param handler {function (AnimationEvent)}
2268
- * @param options {Object | boolean}
2269
- */
2270
- onanimationiteraton(handler, options) {
2271
- return this.listen("animationiteration", handler, options);
2272
- }
2273
- /**
2274
- * @param handler {function (ClipboardEvent)}
2275
- * @param options {Object | boolean}
2276
- */
2277
- onclipboardchange(handler, options) {
2278
- return this.listen("clipboardchange", handler, options);
2279
- }
2280
- /**
2281
- * @param handler {function (ClipboardEvent)}
2282
- * @param options {Object | boolean}
2283
- */
2284
- oncut(handler, options) {
2285
- return this.listen("cut", handler, options);
2286
- }
2287
- /**
2288
- * @param handler {function (ClipboardEvent)}
2289
- * @param options {Object | boolean}
2290
- */
2291
- oncopy(handler, options) {
2292
- return this.listen("copy", handler, options);
2293
- }
2294
- /**
2295
- * @param handler {function (ClipboardEvent)}
2296
- * @param options {Object | boolean}
2297
- */
2298
- onpaste(handler, options) {
2299
- return this.listen("paste", handler, options);
2300
- }
2301
- insertAdjacent(node) {
2302
- const $ = this.$;
2303
- $.app.run.insertBefore($.node, node);
2304
- }
2305
- /**
2306
- * A v-show & ngShow alternative
2307
- * @param cond {IValue} show condition
2308
- */
2309
- bindShow(cond) {
2310
- const $ = this.$;
2311
- const node = $.node;
2312
- if (node instanceof HTMLElement) {
2313
- let lastDisplay = node.style.display;
2314
- const htmlNode = node;
2315
- return this.bindAlive(cond, () => {
2316
- lastDisplay = htmlNode.style.display;
2317
- htmlNode.style.display = 'none';
2318
- }, () => {
2319
- htmlNode.style.display = lastDisplay;
2320
- });
2321
- }
2322
- else {
2323
- throw userError('the element must be a html element', 'bind-show');
2324
- }
2325
- }
2326
- /**
2327
- * bind HTML
2328
- * @param value {IValue}
2329
- */
2330
- html(value) {
2331
- const $ = this.$;
2332
- const node = $.node;
2333
- if (node instanceof HTMLElement) {
2334
- node.innerHTML = value.$;
2335
- this.watch((v) => {
2336
- node.innerHTML = v;
2337
- }, value);
2338
- }
2339
- else {
2340
- throw userError("HTML can be bound for HTML nodes only", "dom-error");
2341
- }
2342
- }
2343
- }
2344
- /**
2345
- * Represents an Vasille.js HTML element node
2346
- * @class Tag
2347
- * @extends INode
2348
- */
2349
- class Tag extends INode {
2350
- constructor() {
2351
- super();
2352
- this.seal();
2353
- }
2354
- preinit(app, parent, tagName) {
2355
- if (!tagName || typeof tagName !== "string") {
2356
- throw internalError('wrong Tag::$preinit call');
2357
- }
2358
- const node = document.createElement(tagName);
2359
- const $ = this.$;
2360
- $.preinit(app, parent);
2361
- $.node = node;
2362
- $.parent.appendNode(node);
2109
+ compose(input) {
2110
+ input.slot && input.slot(this);
2363
2111
  }
2364
2112
  findFirstChild() {
2365
2113
  return this.$.unmounted ? null : this.$.node;
@@ -2378,8 +2126,7 @@ class Tag extends INode {
2378
2126
  }
2379
2127
  }
2380
2128
  appendNode(node) {
2381
- const $ = this.$;
2382
- $.app.run.appendChild($.node, node);
2129
+ this.$.node.appendChild(node);
2383
2130
  }
2384
2131
  /**
2385
2132
  * Mount/Unmount a node
@@ -2400,9 +2147,9 @@ class Tag extends INode {
2400
2147
  /**
2401
2148
  * Runs GC
2402
2149
  */
2403
- destroy() {
2150
+ $destroy() {
2404
2151
  this.node.remove();
2405
- super.destroy();
2152
+ super.$destroy();
2406
2153
  }
2407
2154
  }
2408
2155
  /**
@@ -2412,21 +2159,21 @@ class Tag extends INode {
2412
2159
  */
2413
2160
  class Extension extends INode {
2414
2161
  preinit(app, parent) {
2415
- if (parent instanceof INode) {
2416
- const $ = this.$;
2417
- $.preinit(app, parent);
2418
- $.node = parent.node;
2162
+ const $ = this.$;
2163
+ let it = parent;
2164
+ while (it && !(it instanceof INode)) {
2165
+ it = it.parent;
2419
2166
  }
2420
- else {
2167
+ if (it && it instanceof INode) {
2168
+ $.node = it.node;
2169
+ }
2170
+ $.preinit(app, parent);
2171
+ if (!it) {
2421
2172
  throw userError("A extension node can be encapsulated only in a tag/extension/component", "virtual-dom");
2422
2173
  }
2423
2174
  }
2424
- constructor($) {
2425
- super($);
2426
- this.seal();
2427
- }
2428
- destroy() {
2429
- super.destroy();
2175
+ $destroy() {
2176
+ super.$destroy();
2430
2177
  }
2431
2178
  }
2432
2179
  /**
@@ -2435,12 +2182,13 @@ class Extension extends INode {
2435
2182
  * @extends Extension
2436
2183
  */
2437
2184
  class Component extends Extension {
2438
- constructor() {
2439
- super();
2440
- this.seal();
2185
+ init() {
2186
+ super.composeNow();
2187
+ this.ready();
2188
+ super.applyOptionsNow();
2441
2189
  }
2442
- mounted() {
2443
- super.mounted();
2190
+ ready() {
2191
+ super.ready();
2444
2192
  if (this.children.size !== 1) {
2445
2193
  throw userError("Component must have a child only", "dom-error");
2446
2194
  }
@@ -2465,18 +2213,23 @@ class Component extends Extension {
2465
2213
  class SwitchedNodePrivate extends FragmentPrivate {
2466
2214
  constructor() {
2467
2215
  super();
2468
- this.seal();
2216
+ /**
2217
+ * Array of possible cases
2218
+ * @type {Array<{cond : IValue<boolean>, cb : function(Fragment)}>}
2219
+ */
2220
+ this.cases = [];
2221
+ this.$seal();
2469
2222
  }
2470
2223
  /**
2471
2224
  * Runs GC
2472
2225
  */
2473
- destroy() {
2226
+ $destroy() {
2474
2227
  this.cases.forEach(c => {
2475
2228
  delete c.cond;
2476
2229
  delete c.cb;
2477
2230
  });
2478
2231
  this.cases.splice(0);
2479
- super.destroy();
2232
+ super.$destroy();
2480
2233
  }
2481
2234
  }
2482
2235
  /**
@@ -2487,7 +2240,7 @@ class SwitchedNode extends Fragment {
2487
2240
  * Constructs a switch node and define a sync function
2488
2241
  */
2489
2242
  constructor() {
2490
- super(new SwitchedNodePrivate);
2243
+ super({}, new SwitchedNodePrivate);
2491
2244
  this.$.sync = () => {
2492
2245
  const $ = this.$;
2493
2246
  let i = 0;
@@ -2500,7 +2253,7 @@ class SwitchedNode extends Fragment {
2500
2253
  return;
2501
2254
  }
2502
2255
  if (this.lastChild) {
2503
- this.lastChild.destroy();
2256
+ this.lastChild.$destroy();
2504
2257
  this.children.clear();
2505
2258
  this.lastChild = null;
2506
2259
  }
@@ -2512,22 +2265,19 @@ class SwitchedNode extends Fragment {
2512
2265
  $.index = -1;
2513
2266
  }
2514
2267
  };
2515
- this.seal();
2268
+ this.$seal();
2516
2269
  }
2517
- /**
2518
- * Set up switch cases
2519
- * @param cases {{ cond : IValue, cb : function(Fragment) }}
2520
- */
2521
- setCases(cases) {
2522
- const $ = this.$;
2523
- $.cases = [...cases];
2270
+ addCase(case_) {
2271
+ this.$.cases.push(case_);
2272
+ case_.cond.$on(this.$.sync);
2273
+ this.$.sync();
2524
2274
  }
2525
2275
  /**
2526
2276
  * Creates a child node
2527
2277
  * @param cb {function(Fragment)} Call-back
2528
2278
  */
2529
2279
  createChild(cb) {
2530
- const node = new Fragment();
2280
+ const node = new Fragment({});
2531
2281
  node.preinit(this.$.app, this);
2532
2282
  node.init();
2533
2283
  this.lastChild = node;
@@ -2537,16 +2287,16 @@ class SwitchedNode extends Fragment {
2537
2287
  ready() {
2538
2288
  const $ = this.$;
2539
2289
  $.cases.forEach(c => {
2540
- c.cond.on($.sync);
2290
+ c.cond.$on($.sync);
2541
2291
  });
2542
2292
  $.sync();
2543
2293
  }
2544
- destroy() {
2294
+ $destroy() {
2545
2295
  const $ = this.$;
2546
2296
  $.cases.forEach(c => {
2547
- c.cond.off($.sync);
2297
+ c.cond.$off($.sync);
2548
2298
  });
2549
- super.destroy();
2299
+ super.$destroy();
2550
2300
  }
2551
2301
  }
2552
2302
  /**
@@ -2555,7 +2305,7 @@ class SwitchedNode extends Fragment {
2555
2305
  class DebugPrivate extends FragmentPrivate {
2556
2306
  constructor() {
2557
2307
  super();
2558
- this.seal();
2308
+ this.$seal();
2559
2309
  }
2560
2310
  /**
2561
2311
  * Pre-initializes a text node
@@ -2574,9 +2324,9 @@ class DebugPrivate extends FragmentPrivate {
2574
2324
  /**
2575
2325
  * Clear node data
2576
2326
  */
2577
- destroy() {
2327
+ $destroy() {
2578
2328
  this.node.remove();
2579
- super.destroy();
2329
+ super.$destroy();
2580
2330
  }
2581
2331
  }
2582
2332
  /**
@@ -2586,13 +2336,13 @@ class DebugPrivate extends FragmentPrivate {
2586
2336
  */
2587
2337
  class DebugNode extends Fragment {
2588
2338
  constructor() {
2589
- super();
2339
+ super({});
2590
2340
  /**
2591
2341
  * private data
2592
2342
  * @type {DebugNode}
2593
2343
  */
2594
2344
  this.$ = new DebugPrivate();
2595
- this.seal();
2345
+ this.$seal();
2596
2346
  }
2597
2347
  preinit(app, parent, text) {
2598
2348
  const $ = this.$;
@@ -2604,9 +2354,9 @@ class DebugNode extends Fragment {
2604
2354
  /**
2605
2355
  * Runs garbage collector
2606
2356
  */
2607
- destroy() {
2608
- this.$.destroy();
2609
- super.destroy();
2357
+ $destroy() {
2358
+ this.$.$destroy();
2359
+ super.$destroy();
2610
2360
  }
2611
2361
  }
2612
2362
 
@@ -2620,6 +2370,7 @@ window.Tag = Tag;
2620
2370
  window.Extension = Extension;
2621
2371
  window.Component = Component;
2622
2372
  window.SwitchedNodePrivate = SwitchedNodePrivate;
2373
+ window.SwitchedNode = SwitchedNode;
2623
2374
  window.DebugPrivate = DebugPrivate;
2624
2375
  window.DebugNode = DebugNode;
2625
2376
 
@@ -2631,12 +2382,12 @@ window.DebugNode = DebugNode;
2631
2382
  */
2632
2383
  class AppNode extends INode {
2633
2384
  /**
2634
- * @param options {Object} Application options
2385
+ * @param input
2635
2386
  */
2636
- constructor(options) {
2637
- super();
2638
- this.run = (options === null || options === void 0 ? void 0 : options.executor) || ((options === null || options === void 0 ? void 0 : options.freezeUi) === false ? timeoutExecutor : instantExecutor);
2639
- this.debugUi = (options === null || options === void 0 ? void 0 : options.debugUi) || false;
2387
+ constructor(input) {
2388
+ super(input);
2389
+ this.debugUi = input.debugUi || false;
2390
+ this.$seal();
2640
2391
  }
2641
2392
  }
2642
2393
  /**
@@ -2648,22 +2399,33 @@ class App extends AppNode {
2648
2399
  /**
2649
2400
  * Constructs an app node
2650
2401
  * @param node {Element} The root of application
2651
- * @param options {Object} Application options
2402
+ * @param input
2652
2403
  */
2653
- constructor(node, options) {
2654
- super(options);
2404
+ constructor(node, input) {
2405
+ super(input);
2655
2406
  this.$.node = node;
2656
2407
  this.preinit(this, this);
2657
- this.seal();
2408
+ this.init();
2409
+ this.$seal();
2658
2410
  }
2659
2411
  appendNode(node) {
2660
- const $ = this.$;
2661
- this.run.appendChild($.node, node);
2412
+ this.$.node.appendChild(node);
2413
+ }
2414
+ }
2415
+ class Portal extends AppNode {
2416
+ constructor(input) {
2417
+ super(input);
2418
+ this.$.node = input.node;
2419
+ this.$seal();
2420
+ }
2421
+ appendNode(node) {
2422
+ this.$.node.appendChild(node);
2662
2423
  }
2663
2424
  }
2664
2425
 
2665
2426
  window.AppNode = AppNode;
2666
2427
  window.App = App;
2428
+ window.Portal = Portal;
2667
2429
 
2668
2430
  // ./lib/node/interceptor.js
2669
2431
  /**
@@ -2766,13 +2528,18 @@ class AttributeBinding extends Binding {
2766
2528
  super(value);
2767
2529
  this.init((value) => {
2768
2530
  if (value) {
2769
- node.app.run.setAttribute(node.node, name, value);
2531
+ if (typeof value === 'boolean') {
2532
+ node.node.setAttribute(name, "");
2533
+ }
2534
+ else {
2535
+ node.node.setAttribute(name, `${value}`);
2536
+ }
2770
2537
  }
2771
2538
  else {
2772
- node.app.run.removeAttribute(node.node, name);
2539
+ node.node.removeAttribute(name);
2773
2540
  }
2774
2541
  });
2775
- this.seal();
2542
+ this.$seal();
2776
2543
  }
2777
2544
  }
2778
2545
 
@@ -2795,10 +2562,10 @@ class StyleBinding extends Binding {
2795
2562
  super(value);
2796
2563
  this.init((value) => {
2797
2564
  if (node.node instanceof HTMLElement) {
2798
- node.app.run.setStyle(node.node, name, value);
2565
+ node.node.style.setProperty(name, value);
2799
2566
  }
2800
2567
  });
2801
- this.seal();
2568
+ this.$seal();
2802
2569
  }
2803
2570
  }
2804
2571
 
@@ -2806,10 +2573,10 @@ window.StyleBinding = StyleBinding;
2806
2573
 
2807
2574
  // ./lib/binding/class.js
2808
2575
  function addClass(node, cl) {
2809
- node.app.run.addClass(node.node, cl);
2576
+ node.node.classList.add(cl);
2810
2577
  }
2811
2578
  function removeClass(node, cl) {
2812
- node.app.run.removeClass(node.node, cl);
2579
+ node.node.classList.remove(cl);
2813
2580
  }
2814
2581
  class StaticClassBinding extends Binding {
2815
2582
  constructor(node, name, value) {
@@ -2826,7 +2593,7 @@ class StaticClassBinding extends Binding {
2826
2593
  this.current = value;
2827
2594
  }
2828
2595
  });
2829
- this.seal();
2596
+ this.$seal();
2830
2597
  }
2831
2598
  }
2832
2599
  class DynamicalClassBinding extends Binding {
@@ -2844,7 +2611,7 @@ class DynamicalClassBinding extends Binding {
2844
2611
  this.current = value;
2845
2612
  }
2846
2613
  });
2847
- this.seal();
2614
+ this.$seal();
2848
2615
  }
2849
2616
  }
2850
2617
 
@@ -2865,11 +2632,11 @@ class RepeatNodePrivate extends INodePrivate {
2865
2632
  * @type {Map}
2866
2633
  */
2867
2634
  this.nodes = new Map();
2868
- this.seal();
2635
+ this.$seal();
2869
2636
  }
2870
- destroy() {
2637
+ $destroy() {
2871
2638
  this.nodes.clear();
2872
- super.destroy();
2639
+ super.$destroy();
2873
2640
  }
2874
2641
  }
2875
2642
  /**
@@ -2878,17 +2645,15 @@ class RepeatNodePrivate extends INodePrivate {
2878
2645
  * @extends Fragment
2879
2646
  */
2880
2647
  class RepeatNode extends Fragment {
2881
- constructor($) {
2882
- super($ || new RepeatNodePrivate);
2648
+ constructor(input, $) {
2649
+ super(input, $);
2883
2650
  /**
2884
2651
  * If false will use timeout executor, otherwise the app executor
2885
2652
  */
2886
2653
  this.freezeUi = true;
2887
- this.slot = new Slot;
2888
2654
  }
2889
- createChild(id, item, before) {
2890
- // TODO: Refactor: remove @ts-ignore
2891
- const node = new Fragment();
2655
+ createChild(opts, id, item, before) {
2656
+ const node = new Fragment({});
2892
2657
  this.destroyChild(id, item);
2893
2658
  if (before) {
2894
2659
  this.children.add(node);
@@ -2904,16 +2669,8 @@ class RepeatNode extends Fragment {
2904
2669
  this.lastChild = node;
2905
2670
  node.preinit(this.$.app, this);
2906
2671
  node.init();
2907
- const callback = () => {
2908
- this.slot.release(node, item, id);
2909
- node.ready();
2910
- };
2911
- if (this.freezeUi) {
2912
- this.$.app.run.callCallback(callback);
2913
- }
2914
- else {
2915
- timeoutExecutor.callCallback(callback);
2916
- }
2672
+ opts.slot && opts.slot(node, item, id);
2673
+ node.ready();
2917
2674
  this.$.nodes.set(id, node);
2918
2675
  }
2919
2676
  destroyChild(id, item) {
@@ -2921,7 +2678,7 @@ class RepeatNode extends Fragment {
2921
2678
  const child = $.nodes.get(id);
2922
2679
  if (child) {
2923
2680
  child.remove();
2924
- child.destroy();
2681
+ child.$destroy();
2925
2682
  this.$.nodes.delete(id);
2926
2683
  this.children.delete(child);
2927
2684
  }
@@ -3006,7 +2763,7 @@ window.Repeater = Repeater;
3006
2763
  class BaseViewPrivate extends RepeatNodePrivate {
3007
2764
  constructor() {
3008
2765
  super();
3009
- this.seal();
2766
+ this.$seal();
3010
2767
  }
3011
2768
  }
3012
2769
  /**
@@ -3016,34 +2773,23 @@ class BaseViewPrivate extends RepeatNodePrivate {
3016
2773
  * @implements IModel
3017
2774
  */
3018
2775
  class BaseView extends RepeatNode {
3019
- constructor($1) {
3020
- super($1 || new BaseViewPrivate);
2776
+ constructor(input, $) {
2777
+ super(input, $ || new BaseViewPrivate);
2778
+ }
2779
+ compose(input) {
3021
2780
  const $ = this.$;
3022
2781
  $.addHandler = (id, item) => {
3023
- this.createChild(id, item);
2782
+ this.createChild(input, id, item);
3024
2783
  };
3025
2784
  $.removeHandler = (id, item) => {
3026
2785
  this.destroyChild(id, item);
3027
2786
  };
3028
- this.seal();
3029
- }
3030
- /**
3031
- * Handle ready event
3032
- */
3033
- ready() {
3034
- const $ = this.$;
3035
- this.model.listener.onAdd($.addHandler);
3036
- this.model.listener.onRemove($.removeHandler);
3037
- super.ready();
3038
- }
3039
- /**
3040
- * Handles destroy event
3041
- */
3042
- destroy() {
3043
- const $ = this.$;
3044
- this.model.listener.offAdd($.addHandler);
3045
- this.model.listener.offRemove($.removeHandler);
3046
- super.destroy();
2787
+ input.model.listener.onAdd($.addHandler);
2788
+ input.model.listener.onRemove($.removeHandler);
2789
+ this.runOnDestroy(() => {
2790
+ input.model.listener.offAdd($.addHandler);
2791
+ input.model.listener.offRemove($.removeHandler);
2792
+ });
3047
2793
  }
3048
2794
  }
3049
2795
 
@@ -3057,18 +2803,14 @@ window.BaseView = BaseView;
3057
2803
  * @extends BaseView
3058
2804
  */
3059
2805
  class ArrayView extends BaseView {
3060
- constructor(model) {
3061
- super();
3062
- this.model = model;
2806
+ createChild(input, id, item, before) {
2807
+ super.createChild(input, item, item, before || this.$.nodes.get(id));
3063
2808
  }
3064
- createChild(id, item, before) {
3065
- super.createChild(item, item, before || this.$.nodes.get(id));
3066
- }
3067
- ready() {
3068
- this.model.forEach(item => {
3069
- this.createChild(item, item);
2809
+ compose(input) {
2810
+ super.compose(input);
2811
+ input.model.forEach(item => {
2812
+ this.createChild(input, item, item);
3070
2813
  });
3071
- super.ready();
3072
2814
  }
3073
2815
  }
3074
2816
 
@@ -3081,23 +2823,16 @@ window.ArrayView = ArrayView;
3081
2823
  * @extends Fragment
3082
2824
  */
3083
2825
  class Watch extends Fragment {
3084
- constructor() {
3085
- super();
3086
- this.slot = new Slot;
3087
- this.model = this.ref(null);
3088
- this.seal();
3089
- }
3090
- createWatchers() {
2826
+ compose(input) {
3091
2827
  this.watch((value) => {
3092
2828
  this.children.forEach(child => {
3093
- child.destroy();
2829
+ child.$destroy();
3094
2830
  });
3095
2831
  this.children.clear();
3096
- this.slot.release(this, value);
3097
- }, this.model);
3098
- }
3099
- compose() {
3100
- this.slot.release(this, this.model.$);
2832
+ this.lastChild = null;
2833
+ input.slot && input.slot(this, value);
2834
+ }, input.model);
2835
+ input.slot(this, input.model.$);
3101
2836
  }
3102
2837
  }
3103
2838
 
@@ -3110,14 +2845,11 @@ window.Watch = Watch;
3110
2845
  * @extends BaseView
3111
2846
  */
3112
2847
  class ObjectView extends BaseView {
3113
- constructor(model) {
3114
- super();
3115
- this.model = model;
3116
- }
3117
- ready() {
3118
- const obj = this.model;
2848
+ compose(input) {
2849
+ super.compose(input);
2850
+ const obj = input.model.proxy();
3119
2851
  for (const key in obj) {
3120
- this.createChild(key, obj[key]);
2852
+ this.createChild(input, key, obj[key]);
3121
2853
  }
3122
2854
  super.ready();
3123
2855
  }
@@ -3132,16 +2864,11 @@ window.ObjectView = ObjectView;
3132
2864
  * @extends BaseView
3133
2865
  */
3134
2866
  class MapView extends BaseView {
3135
- constructor(model) {
3136
- super();
3137
- this.model = model;
3138
- }
3139
- ready() {
3140
- const map = this.model;
3141
- map.forEach((value, key) => {
3142
- this.createChild(key, value);
2867
+ compose(input) {
2868
+ super.compose(input);
2869
+ input.model.forEach((value, key) => {
2870
+ this.createChild(input, key, value);
3143
2871
  });
3144
- super.ready();
3145
2872
  }
3146
2873
  }
3147
2874
 
@@ -3154,22 +2881,295 @@ window.MapView = MapView;
3154
2881
  * @extends BaseView
3155
2882
  */
3156
2883
  class SetView extends BaseView {
3157
- constructor(model) {
3158
- super();
3159
- this.model = model;
3160
- }
3161
- ready() {
3162
- const $ = this.$;
3163
- const set = this.model;
2884
+ compose(input) {
2885
+ super.compose(input);
2886
+ const set = input.model;
3164
2887
  set.forEach(item => {
3165
- $.app.run.callCallback(() => {
3166
- this.createChild(item, item);
3167
- });
2888
+ this.createChild(input, item, item);
3168
2889
  });
3169
- super.ready();
3170
2890
  }
3171
2891
  }
3172
2892
 
3173
2893
  window.SetView = SetView;
3174
2894
 
2895
+ // ./lib/functional/merge.js
2896
+ function merge(main, ...targets) {
2897
+ function refactorClass(obj) {
2898
+ if (Array.isArray(obj.class)) {
2899
+ const out = {
2900
+ $: []
2901
+ };
2902
+ obj.class.forEach(item => {
2903
+ if (item instanceof IValue) {
2904
+ out.$.push(item);
2905
+ }
2906
+ else if (typeof item === 'string') {
2907
+ out[item] = true;
2908
+ }
2909
+ else if (typeof item === 'object') {
2910
+ Object.assign(out, item);
2911
+ }
2912
+ });
2913
+ obj.class = out;
2914
+ }
2915
+ }
2916
+ refactorClass(main);
2917
+ targets.forEach(target => {
2918
+ Reflect.ownKeys(target).forEach((prop) => {
2919
+ if (!Reflect.has(main, prop)) {
2920
+ main[prop] = target[prop];
2921
+ }
2922
+ else if (typeof main[prop] === 'object' && typeof target[prop] === 'object') {
2923
+ if (prop === 'class') {
2924
+ refactorClass(target);
2925
+ }
2926
+ if (prop === '$' && Array.isArray(main[prop]) && Array.isArray(target[prop])) {
2927
+ main.$.push(...target.$);
2928
+ }
2929
+ else {
2930
+ merge(main[prop], target[prop]);
2931
+ }
2932
+ }
2933
+ });
2934
+ });
2935
+ }
2936
+
2937
+ window.merge = merge;
2938
+
2939
+ // ./lib/functional/stack.js
2940
+ function app(renderer) {
2941
+ return (node, opts) => {
2942
+ return new App(node, opts).runFunctional(renderer, opts);
2943
+ };
2944
+ }
2945
+ function component(renderer) {
2946
+ return (opts, callback) => {
2947
+ const component = new Component(opts);
2948
+ if (!(current instanceof Fragment))
2949
+ throw userError('missing parent node', 'out-of-context');
2950
+ let ret;
2951
+ if (callback)
2952
+ opts.slot = callback;
2953
+ current.create(component, node => {
2954
+ ret = node.runFunctional(renderer, opts);
2955
+ });
2956
+ return ret;
2957
+ };
2958
+ }
2959
+ function fragment(renderer) {
2960
+ return (opts, callback) => {
2961
+ const frag = new Fragment(opts);
2962
+ if (!(current instanceof Fragment))
2963
+ throw userError('missing parent node', 'out-of-context');
2964
+ if (callback)
2965
+ opts.slot = callback;
2966
+ current.create(frag);
2967
+ return frag.runFunctional(renderer, opts);
2968
+ };
2969
+ }
2970
+ function extension(renderer) {
2971
+ return (opts, callback) => {
2972
+ const ext = new Extension(opts);
2973
+ if (!(current instanceof Fragment))
2974
+ throw userError('missing parent node', 'out-of-context');
2975
+ if (callback)
2976
+ opts.slot = callback;
2977
+ current.create(ext);
2978
+ return ext.runFunctional(renderer, opts);
2979
+ };
2980
+ }
2981
+ function tag(name, opts, callback) {
2982
+ if (!(current instanceof Fragment))
2983
+ throw userError('missing parent node', 'out-of-context');
2984
+ return {
2985
+ node: current.tag(name, opts, (node) => {
2986
+ callback && node.runFunctional(callback);
2987
+ })
2988
+ };
2989
+ }
2990
+ function create(node, callback) {
2991
+ if (!(current instanceof Fragment))
2992
+ throw userError('missing current node', 'out-of-context');
2993
+ current.create(node, (node, ...args) => {
2994
+ callback && node.runFunctional(callback, ...args);
2995
+ });
2996
+ return node;
2997
+ }
2998
+ const vx = {
2999
+ if(condition, callback) {
3000
+ if (current instanceof Fragment) {
3001
+ current.if(condition, node => node.runFunctional(callback));
3002
+ }
3003
+ else {
3004
+ throw userError("wrong use of `v.if` function", "logic-error");
3005
+ }
3006
+ },
3007
+ else(callback) {
3008
+ if (current instanceof Fragment) {
3009
+ current.else(node => node.runFunctional(callback));
3010
+ }
3011
+ else {
3012
+ throw userError("wrong use of `v.else` function", "logic-error");
3013
+ }
3014
+ },
3015
+ elif(condition, callback) {
3016
+ if (current instanceof Fragment) {
3017
+ current.elif(condition, node => node.runFunctional(callback));
3018
+ }
3019
+ else {
3020
+ throw userError("wrong use of `v.elif` function", "logic-error");
3021
+ }
3022
+ },
3023
+ for(model, callback) {
3024
+ if (model instanceof ArrayModel) {
3025
+ // for arrays T & K are the same type
3026
+ create(new ArrayView({ model }), callback);
3027
+ }
3028
+ else if (model instanceof MapModel) {
3029
+ create(new MapView({ model }), callback);
3030
+ }
3031
+ else if (model instanceof SetModel) {
3032
+ // for sets T & K are the same type
3033
+ create(new SetView({ model }), callback);
3034
+ }
3035
+ else if (model instanceof ObjectModel) {
3036
+ // for objects K is always string
3037
+ create(new ObjectView({ model }), callback);
3038
+ }
3039
+ else {
3040
+ throw userError("wrong use of `v.for` function", 'wrong-model');
3041
+ }
3042
+ },
3043
+ watch(model, callback) {
3044
+ const opts = { model };
3045
+ create(new Watch(opts), callback);
3046
+ },
3047
+ nextTick(callback) {
3048
+ const node = current;
3049
+ window.setTimeout(() => {
3050
+ node.runFunctional(callback);
3051
+ }, 0);
3052
+ }
3053
+ };
3054
+
3055
+ window.app = app;
3056
+ window.component = component;
3057
+ window.fragment = fragment;
3058
+ window.extension = extension;
3059
+ window.tag = tag;
3060
+ window.create = create;
3061
+ window.vx = vx;
3062
+
3063
+ // ./lib/functional/models.js
3064
+ function arrayModel(arr = []) {
3065
+ if (!current)
3066
+ throw userError('missing parent node', 'out-of-context');
3067
+ return current.register(new ArrayModel(arr)).proxy();
3068
+ }
3069
+ function mapModel(map = []) {
3070
+ if (!current)
3071
+ throw userError('missing parent node', 'out-of-context');
3072
+ return current.register(new MapModel(map));
3073
+ }
3074
+ function setModel(arr = []) {
3075
+ if (!current)
3076
+ throw userError('missing parent node', 'out-of-context');
3077
+ return current.register(new SetModel(arr));
3078
+ }
3079
+ function objectModel(obj = {}) {
3080
+ if (!current)
3081
+ throw userError('missing parent node', 'out-of-context');
3082
+ return current.register(new ObjectModel(obj));
3083
+ }
3084
+
3085
+ window.arrayModel = arrayModel;
3086
+ window.mapModel = mapModel;
3087
+ window.setModel = setModel;
3088
+ window.objectModel = objectModel;
3089
+
3090
+ // ./lib/functional/options.js
3091
+
3092
+
3093
+
3094
+ // ./lib/functional/reactivity.js
3095
+ function ref(value) {
3096
+ const ref = current.ref(value);
3097
+ return [ref, (value) => ref.$ = value];
3098
+ }
3099
+ function mirror(value) {
3100
+ return current.mirror(value);
3101
+ }
3102
+ function forward(value) {
3103
+ return current.forward(value);
3104
+ }
3105
+ function point(value) {
3106
+ return current.point(value);
3107
+ }
3108
+ function expr(func, ...values) {
3109
+ return current.expr(func, ...values);
3110
+ }
3111
+ function watch(func, ...values) {
3112
+ current.watch(func, ...values);
3113
+ }
3114
+ function valueOf(value) {
3115
+ return value.$;
3116
+ }
3117
+ function setValue(ref, value) {
3118
+ if (ref instanceof Pointer && value instanceof IValue) {
3119
+ ref.$$ = value;
3120
+ }
3121
+ else {
3122
+ ref.$ = value instanceof IValue ? value.$ : value;
3123
+ }
3124
+ }
3125
+
3126
+ window.ref = ref;
3127
+ window.mirror = mirror;
3128
+ window.forward = forward;
3129
+ window.point = point;
3130
+ window.expr = expr;
3131
+ window.watch = watch;
3132
+ window.valueOf = valueOf;
3133
+ window.setValue = setValue;
3134
+
3135
+ // ./lib/functional/components.js
3136
+ function text(text) {
3137
+ if (!(current instanceof Fragment))
3138
+ throw userError('missing parent node', 'out-of-context');
3139
+ ;
3140
+ current.text(text);
3141
+ }
3142
+ function debug(text) {
3143
+ if (!(current instanceof Fragment))
3144
+ throw userError('missing parent node', 'out-of-context');
3145
+ current.debug(text);
3146
+ }
3147
+ function predefine(slot, predefined) {
3148
+ return slot || predefined;
3149
+ }
3150
+
3151
+ window.text = text;
3152
+ window.debug = debug;
3153
+ window.predefine = predefine;
3154
+
3155
+ // ./lib/v/index.js
3156
+
3157
+ const v = Object.assign(Object.assign({ ref(value) {
3158
+ return current.ref(value);
3159
+ }, expr: expr, of: valueOf, sv: setValue, alwaysFalse: new Reference(false), app,
3160
+ component,
3161
+ fragment,
3162
+ extension,
3163
+ text,
3164
+ tag,
3165
+ create }, vx), { merge,
3166
+ destructor() {
3167
+ return current.$destroy.bind(current);
3168
+ },
3169
+ runOnDestroy(callback) {
3170
+ current.runOnDestroy(callback);
3171
+ } });
3172
+
3173
+ window.v = v;
3174
+
3175
3175
  })();