vsn 0.1.23 → 0.1.27
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.
- package/demo/demo.html +16 -7
- package/demo/vsn.js +1 -0
- package/dist/AST.d.ts +2 -1
- package/dist/AST.js +94 -4
- package/dist/AST.js.map +1 -1
- package/dist/Attribute.d.ts +1 -1
- package/dist/Attribute.js +3 -3
- package/dist/Attribute.js.map +1 -1
- package/dist/Configuration.d.ts +1 -1
- package/dist/Configuration.js +4 -4
- package/dist/Configuration.js.map +1 -1
- package/dist/Controller.d.ts +10 -5
- package/dist/Controller.js +21 -6
- package/dist/Controller.js.map +1 -1
- package/dist/DOM/DOMObject.d.ts +1 -1
- package/dist/DOM/DOMObject.js +2 -2
- package/dist/DOM/DOMObject.js.map +1 -1
- package/dist/DOM.d.ts +1 -1
- package/dist/DOM.js +4 -4
- package/dist/DOM.js.map +1 -1
- package/dist/EventDispatcher.d.ts +26 -0
- package/dist/EventDispatcher.js +117 -0
- package/dist/EventDispatcher.js.map +1 -0
- package/dist/Formats.js +2 -2
- package/dist/Formats.js.map +1 -1
- package/dist/MessageList.d.ts +14 -0
- package/dist/MessageList.js +88 -0
- package/dist/MessageList.js.map +1 -0
- package/dist/Model/Collection.d.ts +5 -0
- package/dist/Model/Collection.js +37 -0
- package/dist/Model/Collection.js.map +1 -0
- package/dist/Model/DataModel.d.ts +6 -0
- package/dist/Model/DataModel.js +54 -0
- package/dist/Model/DataModel.js.map +1 -0
- package/dist/Model/ModelAbstract.d.ts +20 -0
- package/dist/Model/ModelAbstract.js +122 -0
- package/dist/Model/ModelAbstract.js.map +1 -0
- package/dist/Model/fields/BooleanField.d.ts +5 -0
- package/dist/Model/fields/BooleanField.js +43 -0
- package/dist/Model/fields/BooleanField.js.map +1 -0
- package/dist/Model/fields/EmailField.d.ts +5 -0
- package/dist/Model/fields/EmailField.js +36 -0
- package/dist/Model/fields/EmailField.js.map +1 -0
- package/dist/Model/fields/Field.d.ts +13 -0
- package/dist/Model/fields/Field.js +79 -0
- package/dist/Model/fields/Field.js.map +1 -0
- package/dist/Model/fields/FloatField.d.ts +5 -0
- package/dist/Model/fields/FloatField.js +47 -0
- package/dist/Model/fields/FloatField.js.map +1 -0
- package/dist/Model/fields/PositiveNumberField.d.ts +5 -0
- package/dist/Model/fields/PositiveNumberField.js +51 -0
- package/dist/Model/fields/PositiveNumberField.js.map +1 -0
- package/dist/Model/fields/StringField.d.ts +5 -0
- package/dist/Model/fields/StringField.js +43 -0
- package/dist/Model/fields/StringField.js.map +1 -0
- package/dist/Model.d.ts +11 -0
- package/dist/Model.js +72 -0
- package/dist/Model.js.map +1 -0
- package/dist/Registry.d.ts +2 -2
- package/dist/Registry.js +6 -16
- package/dist/Registry.js.map +1 -1
- package/dist/Scope.d.ts +7 -10
- package/dist/Scope.js +40 -90
- package/dist/Scope.js.map +1 -1
- package/dist/SimplePromise.d.ts +42 -0
- package/dist/SimplePromise.js +217 -0
- package/dist/SimplePromise.js.map +1 -0
- package/dist/Tag.js +12 -6
- package/dist/Tag.js.map +1 -1
- package/dist/attributes/Bind.js +1 -1
- package/dist/attributes/Bind.js.map +1 -1
- package/dist/attributes/ClickRemoveClass.js +17 -5
- package/dist/attributes/ClickRemoveClass.js.map +1 -1
- package/dist/attributes/ClickToggleClass.js +17 -5
- package/dist/attributes/ClickToggleClass.js.map +1 -1
- package/dist/attributes/Exec.js +6 -0
- package/dist/attributes/Exec.js.map +1 -1
- package/dist/attributes/Format.js +3 -0
- package/dist/attributes/Format.js.map +1 -1
- package/dist/attributes/If.js +12 -0
- package/dist/attributes/If.js.map +1 -1
- package/dist/attributes/JSONAttribute.js +3 -0
- package/dist/attributes/JSONAttribute.js.map +1 -1
- package/dist/attributes/KeyAbstract.js +11 -4
- package/dist/attributes/KeyAbstract.js.map +1 -1
- package/dist/attributes/KeyDown.js +8 -2
- package/dist/attributes/KeyDown.js.map +1 -1
- package/dist/attributes/KeyUp.js +8 -2
- package/dist/attributes/KeyUp.js.map +1 -1
- package/dist/attributes/List.js +14 -5
- package/dist/attributes/List.js.map +1 -1
- package/dist/attributes/ListItem.js +3 -0
- package/dist/attributes/ListItem.js.map +1 -1
- package/dist/attributes/On.js +15 -3
- package/dist/attributes/On.js.map +1 -1
- package/dist/attributes/Radio.d.ts +2 -0
- package/dist/attributes/Radio.js +52 -5
- package/dist/attributes/Radio.js.map +1 -1
- package/dist/attributes/RootAttribute.js +8 -2
- package/dist/attributes/RootAttribute.js.map +1 -1
- package/dist/attributes/ScopeChange.js +7 -1
- package/dist/attributes/ScopeChange.js.map +1 -1
- package/dist/attributes/SetAttribute.js +3 -0
- package/dist/attributes/SetAttribute.js.map +1 -1
- package/dist/attributes/StandardAttribute.js +25 -7
- package/dist/attributes/StandardAttribute.js.map +1 -1
- package/dist/attributes/StyleAttribute.js +1 -1
- package/dist/attributes/StyleAttribute.js.map +1 -1
- package/dist/attributes/TypeAttribute.js +3 -0
- package/dist/attributes/TypeAttribute.js.map +1 -1
- package/dist/{Vision.d.ts → vsn.d.ts} +3 -1
- package/dist/{Vision.js → vsn.js} +10 -6
- package/dist/vsn.js.map +1 -0
- package/package.json +9 -13
- package/src/AST.ts +96 -5
- package/src/Attribute.ts +2 -2
- package/src/Configuration.ts +3 -3
- package/src/Controller.ts +16 -7
- package/src/DOM/DOMObject.ts +1 -1
- package/src/DOM.ts +4 -4
- package/src/EventDispatcher.ts +117 -0
- package/src/Formats.ts +2 -2
- package/src/MessageList.ts +81 -0
- package/src/Model/Collection.ts +13 -0
- package/src/Model/DataModel.ts +29 -0
- package/src/Model/ModelAbstract.ts +114 -0
- package/src/Model/fields/BooleanField.ts +16 -0
- package/src/Model/fields/EmailField.ts +12 -0
- package/src/Model/fields/Field.ts +65 -0
- package/src/Model/fields/FloatField.ts +22 -0
- package/src/Model/fields/PositiveNumberField.ts +24 -0
- package/src/Model/fields/StringField.ts +16 -0
- package/src/Model.ts +57 -0
- package/src/Registry.ts +3 -5
- package/src/Scope.ts +39 -90
- package/src/SimplePromise.ts +219 -0
- package/src/Tag.ts +12 -9
- package/src/attributes/Bind.ts +1 -1
- package/src/attributes/ClickRemoveClass.ts +2 -0
- package/src/attributes/ClickToggleClass.ts +2 -0
- package/src/attributes/Exec.ts +2 -0
- package/src/attributes/Format.ts +1 -0
- package/src/attributes/If.ts +4 -0
- package/src/attributes/JSONAttribute.ts +1 -0
- package/src/attributes/KeyAbstract.ts +2 -1
- package/src/attributes/KeyDown.ts +1 -0
- package/src/attributes/KeyUp.ts +1 -0
- package/src/attributes/List.ts +6 -3
- package/src/attributes/ListItem.ts +1 -0
- package/src/attributes/On.ts +4 -0
- package/src/attributes/Radio.ts +18 -3
- package/src/attributes/RootAttribute.ts +1 -0
- package/src/attributes/ScopeChange.ts +3 -1
- package/src/attributes/SetAttribute.ts +1 -0
- package/src/attributes/StandardAttribute.ts +4 -1
- package/src/attributes/StyleAttribute.ts +1 -1
- package/src/attributes/TypeAttribute.ts +1 -0
- package/src/{Vision.ts → vsn.ts} +4 -2
- package/test/AST.spec.ts +2 -1
- package/test/DOM.spec.ts +1 -1
- package/test/MessageList.spec.ts +101 -0
- package/test/Model/DataModel.spec.ts +141 -0
- package/test/Model.spec.ts +306 -0
- package/test/Scope.spec.ts +2 -2
- package/test/SimplePromise.spec.ts +271 -0
- package/test/attributes/Bind.spec.ts +5 -5
- package/test/attributes/JSONAttribute.spec.ts +1 -1
- package/test/attributes/ListItem.spec.ts +1 -1
- package/webpack.config.js +2 -2
- package/demo/vision.js +0 -1
- package/dist/Vision.js.map +0 -1
- package/main.py +0 -16
package/src/Scope.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {DataModel} from "simple-ts-models";
|
|
2
|
-
import {EventCallback, EventCallbackList, EventDispatcher, EventDispatcherCallback} from "simple-ts-event-dispatcher";
|
|
3
1
|
import {Registry} from "./Registry";
|
|
4
2
|
import {DOM} from "./DOM";
|
|
3
|
+
import {EventDispatcher, EventDispatcherCallback} from "./EventDispatcher";
|
|
4
|
+
import {DataModel} from "./Model/DataModel";
|
|
5
|
+
import {Model} from "./Model";
|
|
5
6
|
|
|
6
7
|
export class ScopeReference {
|
|
7
8
|
private _scope: Scope;
|
|
@@ -64,26 +65,40 @@ export class ScopeVariableType {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
export class WrappedArray<T> extends Array<T> {
|
|
67
|
-
private
|
|
68
|
-
private _lastKey: number;
|
|
68
|
+
private dispatcher: EventDispatcher;
|
|
69
69
|
public readonly $wrapped: boolean = true;
|
|
70
70
|
|
|
71
71
|
constructor(...items: T[]) {
|
|
72
72
|
super(...items);
|
|
73
73
|
Object.setPrototypeOf(this, WrappedArray.prototype);
|
|
74
|
-
this.
|
|
75
|
-
|
|
74
|
+
this.dispatcher = new EventDispatcher();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
dispatch(event: string, ...args: any[]) {
|
|
78
|
+
this.dispatcher.dispatch(event, ...args);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
on(event: string, callback: EventDispatcherCallback) {
|
|
82
|
+
this.dispatcher.on(event, callback);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
off(event: string, key?: number) {
|
|
86
|
+
this.dispatcher.off(event, key);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
once(event: string, callback: EventDispatcherCallback) {
|
|
90
|
+
this.dispatcher.once(event, callback);
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
push(...items: T[]): number {
|
|
79
94
|
const num: number = super.push(...items);
|
|
80
95
|
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
96
|
+
this.dispatch('push', ...items);
|
|
97
|
+
this.dispatch('change', {
|
|
83
98
|
'added': items
|
|
84
99
|
});
|
|
85
100
|
for (const item of items) {
|
|
86
|
-
this.
|
|
101
|
+
this.dispatch('add', item);
|
|
87
102
|
}
|
|
88
103
|
return num;
|
|
89
104
|
}
|
|
@@ -91,11 +106,11 @@ export class WrappedArray<T> extends Array<T> {
|
|
|
91
106
|
splice(start: number, deleteCount?: number): T[] {
|
|
92
107
|
const removed: T[] = super.splice(start, deleteCount);
|
|
93
108
|
|
|
94
|
-
this.
|
|
109
|
+
this.dispatch('change', {
|
|
95
110
|
'removed': removed
|
|
96
111
|
});
|
|
97
112
|
for (const item of removed) {
|
|
98
|
-
this.
|
|
113
|
+
this.dispatch('remove', item);
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
return removed;
|
|
@@ -134,77 +149,6 @@ export class WrappedArray<T> extends Array<T> {
|
|
|
134
149
|
this.splice(this.indexOf(item), 1);
|
|
135
150
|
}
|
|
136
151
|
}
|
|
137
|
-
|
|
138
|
-
bind(event: string, fct: EventDispatcherCallback, context?: any, once?: boolean): number {
|
|
139
|
-
once = once || false;
|
|
140
|
-
this._lastKey++;
|
|
141
|
-
this._listeners[event] = this._listeners[event] || [];
|
|
142
|
-
this._listeners[event].push(new EventCallback(fct, this._lastKey, once, context));
|
|
143
|
-
return this._lastKey;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
once(event: string, fct: EventDispatcherCallback, context?: any): number {
|
|
147
|
-
return this.bind(event, fct, context, true);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
unbind(event: string, key?: number): boolean {
|
|
151
|
-
if(!(event in this._listeners)) return false;
|
|
152
|
-
if(key) {
|
|
153
|
-
for(const cb of this._listeners[event]) {
|
|
154
|
-
if(key == cb.key) {
|
|
155
|
-
this._listeners[event].splice(this._listeners[event].indexOf(cb), 1);
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
this._listeners[event] = [];
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
unbindWithContext(event: string, context: any): number {
|
|
167
|
-
if(!(event in this._listeners)) return 0;
|
|
168
|
-
let toRemove: EventCallback[] = [],
|
|
169
|
-
cnt = 0;
|
|
170
|
-
|
|
171
|
-
for(const cb of this._listeners[event]) {
|
|
172
|
-
if(context == cb.context) {
|
|
173
|
-
toRemove.push(cb);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
for(const cb of toRemove) {
|
|
178
|
-
this._listeners[event].splice(this._listeners[event].indexOf(cb), 1);
|
|
179
|
-
cnt++;
|
|
180
|
-
}
|
|
181
|
-
return cnt;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
getListener(event: string, key: number): EventCallback | undefined {
|
|
185
|
-
for(const cb of this._listeners[event]) {
|
|
186
|
-
if(key == cb.key)
|
|
187
|
-
return cb;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
trigger(event: string, ...args: any[]): void {
|
|
192
|
-
if(!(event in this._listeners)) return;
|
|
193
|
-
|
|
194
|
-
for(let i = 0; i < this._listeners[event].length; i++) {
|
|
195
|
-
const cb: EventCallback = this._listeners[event][i];
|
|
196
|
-
|
|
197
|
-
// We need to unbind callbacks before they're called to prevent
|
|
198
|
-
// infinite loops if the event is somehow triggered within the
|
|
199
|
-
// callback
|
|
200
|
-
if(cb.once) {
|
|
201
|
-
this.unbind(event, cb.key);
|
|
202
|
-
i--;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
cb.call(args);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
152
|
}
|
|
209
153
|
|
|
210
154
|
export class Scope extends EventDispatcher {
|
|
@@ -276,7 +220,7 @@ export class Scope extends EventDispatcher {
|
|
|
276
220
|
if (searchParents && this.parentScope)
|
|
277
221
|
return this.parentScope.get(key, searchParents);
|
|
278
222
|
|
|
279
|
-
return
|
|
223
|
+
return '';
|
|
280
224
|
}
|
|
281
225
|
|
|
282
226
|
return value;
|
|
@@ -307,8 +251,8 @@ export class Scope extends EventDispatcher {
|
|
|
307
251
|
key: key
|
|
308
252
|
};
|
|
309
253
|
|
|
310
|
-
this.
|
|
311
|
-
this.
|
|
254
|
+
this.dispatch(`change:${key}`, event);
|
|
255
|
+
this.dispatch('change', key, event);
|
|
312
256
|
}
|
|
313
257
|
|
|
314
258
|
if (this._keys.indexOf(key) === -1)
|
|
@@ -352,6 +296,11 @@ export class Scope extends EventDispatcher {
|
|
|
352
296
|
}
|
|
353
297
|
|
|
354
298
|
public wrap(toWrap: any, triggerUpdates: boolean = false, updateFromWrapped: boolean = true) {
|
|
299
|
+
if (toWrap instanceof Model) {
|
|
300
|
+
this.data = toWrap;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
355
304
|
if (toWrap instanceof Scope)
|
|
356
305
|
toWrap = toWrap.data;
|
|
357
306
|
|
|
@@ -381,8 +330,8 @@ export class Scope extends EventDispatcher {
|
|
|
381
330
|
if (!(this.wrapped[field] instanceof WrappedArray)) {
|
|
382
331
|
this.wrapped[field] = new WrappedArray(...toWrap[field]);
|
|
383
332
|
}
|
|
384
|
-
this.wrapped[field].
|
|
385
|
-
this.
|
|
333
|
+
this.wrapped[field].on('change', (...args) => {
|
|
334
|
+
this.dispatch(`change:${field}`, ...args);
|
|
386
335
|
})
|
|
387
336
|
}
|
|
388
337
|
|
|
@@ -413,14 +362,14 @@ export class Scope extends EventDispatcher {
|
|
|
413
362
|
});
|
|
414
363
|
|
|
415
364
|
if (triggerUpdates)
|
|
416
|
-
this.
|
|
365
|
+
this.dispatch(`change:${field}`);
|
|
417
366
|
}
|
|
418
367
|
|
|
419
368
|
this.wrapped.get = this.get.bind(this);
|
|
420
369
|
this.wrapped.set = this.set.bind(this);
|
|
421
|
-
this.wrapped.bind = this.
|
|
370
|
+
this.wrapped.bind = this.on.bind(this);
|
|
422
371
|
this.wrapped.once = this.once.bind(this);
|
|
423
|
-
this.wrapped.unbind = this.
|
|
372
|
+
this.wrapped.unbind = this.off.bind(this);
|
|
424
373
|
}
|
|
425
374
|
|
|
426
375
|
public unwrap(): void {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import {EventDispatcher} from "./EventDispatcher";
|
|
2
|
+
|
|
3
|
+
export interface IDeferred<T> {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
promise: SimplePromise<T>;
|
|
6
|
+
resolve(result: T): void;
|
|
7
|
+
reject(reason: string): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type TResolve<T> = (result: T) => void;
|
|
11
|
+
export type TReject = (reason: string) => void;
|
|
12
|
+
export type TResult<T> = T | string | null;
|
|
13
|
+
|
|
14
|
+
export enum EPromiseStates {
|
|
15
|
+
PENDING,
|
|
16
|
+
FULFILLED,
|
|
17
|
+
REJECTED
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface IPromise<T> extends EventDispatcher {
|
|
21
|
+
state: EPromiseStates;
|
|
22
|
+
result: TResult<T>;
|
|
23
|
+
then<X = T>(success?: (result?: T) => X, error?: (reason?: string) => string): IPromise<X>;
|
|
24
|
+
catch(onRejected: (reason: string) => string): IPromise<string>;
|
|
25
|
+
finally<X = T>(finallyCallback: (result: T | string) => X | string): IPromise<X>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function noop<T = any>(result?: T): T { return result as T; }
|
|
29
|
+
|
|
30
|
+
export class SimplePromise<T> extends EventDispatcher implements IPromise<T> {
|
|
31
|
+
protected _state: EPromiseStates;
|
|
32
|
+
protected _result: TResult<T> = null;
|
|
33
|
+
private promiseClass: typeof SimplePromise;
|
|
34
|
+
|
|
35
|
+
constructor(executor: (resolve: TResolve<T>, reject: TReject) => void) {
|
|
36
|
+
super();
|
|
37
|
+
this._state = EPromiseStates.PENDING;
|
|
38
|
+
this.promiseClass = (Object.getPrototypeOf(this).constructor);
|
|
39
|
+
try {
|
|
40
|
+
executor(this._resolve.bind(this), this._reject.bind(this));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
this._reject(e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public get state(): EPromiseStates {
|
|
47
|
+
return this._state;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public get result(): TResult<T> {
|
|
51
|
+
return this._result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public static defer<T>(): IDeferred<T> {
|
|
55
|
+
const promise: SimplePromise<T> = new SimplePromise<T>((res, rej) => {});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
promise: promise,
|
|
59
|
+
resolve: promise._resolve.bind(promise),
|
|
60
|
+
reject: promise._reject.bind(promise)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/*
|
|
65
|
+
* Returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a then
|
|
66
|
+
* method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned
|
|
67
|
+
* promise will be fulfilled with the value. Generally, if you don't know if a value is a promise or not,
|
|
68
|
+
* Promise.resolve(value) it instead and work with the return value as a promise.
|
|
69
|
+
*/
|
|
70
|
+
public static resolve<T>(result: T): IPromise<T> {
|
|
71
|
+
return new SimplePromise<T>((resolve: TResolve<T>): void => {
|
|
72
|
+
if (result instanceof SimplePromise) {
|
|
73
|
+
result.then((innerResult: T) => {
|
|
74
|
+
resolve(innerResult);
|
|
75
|
+
});
|
|
76
|
+
} else {
|
|
77
|
+
resolve(result);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Returns a Promise object that is rejected with the given reason.
|
|
84
|
+
*/
|
|
85
|
+
public static reject(reason: string): IPromise<void> {
|
|
86
|
+
return new SimplePromise<void>((resolve: TResolve<void>, reject: TReject): void => {
|
|
87
|
+
reject(reason);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* Returns a promise that either fulfills when all of the promises in the iterable argument have fulfilled or
|
|
93
|
+
* rejects as soon as one of the promises in the iterable argument rejects. If the returned promise fulfills, it is
|
|
94
|
+
* fulfilled with an array of the values from the fulfilled promises in the same order as defined in the iterable.
|
|
95
|
+
* If the returned promise rejects, it is rejected with the reason from the first promise in the iterable that
|
|
96
|
+
* rejected. This method can be useful for aggregating results of multiple promises.
|
|
97
|
+
*/
|
|
98
|
+
public static all<T>(iter: IPromise<T>[]): IPromise<T[]> {
|
|
99
|
+
const deferred: IDeferred<T[]> = SimplePromise.defer<T[]>();
|
|
100
|
+
let done: boolean = true;
|
|
101
|
+
for (const promise of iter) {
|
|
102
|
+
if (promise.state == EPromiseStates.PENDING) {
|
|
103
|
+
done = false;
|
|
104
|
+
promise.once('fulfilled', (result: T): void => {
|
|
105
|
+
SimplePromise.poolResults(iter, deferred);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
promise.once('rejected', (reason: string): void => {
|
|
109
|
+
deferred.reject(reason);
|
|
110
|
+
});
|
|
111
|
+
} else if(promise.state == EPromiseStates.REJECTED) {
|
|
112
|
+
deferred.reject(promise.result as string);
|
|
113
|
+
done = false;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (done)
|
|
119
|
+
SimplePromise.poolResults(iter, deferred);
|
|
120
|
+
|
|
121
|
+
return deferred.promise;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public static poolResults<T>(iter: IPromise<T>[], deferred: IDeferred<T[]>) {
|
|
125
|
+
let done: boolean = true;
|
|
126
|
+
const results: T[] = [];
|
|
127
|
+
for (const p of iter) {
|
|
128
|
+
if (p.state === EPromiseStates.REJECTED) {
|
|
129
|
+
deferred.reject(p.result as string);
|
|
130
|
+
break;
|
|
131
|
+
} else if (p.state === EPromiseStates.PENDING) {
|
|
132
|
+
done = false;
|
|
133
|
+
}
|
|
134
|
+
results.push(p.result as T);
|
|
135
|
+
}
|
|
136
|
+
if (done)
|
|
137
|
+
deferred.resolve(results);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Returns a promise that fulfills or rejects as soon as one of the promises in the iterable fulfills or rejects,
|
|
142
|
+
* with the value or reason from that promise.
|
|
143
|
+
*/
|
|
144
|
+
public static race<T>(iter: IPromise<T>[]): IPromise<T> {
|
|
145
|
+
const deferred: IDeferred<T> = SimplePromise.defer<T>();
|
|
146
|
+
|
|
147
|
+
for (const promise of iter) {
|
|
148
|
+
promise.once('fulfilled', (result: T) => {
|
|
149
|
+
deferred.resolve(result);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
promise.once('rejected', (reason: string) => {
|
|
153
|
+
deferred.reject(reason);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return deferred.promise;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return
|
|
162
|
+
* value of the called handler, or to its original settled value if the promise was not handled (i.e. if the
|
|
163
|
+
* relevant handler onFulfilled or onRejected is not a function).
|
|
164
|
+
*/
|
|
165
|
+
public then<X = T>(success?: (result: T) => X, error?: (reason: string) => string): IPromise<X> {
|
|
166
|
+
return new this.promiseClass<X>((resolve: TResolve<X>, reject: TReject): void => {
|
|
167
|
+
if (this.state === EPromiseStates.FULFILLED) {
|
|
168
|
+
if (success)
|
|
169
|
+
resolve(success(this.result as T));
|
|
170
|
+
} else if (this.state === EPromiseStates.REJECTED) {
|
|
171
|
+
if (error)
|
|
172
|
+
reject(error(this.result as string));
|
|
173
|
+
} else {
|
|
174
|
+
this.once('fulfilled', (result: T): void => {
|
|
175
|
+
if (success)
|
|
176
|
+
resolve(success(result));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
this.once('rejected', (reason: string): void => {
|
|
180
|
+
if (error)
|
|
181
|
+
reject(error(reason));
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of
|
|
189
|
+
* the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.
|
|
190
|
+
*/
|
|
191
|
+
public catch(onRejected: (reason: string) => string): IPromise<string> {
|
|
192
|
+
return this.then<string>(undefined, onRejected);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* Appends a handler to the promise, and returns a new promise which is resolved when the original promise is
|
|
197
|
+
* resolved. The handler is called when the promise is settled, whether fulfilled or rejected.
|
|
198
|
+
*/
|
|
199
|
+
public finally<X = T>(finallyCallback: (result: T | string) => X | string): IPromise<X> {
|
|
200
|
+
const success: (r: T) => X = (result: T): X => finallyCallback(result) as X;
|
|
201
|
+
const error: (r: string) => string = (reason: string): string => finallyCallback(reason) as string;
|
|
202
|
+
|
|
203
|
+
return this.then<X>(success, error);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected _resolve(result: T): void {
|
|
207
|
+
if (this.state !== EPromiseStates.PENDING) return;
|
|
208
|
+
this._state = EPromiseStates.FULFILLED;
|
|
209
|
+
this._result = result;
|
|
210
|
+
this.dispatch('fulfilled', result);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
protected _reject(reason: string): void {
|
|
214
|
+
if (this.state !== EPromiseStates.PENDING) return;
|
|
215
|
+
this._state = EPromiseStates.REJECTED;
|
|
216
|
+
this._result = reason;
|
|
217
|
+
this.dispatch('rejected', reason);
|
|
218
|
+
}
|
|
219
|
+
}
|
package/src/Tag.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {On} from "./attributes/On";
|
|
|
8
8
|
import {Registry} from "./Registry";
|
|
9
9
|
import {benchmarkEnd, benchmarkStart} from "./Bencmark";
|
|
10
10
|
import {DOMObject} from "./DOM/DOMObject";
|
|
11
|
-
import {
|
|
11
|
+
import {Tree} from "./AST";
|
|
12
12
|
import {StyleAttribute} from "./attributes/StyleAttribute";
|
|
13
13
|
|
|
14
14
|
export enum TagState {
|
|
@@ -122,7 +122,7 @@ export class Tag extends DOMObject {
|
|
|
122
122
|
for (const attr of this.attributes) {
|
|
123
123
|
attr.mutate(mutation);
|
|
124
124
|
}
|
|
125
|
-
this.
|
|
125
|
+
this.dispatch('mutate', mutation);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
public get(attr: string) {
|
|
@@ -251,10 +251,14 @@ export class Tag extends DOMObject {
|
|
|
251
251
|
obj = new obj();
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
if (obj instanceof Controller) {
|
|
255
|
+
obj.init(this.scope, this, this.element);
|
|
256
|
+
} else {
|
|
257
|
+
this.scope.wrap(obj, triggerUpdates, updateFromWrapped);
|
|
258
|
+
obj['$scope'] = this.scope;
|
|
259
|
+
obj['$tag'] = this;
|
|
260
|
+
obj['$el'] = this.element;
|
|
261
|
+
}
|
|
258
262
|
return obj;
|
|
259
263
|
}
|
|
260
264
|
|
|
@@ -344,7 +348,7 @@ export class Tag extends DOMObject {
|
|
|
344
348
|
if (defer && attrClass.canDefer) {
|
|
345
349
|
await attrObj.defer();
|
|
346
350
|
this.deferredAttributes.push(attrObj);
|
|
347
|
-
attrObj.
|
|
351
|
+
attrObj.on('state', this.onAttributeStateChange.bind(this));
|
|
348
352
|
}
|
|
349
353
|
}
|
|
350
354
|
}
|
|
@@ -428,8 +432,7 @@ export class Tag extends DOMObject {
|
|
|
428
432
|
|
|
429
433
|
this.scope.set('$event', e);
|
|
430
434
|
this.scope.set('$value', this.value);
|
|
431
|
-
for (const handler of this.onEventHandlers[eventType])
|
|
432
|
-
{
|
|
435
|
+
for (const handler of this.onEventHandlers[eventType]) {
|
|
433
436
|
handler(e);
|
|
434
437
|
}
|
|
435
438
|
}
|
package/src/attributes/Bind.ts
CHANGED
|
@@ -53,7 +53,7 @@ export class Bind extends Attribute {
|
|
|
53
53
|
public async connect() {
|
|
54
54
|
if (this.doUpdateTo) {
|
|
55
55
|
this.updateTo();
|
|
56
|
-
this.boundScope.
|
|
56
|
+
this.boundScope.on(`change:${this.key}`, this.updateTo, this);
|
|
57
57
|
}
|
|
58
58
|
await super.connect();
|
|
59
59
|
}
|
|
@@ -9,10 +9,12 @@ export class ClickRemoveClass extends Attribute {
|
|
|
9
9
|
public async setup() {
|
|
10
10
|
this.cssClass = this.getAttributeBinding('active');
|
|
11
11
|
this.target = this.getAttributeValue();
|
|
12
|
+
await super.setup();
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
public async connect() {
|
|
15
16
|
this.tag.addEventHandler('click', this.getAttributeModifiers(), this.onClick.bind(this));
|
|
17
|
+
await super.connect();
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
onClick(e) {
|
|
@@ -9,10 +9,12 @@ export class ClickToggleClass extends Attribute {
|
|
|
9
9
|
public async setup() {
|
|
10
10
|
this.cssClass = this.getAttributeBinding( 'active');
|
|
11
11
|
this.target = this.getAttributeValue();
|
|
12
|
+
await super.setup();
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
public async connect() {
|
|
15
16
|
this.tag.addEventHandler('click', this.getAttributeModifiers(), this.onClick.bind(this));
|
|
17
|
+
await super.connect();
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
onClick(e) {
|
package/src/attributes/Exec.ts
CHANGED
|
@@ -10,9 +10,11 @@ export class Exec extends Attribute {
|
|
|
10
10
|
public async compile() {
|
|
11
11
|
this.tree = new Tree(this.getAttributeValue());
|
|
12
12
|
await this.tree.prepare(this.tag.scope, this.tag.dom, this.tag);
|
|
13
|
+
await super.compile();
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
public async extract() {
|
|
16
17
|
await this.tree.evaluate(this.tag.scope, this.tag.dom, this.tag);
|
|
18
|
+
await super.extract();
|
|
17
19
|
}
|
|
18
20
|
}
|
package/src/attributes/Format.ts
CHANGED
package/src/attributes/If.ts
CHANGED
|
@@ -11,18 +11,22 @@ export class If extends Attribute {
|
|
|
11
11
|
const statement: string = this.getAttributeValue();
|
|
12
12
|
this.tree = new Tree(statement);
|
|
13
13
|
await this.tree.prepare(this.tag.scope, this.tag.dom, this.tag);
|
|
14
|
+
await super.compile();
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
public async extract() {
|
|
17
18
|
await this.evaluate();
|
|
19
|
+
await super.extract();
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
public async connect() {
|
|
21
23
|
await this.tree.bindToScopeChanges(this.tag.scope, this.onChange.bind(this), this.tag.dom, this.tag);
|
|
24
|
+
await super.connect();
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
public async evaluate() {
|
|
25
28
|
await this.onChange();
|
|
29
|
+
await super.evaluate();
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
async onChange() {
|
|
@@ -4,12 +4,13 @@ export abstract class KeyAbstract extends On {
|
|
|
4
4
|
protected specificKey: string = null;
|
|
5
5
|
|
|
6
6
|
public async compile() {
|
|
7
|
-
await super.compile();
|
|
8
7
|
this.specificKey = this.getAttributeBinding();
|
|
8
|
+
await super.compile();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
public async connect() {
|
|
12
12
|
this.tag.addEventHandler('keydown', this.getAttributeModifiers(), this.handleEvent.bind(this));
|
|
13
|
+
await super.connect();
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
public async handleEvent(e) {
|
package/src/attributes/KeyUp.ts
CHANGED
package/src/attributes/List.ts
CHANGED
|
@@ -19,6 +19,7 @@ export class List extends Attribute {
|
|
|
19
19
|
const listAttr: string = this.getAttributeBinding();
|
|
20
20
|
this.tree = new Tree(listAttr);
|
|
21
21
|
await this.tree.prepare(this.tag.scope, this.tag.dom, this.tag);
|
|
22
|
+
await super.compile();
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
public async setup() {
|
|
@@ -43,6 +44,7 @@ export class List extends Attribute {
|
|
|
43
44
|
this.template = templateNode.element.content.cloneNode(true);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
await super.setup();
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
public async extract() {
|
|
@@ -55,6 +57,7 @@ export class List extends Attribute {
|
|
|
55
57
|
await this.add({});
|
|
56
58
|
}
|
|
57
59
|
}
|
|
60
|
+
await super.extract();
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
protected async addExistingItems(defaultList: any[] | null) {
|
|
@@ -81,10 +84,10 @@ export class List extends Attribute {
|
|
|
81
84
|
this.items = new WrappedArray(this.items);
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
(this.items as WrappedArray<any>).
|
|
87
|
+
(this.items as WrappedArray<any>).on('add', (item) => {
|
|
85
88
|
this.add(item);
|
|
86
89
|
});
|
|
87
|
-
(this.items as WrappedArray<any>).
|
|
90
|
+
(this.items as WrappedArray<any>).on('remove', (item) => {
|
|
88
91
|
this.remove(item);
|
|
89
92
|
});
|
|
90
93
|
|
|
@@ -134,6 +137,6 @@ export class List extends Attribute {
|
|
|
134
137
|
tag.wrap(obj);
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
this.tag.
|
|
140
|
+
this.tag.dispatch('add', obj);
|
|
138
141
|
}
|
|
139
142
|
}
|
|
@@ -23,6 +23,7 @@ export class ListItem extends Attribute {
|
|
|
23
23
|
const modelName: string = (await this.getList()).listItemModel;
|
|
24
24
|
const cls = await Registry.instance.classes.get(modelName);
|
|
25
25
|
this.instantiateModel(cls);
|
|
26
|
+
await super.setup();
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
public get listItemName(): string {
|
package/src/attributes/On.ts
CHANGED
|
@@ -22,13 +22,17 @@ export abstract class On extends Attribute {
|
|
|
22
22
|
const code: string = this.getAttributeValue();
|
|
23
23
|
this.handler = new Tree(code);
|
|
24
24
|
await this.handler.prepare(this.tag.scope, this.tag.dom, this.tag);
|
|
25
|
+
await super.compile();
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
async handleEvent(e) {
|
|
29
|
+
if (this.hasModifier('preventdefault'))
|
|
30
|
+
e.preventDefault();
|
|
28
31
|
await this.handler.evaluate(this.tag.scope, this.tag.dom, this.tag);
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
public async connect() {
|
|
32
35
|
this.tag.addEventHandler(this.getAttributeBinding(), this.getAttributeModifiers(), this.handleEvent.bind(this));
|
|
36
|
+
await super.connect();
|
|
33
37
|
}
|
|
34
38
|
}
|