vasille 1.2.9 → 2.0.3

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 (133) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +195 -129
  3. package/cdn/es2015.js +3231 -0
  4. package/cdn/es5.js +3675 -0
  5. package/flow-typed/vasille.js +839 -0
  6. package/lib/binding/attribute.js +32 -0
  7. package/lib/binding/binding.js +39 -0
  8. package/lib/binding/class.js +51 -0
  9. package/lib/binding/style.js +29 -0
  10. package/lib/core/core.js +186 -0
  11. package/lib/core/destroyable.js +45 -0
  12. package/lib/core/errors.js +16 -0
  13. package/lib/core/executor.js +154 -0
  14. package/lib/core/ivalue.js +56 -0
  15. package/lib/core/signal.js +50 -0
  16. package/lib/core/slot.js +47 -0
  17. package/lib/index.js +27 -22
  18. package/lib/models/array-model.js +208 -0
  19. package/lib/models/listener.js +130 -0
  20. package/lib/models/map-model.js +66 -0
  21. package/lib/models/model.js +1 -0
  22. package/lib/models/object-model.js +78 -0
  23. package/lib/models/set-model.js +62 -0
  24. package/lib/node/app.js +39 -0
  25. package/lib/node/interceptor.js +83 -0
  26. package/lib/node/node.js +1204 -0
  27. package/lib/node/watch.js +27 -0
  28. package/lib/value/expression.js +83 -0
  29. package/lib/value/mirror.js +58 -0
  30. package/lib/value/pointer.js +26 -0
  31. package/lib/value/reference.js +55 -0
  32. package/lib/views/array-view.js +21 -0
  33. package/lib/views/base-view.js +49 -0
  34. package/lib/views/map-view.js +19 -0
  35. package/lib/views/object-view.js +19 -0
  36. package/lib/views/repeat-node.js +106 -0
  37. package/lib/views/repeater.js +63 -0
  38. package/lib/views/set-view.js +22 -0
  39. package/package.json +26 -18
  40. package/types/binding/attribute.d.ts +23 -0
  41. package/types/binding/binding.d.ts +30 -0
  42. package/types/binding/class.d.ts +23 -0
  43. package/types/binding/style.d.ts +23 -0
  44. package/types/core/core.d.ts +144 -0
  45. package/types/core/destroyable.d.ts +15 -0
  46. package/types/core/errors.d.ts +4 -0
  47. package/types/core/executor.d.ts +87 -0
  48. package/types/core/ivalue.d.ts +45 -0
  49. package/types/core/signal.d.ts +35 -0
  50. package/types/core/slot.d.ts +45 -0
  51. package/types/index.d.ts +27 -21
  52. package/types/models/array-model.d.ts +103 -0
  53. package/types/models/listener.d.ts +74 -0
  54. package/types/models/map-model.d.ts +35 -0
  55. package/types/models/model.d.ts +19 -0
  56. package/types/models/object-model.d.ts +36 -0
  57. package/types/models/set-model.d.ts +34 -0
  58. package/types/node/app.d.ts +42 -0
  59. package/types/node/interceptor.d.ts +50 -0
  60. package/types/node/node.d.ts +741 -0
  61. package/types/node/watch.d.ts +23 -0
  62. package/types/value/expression.d.ts +60 -0
  63. package/types/value/mirror.d.ts +35 -0
  64. package/types/value/pointer.d.ts +19 -0
  65. package/types/value/reference.d.ts +30 -0
  66. package/types/views/array-view.d.ts +13 -0
  67. package/types/views/base-view.d.ts +43 -0
  68. package/types/views/map-view.d.ts +11 -0
  69. package/types/views/object-view.d.ts +11 -0
  70. package/types/views/repeat-node.d.ts +35 -0
  71. package/types/views/repeater.d.ts +38 -0
  72. package/types/views/set-view.d.ts +11 -0
  73. package/CHANGELOG.md +0 -23
  74. package/img/favicon.svg +0 -441
  75. package/img/getLocus.svg +0 -18
  76. package/img/logo.png +0 -0
  77. package/img/logo.svg +0 -550
  78. package/img/scores-o-log.png +0 -0
  79. package/img/scores-o.png +0 -0
  80. package/img/scores-wo-log.png +0 -0
  81. package/img/scores-wo.png +0 -0
  82. package/img/x1-x32.png +0 -0
  83. package/lib/attribute.js +0 -71
  84. package/lib/attribute.js.map +0 -1
  85. package/lib/bind.js +0 -286
  86. package/lib/bind.js.map +0 -1
  87. package/lib/class.js +0 -97
  88. package/lib/class.js.map +0 -1
  89. package/lib/executor.js +0 -167
  90. package/lib/executor.js.map +0 -1
  91. package/lib/index.js.map +0 -1
  92. package/lib/interfaces/core.js +0 -247
  93. package/lib/interfaces/core.js.map +0 -1
  94. package/lib/interfaces/destroyable.js +0 -39
  95. package/lib/interfaces/destroyable.js.map +0 -1
  96. package/lib/interfaces/errors.js +0 -49
  97. package/lib/interfaces/errors.js.map +0 -1
  98. package/lib/interfaces/ibind.js +0 -31
  99. package/lib/interfaces/ibind.js.map +0 -1
  100. package/lib/interfaces/idefinition.js +0 -64
  101. package/lib/interfaces/idefinition.js.map +0 -1
  102. package/lib/interfaces/ivalue.js +0 -60
  103. package/lib/interfaces/ivalue.js.map +0 -1
  104. package/lib/models.js +0 -579
  105. package/lib/models.js.map +0 -1
  106. package/lib/node.js +0 -2155
  107. package/lib/node.js.map +0 -1
  108. package/lib/property.js +0 -38
  109. package/lib/property.js.map +0 -1
  110. package/lib/style.js +0 -66
  111. package/lib/style.js.map +0 -1
  112. package/lib/value.js +0 -203
  113. package/lib/value.js.map +0 -1
  114. package/lib/views.js +0 -688
  115. package/lib/views.js.map +0 -1
  116. package/types/attribute.d.ts +0 -18
  117. package/types/bind.d.ts +0 -72
  118. package/types/class.d.ts +0 -19
  119. package/types/data.d.ts +0 -11
  120. package/types/event.d.ts +0 -10
  121. package/types/executor.d.ts +0 -57
  122. package/types/interfaces/core.d.ts +0 -129
  123. package/types/interfaces/destroyable.d.ts +0 -11
  124. package/types/interfaces/errors.d.ts +0 -24
  125. package/types/interfaces/ibind.d.ts +0 -19
  126. package/types/interfaces/idefinition.d.ts +0 -29
  127. package/types/interfaces/ivalue.d.ts +0 -40
  128. package/types/models.d.ts +0 -179
  129. package/types/node.d.ts +0 -906
  130. package/types/property.d.ts +0 -9
  131. package/types/style.d.ts +0 -28
  132. package/types/value.d.ts +0 -43
  133. package/types/views.d.ts +0 -135
@@ -0,0 +1,1204 @@
1
+ import { Reactive, ReactivePrivate } from "../core/core";
2
+ import { IValue } from "../core/ivalue";
3
+ import { Reference } from "../value/reference";
4
+ import { Expression } from "../value/expression";
5
+ import { AttributeBinding } from "../binding/attribute";
6
+ import { ClassBinding } from "../binding/class";
7
+ import { StyleBinding } from "../binding/style";
8
+ import { internalError, userError } from "../core/errors";
9
+ /**
10
+ * Represents a Vasille.js node
11
+ * @class FragmentPrivate
12
+ * @extends ReactivePrivate
13
+ */
14
+ export class FragmentPrivate extends ReactivePrivate {
15
+ constructor() {
16
+ super();
17
+ this.$seal();
18
+ }
19
+ /**
20
+ * Pre-initializes the base of a fragment
21
+ * @param app {App} the app node
22
+ * @param parent {Fragment} the parent node
23
+ */
24
+ preinit(app, parent) {
25
+ this.app = app;
26
+ this.parent = parent;
27
+ }
28
+ /**
29
+ * Unlinks all bindings
30
+ */
31
+ $destroy() {
32
+ this.next = null;
33
+ this.prev = null;
34
+ super.$destroy();
35
+ }
36
+ }
37
+ /**
38
+ * This class is symbolic
39
+ * @extends Reactive
40
+ */
41
+ export class Fragment extends Reactive {
42
+ /**
43
+ * Constructs a Vasille Node
44
+ * @param $ {FragmentPrivate}
45
+ */
46
+ constructor($) {
47
+ super();
48
+ /**
49
+ * The children list
50
+ * @type Array
51
+ */
52
+ this.$children = [];
53
+ this.$ = $ || new FragmentPrivate;
54
+ }
55
+ /**
56
+ * Gets the app of node
57
+ */
58
+ get app() {
59
+ return this.$.app;
60
+ }
61
+ /**
62
+ * Prepare to init fragment
63
+ * @param app {AppNode} app of node
64
+ * @param parent {Fragment} parent of node
65
+ * @param data {*} additional data
66
+ */
67
+ $preinit(app, parent, data) {
68
+ const $ = this.$;
69
+ $.preinit(app, parent);
70
+ }
71
+ /**
72
+ * Initialize node
73
+ */
74
+ $init() {
75
+ this.$createSignals();
76
+ this.$createWatchers();
77
+ this.$created();
78
+ this.$compose();
79
+ this.$mounted();
80
+ return this;
81
+ }
82
+ /** To be overloaded: created event handler */
83
+ $created() {
84
+ // empty
85
+ }
86
+ /** To be overloaded: mounted event handler */
87
+ $mounted() {
88
+ // empty
89
+ }
90
+ /** To be overloaded: ready event handler */
91
+ $ready() {
92
+ // empty
93
+ }
94
+ /** To be overloaded: signals creation milestone */
95
+ $createSignals() {
96
+ // empty
97
+ }
98
+ /** To be overloaded: watchers creation milestone */
99
+ $createWatchers() {
100
+ // empty
101
+ }
102
+ /** To be overloaded: DOM creation milestone */
103
+ $compose() {
104
+ // empty
105
+ }
106
+ /**
107
+ * Pushes a node to children immediately
108
+ * @param node {Fragment} A node to push
109
+ * @protected
110
+ */
111
+ $$pushNode(node) {
112
+ let lastChild = null;
113
+ if (this.$children.length) {
114
+ lastChild = this.$children[this.$children.length - 1];
115
+ }
116
+ if (lastChild) {
117
+ lastChild.$.next = node;
118
+ }
119
+ node.$.prev = lastChild;
120
+ node.$.parent = this;
121
+ this.$children.push(node);
122
+ }
123
+ /**
124
+ * Find first node in element if so exists
125
+ * @return {?Element}
126
+ * @protected
127
+ */
128
+ $$findFirstChild() {
129
+ let first;
130
+ this.$children.forEach(child => {
131
+ first = first || child.$$findFirstChild();
132
+ });
133
+ return first;
134
+ }
135
+ /**
136
+ * Append a node to end of element
137
+ * @param node {Node} node to insert
138
+ */
139
+ $$appendNode(node) {
140
+ const $ = this.$;
141
+ if ($.next) {
142
+ $.next.$$insertAdjacent(node);
143
+ }
144
+ else {
145
+ $.parent.$$appendNode(node);
146
+ }
147
+ }
148
+ /**
149
+ * Insert a node as a sibling of this
150
+ * @param node {Node} node to insert
151
+ */
152
+ $$insertAdjacent(node) {
153
+ const child = this.$$findFirstChild();
154
+ const $ = this.$;
155
+ if (child) {
156
+ $.app.$run.insertBefore(child, node);
157
+ }
158
+ else if ($.next) {
159
+ $.next.$$insertAdjacent(node);
160
+ }
161
+ else {
162
+ $.parent.$$appendNode(node);
163
+ }
164
+ }
165
+ /**
166
+ * Defines a text fragment
167
+ * @param text {String | IValue} A text fragment string
168
+ * @param cb {function (TextNode)} Callback if previous is slot name
169
+ */
170
+ $text(text, cb) {
171
+ const $ = this.$;
172
+ const node = new TextNode();
173
+ const textValue = text instanceof IValue ? text : this.$ref(text);
174
+ node.$preinit($.app, this, textValue);
175
+ this.$$pushNode(node);
176
+ if (cb) {
177
+ $.app.$run.callCallback(() => {
178
+ cb(node);
179
+ });
180
+ }
181
+ return this;
182
+ }
183
+ $debug(text) {
184
+ if (this.$.app.$debugUi) {
185
+ const node = new DebugNode();
186
+ node.$preinit(this.$.app, this, text);
187
+ this.$$pushNode(node);
188
+ }
189
+ return this;
190
+ }
191
+ $tag(tagName, cb) {
192
+ const $ = this.$;
193
+ const node = new Tag();
194
+ node.$preinit($.app, this, tagName);
195
+ node.$init();
196
+ this.$$pushNode(node);
197
+ $.app.$run.callCallback(() => {
198
+ if (cb) {
199
+ cb(node, node.node);
200
+ }
201
+ node.$ready();
202
+ });
203
+ return this;
204
+ }
205
+ /**
206
+ * Defines a custom element
207
+ * @param node {Fragment} vasille element to insert
208
+ * @param callback {function($ : *)}
209
+ * @param callback1 {function($ : *)}
210
+ */
211
+ $create(node, callback, callback1) {
212
+ const $ = this.$;
213
+ node.$.parent = this;
214
+ node.$preinit($.app, this);
215
+ if (callback) {
216
+ callback(node);
217
+ }
218
+ if (callback1) {
219
+ callback1(node);
220
+ }
221
+ this.$$pushNode(node);
222
+ node.$init().$ready();
223
+ return this;
224
+ }
225
+ /**
226
+ * Defines an if node
227
+ * @param cond {IValue} condition
228
+ * @param cb {function(Fragment)} callback to run on true
229
+ * @return {this}
230
+ */
231
+ $if(cond, cb) {
232
+ return this.$switch({ cond, cb });
233
+ }
234
+ /**
235
+ * Defines a if-else node
236
+ * @param ifCond {IValue} `if` condition
237
+ * @param ifCb {function(Fragment)} Call-back to create `if` child nodes
238
+ * @param elseCb {function(Fragment)} Call-back to create `else` child nodes
239
+ */
240
+ $if_else(ifCond, ifCb, elseCb) {
241
+ return this.$switch({ cond: ifCond, cb: ifCb }, { cond: trueIValue, cb: elseCb });
242
+ }
243
+ /**
244
+ * Defines a switch nodes: Will break after first true condition
245
+ * @param cases {...{ cond : IValue, cb : function(Fragment) }} cases
246
+ * @return {INode}
247
+ */
248
+ $switch(...cases) {
249
+ const $ = this.$;
250
+ const node = new SwitchedNode();
251
+ node.$preinit($.app, this);
252
+ node.$init();
253
+ this.$$pushNode(node);
254
+ node.setCases(cases);
255
+ node.$ready();
256
+ return this;
257
+ }
258
+ /**
259
+ * Create a case for switch
260
+ * @param cond {IValue<boolean>}
261
+ * @param cb {function(Fragment) : void}
262
+ * @return {{cond : IValue, cb : (function(Fragment) : void)}}
263
+ */
264
+ $case(cond, cb) {
265
+ return { cond, cb };
266
+ }
267
+ /**
268
+ * @param cb {(function(Fragment) : void)}
269
+ * @return {{cond : IValue, cb : (function(Fragment) : void)}}
270
+ */
271
+ $default(cb) {
272
+ return { cond: trueIValue, cb };
273
+ }
274
+ $destroy() {
275
+ for (const child of this.$children) {
276
+ child.$destroy();
277
+ }
278
+ this.$children.splice(0);
279
+ super.$destroy();
280
+ }
281
+ }
282
+ const trueIValue = new Reference(true);
283
+ /**
284
+ * The private part of a text node
285
+ * @class TextNodePrivate
286
+ * @extends FragmentPrivate
287
+ */
288
+ export class TextNodePrivate extends FragmentPrivate {
289
+ constructor() {
290
+ super();
291
+ this.$seal();
292
+ }
293
+ /**
294
+ * Pre-initializes a text node
295
+ * @param app {AppNode} the app node
296
+ * @param text {IValue}
297
+ */
298
+ preinitText(app, parent, text) {
299
+ super.preinit(app, parent);
300
+ this.node = document.createTextNode(text.$);
301
+ this.bindings.add(new Expression((v) => {
302
+ this.node.replaceData(0, -1, v);
303
+ }, true, text));
304
+ this.parent.$$appendNode(this.node);
305
+ }
306
+ /**
307
+ * Clear node data
308
+ */
309
+ $destroy() {
310
+ super.$destroy();
311
+ }
312
+ }
313
+ /**
314
+ * Represents a text node
315
+ * @class TextNode
316
+ * @extends Fragment
317
+ */
318
+ export class TextNode extends Fragment {
319
+ constructor() {
320
+ super();
321
+ this.$ = new TextNodePrivate();
322
+ this.$seal();
323
+ }
324
+ $preinit(app, parent, text) {
325
+ const $ = this.$;
326
+ if (!text) {
327
+ throw internalError('wrong TextNode::$preninit call');
328
+ }
329
+ $.preinitText(app, parent, text);
330
+ }
331
+ $$findFirstChild() {
332
+ return this.$.node;
333
+ }
334
+ $destroy() {
335
+ this.$.node.remove();
336
+ this.$.$destroy();
337
+ super.$destroy();
338
+ }
339
+ }
340
+ /**
341
+ * The private part of a base node
342
+ * @class INodePrivate
343
+ * @extends FragmentPrivate
344
+ */
345
+ export class INodePrivate extends FragmentPrivate {
346
+ constructor() {
347
+ super();
348
+ /**
349
+ * Defines if node is unmounted
350
+ * @type {boolean}
351
+ */
352
+ this.unmounted = false;
353
+ this.$seal();
354
+ }
355
+ $destroy() {
356
+ super.$destroy();
357
+ }
358
+ }
359
+ /**
360
+ * Vasille node which can manipulate an element node
361
+ * @class INode
362
+ * @extends Fragment
363
+ */
364
+ export class INode extends Fragment {
365
+ /**
366
+ * Constructs a base node
367
+ * @param $ {?INodePrivate}
368
+ */
369
+ constructor($) {
370
+ super($ || new INodePrivate);
371
+ this.$seal();
372
+ }
373
+ /**
374
+ * Get the bound node
375
+ */
376
+ get node() {
377
+ return this.$.node;
378
+ }
379
+ /**
380
+ * Initialize node
381
+ */
382
+ $init() {
383
+ this.$createSignals();
384
+ this.$createWatchers();
385
+ this.$createAttrs();
386
+ this.$createStyle();
387
+ this.$created();
388
+ this.$compose();
389
+ this.$mounted();
390
+ return this;
391
+ }
392
+ /** To be overloaded: attributes creation milestone */
393
+ $createAttrs() {
394
+ // empty
395
+ }
396
+ /** To be overloaded: $style attributes creation milestone */
397
+ $createStyle() {
398
+ // empty
399
+ }
400
+ /**
401
+ * Bind attribute value
402
+ * @param name {String} name of attribute
403
+ * @param value {IValue} value
404
+ */
405
+ $attr(name, value) {
406
+ const $ = this.$;
407
+ const attr = new AttributeBinding(this, name, value);
408
+ $.bindings.add(attr);
409
+ return this;
410
+ }
411
+ $bindAttr(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
412
+ const $ = this.$;
413
+ const expr = this.$bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
414
+ $.bindings.add(new AttributeBinding(this, name, expr));
415
+ return this;
416
+ }
417
+ /**
418
+ * Set attribute value
419
+ * @param name {string} name of attribute
420
+ * @param value {string} value
421
+ */
422
+ $setAttr(name, value) {
423
+ this.$.app.$run.setAttribute(this.$.node, name, value);
424
+ return this;
425
+ }
426
+ /**
427
+ * Adds a CSS class
428
+ * @param cl {string} Class name
429
+ */
430
+ $addClass(cl) {
431
+ this.$.app.$run.addClass(this.$.node, cl);
432
+ return this;
433
+ }
434
+ /**
435
+ * Adds some CSS classes
436
+ * @param cls {...string} classes names
437
+ */
438
+ $addClasses(...cls) {
439
+ cls.forEach(cl => {
440
+ this.$.app.$run.addClass(this.$.node, cl);
441
+ });
442
+ return this;
443
+ }
444
+ /**
445
+ * Bind a CSS class
446
+ * @param className {IValue}
447
+ */
448
+ $bindClass(className) {
449
+ const $ = this.$;
450
+ $.bindings.add(new ClassBinding(this, "", className));
451
+ return this;
452
+ }
453
+ /**
454
+ * Bind a floating class name
455
+ * @param cond {IValue} condition
456
+ * @param className {string} class name
457
+ */
458
+ $floatingClass(cond, className) {
459
+ this.$.bindings.add(new ClassBinding(this, className, cond));
460
+ return this;
461
+ }
462
+ /**
463
+ * Defines a style attribute
464
+ * @param name {String} name of style attribute
465
+ * @param value {IValue} value
466
+ */
467
+ $style(name, value) {
468
+ const $ = this.$;
469
+ if ($.node instanceof HTMLElement) {
470
+ $.bindings.add(new StyleBinding(this, name, value));
471
+ }
472
+ else {
473
+ throw userError('style can be applied to HTML elements only', 'non-html-element');
474
+ }
475
+ return this;
476
+ }
477
+ $bindStyle(name, calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
478
+ const $ = this.$;
479
+ const expr = this.$bind(calculator, v1, v2, v3, v4, v5, v6, v7, v8, v9);
480
+ if ($.node instanceof HTMLElement) {
481
+ $.bindings.add(new StyleBinding(this, name, expr));
482
+ }
483
+ else {
484
+ throw userError('style can be applied to HTML elements only', 'non-html-element');
485
+ }
486
+ return this;
487
+ }
488
+ /**
489
+ * Sets a style property value
490
+ * @param prop {string} Property name
491
+ * @param value {string} Property value
492
+ */
493
+ $setStyle(prop, value) {
494
+ if (this.$.node instanceof HTMLElement) {
495
+ this.$.app.$run.setStyle(this.$.node, prop, value);
496
+ }
497
+ else {
498
+ throw userError("Style can be setted for HTML elements only", "non-html-element");
499
+ }
500
+ return this;
501
+ }
502
+ /**
503
+ * Add a listener for an event
504
+ * @param name {string} Event name
505
+ * @param handler {function (Event)} Event handler
506
+ * @param options {Object | boolean} addEventListener options
507
+ */
508
+ $listen(name, handler, options) {
509
+ this.$.node.addEventListener(name, handler, options);
510
+ return this;
511
+ }
512
+ /**
513
+ * @param handler {function (MouseEvent)}
514
+ * @param options {Object | boolean}
515
+ */
516
+ $oncontextmenu(handler, options) {
517
+ return this.$listen("contextmenu", handler, options);
518
+ }
519
+ /**
520
+ * @param handler {function (MouseEvent)}
521
+ * @param options {Object | boolean}
522
+ */
523
+ $onmousedown(handler, options) {
524
+ return this.$listen("mousedown", handler, options);
525
+ }
526
+ /**
527
+ * @param handler {function (MouseEvent)}
528
+ * @param options {Object | boolean}
529
+ */
530
+ $onmouseenter(handler, options) {
531
+ return this.$listen("mouseenter", handler, options);
532
+ }
533
+ /**
534
+ * @param handler {function (MouseEvent)}
535
+ * @param options {Object | boolean}
536
+ */
537
+ $onmouseleave(handler, options) {
538
+ return this.$listen("mouseleave", handler, options);
539
+ }
540
+ /**
541
+ * @param handler {function (MouseEvent)}
542
+ * @param options {Object | boolean}
543
+ */
544
+ $onmousemove(handler, options) {
545
+ return this.$listen("mousemove", handler, options);
546
+ }
547
+ /**
548
+ * @param handler {function (MouseEvent)}
549
+ * @param options {Object | boolean}
550
+ */
551
+ $onmouseout(handler, options) {
552
+ return this.$listen("mouseout", handler, options);
553
+ }
554
+ /**
555
+ * @param handler {function (MouseEvent)}
556
+ * @param options {Object | boolean}
557
+ */
558
+ $onmouseover(handler, options) {
559
+ return this.$listen("mouseover", handler, options);
560
+ }
561
+ /**
562
+ * @param handler {function (MouseEvent)}
563
+ * @param options {Object | boolean}
564
+ */
565
+ $onmouseup(handler, options) {
566
+ return this.$listen("mouseup", handler, options);
567
+ }
568
+ /**
569
+ * @param handler {function (MouseEvent)}
570
+ * @param options {Object | boolean}
571
+ */
572
+ $onclick(handler, options) {
573
+ return this.$listen("click", handler, options);
574
+ }
575
+ /**
576
+ * @param handler {function (MouseEvent)}
577
+ * @param options {Object | boolean}
578
+ */
579
+ $ondblclick(handler, options) {
580
+ return this.$listen("dblclick", handler, options);
581
+ }
582
+ /**
583
+ * @param handler {function (FocusEvent)}
584
+ * @param options {Object | boolean}
585
+ */
586
+ $onblur(handler, options) {
587
+ return this.$listen("blur", handler, options);
588
+ }
589
+ /**
590
+ * @param handler {function (FocusEvent)}
591
+ * @param options {Object | boolean}
592
+ */
593
+ $onfocus(handler, options) {
594
+ return this.$listen("focus", handler, options);
595
+ }
596
+ /**
597
+ * @param handler {function (FocusEvent)}
598
+ * @param options {Object | boolean}
599
+ */
600
+ $onfocusin(handler, options) {
601
+ return this.$listen("focusin", handler, options);
602
+ }
603
+ /**
604
+ * @param handler {function (FocusEvent)}
605
+ * @param options {Object | boolean}
606
+ */
607
+ $onfocusout(handler, options) {
608
+ return this.$listen("focusout", handler, options);
609
+ }
610
+ /**
611
+ * @param handler {function (KeyboardEvent)}
612
+ * @param options {Object | boolean}
613
+ */
614
+ $onkeydown(handler, options) {
615
+ return this.$listen("keydown", handler, options);
616
+ }
617
+ /**
618
+ * @param handler {function (KeyboardEvent)}
619
+ * @param options {Object | boolean}
620
+ */
621
+ $onkeyup(handler, options) {
622
+ return this.$listen("keyup", handler, options);
623
+ }
624
+ /**
625
+ * @param handler {function (KeyboardEvent)}
626
+ * @param options {Object | boolean}
627
+ */
628
+ $onkeypress(handler, options) {
629
+ return this.$listen("keypress", handler, options);
630
+ }
631
+ /**
632
+ * @param handler {function (TouchEvent)}
633
+ * @param options {Object | boolean}
634
+ */
635
+ $ontouchstart(handler, options) {
636
+ return this.$listen("touchstart", handler, options);
637
+ }
638
+ /**
639
+ * @param handler {function (TouchEvent)}
640
+ * @param options {Object | boolean}
641
+ */
642
+ $ontouchmove(handler, options) {
643
+ return this.$listen("touchmove", handler, options);
644
+ }
645
+ /**
646
+ * @param handler {function (TouchEvent)}
647
+ * @param options {Object | boolean}
648
+ */
649
+ $ontouchend(handler, options) {
650
+ return this.$listen("touchend", handler, options);
651
+ }
652
+ /**
653
+ * @param handler {function (TouchEvent)}
654
+ * @param options {Object | boolean}
655
+ */
656
+ $ontouchcancel(handler, options) {
657
+ return this.$listen("touchcancel", handler, options);
658
+ }
659
+ /**
660
+ * @param handler {function (WheelEvent)}
661
+ * @param options {Object | boolean}
662
+ */
663
+ $onwheel(handler, options) {
664
+ return this.$listen("wheel", handler, options);
665
+ }
666
+ /**
667
+ * @param handler {function (ProgressEvent)}
668
+ * @param options {Object | boolean}
669
+ */
670
+ $onabort(handler, options) {
671
+ return this.$listen("abort", handler, options);
672
+ }
673
+ /**
674
+ * @param handler {function (ProgressEvent)}
675
+ * @param options {Object | boolean}
676
+ */
677
+ $onerror(handler, options) {
678
+ return this.$listen("error", handler, options);
679
+ }
680
+ /**
681
+ * @param handler {function (ProgressEvent)}
682
+ * @param options {Object | boolean}
683
+ */
684
+ $onload(handler, options) {
685
+ return this.$listen("load", handler, options);
686
+ }
687
+ /**
688
+ * @param handler {function (ProgressEvent)}
689
+ * @param options {Object | boolean}
690
+ */
691
+ $onloadend(handler, options) {
692
+ return this.$listen("loadend", handler, options);
693
+ }
694
+ /**
695
+ * @param handler {function (ProgressEvent)}
696
+ * @param options {Object | boolean}
697
+ */
698
+ $onloadstart(handler, options) {
699
+ return this.$listen("loadstart", handler, options);
700
+ }
701
+ /**
702
+ * @param handler {function (ProgressEvent)}
703
+ * @param options {Object | boolean}
704
+ */
705
+ $onprogress(handler, options) {
706
+ return this.$listen("progress", handler, options);
707
+ }
708
+ /**
709
+ * @param handler {function (ProgressEvent)}
710
+ * @param options {Object | boolean}
711
+ */
712
+ $ontimeout(handler, options) {
713
+ return this.$listen("timeout", handler, options);
714
+ }
715
+ /**
716
+ * @param handler {function (DragEvent)}
717
+ * @param options {Object | boolean}
718
+ */
719
+ $ondrag(handler, options) {
720
+ return this.$listen("drag", handler, options);
721
+ }
722
+ /**
723
+ * @param handler {function (DragEvent)}
724
+ * @param options {Object | boolean}
725
+ */
726
+ $ondragend(handler, options) {
727
+ return this.$listen("dragend", handler, options);
728
+ }
729
+ /**
730
+ * @param handler {function (DragEvent)}
731
+ * @param options {Object | boolean}
732
+ */
733
+ $ondragenter(handler, options) {
734
+ return this.$listen("dragenter", handler, options);
735
+ }
736
+ /**
737
+ * @param handler {function (DragEvent)}
738
+ * @param options {Object | boolean}
739
+ */
740
+ $ondragexit(handler, options) {
741
+ return this.$listen("dragexit", handler, options);
742
+ }
743
+ /**
744
+ * @param handler {function (DragEvent)}
745
+ * @param options {Object | boolean}
746
+ */
747
+ $ondragleave(handler, options) {
748
+ return this.$listen("dragleave", handler, options);
749
+ }
750
+ /**
751
+ * @param handler {function (DragEvent)}
752
+ * @param options {Object | boolean}
753
+ */
754
+ $ondragover(handler, options) {
755
+ return this.$listen("dragover", handler, options);
756
+ }
757
+ /**
758
+ * @param handler {function (DragEvent)}
759
+ * @param options {Object | boolean}
760
+ */
761
+ $ondragstart(handler, options) {
762
+ return this.$listen("dragstart", handler, options);
763
+ }
764
+ /**
765
+ * @param handler {function (DragEvent)}
766
+ * @param options {Object | boolean}
767
+ */
768
+ $ondrop(handler, options) {
769
+ return this.$listen("drop", handler, options);
770
+ }
771
+ /**
772
+ * @param handler {function (PointerEvent)}
773
+ * @param options {Object | boolean}
774
+ */
775
+ $onpointerover(handler, options) {
776
+ return this.$listen("pointerover", handler, options);
777
+ }
778
+ /**
779
+ * @param handler {function (PointerEvent)}
780
+ * @param options {Object | boolean}
781
+ */
782
+ $onpointerenter(handler, options) {
783
+ return this.$listen("pointerenter", handler, options);
784
+ }
785
+ /**
786
+ * @param handler {function (PointerEvent)}
787
+ * @param options {Object | boolean}
788
+ */
789
+ $onpointerdown(handler, options) {
790
+ return this.$listen("pointerdown", handler, options);
791
+ }
792
+ /**
793
+ * @param handler {function (PointerEvent)}
794
+ * @param options {Object | boolean}
795
+ */
796
+ $onpointermove(handler, options) {
797
+ return this.$listen("pointermove", handler, options);
798
+ }
799
+ /**
800
+ * @param handler {function (PointerEvent)}
801
+ * @param options {Object | boolean}
802
+ */
803
+ $onpointerup(handler, options) {
804
+ return this.$listen("pointerup", handler, options);
805
+ }
806
+ /**
807
+ * @param handler {function (PointerEvent)}
808
+ * @param options {Object | boolean}
809
+ */
810
+ $onpointercancel(handler, options) {
811
+ return this.$listen("pointercancel", handler, options);
812
+ }
813
+ /**
814
+ * @param handler {function (PointerEvent)}
815
+ * @param options {Object | boolean}
816
+ */
817
+ $onpointerout(handler, options) {
818
+ return this.$listen("pointerout", handler, options);
819
+ }
820
+ /**
821
+ * @param handler {function (PointerEvent)}
822
+ * @param options {Object | boolean}
823
+ */
824
+ $onpointerleave(handler, options) {
825
+ return this.$listen("pointerleave", handler, options);
826
+ }
827
+ /**
828
+ * @param handler {function (PointerEvent)}
829
+ * @param options {Object | boolean}
830
+ */
831
+ $ongotpointercapture(handler, options) {
832
+ return this.$listen("gotpointercapture", handler, options);
833
+ }
834
+ /**
835
+ * @param handler {function (PointerEvent)}
836
+ * @param options {Object | boolean}
837
+ */
838
+ $onlostpointercapture(handler, options) {
839
+ return this.$listen("lostpointercapture", handler, options);
840
+ }
841
+ /**
842
+ * @param handler {function (AnimationEvent)}
843
+ * @param options {Object | boolean}
844
+ */
845
+ $onanimationstart(handler, options) {
846
+ return this.$listen("animationstart", handler, options);
847
+ }
848
+ /**
849
+ * @param handler {function (AnimationEvent)}
850
+ * @param options {Object | boolean}
851
+ */
852
+ $onanimationend(handler, options) {
853
+ return this.$listen("animationend", handler, options);
854
+ }
855
+ /**
856
+ * @param handler {function (AnimationEvent)}
857
+ * @param options {Object | boolean}
858
+ */
859
+ $onanimationiteraton(handler, options) {
860
+ return this.$listen("animationiteration", handler, options);
861
+ }
862
+ /**
863
+ * @param handler {function (ClipboardEvent)}
864
+ * @param options {Object | boolean}
865
+ */
866
+ $onclipboardchange(handler, options) {
867
+ return this.$listen("clipboardchange", handler, options);
868
+ }
869
+ /**
870
+ * @param handler {function (ClipboardEvent)}
871
+ * @param options {Object | boolean}
872
+ */
873
+ $oncut(handler, options) {
874
+ return this.$listen("cut", handler, options);
875
+ }
876
+ /**
877
+ * @param handler {function (ClipboardEvent)}
878
+ * @param options {Object | boolean}
879
+ */
880
+ $oncopy(handler, options) {
881
+ return this.$listen("copy", handler, options);
882
+ }
883
+ /**
884
+ * @param handler {function (ClipboardEvent)}
885
+ * @param options {Object | boolean}
886
+ */
887
+ $onpaste(handler, options) {
888
+ return this.$listen("paste", handler, options);
889
+ }
890
+ $$insertAdjacent(node) {
891
+ const $ = this.$;
892
+ $.app.$run.insertBefore($.node, node);
893
+ }
894
+ /**
895
+ * A v-show & ngShow alternative
896
+ * @param cond {IValue} show condition
897
+ */
898
+ $bindShow(cond) {
899
+ const $ = this.$;
900
+ const node = $.node;
901
+ if (node instanceof HTMLElement) {
902
+ let lastDisplay = node.style.display;
903
+ const htmlNode = node;
904
+ return this.$bindAlive(cond, () => {
905
+ lastDisplay = htmlNode.style.display;
906
+ htmlNode.style.display = 'none';
907
+ }, () => {
908
+ htmlNode.style.display = lastDisplay;
909
+ });
910
+ }
911
+ else {
912
+ throw userError('the element must be a html element', 'bind-show');
913
+ }
914
+ }
915
+ /**
916
+ * bind HTML
917
+ * @param value {IValue}
918
+ */
919
+ $html(value) {
920
+ const $ = this.$;
921
+ const node = $.node;
922
+ if (node instanceof HTMLElement) {
923
+ node.innerHTML = value.$;
924
+ this.$watch((v) => {
925
+ node.innerHTML = v;
926
+ }, value);
927
+ }
928
+ else {
929
+ throw userError("HTML can be bound for HTML nodes only", "dom-error");
930
+ }
931
+ }
932
+ }
933
+ /**
934
+ * Represents an Vasille.js HTML element node
935
+ * @class Tag
936
+ * @extends INode
937
+ */
938
+ export class Tag extends INode {
939
+ constructor() {
940
+ super();
941
+ this.$seal();
942
+ }
943
+ $preinit(app, parent, tagName) {
944
+ if (!tagName || typeof tagName !== "string") {
945
+ throw internalError('wrong Tag::$preinit call');
946
+ }
947
+ const node = document.createElement(tagName);
948
+ const $ = this.$;
949
+ $.preinit(app, parent);
950
+ $.node = node;
951
+ $.parent.$$appendNode(node);
952
+ }
953
+ $$findFirstChild() {
954
+ return this.$.unmounted ? null : this.$.node;
955
+ }
956
+ $$insertAdjacent(node) {
957
+ if (this.$.unmounted) {
958
+ if (this.$.next) {
959
+ this.$.next.$$insertAdjacent(node);
960
+ }
961
+ else {
962
+ this.$.parent.$$appendNode(node);
963
+ }
964
+ }
965
+ else {
966
+ super.$$insertAdjacent(node);
967
+ }
968
+ }
969
+ $$appendNode(node) {
970
+ const $ = this.$;
971
+ $.app.$run.appendChild($.node, node);
972
+ }
973
+ /**
974
+ * Mount/Unmount a node
975
+ * @param cond {IValue} show condition
976
+ */
977
+ $bindMount(cond) {
978
+ const $ = this.$;
979
+ return this.$bindAlive(cond, () => {
980
+ $.node.remove();
981
+ $.unmounted = true;
982
+ }, () => {
983
+ if (!$.unmounted)
984
+ return;
985
+ if ($.next) {
986
+ $.next.$$insertAdjacent($.node);
987
+ }
988
+ else {
989
+ $.parent.$$appendNode($.node);
990
+ }
991
+ $.unmounted = false;
992
+ });
993
+ }
994
+ /**
995
+ * Runs GC
996
+ */
997
+ $destroy() {
998
+ this.node.remove();
999
+ super.$destroy();
1000
+ }
1001
+ }
1002
+ /**
1003
+ * Represents a vasille extension node
1004
+ * @class Extension
1005
+ * @extends INode
1006
+ */
1007
+ export class Extension extends INode {
1008
+ $preinit(app, parent) {
1009
+ if (parent instanceof INode) {
1010
+ const $ = this.$;
1011
+ $.preinit(app, parent);
1012
+ $.node = parent.node;
1013
+ }
1014
+ else {
1015
+ throw internalError("A extension node can be encapsulated only in a tag/extension/component");
1016
+ }
1017
+ }
1018
+ constructor($) {
1019
+ super($);
1020
+ this.$seal();
1021
+ }
1022
+ $destroy() {
1023
+ super.$destroy();
1024
+ }
1025
+ }
1026
+ /**
1027
+ * Node which cas has just a child
1028
+ * @class Component
1029
+ * @extends Extension
1030
+ */
1031
+ export class Component extends Extension {
1032
+ constructor() {
1033
+ super();
1034
+ this.$seal();
1035
+ }
1036
+ $mounted() {
1037
+ super.$mounted();
1038
+ if (this.$children.length !== 1) {
1039
+ throw userError("UserNode must have a child only", "dom-error");
1040
+ }
1041
+ const child = this.$children[0];
1042
+ if (child instanceof Tag || child instanceof Component) {
1043
+ const $ = this.$;
1044
+ $.node = child.node;
1045
+ }
1046
+ else {
1047
+ throw userError("UserNode child must be Tag or Component", "dom-error");
1048
+ }
1049
+ }
1050
+ }
1051
+ /**
1052
+ * Private part of switch node
1053
+ * @class SwitchedNodePrivate
1054
+ * @extends INodePrivate
1055
+ */
1056
+ export class SwitchedNodePrivate extends INodePrivate {
1057
+ constructor() {
1058
+ super();
1059
+ this.$seal();
1060
+ }
1061
+ /**
1062
+ * Runs GC
1063
+ */
1064
+ $destroy() {
1065
+ this.cases.forEach(c => {
1066
+ delete c.cond;
1067
+ delete c.cb;
1068
+ });
1069
+ this.cases.splice(0);
1070
+ super.$destroy();
1071
+ }
1072
+ }
1073
+ /**
1074
+ * Defines a node witch can switch its children conditionally
1075
+ */
1076
+ class SwitchedNode extends Fragment {
1077
+ /**
1078
+ * Constructs a switch node and define a sync function
1079
+ */
1080
+ constructor() {
1081
+ super(new SwitchedNodePrivate);
1082
+ this.$.sync = () => {
1083
+ const $ = this.$;
1084
+ let i = 0;
1085
+ for (; i < $.cases.length; i++) {
1086
+ if ($.cases[i].cond.$) {
1087
+ break;
1088
+ }
1089
+ }
1090
+ if (i === $.index) {
1091
+ return;
1092
+ }
1093
+ if ($.fragment) {
1094
+ $.fragment.$destroy();
1095
+ this.$children.splice(0);
1096
+ $.fragment = null;
1097
+ }
1098
+ if (i !== $.cases.length) {
1099
+ $.index = i;
1100
+ this.createChild($.cases[i].cb);
1101
+ }
1102
+ else {
1103
+ $.index = -1;
1104
+ }
1105
+ };
1106
+ this.$seal();
1107
+ }
1108
+ /**
1109
+ * Set up switch cases
1110
+ * @param cases {{ cond : IValue, cb : function(Fragment) }}
1111
+ */
1112
+ setCases(cases) {
1113
+ const $ = this.$;
1114
+ $.cases = [...cases];
1115
+ }
1116
+ /**
1117
+ * Creates a child node
1118
+ * @param cb {function(Fragment)} Call-back
1119
+ */
1120
+ createChild(cb) {
1121
+ const node = new Fragment();
1122
+ node.$preinit(this.$.app, this);
1123
+ node.$init();
1124
+ node.$ready();
1125
+ this.$.fragment = node;
1126
+ this.$children.push(node);
1127
+ cb(node);
1128
+ }
1129
+ $ready() {
1130
+ const $ = this.$;
1131
+ super.$ready();
1132
+ $.cases.forEach(c => {
1133
+ c.cond.on($.sync);
1134
+ });
1135
+ $.sync();
1136
+ }
1137
+ $destroy() {
1138
+ const $ = this.$;
1139
+ $.cases.forEach(c => {
1140
+ c.cond.off($.sync);
1141
+ });
1142
+ super.$destroy();
1143
+ }
1144
+ }
1145
+ /**
1146
+ * The private part of a text node
1147
+ */
1148
+ export class DebugPrivate extends FragmentPrivate {
1149
+ constructor() {
1150
+ super();
1151
+ this.$seal();
1152
+ }
1153
+ /**
1154
+ * Pre-initializes a text node
1155
+ * @param app {App} the app node
1156
+ * @param parent {Fragment} parent node
1157
+ * @param text {String | IValue}
1158
+ */
1159
+ preinitComment(app, parent, text) {
1160
+ super.preinit(app, parent);
1161
+ this.node = document.createComment(text.$);
1162
+ this.bindings.add(new Expression((v) => {
1163
+ this.node.replaceData(0, -1, v);
1164
+ }, true, text));
1165
+ this.parent.$$appendNode(this.node);
1166
+ }
1167
+ /**
1168
+ * Clear node data
1169
+ */
1170
+ $destroy() {
1171
+ this.node.remove();
1172
+ super.$destroy();
1173
+ }
1174
+ }
1175
+ /**
1176
+ * Represents a debug node
1177
+ * @class DebugNode
1178
+ * @extends Fragment
1179
+ */
1180
+ export class DebugNode extends Fragment {
1181
+ constructor() {
1182
+ super();
1183
+ /**
1184
+ * private data
1185
+ * @type {DebugNode}
1186
+ */
1187
+ this.$ = new DebugPrivate();
1188
+ this.$seal();
1189
+ }
1190
+ $preinit(app, parent, text) {
1191
+ const $ = this.$;
1192
+ if (!text) {
1193
+ throw internalError('wrong DebugNode::$preninit call');
1194
+ }
1195
+ $.preinitComment(app, parent, text);
1196
+ }
1197
+ /**
1198
+ * Runs garbage collector
1199
+ */
1200
+ $destroy() {
1201
+ this.$.$destroy();
1202
+ super.$destroy();
1203
+ }
1204
+ }