@angular-wave/angular.ts 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +57 -0
- package/README.md +1 -1
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/core/compile/attributes.js +1 -1
- package/src/core/compile/compile.js +1 -1
- package/src/core/compile/compile.test.js +1 -1
- package/src/core/exception-handler.js +1 -5
- package/src/core/interval/interval-factory.js +6 -22
- package/src/core/interval/interval.spec.js +0 -25
- package/src/core/q/q.js +0 -27
- package/src/core/q/q.spec.js +0 -44
- package/src/core/scope/scope.js +34 -40
- package/src/core/scope/scope.spec.js +71 -13
- package/src/core/timeout/timeout.js +2 -6
- package/src/directive/attrs/attrs.js +1 -1
- package/src/directive/input/input.spec.js +0 -1
- package/src/directive/observe/observe.html +18 -0
- package/src/directive/observe/observe.js +37 -0
- package/src/directive/observe/observe.spec.js +92 -0
- package/src/directive/observe/observe.test.js +9 -0
- package/src/directive/observe/test.html +197 -0
- package/src/public.js +7 -6
- package/src/router/state/state-service.js +3 -3
- package/src/router/view-scroll.js +13 -8
- package/src/services/log.js +0 -6
- package/types/core/compile/attributes.d.ts +3 -3
- package/types/core/compile/compile.d.ts +1 -1
- package/types/core/exception-handler.d.ts +2 -2
- package/types/core/interval/interval-factory.d.ts +1 -1
- package/types/core/q/q.d.ts +0 -5
- package/types/core/scope/scope.d.ts +11 -2
- package/types/core/timeout/timeout.d.ts +2 -2
- package/types/directive/observe/observe.d.ts +4 -0
- package/types/router/state/state-service.d.ts +1 -1
- package/types/router/view-scroll.d.ts +3 -3
- package/types/services/log.d.ts +0 -5
- package/.github/workflows/lint.yml +0 -19
- package/.github/workflows/playwright.yml +0 -27
- package/.github/workflows/types.yml +0 -19
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@angular-wave/angular.ts",
|
|
3
3
|
"description": "A modern, optimized and typesafe version of AngularJS",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/angular-ts.esm.js",
|
|
8
8
|
"browser": "dist/angular-ts.umd.js",
|
|
@@ -27,7 +27,7 @@ export class Attributes {
|
|
|
27
27
|
/**
|
|
28
28
|
* @param {import('../scope/scope').Scope} $rootScope
|
|
29
29
|
* @param {*} $animate
|
|
30
|
-
* @param {import("../exception-handler").
|
|
30
|
+
* @param {import("../exception-handler").ErrorHandler} $exceptionHandler
|
|
31
31
|
* @param {*} $sce
|
|
32
32
|
* @param {import('../../shared/jqlite/jqlite').JQLite} [element]
|
|
33
33
|
* @param {*} [attributesToCopy]
|
|
@@ -526,7 +526,7 @@ export function CompileProvider($provide, $$sanitizeUriProvider) {
|
|
|
526
526
|
/**
|
|
527
527
|
* @param {import("../../core/di/internal-injector").InjectorService} $injector
|
|
528
528
|
* @param {*} $interpolate
|
|
529
|
-
* @param {import("../exception-handler").
|
|
529
|
+
* @param {import("../exception-handler").ErrorHandler} $exceptionHandler
|
|
530
530
|
* @param {*} $templateRequest
|
|
531
531
|
* @param {import("../parser/parse").ParseService} $parse
|
|
532
532
|
* @param {*} $controller
|
|
@@ -31,10 +31,6 @@
|
|
|
31
31
|
*
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
/**
|
|
35
|
-
* @typedef {import('../types').ServiceProvider} ExceptionHandlerProvider
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
34
|
/** @type {import('../services/log').LogService} */
|
|
39
35
|
let log;
|
|
40
36
|
|
|
@@ -50,7 +46,7 @@ export const errorHandler = (exception, cause) => {
|
|
|
50
46
|
|
|
51
47
|
/**
|
|
52
48
|
* @constructor
|
|
53
|
-
* @this {
|
|
49
|
+
* @this {import('../types').ServiceProvider}
|
|
54
50
|
*/
|
|
55
51
|
export function ExceptionHandlerProvider() {
|
|
56
52
|
this.$get = [
|
|
@@ -2,26 +2,20 @@ import { isDefined, sliceArgs } from "../../shared/utils";
|
|
|
2
2
|
|
|
3
3
|
export function $IntervalFactoryProvider() {
|
|
4
4
|
this.$get = [
|
|
5
|
-
"$browser",
|
|
6
5
|
"$q",
|
|
7
|
-
"$$q",
|
|
8
6
|
"$rootScope",
|
|
9
7
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @param {import('../../services/browser').Browser} $browser
|
|
12
8
|
* @param {*} $q
|
|
13
|
-
* @param {*} $$q
|
|
14
9
|
* @param {import('../scope/scope').Scope} $rootScope
|
|
15
10
|
* @returns
|
|
16
11
|
*/
|
|
17
|
-
function ($
|
|
12
|
+
function ($q, $rootScope) {
|
|
18
13
|
return function intervalFactory(setIntervalFn, clearIntervalFn) {
|
|
19
|
-
return function intervalFn(fn, delay, count
|
|
14
|
+
return function intervalFn(fn, delay, count) {
|
|
20
15
|
const hasParams = arguments.length > 4;
|
|
21
16
|
const args = hasParams ? sliceArgs(arguments, 4) : [];
|
|
22
17
|
let iteration = 0;
|
|
23
|
-
const
|
|
24
|
-
const deferred = (skipApply ? $$q : $q).defer();
|
|
18
|
+
const deferred = $q.defer();
|
|
25
19
|
const { promise } = deferred;
|
|
26
20
|
|
|
27
21
|
count = isDefined(count) ? count : 0;
|
|
@@ -35,11 +29,7 @@ export function $IntervalFactoryProvider() {
|
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
function tick() {
|
|
38
|
-
|
|
39
|
-
$browser.defer(callback);
|
|
40
|
-
} else {
|
|
41
|
-
$rootScope.$evalAsync(callback);
|
|
42
|
-
}
|
|
32
|
+
$rootScope.$evalAsync(callback);
|
|
43
33
|
|
|
44
34
|
iteration++;
|
|
45
35
|
|
|
@@ -47,16 +37,10 @@ export function $IntervalFactoryProvider() {
|
|
|
47
37
|
deferred.resolve(iteration);
|
|
48
38
|
clearIntervalFn(promise.$$intervalId);
|
|
49
39
|
}
|
|
50
|
-
|
|
51
|
-
if (!skipApply) $rootScope.$apply();
|
|
40
|
+
$rootScope.$apply();
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
promise.$$intervalId = setIntervalFn(
|
|
55
|
-
tick,
|
|
56
|
-
delay,
|
|
57
|
-
deferred,
|
|
58
|
-
skipApply,
|
|
59
|
-
);
|
|
43
|
+
promise.$$intervalId = setIntervalFn(tick, delay, deferred);
|
|
60
44
|
|
|
61
45
|
return promise;
|
|
62
46
|
};
|
|
@@ -55,31 +55,6 @@ describe("$interval", () => {
|
|
|
55
55
|
}, 1);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it("should NOT call $apply if invokeApply is set to false", (done) => {
|
|
59
|
-
const applySpy = spyOn($rootScope, "$apply").and.callThrough();
|
|
60
|
-
|
|
61
|
-
$interval(() => {}, 1, 0, false);
|
|
62
|
-
expect(applySpy).not.toHaveBeenCalled();
|
|
63
|
-
|
|
64
|
-
setTimeout(() => {
|
|
65
|
-
expect(applySpy).not.toHaveBeenCalled();
|
|
66
|
-
done();
|
|
67
|
-
}, 2);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("should NOT call $evalAsync or $digest if invokeApply is set to false", async () => {
|
|
71
|
-
const evalAsyncSpy = spyOn($rootScope, "$evalAsync").and.callThrough();
|
|
72
|
-
const digestSpy = spyOn($rootScope, "$digest").and.callThrough();
|
|
73
|
-
const notifySpy = jasmine.createSpy("notify");
|
|
74
|
-
|
|
75
|
-
$interval(notifySpy, 1, 1, false);
|
|
76
|
-
|
|
77
|
-
await wait(100);
|
|
78
|
-
expect(notifySpy).toHaveBeenCalled();
|
|
79
|
-
expect(evalAsyncSpy).not.toHaveBeenCalled();
|
|
80
|
-
expect(digestSpy).not.toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
58
|
it("should allow you to specify a number of iterations", async () => {
|
|
84
59
|
let counter = 0;
|
|
85
60
|
$interval(
|
package/src/core/q/q.js
CHANGED
|
@@ -98,33 +98,6 @@ export class $QProvider {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export class $$QProvider {
|
|
102
|
-
constructor() {
|
|
103
|
-
this.errorOn = true;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
$get = [
|
|
107
|
-
"$exceptionHandler",
|
|
108
|
-
function ($exceptionHandler) {
|
|
109
|
-
return qFactory(
|
|
110
|
-
(callback) => {
|
|
111
|
-
window.setTimeout(callback);
|
|
112
|
-
},
|
|
113
|
-
$exceptionHandler,
|
|
114
|
-
this.errorOn,
|
|
115
|
-
);
|
|
116
|
-
},
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
errorOnUnhandledRejections(value) {
|
|
120
|
-
if (isDefined(value)) {
|
|
121
|
-
this.errorOn = value;
|
|
122
|
-
return this;
|
|
123
|
-
}
|
|
124
|
-
return this.errorOn;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
101
|
/**
|
|
129
102
|
* Constructs a promise manager.
|
|
130
103
|
*
|
package/src/core/q/q.spec.js
CHANGED
|
@@ -626,50 +626,6 @@ describe("all", function () {
|
|
|
626
626
|
});
|
|
627
627
|
});
|
|
628
628
|
|
|
629
|
-
describe("$qq", function () {
|
|
630
|
-
let $q, $$q, $rootScope, $injector;
|
|
631
|
-
|
|
632
|
-
beforeEach(() => {
|
|
633
|
-
window.angular = new Angular();
|
|
634
|
-
$injector = createInjector(["ng"]);
|
|
635
|
-
$q = $injector.get("$q");
|
|
636
|
-
$$q = $injector.get("$$q");
|
|
637
|
-
$rootScope = $injector.get("$rootScope");
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
afterEach(function () {});
|
|
641
|
-
|
|
642
|
-
it("uses deferreds that do not resolve at digest", function () {
|
|
643
|
-
var d = $$q.defer();
|
|
644
|
-
var fulfilledSpy = jasmine.createSpy();
|
|
645
|
-
d.promise.then(fulfilledSpy);
|
|
646
|
-
d.resolve("ok");
|
|
647
|
-
$rootScope.$apply();
|
|
648
|
-
expect(fulfilledSpy).not.toHaveBeenCalled();
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
it("uses deferreds that resolve later", (done) => {
|
|
652
|
-
var d = $$q.defer();
|
|
653
|
-
d.promise.then((val) => {
|
|
654
|
-
expect(val).toBe("ok");
|
|
655
|
-
done();
|
|
656
|
-
});
|
|
657
|
-
d.resolve("ok");
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
it("does not invoke digest", (done) => {
|
|
661
|
-
var d = $$q.defer();
|
|
662
|
-
var watchSpy = jasmine.createSpy();
|
|
663
|
-
d.promise.then(() => {
|
|
664
|
-
watchSpy();
|
|
665
|
-
done();
|
|
666
|
-
});
|
|
667
|
-
d.resolve("ok");
|
|
668
|
-
$rootScope.$watch(watchSpy);
|
|
669
|
-
expect(watchSpy).not.toHaveBeenCalled();
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
|
|
673
629
|
describe("$Q", () => {
|
|
674
630
|
let resolve;
|
|
675
631
|
let reject;
|
package/src/core/scope/scope.js
CHANGED
|
@@ -76,11 +76,6 @@ let $browser;
|
|
|
76
76
|
/**@type {import('../exception-handler').ErrorHandler} */
|
|
77
77
|
let $exceptionHandler;
|
|
78
78
|
|
|
79
|
-
/**
|
|
80
|
-
* @type {Scope}
|
|
81
|
-
*/
|
|
82
|
-
let rootScope;
|
|
83
|
-
|
|
84
79
|
/**
|
|
85
80
|
* Provider responsible for instantiating the initial scope, aka - root scope.
|
|
86
81
|
* Every application has a single root {@link ng.$rootScope.Scope scope}.
|
|
@@ -94,7 +89,7 @@ let rootScope;
|
|
|
94
89
|
*/
|
|
95
90
|
export class RootScopeProvider {
|
|
96
91
|
constructor() {
|
|
97
|
-
rootScope = new Scope();
|
|
92
|
+
this.rootScope = new Scope(true);
|
|
98
93
|
}
|
|
99
94
|
|
|
100
95
|
$get = [
|
|
@@ -111,7 +106,7 @@ export class RootScopeProvider {
|
|
|
111
106
|
$exceptionHandler = exceptionHandler;
|
|
112
107
|
$parse = parse;
|
|
113
108
|
$browser = browser;
|
|
114
|
-
return rootScope;
|
|
109
|
+
return this.rootScope;
|
|
115
110
|
},
|
|
116
111
|
];
|
|
117
112
|
}
|
|
@@ -142,7 +137,15 @@ export class RootScopeProvider {
|
|
|
142
137
|
*/
|
|
143
138
|
|
|
144
139
|
export class Scope {
|
|
145
|
-
|
|
140
|
+
/**
|
|
141
|
+
* @param {boolean} [root=false] - Indicates if this scope is the root scope.
|
|
142
|
+
*/
|
|
143
|
+
constructor(root = false) {
|
|
144
|
+
/**
|
|
145
|
+
* @type {boolean}
|
|
146
|
+
*/
|
|
147
|
+
this.isRoot = root;
|
|
148
|
+
|
|
146
149
|
/**
|
|
147
150
|
* @type {number} Unique scope ID (monotonically increasing) useful for debugging.
|
|
148
151
|
*/
|
|
@@ -194,13 +197,12 @@ export class Scope {
|
|
|
194
197
|
/** @type {boolean} */
|
|
195
198
|
this.$$destroyed = false;
|
|
196
199
|
|
|
197
|
-
// TODO use maps
|
|
198
200
|
/** @type {boolean} */
|
|
199
201
|
this.$$suspended = false;
|
|
200
202
|
|
|
201
203
|
// TODO use maps
|
|
202
|
-
/** @type {
|
|
203
|
-
this.$$listeners =
|
|
204
|
+
/** @type {Map<String, Function[]>} */
|
|
205
|
+
this.$$listeners = new Map();
|
|
204
206
|
|
|
205
207
|
/** @type {object} */
|
|
206
208
|
this.$$listenerCount = {};
|
|
@@ -240,19 +242,18 @@ export class Scope {
|
|
|
240
242
|
*
|
|
241
243
|
*/
|
|
242
244
|
$new(isolate, parent) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
let child = isolate ? new Scope() : Object.create(this);
|
|
246
|
+
|
|
245
247
|
if (isolate) {
|
|
246
|
-
child =
|
|
247
|
-
child.$root = rootScope;
|
|
248
|
+
child.$root = this.isRoot ? this : this.$root;
|
|
248
249
|
} else {
|
|
249
|
-
child
|
|
250
|
+
// Initialize properties for a non-isolated child scope
|
|
250
251
|
child.$id = nextUid();
|
|
251
252
|
child.$$watchers = [];
|
|
252
253
|
child.$$nextSibling = null;
|
|
253
254
|
child.$$childHead = null;
|
|
254
255
|
child.$$childTail = null;
|
|
255
|
-
child.$$listeners =
|
|
256
|
+
child.$$listeners = new Map();
|
|
256
257
|
child.$$listenerCount = {};
|
|
257
258
|
child.$$watchersCount = 0;
|
|
258
259
|
child.$$ChildScope = null;
|
|
@@ -261,6 +262,7 @@ export class Scope {
|
|
|
261
262
|
|
|
262
263
|
child.$parent = parent || this;
|
|
263
264
|
child.$$prevSibling = child.$parent.$$childTail;
|
|
265
|
+
|
|
264
266
|
if (child.$parent.$$childHead) {
|
|
265
267
|
child.$parent.$$childTail.$$nextSibling = child;
|
|
266
268
|
child.$parent.$$childTail = child;
|
|
@@ -269,20 +271,13 @@ export class Scope {
|
|
|
269
271
|
child.$parent.$$childTail = child;
|
|
270
272
|
}
|
|
271
273
|
|
|
272
|
-
//
|
|
273
|
-
// the parent scope is destroyed, the property `$$destroyed` is inherited
|
|
274
|
-
// prototypically. In all other cases, this property needs to be set
|
|
275
|
-
// when the parent scope is destroyed.
|
|
276
|
-
// The listener needs to be added after the parent is set
|
|
274
|
+
// Add a destroy listener if isolated or the parent differs from `this`
|
|
277
275
|
if (isolate || parent !== this) {
|
|
278
|
-
child.$on(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
($event) => {
|
|
282
|
-
$event.currentScope.$$destroyed = true;
|
|
283
|
-
},
|
|
284
|
-
);
|
|
276
|
+
child.$on("$destroy", ($event) => {
|
|
277
|
+
$event.currentScope.$$destroyed = true;
|
|
278
|
+
});
|
|
285
279
|
}
|
|
280
|
+
|
|
286
281
|
return child;
|
|
287
282
|
}
|
|
288
283
|
|
|
@@ -732,7 +727,6 @@ export class Scope {
|
|
|
732
727
|
*
|
|
733
728
|
*/
|
|
734
729
|
$digest() {
|
|
735
|
-
let watch;
|
|
736
730
|
let value;
|
|
737
731
|
let last;
|
|
738
732
|
let fn;
|
|
@@ -741,10 +735,9 @@ export class Scope {
|
|
|
741
735
|
let dirty;
|
|
742
736
|
let ttl = TTL;
|
|
743
737
|
let next;
|
|
744
|
-
/**
|
|
745
|
-
* @type {Scope}
|
|
746
|
-
*/
|
|
738
|
+
/** @type {Scope} */
|
|
747
739
|
let current;
|
|
740
|
+
/** @type {Scope} */
|
|
748
741
|
const target = $$asyncQueue.length ? this.$root : this;
|
|
749
742
|
const watchLog = [];
|
|
750
743
|
let logIdx;
|
|
@@ -755,7 +748,7 @@ export class Scope {
|
|
|
755
748
|
// TODO Implement browser
|
|
756
749
|
$browser.$$checkUrlChange();
|
|
757
750
|
|
|
758
|
-
if (this
|
|
751
|
+
if (this.isRoot && applyAsyncId !== null) {
|
|
759
752
|
// If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
|
|
760
753
|
// cancel the scheduled $apply and flush the queue of expressions to be evaluated.
|
|
761
754
|
$browser.cancel(applyAsyncId);
|
|
@@ -795,7 +788,7 @@ export class Scope {
|
|
|
795
788
|
current.$$digestWatchIndex = watchers.length;
|
|
796
789
|
while (current.$$digestWatchIndex--) {
|
|
797
790
|
try {
|
|
798
|
-
watch = watchers[current.$$digestWatchIndex];
|
|
791
|
+
const watch = watchers[current.$$digestWatchIndex];
|
|
799
792
|
// Most common watches are on primitives, in which case we can short
|
|
800
793
|
// circuit it with === operator, only when === fails do we use .equals
|
|
801
794
|
if (watch) {
|
|
@@ -1038,7 +1031,7 @@ export class Scope {
|
|
|
1038
1031
|
function () {
|
|
1039
1032
|
return () => {};
|
|
1040
1033
|
};
|
|
1041
|
-
this.$$listeners
|
|
1034
|
+
this.$$listeners.clear();
|
|
1042
1035
|
|
|
1043
1036
|
// Disconnect the next sibling to prevent `cleanUpScope` destroying those too
|
|
1044
1037
|
this.$$nextSibling = null;
|
|
@@ -1251,9 +1244,10 @@ export class Scope {
|
|
|
1251
1244
|
* @returns {function()} Returns a deregistration function for this listener.
|
|
1252
1245
|
*/
|
|
1253
1246
|
$on(name, listener) {
|
|
1254
|
-
let namedListeners = this.$$listeners
|
|
1247
|
+
let namedListeners = this.$$listeners.get(name);
|
|
1255
1248
|
if (!namedListeners) {
|
|
1256
|
-
|
|
1249
|
+
namedListeners = [];
|
|
1250
|
+
this.$$listeners.set(name, namedListeners);
|
|
1257
1251
|
}
|
|
1258
1252
|
namedListeners.push(listener);
|
|
1259
1253
|
|
|
@@ -1342,7 +1336,7 @@ export class Scope {
|
|
|
1342
1336
|
let length;
|
|
1343
1337
|
|
|
1344
1338
|
do {
|
|
1345
|
-
namedListeners = scope.$$listeners
|
|
1339
|
+
namedListeners = scope.$$listeners.get(name) || empty;
|
|
1346
1340
|
event.currentScope = scope;
|
|
1347
1341
|
for (i = 0, length = namedListeners.length; i < length; i++) {
|
|
1348
1342
|
// if listeners were deregistered, defragment the array
|
|
@@ -1414,7 +1408,7 @@ export class Scope {
|
|
|
1414
1408
|
// down while you can, then up and next sibling or up and next sibling until back at root
|
|
1415
1409
|
while ((current = next)) {
|
|
1416
1410
|
event.currentScope = current;
|
|
1417
|
-
listeners = current.$$listeners
|
|
1411
|
+
listeners = current.$$listeners.get(name) || [];
|
|
1418
1412
|
for (i = 0, length = listeners.length; i < length; i++) {
|
|
1419
1413
|
// if listeners were deregistered, defragment the array
|
|
1420
1414
|
if (!listeners[i]) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $$asyncQueue } from "./scope";
|
|
1
|
+
import { $$asyncQueue, Scope } from "./scope";
|
|
2
2
|
import { extend, sliceArgs } from "../../shared/utils";
|
|
3
3
|
import { Angular } from "../../loader";
|
|
4
4
|
import { createInjector } from "../di/injector";
|
|
@@ -8,6 +8,7 @@ describe("Scope", function () {
|
|
|
8
8
|
let $parse;
|
|
9
9
|
let $browser;
|
|
10
10
|
let logs;
|
|
11
|
+
let scope;
|
|
11
12
|
|
|
12
13
|
beforeEach(() => {
|
|
13
14
|
logs = [];
|
|
@@ -27,6 +28,21 @@ describe("Scope", function () {
|
|
|
27
28
|
$browser = injector.get("$browser");
|
|
28
29
|
|
|
29
30
|
$rootScope = injector.get("$rootScope");
|
|
31
|
+
scope = $rootScope;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("class", () => {
|
|
35
|
+
it("can be constructed as a class", () => {
|
|
36
|
+
const scope = new Scope();
|
|
37
|
+
expect(scope).toBeDefined();
|
|
38
|
+
expect(scope.isRoot).toBeFalse();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("can be constructed as a root scope", () => {
|
|
42
|
+
const scope = new Scope(true);
|
|
43
|
+
expect(scope).toBeDefined();
|
|
44
|
+
expect(scope.isRoot).toBeTrue();
|
|
45
|
+
});
|
|
30
46
|
});
|
|
31
47
|
|
|
32
48
|
describe("inheritance", () => {
|
|
@@ -49,7 +65,7 @@ describe("Scope", function () {
|
|
|
49
65
|
const child = $rootScope.$new();
|
|
50
66
|
child.aValue = [1, 2, 3];
|
|
51
67
|
|
|
52
|
-
expect(
|
|
68
|
+
expect($rootScope.aValue).toBeUndefined();
|
|
53
69
|
});
|
|
54
70
|
|
|
55
71
|
it("inherits the parents properties whenever they are defined", () => {
|
|
@@ -91,6 +107,7 @@ describe("Scope", function () {
|
|
|
91
107
|
|
|
92
108
|
expect(child.aValue).toEqual([1, 2, 3, 4]);
|
|
93
109
|
expect($rootScope.aValue).toEqual([1, 2, 3, 4]);
|
|
110
|
+
expect(child.aValue).toEqual($rootScope.aValue);
|
|
94
111
|
});
|
|
95
112
|
});
|
|
96
113
|
|
|
@@ -122,6 +139,7 @@ describe("Scope", function () {
|
|
|
122
139
|
$rootScope.a = 123;
|
|
123
140
|
expect(isolated.a).toBeUndefined();
|
|
124
141
|
expect(trans.a).toEqual(123);
|
|
142
|
+
expect(trans.$root).toBe($rootScope);
|
|
125
143
|
expect(trans.$parent).toBe(isolated);
|
|
126
144
|
});
|
|
127
145
|
});
|
|
@@ -171,13 +189,53 @@ describe("Scope", function () {
|
|
|
171
189
|
expect($rootScope.$eval("this")).toEqual($rootScope);
|
|
172
190
|
});
|
|
173
191
|
|
|
174
|
-
it("should be able to access a
|
|
192
|
+
it("should be able to access a constant variable named 'this'", () => {
|
|
175
193
|
$rootScope.this = 42;
|
|
176
194
|
expect($rootScope.$eval("this['this']")).toBe(42);
|
|
177
195
|
});
|
|
178
196
|
});
|
|
179
197
|
|
|
180
198
|
describe("$watch/$digest", () => {
|
|
199
|
+
it("calls the listener function of a watch on first $digest", function () {
|
|
200
|
+
var watchFn = function () {
|
|
201
|
+
return "wat";
|
|
202
|
+
};
|
|
203
|
+
var listenerFn = jasmine.createSpy();
|
|
204
|
+
$rootScope.$watch(watchFn, listenerFn);
|
|
205
|
+
$rootScope.$digest();
|
|
206
|
+
expect(listenerFn).toHaveBeenCalled();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("calls the watch function with the scope as the argument", function () {
|
|
210
|
+
var watchFn = jasmine.createSpy();
|
|
211
|
+
var listenerFn = function () {};
|
|
212
|
+
$rootScope.$watch(watchFn, listenerFn);
|
|
213
|
+
$rootScope.$digest();
|
|
214
|
+
expect(watchFn).toHaveBeenCalledWith($rootScope);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("calls the listener function when the watched value changes", function () {
|
|
218
|
+
scope.someValue = "a";
|
|
219
|
+
scope.counter = 0;
|
|
220
|
+
scope.$watch(
|
|
221
|
+
function (scope) {
|
|
222
|
+
return scope.someValue;
|
|
223
|
+
},
|
|
224
|
+
function (newValue, oldValue, scope) {
|
|
225
|
+
scope.counter++;
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
expect(scope.counter).toBe(0);
|
|
229
|
+
scope.$digest();
|
|
230
|
+
expect(scope.counter).toBe(1);
|
|
231
|
+
scope.$digest();
|
|
232
|
+
expect(scope.counter).toBe(1);
|
|
233
|
+
scope.someValue = "b";
|
|
234
|
+
expect(scope.counter).toBe(1);
|
|
235
|
+
scope.$digest();
|
|
236
|
+
expect(scope.counter).toBe(2);
|
|
237
|
+
});
|
|
238
|
+
|
|
181
239
|
it("should watch and fire on simple property change", () => {
|
|
182
240
|
const spy = jasmine.createSpy();
|
|
183
241
|
$rootScope.$watch("name", spy);
|
|
@@ -2870,13 +2928,13 @@ describe("Scope", function () {
|
|
|
2870
2928
|
const remove1 = $rootScope.$on("abc", () => {});
|
|
2871
2929
|
$rootScope.$on("abc", () => {});
|
|
2872
2930
|
|
|
2873
|
-
expect($rootScope.$$listeners.abc.length).toBe(2);
|
|
2874
|
-
expect(0 in $rootScope.$$listeners.abc).toBe(true);
|
|
2931
|
+
expect($rootScope.$$listeners.get("abc").length).toBe(2);
|
|
2932
|
+
expect(0 in $rootScope.$$listeners.get("abc")).toBe(true);
|
|
2875
2933
|
|
|
2876
2934
|
remove1();
|
|
2877
2935
|
|
|
2878
|
-
expect($rootScope.$$listeners.abc.length).toBe(2);
|
|
2879
|
-
expect(0 in $rootScope.$$listeners.abc).toBe(false);
|
|
2936
|
+
expect($rootScope.$$listeners.get("abc").length).toBe(2);
|
|
2937
|
+
expect(0 in $rootScope.$$listeners.get("abc")).toBe(false);
|
|
2880
2938
|
});
|
|
2881
2939
|
|
|
2882
2940
|
it("should call next listener after removing the current listener via its own handler", () => {
|
|
@@ -3097,14 +3155,14 @@ describe("Scope", function () {
|
|
|
3097
3155
|
|
|
3098
3156
|
spy1.and.callFake(remove1);
|
|
3099
3157
|
|
|
3100
|
-
expect(child.$$listeners.evt.length).toBe(3);
|
|
3158
|
+
expect(child.$$listeners.get("evt").length).toBe(3);
|
|
3101
3159
|
|
|
3102
3160
|
// should call all listeners and remove 1st
|
|
3103
3161
|
child.$emit("evt");
|
|
3104
3162
|
expect(spy1).toHaveBeenCalled();
|
|
3105
3163
|
expect(spy2).toHaveBeenCalled();
|
|
3106
3164
|
expect(spy3).toHaveBeenCalled();
|
|
3107
|
-
expect(child.$$listeners.evt.length).toBe(3); // cleanup will happen on next $emit
|
|
3165
|
+
expect(child.$$listeners.get("evt").length).toBe(3); // cleanup will happen on next $emit
|
|
3108
3166
|
|
|
3109
3167
|
spy1.calls.reset();
|
|
3110
3168
|
spy2.calls.reset();
|
|
@@ -3116,7 +3174,7 @@ describe("Scope", function () {
|
|
|
3116
3174
|
expect(spy1).not.toHaveBeenCalled();
|
|
3117
3175
|
expect(spy2).toHaveBeenCalled();
|
|
3118
3176
|
expect(spy3).not.toHaveBeenCalled();
|
|
3119
|
-
expect(child.$$listeners.evt.length).toBe(1);
|
|
3177
|
+
expect(child.$$listeners.get("evt").length).toBe(1);
|
|
3120
3178
|
});
|
|
3121
3179
|
|
|
3122
3180
|
it("should allow removing event listener inside a listener on $broadcast", () => {
|
|
@@ -3130,14 +3188,14 @@ describe("Scope", function () {
|
|
|
3130
3188
|
|
|
3131
3189
|
spy1.and.callFake(remove1);
|
|
3132
3190
|
|
|
3133
|
-
expect(child.$$listeners.evt.length).toBe(3);
|
|
3191
|
+
expect(child.$$listeners.get("evt").length).toBe(3);
|
|
3134
3192
|
|
|
3135
3193
|
// should call all listeners and remove 1st
|
|
3136
3194
|
child.$broadcast("evt");
|
|
3137
3195
|
expect(spy1).toHaveBeenCalled();
|
|
3138
3196
|
expect(spy2).toHaveBeenCalled();
|
|
3139
3197
|
expect(spy3).toHaveBeenCalled();
|
|
3140
|
-
expect(child.$$listeners.evt.length).toBe(3); // cleanup will happen on next $broadcast
|
|
3198
|
+
expect(child.$$listeners.get("evt").length).toBe(3); // cleanup will happen on next $broadcast
|
|
3141
3199
|
|
|
3142
3200
|
spy1.calls.reset();
|
|
3143
3201
|
spy2.calls.reset();
|
|
@@ -3149,7 +3207,7 @@ describe("Scope", function () {
|
|
|
3149
3207
|
expect(spy1).not.toHaveBeenCalled();
|
|
3150
3208
|
expect(spy2).toHaveBeenCalled();
|
|
3151
3209
|
expect(spy3).not.toHaveBeenCalled();
|
|
3152
|
-
expect(child.$$listeners.evt.length).toBe(1);
|
|
3210
|
+
expect(child.$$listeners.get("evt").length).toBe(1);
|
|
3153
3211
|
});
|
|
3154
3212
|
|
|
3155
3213
|
describe("event object", () => {
|
|
@@ -8,18 +8,16 @@ export class TimeoutProvider {
|
|
|
8
8
|
"$rootScope",
|
|
9
9
|
"$browser",
|
|
10
10
|
"$q",
|
|
11
|
-
"$$q",
|
|
12
11
|
"$exceptionHandler",
|
|
13
12
|
/**
|
|
14
13
|
*
|
|
15
14
|
* @param {import('../scope/scope').Scope} $rootScope
|
|
16
15
|
* @param {import('../../services/browser').Browser} $browser
|
|
17
16
|
* @param {*} $q
|
|
18
|
-
* @param {*} $$q
|
|
19
17
|
* @param {import('../exception-handler').ErrorHandler} $exceptionHandler
|
|
20
18
|
* @returns
|
|
21
19
|
*/
|
|
22
|
-
($rootScope, $browser, $q,
|
|
20
|
+
($rootScope, $browser, $q, $exceptionHandler) => {
|
|
23
21
|
const deferreds = {};
|
|
24
22
|
|
|
25
23
|
/**
|
|
@@ -38,8 +36,6 @@ export class TimeoutProvider {
|
|
|
38
36
|
*
|
|
39
37
|
* @param {function()=} fn A function, whose execution should be delayed.
|
|
40
38
|
* @param {number=} [delay=0] Delay in milliseconds.
|
|
41
|
-
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
|
42
|
-
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
|
43
39
|
* @returns {import("../q/q").QPromise<any>} Promise that will be resolved when the timeout is reached. The promise
|
|
44
40
|
* will be resolved with the return value of the `fn` function.
|
|
45
41
|
*
|
|
@@ -47,7 +43,7 @@ export class TimeoutProvider {
|
|
|
47
43
|
function timeout(fn, delay, invokeApply = true) {
|
|
48
44
|
const args = sliceArgs(arguments, 3);
|
|
49
45
|
const skipApply = isDefined(invokeApply) && !invokeApply;
|
|
50
|
-
const deferred =
|
|
46
|
+
const deferred = $q.defer();
|
|
51
47
|
const { promise } = deferred;
|
|
52
48
|
let timeoutId;
|
|
53
49
|
|
|
@@ -11,7 +11,7 @@ Object.entries(BOOLEAN_ATTR).forEach(([attrName, propName]) => {
|
|
|
11
11
|
// binding to multiple is not supported
|
|
12
12
|
if (propName === "multiple") return;
|
|
13
13
|
|
|
14
|
-
function defaultLinkFn(scope,
|
|
14
|
+
function defaultLinkFn(scope, _element, attr) {
|
|
15
15
|
scope.$watch(attr[normalized], (value) => {
|
|
16
16
|
attr.$set(attrName, !!value);
|
|
17
17
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Angular } from "../../loader";
|
|
2
|
-
import { createInjector } from "../../core/di/injector";
|
|
3
2
|
import { dealoc, JQLite } from "../../shared/jqlite/jqlite";
|
|
4
3
|
import { EMAIL_REGEXP, ISO_DATE_REGEXP, URL_REGEXP } from "./input";
|
|
5
4
|
import { forEach } from "../../shared/utils";
|