@angular-wave/angular.ts 0.0.1
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/.eslintignore +1 -0
- package/.eslintrc.cjs +29 -0
- package/.github/workflows/playwright.yml +27 -0
- package/CHANGELOG.md +17974 -0
- package/CODE_OF_CONDUCT.md +3 -0
- package/CONTRIBUTING.md +246 -0
- package/DEVELOPERS.md +488 -0
- package/LICENSE +22 -0
- package/Makefile +31 -0
- package/README.md +115 -0
- package/RELEASE.md +98 -0
- package/SECURITY.md +16 -0
- package/TRIAGING.md +135 -0
- package/css/angular.css +22 -0
- package/dist/angular-ts.cjs.js +36843 -0
- package/dist/angular-ts.esm.js +36841 -0
- package/dist/angular-ts.umd.js +36848 -0
- package/dist/build/angular-animate.js +4272 -0
- package/dist/build/angular-aria.js +426 -0
- package/dist/build/angular-message-format.js +1072 -0
- package/dist/build/angular-messages.js +829 -0
- package/dist/build/angular-mocks.js +3757 -0
- package/dist/build/angular-parse-ext.js +1275 -0
- package/dist/build/angular-resource.js +911 -0
- package/dist/build/angular-route.js +1266 -0
- package/dist/build/angular-sanitize.js +891 -0
- package/dist/build/angular-touch.js +368 -0
- package/dist/build/angular.js +36600 -0
- package/e2e/unit.spec.ts +15 -0
- package/images/android-chrome-192x192.png +0 -0
- package/images/android-chrome-512x512.png +0 -0
- package/images/apple-touch-icon.png +0 -0
- package/images/favicon-16x16.png +0 -0
- package/images/favicon-32x32.png +0 -0
- package/images/favicon.ico +0 -0
- package/images/site.webmanifest +1 -0
- package/index.html +104 -0
- package/package.json +47 -0
- package/playwright.config.ts +78 -0
- package/public/circle.html +1 -0
- package/public/my_child_directive.html +1 -0
- package/public/my_directive.html +1 -0
- package/public/my_other_directive.html +1 -0
- package/public/test.html +1 -0
- package/rollup.config.js +31 -0
- package/src/animations/animateCache.js +55 -0
- package/src/animations/animateChildrenDirective.js +105 -0
- package/src/animations/animateCss.js +1139 -0
- package/src/animations/animateCssDriver.js +291 -0
- package/src/animations/animateJs.js +367 -0
- package/src/animations/animateJsDriver.js +67 -0
- package/src/animations/animateQueue.js +851 -0
- package/src/animations/animation.js +506 -0
- package/src/animations/module.js +779 -0
- package/src/animations/ngAnimateSwap.js +119 -0
- package/src/animations/rafScheduler.js +50 -0
- package/src/animations/shared.js +378 -0
- package/src/constants.js +20 -0
- package/src/core/animate.js +845 -0
- package/src/core/animateCss.js +73 -0
- package/src/core/animateRunner.js +195 -0
- package/src/core/attributes.js +199 -0
- package/src/core/cache.js +45 -0
- package/src/core/compile.js +4727 -0
- package/src/core/controller.js +225 -0
- package/src/core/exceptionHandler.js +63 -0
- package/src/core/filter.js +146 -0
- package/src/core/interpolate.js +442 -0
- package/src/core/interval.js +188 -0
- package/src/core/intervalFactory.js +57 -0
- package/src/core/location.js +1086 -0
- package/src/core/parser/parse.js +2562 -0
- package/src/core/parser/parse.md +13 -0
- package/src/core/q.js +746 -0
- package/src/core/rootScope.js +1596 -0
- package/src/core/sanitizeUri.js +85 -0
- package/src/core/sce.js +1161 -0
- package/src/core/taskTrackerFactory.js +125 -0
- package/src/core/timeout.js +121 -0
- package/src/core/urlUtils.js +187 -0
- package/src/core/utils.js +1349 -0
- package/src/directive/a.js +37 -0
- package/src/directive/attrs.js +283 -0
- package/src/directive/bind.js +51 -0
- package/src/directive/bind.md +142 -0
- package/src/directive/change.js +12 -0
- package/src/directive/change.md +25 -0
- package/src/directive/cloak.js +12 -0
- package/src/directive/cloak.md +24 -0
- package/src/directive/events.js +75 -0
- package/src/directive/events.md +166 -0
- package/src/directive/form.js +725 -0
- package/src/directive/init.js +15 -0
- package/src/directive/init.md +41 -0
- package/src/directive/input.js +1783 -0
- package/src/directive/list.js +46 -0
- package/src/directive/list.md +22 -0
- package/src/directive/ngClass.js +249 -0
- package/src/directive/ngController.js +64 -0
- package/src/directive/ngCsp.js +82 -0
- package/src/directive/ngIf.js +134 -0
- package/src/directive/ngInclude.js +217 -0
- package/src/directive/ngModel.js +1356 -0
- package/src/directive/ngModelOptions.js +509 -0
- package/src/directive/ngOptions.js +670 -0
- package/src/directive/ngRef.js +90 -0
- package/src/directive/ngRepeat.js +650 -0
- package/src/directive/ngShowHide.js +255 -0
- package/src/directive/ngSwitch.js +178 -0
- package/src/directive/ngTransclude.js +98 -0
- package/src/directive/non-bindable.js +11 -0
- package/src/directive/non-bindable.md +17 -0
- package/src/directive/script.js +30 -0
- package/src/directive/select.js +624 -0
- package/src/directive/style.js +25 -0
- package/src/directive/style.md +23 -0
- package/src/directive/validators.js +329 -0
- package/src/exts/aria.js +544 -0
- package/src/exts/messages.js +852 -0
- package/src/filters/filter.js +207 -0
- package/src/filters/filter.md +69 -0
- package/src/filters/filters.js +239 -0
- package/src/filters/json.md +16 -0
- package/src/filters/limit-to.js +43 -0
- package/src/filters/limit-to.md +19 -0
- package/src/filters/order-by.js +183 -0
- package/src/filters/order-by.md +83 -0
- package/src/index.js +13 -0
- package/src/injector.js +1034 -0
- package/src/jqLite.js +1117 -0
- package/src/loader.js +1320 -0
- package/src/public.js +215 -0
- package/src/routeToRegExp.js +41 -0
- package/src/services/anchorScroll.js +135 -0
- package/src/services/browser.js +321 -0
- package/src/services/cacheFactory.js +398 -0
- package/src/services/cookieReader.js +72 -0
- package/src/services/document.js +64 -0
- package/src/services/http.js +1537 -0
- package/src/services/httpBackend.js +206 -0
- package/src/services/log.js +160 -0
- package/src/services/templateRequest.js +139 -0
- package/test/angular.spec.js +2153 -0
- package/test/aria/aria.spec.js +1245 -0
- package/test/binding.spec.js +504 -0
- package/test/build-test.html +14 -0
- package/test/injector.spec.js +2327 -0
- package/test/jasmine/jasmine-5.1.2/boot0.js +65 -0
- package/test/jasmine/jasmine-5.1.2/boot1.js +133 -0
- package/test/jasmine/jasmine-5.1.2/jasmine-html.js +963 -0
- package/test/jasmine/jasmine-5.1.2/jasmine.css +320 -0
- package/test/jasmine/jasmine-5.1.2/jasmine.js +10824 -0
- package/test/jasmine/jasmine-5.1.2/jasmine_favicon.png +0 -0
- package/test/jasmine/jasmine-browser.json +17 -0
- package/test/jasmine/jasmine.json +9 -0
- package/test/jqlite.spec.js +2133 -0
- package/test/loader.spec.js +219 -0
- package/test/messages/messages.spec.js +1146 -0
- package/test/min-err.spec.js +174 -0
- package/test/mock-test.html +13 -0
- package/test/module-test.html +15 -0
- package/test/ng/anomate.spec.js +606 -0
- package/test/ng/cache-factor.spec.js +334 -0
- package/test/ng/compile.spec.js +17956 -0
- package/test/ng/controller-provider.spec.js +227 -0
- package/test/ng/cookie-reader.spec.js +98 -0
- package/test/ng/directive/a.spec.js +192 -0
- package/test/ng/directive/bind.spec.js +334 -0
- package/test/ng/directive/boolean.spec.js +136 -0
- package/test/ng/directive/change.spec.js +71 -0
- package/test/ng/directive/class.spec.js +858 -0
- package/test/ng/directive/click.spec.js +38 -0
- package/test/ng/directive/cloak.spec.js +44 -0
- package/test/ng/directive/constoller.spec.js +194 -0
- package/test/ng/directive/element-style.spec.js +92 -0
- package/test/ng/directive/event.spec.js +282 -0
- package/test/ng/directive/form.spec.js +1518 -0
- package/test/ng/directive/href.spec.js +143 -0
- package/test/ng/directive/if.spec.js +402 -0
- package/test/ng/directive/include.spec.js +828 -0
- package/test/ng/directive/init.spec.js +68 -0
- package/test/ng/directive/input.spec.js +3810 -0
- package/test/ng/directive/list.spec.js +170 -0
- package/test/ng/directive/model-options.spec.js +1008 -0
- package/test/ng/directive/model.spec.js +1905 -0
- package/test/ng/directive/non-bindable.spec.js +55 -0
- package/test/ng/directive/options.spec.js +3583 -0
- package/test/ng/directive/ref.spec.js +575 -0
- package/test/ng/directive/repeat.spec.js +1675 -0
- package/test/ng/directive/script.spec.js +52 -0
- package/test/ng/directive/scrset.spec.js +67 -0
- package/test/ng/directive/select.spec.js +2541 -0
- package/test/ng/directive/show-hide.spec.js +253 -0
- package/test/ng/directive/src.spec.js +157 -0
- package/test/ng/directive/style.spec.js +178 -0
- package/test/ng/directive/switch.spec.js +647 -0
- package/test/ng/directive/validators.spec.js +717 -0
- package/test/ng/document.spec.js +52 -0
- package/test/ng/filter/filter.spec.js +714 -0
- package/test/ng/filter/filters.spec.js +35 -0
- package/test/ng/filter/limit-to.spec.js +251 -0
- package/test/ng/filter/order-by.spec.js +891 -0
- package/test/ng/filter.spec.js +149 -0
- package/test/ng/http-backend.spec.js +398 -0
- package/test/ng/http.spec.js +4071 -0
- package/test/ng/interpolate.spec.js +642 -0
- package/test/ng/interval.spec.js +343 -0
- package/test/ng/location.spec.js +3488 -0
- package/test/ng/on.spec.js +229 -0
- package/test/ng/parse.spec.js +4655 -0
- package/test/ng/prop.spec.js +805 -0
- package/test/ng/q.spec.js +2904 -0
- package/test/ng/root-element.spec.js +16 -0
- package/test/ng/sanitize-uri.spec.js +249 -0
- package/test/ng/sce.spec.js +660 -0
- package/test/ng/scope.spec.js +3442 -0
- package/test/ng/template-request.spec.js +236 -0
- package/test/ng/timeout.spec.js +351 -0
- package/test/ng/url-utils.spec.js +156 -0
- package/test/ng/utils.spec.js +144 -0
- package/test/original-test.html +21 -0
- package/test/public.spec.js +34 -0
- package/test/sanitize/bing-html.spec.js +36 -0
- package/test/server/express.js +158 -0
- package/test/test-utils.js +11 -0
- package/tsconfig.json +17 -0
- package/types/angular.d.ts +138 -0
- package/types/global.d.ts +9 -0
- package/types/index.d.ts +2357 -0
- package/types/jqlite.d.ts +558 -0
- package/vite.config.js +14 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import {
|
|
2
|
+
minErr,
|
|
3
|
+
isDefined,
|
|
4
|
+
isUndefined,
|
|
5
|
+
stringify,
|
|
6
|
+
valueFn,
|
|
7
|
+
extend,
|
|
8
|
+
} from "./utils";
|
|
9
|
+
|
|
10
|
+
const $interpolateMinErr = minErr("$interpolate");
|
|
11
|
+
$interpolateMinErr.throwNoconcat = function (text) {
|
|
12
|
+
throw $interpolateMinErr(
|
|
13
|
+
"noconcat",
|
|
14
|
+
"Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
|
|
15
|
+
"interpolations that concatenate multiple expressions when a trusted value is " +
|
|
16
|
+
"required. See http://docs.angularjs.org/api/ng.$sce",
|
|
17
|
+
text,
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
$interpolateMinErr.interr = function (text, err) {
|
|
22
|
+
throw $interpolateMinErr(
|
|
23
|
+
"interr",
|
|
24
|
+
"Can't interpolate: {0}\n{1}",
|
|
25
|
+
text,
|
|
26
|
+
err.toString(),
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @ngdoc provider
|
|
32
|
+
* @name $interpolateProvider
|
|
33
|
+
*
|
|
34
|
+
*
|
|
35
|
+
* @description
|
|
36
|
+
*
|
|
37
|
+
* Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
|
|
38
|
+
*
|
|
39
|
+
* <div class="alert alert-danger">
|
|
40
|
+
* This feature is sometimes used to mix different markup languages, e.g. to wrap an AngularJS
|
|
41
|
+
* template within a Python Jinja template (or any other template language). Mixing templating
|
|
42
|
+
* languages is **very dangerous**. The embedding template language will not safely escape AngularJS
|
|
43
|
+
* expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
|
|
44
|
+
* security bugs!
|
|
45
|
+
* </div>
|
|
46
|
+
*/
|
|
47
|
+
export function $InterpolateProvider() {
|
|
48
|
+
let startSymbol = "{{";
|
|
49
|
+
let endSymbol = "}}";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @ngdoc method
|
|
53
|
+
* @name $interpolateProvider#startSymbol
|
|
54
|
+
* @description
|
|
55
|
+
* Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
|
|
56
|
+
*
|
|
57
|
+
* @param {string=} value new value to set the starting symbol to.
|
|
58
|
+
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
|
|
59
|
+
*/
|
|
60
|
+
this.startSymbol = function (value) {
|
|
61
|
+
if (value) {
|
|
62
|
+
startSymbol = value;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
return startSymbol;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @ngdoc method
|
|
70
|
+
* @name $interpolateProvider#endSymbol
|
|
71
|
+
* @description
|
|
72
|
+
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
|
73
|
+
*
|
|
74
|
+
* @param {string=} value new value to set the ending symbol to.
|
|
75
|
+
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
|
|
76
|
+
*/
|
|
77
|
+
this.endSymbol = function (value) {
|
|
78
|
+
if (value) {
|
|
79
|
+
endSymbol = value;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
return endSymbol;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
this.$get = [
|
|
86
|
+
"$parse",
|
|
87
|
+
"$exceptionHandler",
|
|
88
|
+
"$sce",
|
|
89
|
+
function ($parse, $exceptionHandler, $sce) {
|
|
90
|
+
const startSymbolLength = startSymbol.length;
|
|
91
|
+
const endSymbolLength = endSymbol.length;
|
|
92
|
+
const escapedStartRegexp = new RegExp(
|
|
93
|
+
startSymbol.replace(/./g, escape),
|
|
94
|
+
"g",
|
|
95
|
+
);
|
|
96
|
+
const escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), "g");
|
|
97
|
+
|
|
98
|
+
function escape(ch) {
|
|
99
|
+
return `\\\\\\${ch}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function unescapeText(text) {
|
|
103
|
+
return text
|
|
104
|
+
.replace(escapedStartRegexp, startSymbol)
|
|
105
|
+
.replace(escapedEndRegexp, endSymbol);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// TODO: this is the same as the constantWatchDelegate in parse.js
|
|
109
|
+
function constantWatchDelegate(
|
|
110
|
+
scope,
|
|
111
|
+
listener,
|
|
112
|
+
objectEquality,
|
|
113
|
+
constantInterp,
|
|
114
|
+
) {
|
|
115
|
+
const unwatch = scope.$watch(
|
|
116
|
+
(scope) => {
|
|
117
|
+
unwatch();
|
|
118
|
+
return constantInterp(scope);
|
|
119
|
+
},
|
|
120
|
+
listener,
|
|
121
|
+
objectEquality,
|
|
122
|
+
);
|
|
123
|
+
return unwatch;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @ngdoc service
|
|
128
|
+
* @name $interpolate
|
|
129
|
+
* @kind function
|
|
130
|
+
*
|
|
131
|
+
* @requires $parse
|
|
132
|
+
* @requires $sce
|
|
133
|
+
*
|
|
134
|
+
* @description
|
|
135
|
+
*
|
|
136
|
+
* Compiles a string with markup into an interpolation function. This service is used by the
|
|
137
|
+
* HTML {@link ng.$compile $compile} service for data binding. See
|
|
138
|
+
* {@link ng.$interpolateProvider $interpolateProvider} for configuring the
|
|
139
|
+
* interpolation markup.
|
|
140
|
+
*
|
|
141
|
+
*
|
|
142
|
+
* ```js
|
|
143
|
+
* let $interpolate = ...; // injected
|
|
144
|
+
* let exp = $interpolate('Hello {{name | uppercase}}!');
|
|
145
|
+
* expect(exp({name:'AngularJS'})).toEqual('Hello ANGULARJS!');
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
|
|
149
|
+
* `true`, the interpolation function will return `undefined` unless all embedded expressions
|
|
150
|
+
* evaluate to a value other than `undefined`.
|
|
151
|
+
*
|
|
152
|
+
* ```js
|
|
153
|
+
* let $interpolate = ...; // injected
|
|
154
|
+
* let context = {greeting: 'Hello', name: undefined };
|
|
155
|
+
*
|
|
156
|
+
* // default "forgiving" mode
|
|
157
|
+
* let exp = $interpolate('{{greeting}} {{name}}!');
|
|
158
|
+
* expect(exp(context)).toEqual('Hello !');
|
|
159
|
+
*
|
|
160
|
+
* // "allOrNothing" mode
|
|
161
|
+
* exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
|
|
162
|
+
* expect(exp(context)).toBeUndefined();
|
|
163
|
+
* context.name = 'AngularJS';
|
|
164
|
+
* expect(exp(context)).toEqual('Hello AngularJS!');
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
|
|
168
|
+
*
|
|
169
|
+
* #### Escaped Interpolation
|
|
170
|
+
* $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
|
|
171
|
+
* can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
|
|
172
|
+
* It will be rendered as a regular start/end marker, and will not be interpreted as an expression
|
|
173
|
+
* or binding.
|
|
174
|
+
*
|
|
175
|
+
* This enables web-servers to prevent script injection attacks and defacing attacks, to some
|
|
176
|
+
* degree, while also enabling code examples to work without relying on the
|
|
177
|
+
* {@link ng.directive:ngNonBindable ngNonBindable} directive.
|
|
178
|
+
*
|
|
179
|
+
* **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
|
|
180
|
+
* replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all
|
|
181
|
+
* interpolation start/end markers with their escaped counterparts.**
|
|
182
|
+
*
|
|
183
|
+
* Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
|
|
184
|
+
* output when the $interpolate service processes the text. So, for HTML elements interpolated
|
|
185
|
+
* by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
|
|
186
|
+
* set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
|
|
187
|
+
* this is typically useful only when user-data is used in rendering a template from the server, or
|
|
188
|
+
* when otherwise untrusted data is used by a directive.
|
|
189
|
+
*
|
|
190
|
+
* <example name="interpolation">
|
|
191
|
+
* <file name="index.html">
|
|
192
|
+
* <div ng-init="username='A user'">
|
|
193
|
+
* <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
|
|
194
|
+
* </p>
|
|
195
|
+
* <p><strong>{{username}}</strong> attempts to inject code which will deface the
|
|
196
|
+
* application, but fails to accomplish their task, because the server has correctly
|
|
197
|
+
* escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
|
|
198
|
+
* characters.</p>
|
|
199
|
+
* <p>Instead, the result of the attempted script injection is visible, and can be removed
|
|
200
|
+
* from the database by an administrator.</p>
|
|
201
|
+
* </div>
|
|
202
|
+
* </file>
|
|
203
|
+
* </example>
|
|
204
|
+
*
|
|
205
|
+
* @knownIssue
|
|
206
|
+
* It is currently not possible for an interpolated expression to contain the interpolation end
|
|
207
|
+
* symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
|
|
208
|
+
* an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
|
|
209
|
+
*
|
|
210
|
+
* @knownIssue
|
|
211
|
+
* All directives and components must use the standard `{{` `}}` interpolation symbols
|
|
212
|
+
* in their templates. If you change the application interpolation symbols the {@link $compile}
|
|
213
|
+
* service will attempt to denormalize the standard symbols to the custom symbols.
|
|
214
|
+
* The denormalization process is not clever enough to know not to replace instances of the standard
|
|
215
|
+
* symbols where they would not normally be treated as interpolation symbols. For example in the following
|
|
216
|
+
* code snippet the closing braces of the literal object will get incorrectly denormalized:
|
|
217
|
+
*
|
|
218
|
+
* ```
|
|
219
|
+
* <div data-context='{"context":{"id":3,"type":"page"}}">
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* The workaround is to ensure that such instances are separated by whitespace:
|
|
223
|
+
* ```
|
|
224
|
+
* <div data-context='{"context":{"id":3,"type":"page"} }">
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.
|
|
228
|
+
*
|
|
229
|
+
* @param {string} text The text with markup to interpolate.
|
|
230
|
+
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
|
|
231
|
+
* embedded expression in order to return an interpolation function. Strings with no
|
|
232
|
+
* embedded expression will return null for the interpolation function.
|
|
233
|
+
* @param {string=} trustedContext when provided, the returned function passes the interpolated
|
|
234
|
+
* result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
|
|
235
|
+
* trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
|
|
236
|
+
* provides Strict Contextual Escaping for details.
|
|
237
|
+
* @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
|
|
238
|
+
* unless all embedded expressions evaluate to a value other than `undefined`.
|
|
239
|
+
* @returns {function(context)} an interpolation function which is used to compute the
|
|
240
|
+
* interpolated string. The function has these parameters:
|
|
241
|
+
*
|
|
242
|
+
* - `context`: evaluation context for all expressions embedded in the interpolated text
|
|
243
|
+
*/
|
|
244
|
+
function $interpolate(
|
|
245
|
+
text,
|
|
246
|
+
mustHaveExpression,
|
|
247
|
+
trustedContext,
|
|
248
|
+
allOrNothing,
|
|
249
|
+
) {
|
|
250
|
+
const contextAllowsConcatenation =
|
|
251
|
+
trustedContext === $sce.URL || trustedContext === $sce.MEDIA_URL;
|
|
252
|
+
|
|
253
|
+
// Provide a quick exit and simplified result function for text with no interpolation
|
|
254
|
+
if (!text.length || text.indexOf(startSymbol) === -1) {
|
|
255
|
+
if (mustHaveExpression) return;
|
|
256
|
+
|
|
257
|
+
let unescapedText = unescapeText(text);
|
|
258
|
+
if (contextAllowsConcatenation) {
|
|
259
|
+
unescapedText = $sce.getTrusted(trustedContext, unescapedText);
|
|
260
|
+
}
|
|
261
|
+
const constantInterp = valueFn(unescapedText);
|
|
262
|
+
constantInterp.exp = text;
|
|
263
|
+
constantInterp.expressions = [];
|
|
264
|
+
constantInterp.$$watchDelegate = constantWatchDelegate;
|
|
265
|
+
|
|
266
|
+
return constantInterp;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
allOrNothing = !!allOrNothing;
|
|
270
|
+
let startIndex;
|
|
271
|
+
let endIndex;
|
|
272
|
+
let index = 0;
|
|
273
|
+
const expressions = [];
|
|
274
|
+
let parseFns;
|
|
275
|
+
const textLength = text.length;
|
|
276
|
+
let exp;
|
|
277
|
+
const concat = [];
|
|
278
|
+
const expressionPositions = [];
|
|
279
|
+
let singleExpression;
|
|
280
|
+
|
|
281
|
+
while (index < textLength) {
|
|
282
|
+
if (
|
|
283
|
+
(startIndex = text.indexOf(startSymbol, index)) !== -1 &&
|
|
284
|
+
(endIndex = text.indexOf(
|
|
285
|
+
endSymbol,
|
|
286
|
+
startIndex + startSymbolLength,
|
|
287
|
+
)) !== -1
|
|
288
|
+
) {
|
|
289
|
+
if (index !== startIndex) {
|
|
290
|
+
concat.push(unescapeText(text.substring(index, startIndex)));
|
|
291
|
+
}
|
|
292
|
+
exp = text.substring(startIndex + startSymbolLength, endIndex);
|
|
293
|
+
expressions.push(exp);
|
|
294
|
+
index = endIndex + endSymbolLength;
|
|
295
|
+
expressionPositions.push(concat.length);
|
|
296
|
+
concat.push(""); // Placeholder that will get replaced with the evaluated expression.
|
|
297
|
+
} else {
|
|
298
|
+
// we did not find an interpolation, so we have to add the remainder to the separators array
|
|
299
|
+
if (index !== textLength) {
|
|
300
|
+
concat.push(unescapeText(text.substring(index)));
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
singleExpression =
|
|
307
|
+
concat.length === 1 && expressionPositions.length === 1;
|
|
308
|
+
// Intercept expression if we need to stringify concatenated inputs, which may be SCE trusted
|
|
309
|
+
// objects rather than simple strings
|
|
310
|
+
// (we don't modify the expression if the input consists of only a single trusted input)
|
|
311
|
+
const interceptor =
|
|
312
|
+
contextAllowsConcatenation && singleExpression
|
|
313
|
+
? undefined
|
|
314
|
+
: parseStringifyInterceptor;
|
|
315
|
+
parseFns = expressions.map((exp) => $parse(exp, interceptor));
|
|
316
|
+
|
|
317
|
+
// Concatenating expressions makes it hard to reason about whether some combination of
|
|
318
|
+
// concatenated values are unsafe to use and could easily lead to XSS. By requiring that a
|
|
319
|
+
// single expression be used for some $sce-managed secure contexts (RESOURCE_URLs mostly),
|
|
320
|
+
// we ensure that the value that's used is assigned or constructed by some JS code somewhere
|
|
321
|
+
// that is more testable or make it obvious that you bound the value to some user controlled
|
|
322
|
+
// value. This helps reduce the load when auditing for XSS issues.
|
|
323
|
+
|
|
324
|
+
// Note that URL and MEDIA_URL $sce contexts do not need this, since `$sce` can sanitize the values
|
|
325
|
+
// passed to it. In that case, `$sce.getTrusted` will be called on either the single expression
|
|
326
|
+
// or on the overall concatenated string (losing trusted types used in the mix, by design).
|
|
327
|
+
// Both these methods will sanitize plain strings. Also, HTML could be included, but since it's
|
|
328
|
+
// only used in srcdoc attributes, this would not be very useful.
|
|
329
|
+
|
|
330
|
+
if (!mustHaveExpression || expressions.length) {
|
|
331
|
+
const compute = function (values) {
|
|
332
|
+
for (let i = 0, ii = expressions.length; i < ii; i++) {
|
|
333
|
+
if (allOrNothing && isUndefined(values[i])) return;
|
|
334
|
+
concat[expressionPositions[i]] = values[i];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (contextAllowsConcatenation) {
|
|
338
|
+
// If `singleExpression` then `concat[0]` might be a "trusted" value or `null`, rather than a string
|
|
339
|
+
return $sce.getTrusted(
|
|
340
|
+
trustedContext,
|
|
341
|
+
singleExpression ? concat[0] : concat.join(""),
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (trustedContext && concat.length > 1) {
|
|
345
|
+
// This context does not allow more than one part, e.g. expr + string or exp + exp.
|
|
346
|
+
$interpolateMinErr.throwNoconcat(text);
|
|
347
|
+
}
|
|
348
|
+
// In an unprivileged context or only one part: just concatenate and return.
|
|
349
|
+
return concat.join("");
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
return extend(
|
|
353
|
+
(context) => {
|
|
354
|
+
let i = 0;
|
|
355
|
+
const ii = expressions.length;
|
|
356
|
+
const values = new Array(ii);
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
for (; i < ii; i++) {
|
|
360
|
+
values[i] = parseFns[i](context);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return compute(values);
|
|
364
|
+
} catch (err) {
|
|
365
|
+
$exceptionHandler($interpolateMinErr.interr(text, err));
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
// all of these properties are undocumented for now
|
|
370
|
+
exp: text, // just for compatibility with regular watchers created via $watch
|
|
371
|
+
expressions,
|
|
372
|
+
$$watchDelegate(scope, listener) {
|
|
373
|
+
let lastValue;
|
|
374
|
+
return scope.$watchGroup(
|
|
375
|
+
parseFns,
|
|
376
|
+
function interpolateFnWatcher(values, oldValues) {
|
|
377
|
+
const currValue = compute(values);
|
|
378
|
+
listener.call(
|
|
379
|
+
this,
|
|
380
|
+
currValue,
|
|
381
|
+
values !== oldValues ? lastValue : currValue,
|
|
382
|
+
scope,
|
|
383
|
+
);
|
|
384
|
+
lastValue = currValue;
|
|
385
|
+
},
|
|
386
|
+
);
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function parseStringifyInterceptor(value) {
|
|
393
|
+
try {
|
|
394
|
+
// In concatenable contexts, getTrusted comes at the end, to avoid sanitizing individual
|
|
395
|
+
// parts of a full URL. We don't care about losing the trustedness here.
|
|
396
|
+
// In non-concatenable contexts, where there is only one expression, this interceptor is
|
|
397
|
+
// not applied to the expression.
|
|
398
|
+
value =
|
|
399
|
+
trustedContext && !contextAllowsConcatenation
|
|
400
|
+
? $sce.getTrusted(trustedContext, value)
|
|
401
|
+
: $sce.valueOf(value);
|
|
402
|
+
return allOrNothing && !isDefined(value) ? value : stringify(value);
|
|
403
|
+
} catch (err) {
|
|
404
|
+
$exceptionHandler($interpolateMinErr.interr(text, err));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* @ngdoc method
|
|
411
|
+
* @name $interpolate#startSymbol
|
|
412
|
+
* @description
|
|
413
|
+
* Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
|
|
414
|
+
*
|
|
415
|
+
* Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
|
|
416
|
+
* the symbol.
|
|
417
|
+
*
|
|
418
|
+
* @returns {string} start symbol.
|
|
419
|
+
*/
|
|
420
|
+
$interpolate.startSymbol = function () {
|
|
421
|
+
return startSymbol;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @ngdoc method
|
|
426
|
+
* @name $interpolate#endSymbol
|
|
427
|
+
* @description
|
|
428
|
+
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
|
429
|
+
*
|
|
430
|
+
* Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
|
|
431
|
+
* the symbol.
|
|
432
|
+
*
|
|
433
|
+
* @returns {string} end symbol.
|
|
434
|
+
*/
|
|
435
|
+
$interpolate.endSymbol = function () {
|
|
436
|
+
return endSymbol;
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
return $interpolate;
|
|
440
|
+
},
|
|
441
|
+
];
|
|
442
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { markQExceptionHandled } from "./q";
|
|
2
|
+
import { minErr } from "./utils";
|
|
3
|
+
|
|
4
|
+
const $intervalMinErr = minErr("$interval");
|
|
5
|
+
|
|
6
|
+
export function $IntervalProvider() {
|
|
7
|
+
this.$get = [
|
|
8
|
+
"$$intervalFactory",
|
|
9
|
+
function ($$intervalFactory) {
|
|
10
|
+
const intervals = {};
|
|
11
|
+
const setIntervalFn = function (tick, delay, deferred) {
|
|
12
|
+
const id = window.setInterval(tick, delay);
|
|
13
|
+
intervals[id] = deferred;
|
|
14
|
+
return id;
|
|
15
|
+
};
|
|
16
|
+
const clearIntervalFn = function (id) {
|
|
17
|
+
window.clearInterval(id);
|
|
18
|
+
delete intervals[id];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @ngdoc service
|
|
23
|
+
* @name $interval
|
|
24
|
+
*
|
|
25
|
+
* @description
|
|
26
|
+
* AngularJS's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
|
|
27
|
+
* milliseconds.
|
|
28
|
+
*
|
|
29
|
+
* The return value of registering an interval function is a promise. This promise will be
|
|
30
|
+
* notified upon each tick of the interval, and will be resolved after `count` iterations, or
|
|
31
|
+
* run indefinitely if `count` is not defined. The value of the notification will be the
|
|
32
|
+
* number of iterations that have run.
|
|
33
|
+
* To cancel an interval, call `$interval.cancel(promise)`.
|
|
34
|
+
*
|
|
35
|
+
* In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
|
|
36
|
+
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
|
|
37
|
+
* time.
|
|
38
|
+
*
|
|
39
|
+
* <div class="alert alert-warning">
|
|
40
|
+
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
|
|
41
|
+
* with them. In particular they are not automatically destroyed when a controller's scope or a
|
|
42
|
+
* directive's element are destroyed.
|
|
43
|
+
* You should take this into consideration and make sure to always cancel the interval at the
|
|
44
|
+
* appropriate moment. See the example below for more details on how and when to do this.
|
|
45
|
+
* </div>
|
|
46
|
+
*
|
|
47
|
+
* @param {function()} fn A function that should be called repeatedly. If no additional arguments
|
|
48
|
+
* are passed (see below), the function is called with the current iteration count.
|
|
49
|
+
* @param {number} delay Number of milliseconds between each function call.
|
|
50
|
+
* @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
|
|
51
|
+
* indefinitely.
|
|
52
|
+
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
|
53
|
+
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
|
54
|
+
* @param {...*=} Pass additional parameters to the executed function.
|
|
55
|
+
* @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* <example module="intervalExample" name="interval-service">
|
|
59
|
+
* <file name="index.html">
|
|
60
|
+
* <script>
|
|
61
|
+
* angular.module('intervalExample', [])
|
|
62
|
+
* .controller('ExampleController', ['$scope', '$interval',
|
|
63
|
+
* function($scope, $interval) {
|
|
64
|
+
* $scope.format = 'M/d/yy h:mm:ss a';
|
|
65
|
+
* $scope.blood_1 = 100;
|
|
66
|
+
* $scope.blood_2 = 120;
|
|
67
|
+
*
|
|
68
|
+
* let stop;
|
|
69
|
+
* $scope.fight = function() {
|
|
70
|
+
* // Don't start a new fight if we are already fighting
|
|
71
|
+
* if ( angular.isDefined(stop) ) return;
|
|
72
|
+
*
|
|
73
|
+
* stop = $interval(function() {
|
|
74
|
+
* if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
|
75
|
+
* $scope.blood_1 = $scope.blood_1 - 3;
|
|
76
|
+
* $scope.blood_2 = $scope.blood_2 - 4;
|
|
77
|
+
* } else {
|
|
78
|
+
* $scope.stopFight();
|
|
79
|
+
* }
|
|
80
|
+
* }, 100);
|
|
81
|
+
* };
|
|
82
|
+
*
|
|
83
|
+
* $scope.stopFight = function() {
|
|
84
|
+
* if (angular.isDefined(stop)) {
|
|
85
|
+
* $interval.cancel(stop);
|
|
86
|
+
* stop = undefined;
|
|
87
|
+
* }
|
|
88
|
+
* };
|
|
89
|
+
*
|
|
90
|
+
* $scope.resetFight = function() {
|
|
91
|
+
* $scope.blood_1 = 100;
|
|
92
|
+
* $scope.blood_2 = 120;
|
|
93
|
+
* };
|
|
94
|
+
*
|
|
95
|
+
* $scope.$on('$destroy', function() {
|
|
96
|
+
* // Make sure that the interval is destroyed too
|
|
97
|
+
* $scope.stopFight();
|
|
98
|
+
* });
|
|
99
|
+
* }])
|
|
100
|
+
* // Register the 'myCurrentTime' directive factory method.
|
|
101
|
+
* // We inject $interval and dateFilter service since the factory method is DI.
|
|
102
|
+
* .directive('myCurrentTime', ['$interval', 'dateFilter',
|
|
103
|
+
* function($interval, dateFilter) {
|
|
104
|
+
* // return the directive link function. (compile function not needed)
|
|
105
|
+
* return function(scope, element, attrs) {
|
|
106
|
+
* let format, // date format
|
|
107
|
+
* stopTime; // so that we can cancel the time updates
|
|
108
|
+
*
|
|
109
|
+
* // used to update the UI
|
|
110
|
+
* function updateTime() {
|
|
111
|
+
* element.text(dateFilter(new Date(), format));
|
|
112
|
+
* }
|
|
113
|
+
*
|
|
114
|
+
* // watch the expression, and update the UI on change.
|
|
115
|
+
* scope.$watch(attrs.myCurrentTime, function(value) {
|
|
116
|
+
* format = value;
|
|
117
|
+
* updateTime();
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* stopTime = $interval(updateTime, 1000);
|
|
121
|
+
*
|
|
122
|
+
* // listen on DOM destroy (removal) event, and cancel the next UI update
|
|
123
|
+
* // to prevent updating time after the DOM element was removed.
|
|
124
|
+
* element.on('$destroy', function() {
|
|
125
|
+
* $interval.cancel(stopTime);
|
|
126
|
+
* });
|
|
127
|
+
* }
|
|
128
|
+
* }]);
|
|
129
|
+
* </script>
|
|
130
|
+
*
|
|
131
|
+
* <div>
|
|
132
|
+
* <div ng-controller="ExampleController">
|
|
133
|
+
* <label>Date format: <input ng-model="format"></label> <hr/>
|
|
134
|
+
* Current time is: <span my-current-time="format"></span>
|
|
135
|
+
* <hr/>
|
|
136
|
+
* Blood 1 : <font color='red'>{{blood_1}}</font>
|
|
137
|
+
* Blood 2 : <font color='red'>{{blood_2}}</font>
|
|
138
|
+
* <button type="button" data-ng-click="fight()">Fight</button>
|
|
139
|
+
* <button type="button" data-ng-click="stopFight()">StopFight</button>
|
|
140
|
+
* <button type="button" data-ng-click="resetFight()">resetFight</button>
|
|
141
|
+
* </div>
|
|
142
|
+
* </div>
|
|
143
|
+
*
|
|
144
|
+
* </file>
|
|
145
|
+
* </example>
|
|
146
|
+
*/
|
|
147
|
+
const interval = $$intervalFactory(setIntervalFn, clearIntervalFn);
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @ngdoc method
|
|
151
|
+
* @name $interval#cancel
|
|
152
|
+
*
|
|
153
|
+
* @description
|
|
154
|
+
* Cancels a task associated with the `promise`.
|
|
155
|
+
*
|
|
156
|
+
* @param {Promise=} promise returned by the `$interval` function.
|
|
157
|
+
* @returns {boolean} Returns `true` if the task was successfully canceled.
|
|
158
|
+
*/
|
|
159
|
+
interval.cancel = function (promise) {
|
|
160
|
+
if (!promise) return false;
|
|
161
|
+
|
|
162
|
+
if (!Object.prototype.hasOwnProperty.call(promise, "$$intervalId")) {
|
|
163
|
+
throw $intervalMinErr(
|
|
164
|
+
"badprom",
|
|
165
|
+
"`$interval.cancel()` called with a promise that was not generated by `$interval()`.",
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
!Object.prototype.hasOwnProperty.call(intervals, promise.$$intervalId)
|
|
171
|
+
)
|
|
172
|
+
return false;
|
|
173
|
+
|
|
174
|
+
const id = promise.$$intervalId;
|
|
175
|
+
const deferred = intervals[id];
|
|
176
|
+
|
|
177
|
+
// Interval cancels should not report an unhandled promise.
|
|
178
|
+
markQExceptionHandled(deferred.promise);
|
|
179
|
+
deferred.reject("canceled");
|
|
180
|
+
clearIntervalFn(id);
|
|
181
|
+
|
|
182
|
+
return true;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return interval;
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isDefined, sliceArgs } from "./utils";
|
|
2
|
+
|
|
3
|
+
export function $$IntervalFactoryProvider() {
|
|
4
|
+
this.$get = [
|
|
5
|
+
"$browser",
|
|
6
|
+
"$q",
|
|
7
|
+
"$$q",
|
|
8
|
+
"$rootScope",
|
|
9
|
+
function ($browser, $q, $$q, $rootScope) {
|
|
10
|
+
return function intervalFactory(setIntervalFn, clearIntervalFn) {
|
|
11
|
+
return function intervalFn(fn, delay, count, invokeApply) {
|
|
12
|
+
const hasParams = arguments.length > 4;
|
|
13
|
+
const args = hasParams ? sliceArgs(arguments, 4) : [];
|
|
14
|
+
let iteration = 0;
|
|
15
|
+
const skipApply = isDefined(invokeApply) && !invokeApply;
|
|
16
|
+
const deferred = (skipApply ? $$q : $q).defer();
|
|
17
|
+
const { promise } = deferred;
|
|
18
|
+
|
|
19
|
+
count = isDefined(count) ? count : 0;
|
|
20
|
+
|
|
21
|
+
function callback() {
|
|
22
|
+
if (!hasParams) {
|
|
23
|
+
fn(iteration);
|
|
24
|
+
} else {
|
|
25
|
+
fn.apply(null, args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function tick() {
|
|
30
|
+
if (skipApply) {
|
|
31
|
+
$browser.defer(callback);
|
|
32
|
+
} else {
|
|
33
|
+
$rootScope.$evalAsync(callback);
|
|
34
|
+
}
|
|
35
|
+
deferred.notify(iteration++);
|
|
36
|
+
|
|
37
|
+
if (count > 0 && iteration >= count) {
|
|
38
|
+
deferred.resolve(iteration);
|
|
39
|
+
clearIntervalFn(promise.$$intervalId);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!skipApply) $rootScope.$apply();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
promise.$$intervalId = setIntervalFn(
|
|
46
|
+
tick,
|
|
47
|
+
delay,
|
|
48
|
+
deferred,
|
|
49
|
+
skipApply,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return promise;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
}
|