@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,805 @@
|
|
|
1
|
+
import { publishExternalAPI } from "../../src/public";
|
|
2
|
+
import { createInjector } from "../../src/injector";
|
|
3
|
+
import { jqLite } from "../../src/jqLite";
|
|
4
|
+
import { valueFn } from "../../src/core/utils";
|
|
5
|
+
|
|
6
|
+
describe("ngProp*", () => {
|
|
7
|
+
let $compile, $rootScope, compileProvider, $sce;
|
|
8
|
+
let logs = [];
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
logs = [];
|
|
12
|
+
publishExternalAPI().decorator("$exceptionHandler", function () {
|
|
13
|
+
return (exception) => {
|
|
14
|
+
logs.push(exception);
|
|
15
|
+
throw new Error(exception);
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
let injector = createInjector([
|
|
19
|
+
"ng",
|
|
20
|
+
function ($compileProvider) {
|
|
21
|
+
compileProvider = $compileProvider;
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
$compile = injector.get("$compile");
|
|
25
|
+
$rootScope = injector.get("$rootScope");
|
|
26
|
+
$sce = injector.get("$sce");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should bind boolean properties (input disabled)", () => {
|
|
30
|
+
const element = $compile(
|
|
31
|
+
'<button ng-prop-disabled="isDisabled">Button</button>',
|
|
32
|
+
)($rootScope);
|
|
33
|
+
$rootScope.$digest();
|
|
34
|
+
expect(element.prop("disabled")).toBe(false);
|
|
35
|
+
$rootScope.isDisabled = true;
|
|
36
|
+
$rootScope.$digest();
|
|
37
|
+
expect(element.prop("disabled")).toBe(true);
|
|
38
|
+
$rootScope.isDisabled = false;
|
|
39
|
+
$rootScope.$digest();
|
|
40
|
+
expect(element.prop("disabled")).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should bind boolean properties (input checked)", () => {
|
|
44
|
+
const element = $compile(
|
|
45
|
+
'<input type="checkbox" ng-prop-checked="isChecked" />',
|
|
46
|
+
)($rootScope);
|
|
47
|
+
expect(element.prop("checked")).toBe(false);
|
|
48
|
+
$rootScope.isChecked = true;
|
|
49
|
+
$rootScope.$digest();
|
|
50
|
+
expect(element.prop("checked")).toBe(true);
|
|
51
|
+
$rootScope.isChecked = false;
|
|
52
|
+
$rootScope.$digest();
|
|
53
|
+
expect(element.prop("checked")).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should bind string properties (title)", () => {
|
|
57
|
+
const element = $compile('<span ng-prop-title="title" />')($rootScope);
|
|
58
|
+
$rootScope.title = 123;
|
|
59
|
+
$rootScope.$digest();
|
|
60
|
+
expect(element.prop("title")).toBe("123");
|
|
61
|
+
$rootScope.title = "foobar";
|
|
62
|
+
$rootScope.$digest();
|
|
63
|
+
expect(element.prop("title")).toBe("foobar");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should bind variable type properties", () => {
|
|
67
|
+
const element = $compile('<span ng-prop-asdf="asdf" />')($rootScope);
|
|
68
|
+
$rootScope.asdf = 123;
|
|
69
|
+
$rootScope.$digest();
|
|
70
|
+
expect(element.prop("asdf")).toBe(123);
|
|
71
|
+
$rootScope.asdf = "foobar";
|
|
72
|
+
$rootScope.$digest();
|
|
73
|
+
expect(element.prop("asdf")).toBe("foobar");
|
|
74
|
+
$rootScope.asdf = true;
|
|
75
|
+
$rootScope.$digest();
|
|
76
|
+
expect(element.prop("asdf")).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// https://github.com/angular/angular.js/issues/16797
|
|
80
|
+
it("should support falsy property values", () => {
|
|
81
|
+
const element = $compile('<span ng-prop-text="myText" />')($rootScope);
|
|
82
|
+
// Initialize to truthy value
|
|
83
|
+
$rootScope.myText = "abc";
|
|
84
|
+
$rootScope.$digest();
|
|
85
|
+
expect(element.prop("text")).toBe("abc");
|
|
86
|
+
|
|
87
|
+
// Assert various falsey values get assigned to the property
|
|
88
|
+
$rootScope.myText = "";
|
|
89
|
+
$rootScope.$digest();
|
|
90
|
+
expect(element.prop("text")).toBe("");
|
|
91
|
+
$rootScope.myText = 0;
|
|
92
|
+
$rootScope.$digest();
|
|
93
|
+
expect(element.prop("text")).toBe(0);
|
|
94
|
+
$rootScope.myText = false;
|
|
95
|
+
$rootScope.$digest();
|
|
96
|
+
expect(element.prop("text")).toBe(false);
|
|
97
|
+
$rootScope.myText = undefined;
|
|
98
|
+
$rootScope.$digest();
|
|
99
|
+
expect(element.prop("text")).toBeUndefined();
|
|
100
|
+
$rootScope.myText = null;
|
|
101
|
+
$rootScope.$digest();
|
|
102
|
+
expect(element.prop("text")).toBe(null);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should directly map special properties (class)", () => {
|
|
106
|
+
const element = $compile('<span ng-prop-class="myText" />')($rootScope);
|
|
107
|
+
$rootScope.myText = "abc";
|
|
108
|
+
$rootScope.$digest();
|
|
109
|
+
expect(element[0].class).toBe("abc");
|
|
110
|
+
expect(element[0]).not.toHaveClass("abc");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should not use jQuery .prop() to avoid jQuery propFix/hooks", () => {
|
|
114
|
+
const element = $compile('<span ng-prop-class="myText" />')($rootScope);
|
|
115
|
+
spyOn(jqLite.prototype, "prop");
|
|
116
|
+
$rootScope.myText = "abc";
|
|
117
|
+
$rootScope.$digest();
|
|
118
|
+
expect(jqLite.prototype.prop).not.toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should support mixed case using underscore-separated names", () => {
|
|
122
|
+
const element = $compile('<span ng-prop-a_bcd_e="value" />')($rootScope);
|
|
123
|
+
$rootScope.value = 123;
|
|
124
|
+
$rootScope.$digest();
|
|
125
|
+
expect(element.prop("aBcdE")).toBe(123);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should work with different prefixes", () => {
|
|
129
|
+
$rootScope.name = "Misko";
|
|
130
|
+
const element = $compile(
|
|
131
|
+
'<span ng:prop:test="name" ng-Prop-test2="name" ng_Prop_test3="name"></span>',
|
|
132
|
+
)($rootScope);
|
|
133
|
+
expect(element.prop("test")).toBe("Misko");
|
|
134
|
+
expect(element.prop("test2")).toBe("Misko");
|
|
135
|
+
expect(element.prop("test3")).toBe("Misko");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should work with the "href" property', () => {
|
|
139
|
+
$rootScope.value = "test";
|
|
140
|
+
const element = $compile("<a ng-prop-href=\"'test/' + value\"></a>")(
|
|
141
|
+
$rootScope,
|
|
142
|
+
);
|
|
143
|
+
$rootScope.$digest();
|
|
144
|
+
expect(element.prop("href")).toMatch(/\/test\/test$/);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should work if they are prefixed with x- or data- and different prefixes", () => {
|
|
148
|
+
$rootScope.name = "Misko";
|
|
149
|
+
const element = $compile(
|
|
150
|
+
'<span data-ng-prop-test2="name" x-ng-prop-test3="name" data-ng:prop-test4="name" ' +
|
|
151
|
+
'x_ng-prop-test5="name" data:ng-prop-test6="name"></span>',
|
|
152
|
+
)($rootScope);
|
|
153
|
+
expect(element.prop("test2")).toBe("Misko");
|
|
154
|
+
expect(element.prop("test3")).toBe("Misko");
|
|
155
|
+
expect(element.prop("test4")).toBe("Misko");
|
|
156
|
+
expect(element.prop("test5")).toBe("Misko");
|
|
157
|
+
expect(element.prop("test6")).toBe("Misko");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should work independently of attributes with the same name", () => {
|
|
161
|
+
const element = $compile('<span ng-prop-asdf="asdf" asdf="foo" />')(
|
|
162
|
+
$rootScope,
|
|
163
|
+
);
|
|
164
|
+
$rootScope.asdf = 123;
|
|
165
|
+
$rootScope.$digest();
|
|
166
|
+
expect(element.prop("asdf")).toBe(123);
|
|
167
|
+
expect(element.attr("asdf")).toBe("foo");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should work independently of (ng-)attributes with the same name", () => {
|
|
171
|
+
const element = $compile('<span ng-prop-asdf="asdf" ng-attr-asdf="foo" />')(
|
|
172
|
+
$rootScope,
|
|
173
|
+
);
|
|
174
|
+
$rootScope.asdf = 123;
|
|
175
|
+
$rootScope.$digest();
|
|
176
|
+
expect(element.prop("asdf")).toBe(123);
|
|
177
|
+
expect(element.attr("asdf")).toBe("foo");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should use the full ng-prop-* attribute name in $attr mappings", () => {
|
|
181
|
+
let attrs;
|
|
182
|
+
compileProvider.directive(
|
|
183
|
+
"attrExposer",
|
|
184
|
+
valueFn({
|
|
185
|
+
link($scope, $element, $attrs) {
|
|
186
|
+
attrs = $attrs;
|
|
187
|
+
},
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
$compile(
|
|
191
|
+
'<div attr-exposer ng-prop-title="12" ng-prop-super-title="34" ng-prop-my-camel_title="56">',
|
|
192
|
+
)($rootScope);
|
|
193
|
+
|
|
194
|
+
expect(attrs.title).toBeUndefined();
|
|
195
|
+
expect(attrs.$attr.title).toBeUndefined();
|
|
196
|
+
expect(attrs.ngPropTitle).toBe("12");
|
|
197
|
+
expect(attrs.$attr.ngPropTitle).toBe("ng-prop-title");
|
|
198
|
+
|
|
199
|
+
expect(attrs.superTitle).toBeUndefined();
|
|
200
|
+
expect(attrs.$attr.superTitle).toBeUndefined();
|
|
201
|
+
expect(attrs.ngPropSuperTitle).toBe("34");
|
|
202
|
+
expect(attrs.$attr.ngPropSuperTitle).toBe("ng-prop-super-title");
|
|
203
|
+
|
|
204
|
+
expect(attrs.myCamelTitle).toBeUndefined();
|
|
205
|
+
expect(attrs.$attr.myCamelTitle).toBeUndefined();
|
|
206
|
+
expect(attrs.ngPropMyCamelTitle).toBe("56");
|
|
207
|
+
expect(attrs.$attr.ngPropMyCamelTitle).toBe("ng-prop-my-camel_title");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should not conflict with (ng-attr-)attribute mappings of the same name", () => {
|
|
211
|
+
let attrs;
|
|
212
|
+
compileProvider.directive(
|
|
213
|
+
"attrExposer",
|
|
214
|
+
valueFn({
|
|
215
|
+
link($scope, $element, $attrs) {
|
|
216
|
+
attrs = $attrs;
|
|
217
|
+
},
|
|
218
|
+
}),
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
$compile(
|
|
222
|
+
'<div attr-exposer ng-prop-title="42" ng-attr-title="foo" title="bar">',
|
|
223
|
+
)($rootScope);
|
|
224
|
+
expect(attrs.title).toBe("foo");
|
|
225
|
+
expect(attrs.$attr.title).toBe("title");
|
|
226
|
+
expect(attrs.$attr.ngPropTitle).toBe("ng-prop-title");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should disallow property binding to onclick", () => {
|
|
230
|
+
// All event prop bindings are disallowed.
|
|
231
|
+
expect(() => {
|
|
232
|
+
$compile('<button ng-prop-onclick="onClickJs"></button>');
|
|
233
|
+
}).toThrowError(/nodomevents/);
|
|
234
|
+
expect(() => {
|
|
235
|
+
$compile('<button ng-prop-ONCLICK="onClickJs"></button>');
|
|
236
|
+
}).toThrowError(/nodomevents/);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("should process property bindings in pre-linking phase at priority 100", () => {
|
|
240
|
+
compileProvider.directive("propLog", () => ({
|
|
241
|
+
compile($element, $attrs) {
|
|
242
|
+
logs.push(`compile=${$element.prop("myName")}`);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
pre($scope, $element, $attrs) {
|
|
246
|
+
logs.push(`preLinkP0=${$element.prop("myName")}`);
|
|
247
|
+
$rootScope.name = "pre0";
|
|
248
|
+
},
|
|
249
|
+
post($scope, $element, $attrs) {
|
|
250
|
+
logs.push(`postLink=${$element.prop("myName")}`);
|
|
251
|
+
$rootScope.name = "post0";
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
},
|
|
255
|
+
}));
|
|
256
|
+
|
|
257
|
+
compileProvider.directive("propLogHighPriority", () => ({
|
|
258
|
+
priority: 101,
|
|
259
|
+
compile() {
|
|
260
|
+
return {
|
|
261
|
+
pre($scope, $element, $attrs) {
|
|
262
|
+
logs.push(`preLinkP101=${$element.prop("myName")}`);
|
|
263
|
+
$rootScope.name = "pre101";
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
}));
|
|
268
|
+
const element = $compile(
|
|
269
|
+
'<div prop-log-high-priority prop-log ng-prop-my_name="name"></div>',
|
|
270
|
+
)($rootScope);
|
|
271
|
+
$rootScope.name = "loader";
|
|
272
|
+
$rootScope.$apply();
|
|
273
|
+
logs.push(`digest=${element.prop("myName")}`);
|
|
274
|
+
expect(logs.join("; ")).toEqual(
|
|
275
|
+
"compile=undefined; preLinkP101=undefined; preLinkP0=pre101; postLink=pre101; digest=loader",
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("img[src] sanitization", () => {
|
|
280
|
+
it("should accept trusted values", () => {
|
|
281
|
+
const element = $compile('<img ng-prop-src="testUrl"></img>')($rootScope);
|
|
282
|
+
// Some browsers complain if you try to write `javascript:` into an `img[src]`
|
|
283
|
+
// So for the test use something different
|
|
284
|
+
$rootScope.testUrl = $sce.trustAsMediaUrl("someuntrustedthing:foo();");
|
|
285
|
+
$rootScope.$digest();
|
|
286
|
+
expect(element.prop("src")).toEqual("someuntrustedthing:foo();");
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should use $$sanitizeUri", () => {
|
|
290
|
+
const $$sanitizeUri = jasmine
|
|
291
|
+
.createSpy("$$sanitizeUri")
|
|
292
|
+
.and.returnValue("someSanitizedUrl");
|
|
293
|
+
createInjector([
|
|
294
|
+
"ng",
|
|
295
|
+
($provide) => {
|
|
296
|
+
$provide.value("$$sanitizeUri", $$sanitizeUri);
|
|
297
|
+
},
|
|
298
|
+
]).invoke((_$compile_, _$rootScope_) => {
|
|
299
|
+
$compile = _$compile_;
|
|
300
|
+
$rootScope = _$rootScope_;
|
|
301
|
+
});
|
|
302
|
+
const element = $compile('<img ng-prop-src="testUrl"></img>')($rootScope);
|
|
303
|
+
$rootScope.testUrl = "someUrl";
|
|
304
|
+
|
|
305
|
+
$rootScope.$apply();
|
|
306
|
+
expect(element.prop("src")).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
|
|
307
|
+
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, true);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("should not use $$sanitizeUri with trusted values", () => {
|
|
311
|
+
const $$sanitizeUri = jasmine
|
|
312
|
+
.createSpy("$$sanitizeUri")
|
|
313
|
+
.and.throwError("Should not have been called");
|
|
314
|
+
createInjector([
|
|
315
|
+
"ng",
|
|
316
|
+
($provide) => {
|
|
317
|
+
$provide.value("$$sanitizeUri", $$sanitizeUri);
|
|
318
|
+
},
|
|
319
|
+
]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
320
|
+
$compile = _$compile_;
|
|
321
|
+
$rootScope = _$rootScope_;
|
|
322
|
+
$sce = _$sce_;
|
|
323
|
+
});
|
|
324
|
+
const element = $compile('<img ng-prop-src="testUrl"></img>')($rootScope);
|
|
325
|
+
// Assigning javascript:foo to src makes at least IE9-11 complain, so use another
|
|
326
|
+
// protocol name.
|
|
327
|
+
$rootScope.testUrl = $sce.trustAsMediaUrl("untrusted:foo();");
|
|
328
|
+
$rootScope.$apply();
|
|
329
|
+
expect(element.prop("src")).toBe("untrusted:foo();");
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("a[href] sanitization", () => {
|
|
334
|
+
it("should NOT require trusted values for trusted URI values", () => {
|
|
335
|
+
$rootScope.testUrl = "http://example.com/image.png"; // `http` is trusted
|
|
336
|
+
let element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
337
|
+
$rootScope.$digest();
|
|
338
|
+
expect(element.prop("href")).toEqual("http://example.com/image.png");
|
|
339
|
+
|
|
340
|
+
element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
341
|
+
$rootScope.$digest();
|
|
342
|
+
expect(element.prop("href")).toEqual("http://example.com/image.png");
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("should accept trusted values for non-trusted URI values", () => {
|
|
346
|
+
$rootScope.testUrl = $sce.trustAsUrl("javascript:foo()"); // `javascript` is not trusted
|
|
347
|
+
let element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
348
|
+
$rootScope.$digest();
|
|
349
|
+
expect(element.prop("href")).toEqual("javascript:foo()");
|
|
350
|
+
|
|
351
|
+
element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
352
|
+
$rootScope.$digest();
|
|
353
|
+
expect(element.prop("href")).toEqual("javascript:foo()");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("should sanitize non-trusted values", () => {
|
|
357
|
+
$rootScope.testUrl = "javascript:foo()"; // `javascript` is not trusted
|
|
358
|
+
let element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
359
|
+
$rootScope.$digest();
|
|
360
|
+
expect(element.prop("href")).toEqual("unsafe:javascript:foo()");
|
|
361
|
+
|
|
362
|
+
element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
363
|
+
$rootScope.$digest();
|
|
364
|
+
expect(element.prop("href")).toEqual("unsafe:javascript:foo()");
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("should not sanitize href on elements other than anchor", () => {
|
|
368
|
+
const element = $compile('<div ng-prop-href="testUrl"></div>')(
|
|
369
|
+
$rootScope,
|
|
370
|
+
);
|
|
371
|
+
$rootScope.testUrl = "javascript:doEvilStuff()";
|
|
372
|
+
$rootScope.$apply();
|
|
373
|
+
|
|
374
|
+
expect(element.prop("href")).toBe("javascript:doEvilStuff()");
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should not sanitize properties other then those configured", () => {
|
|
378
|
+
const element = $compile('<a ng-prop-title="testUrl"></a>')($rootScope);
|
|
379
|
+
$rootScope.testUrl = "javascript:doEvilStuff()";
|
|
380
|
+
$rootScope.$apply();
|
|
381
|
+
|
|
382
|
+
expect(element.prop("title")).toBe("javascript:doEvilStuff()");
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("should use $$sanitizeUri", () => {
|
|
386
|
+
const $$sanitizeUri = jasmine
|
|
387
|
+
.createSpy("$$sanitizeUri")
|
|
388
|
+
.and.returnValue("someSanitizedUrl");
|
|
389
|
+
createInjector([
|
|
390
|
+
"ng",
|
|
391
|
+
($provide) => {
|
|
392
|
+
$provide.value("$$sanitizeUri", $$sanitizeUri);
|
|
393
|
+
},
|
|
394
|
+
]).invoke((_$compile_, _$rootScope_) => {
|
|
395
|
+
$compile = _$compile_;
|
|
396
|
+
$rootScope = _$rootScope_;
|
|
397
|
+
});
|
|
398
|
+
let element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
399
|
+
$rootScope.testUrl = "someUrl";
|
|
400
|
+
$rootScope.$apply();
|
|
401
|
+
expect(element.prop("href")).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
|
|
402
|
+
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
|
|
403
|
+
|
|
404
|
+
$$sanitizeUri.calls.reset();
|
|
405
|
+
|
|
406
|
+
element = $compile('<a ng-prop-href="testUrl"></a>')($rootScope);
|
|
407
|
+
$rootScope.$apply();
|
|
408
|
+
expect(element.prop("href")).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
|
|
409
|
+
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
it("should not have endless digests when given arrays in concatenable context", () => {
|
|
413
|
+
const element = $compile(
|
|
414
|
+
'<foo ng-prop-href="testUrl"></foo><foo ng-prop-href="::testUrl"></foo>' +
|
|
415
|
+
"<foo ng-prop-href=\"'http://example.com/' + testUrl\"></foo><foo ng-prop-href=\"::'http://example.com/' + testUrl\"></foo>",
|
|
416
|
+
)($rootScope);
|
|
417
|
+
$rootScope.testUrl = [1];
|
|
418
|
+
$rootScope.$digest();
|
|
419
|
+
|
|
420
|
+
$rootScope.testUrl = [];
|
|
421
|
+
$rootScope.$digest();
|
|
422
|
+
|
|
423
|
+
$rootScope.testUrl = { a: "b" };
|
|
424
|
+
$rootScope.$digest();
|
|
425
|
+
|
|
426
|
+
$rootScope.testUrl = {};
|
|
427
|
+
$rootScope.$digest();
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
describe("iframe[src]", () => {
|
|
432
|
+
beforeEach(() => {
|
|
433
|
+
createInjector(["ng"]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
434
|
+
$compile = _$compile_;
|
|
435
|
+
$rootScope = _$rootScope_;
|
|
436
|
+
$sce = _$sce_;
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("should pass through src properties for the same domain", () => {
|
|
441
|
+
const element = $compile('<iframe ng-prop-src="testUrl"></iframe>')(
|
|
442
|
+
$rootScope,
|
|
443
|
+
);
|
|
444
|
+
$rootScope.testUrl = "different_page";
|
|
445
|
+
$rootScope.$apply();
|
|
446
|
+
expect(element.prop("src")).toMatch(/\/different_page$/);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it("should clear out src properties for a different domain", () => {
|
|
450
|
+
const element = $compile('<iframe ng-prop-src="testUrl"></iframe>')(
|
|
451
|
+
$rootScope,
|
|
452
|
+
);
|
|
453
|
+
$rootScope.testUrl = "http://a.different.domain.example.com";
|
|
454
|
+
expect(() => {
|
|
455
|
+
$rootScope.$apply();
|
|
456
|
+
}).toThrowError(/insecurl/);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it("should clear out JS src properties", () => {
|
|
460
|
+
const element = $compile('<iframe ng-prop-src="testUrl"></iframe>')(
|
|
461
|
+
$rootScope,
|
|
462
|
+
);
|
|
463
|
+
$rootScope.testUrl = "javascript:alert(1);";
|
|
464
|
+
expect(() => {
|
|
465
|
+
$rootScope.$apply();
|
|
466
|
+
}).toThrowError(/insecurl/);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it("should clear out non-resource_url src properties", () => {
|
|
470
|
+
const element = $compile('<iframe ng-prop-src="testUrl"></iframe>')(
|
|
471
|
+
$rootScope,
|
|
472
|
+
);
|
|
473
|
+
$rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
|
|
474
|
+
expect(() => {
|
|
475
|
+
$rootScope.$apply();
|
|
476
|
+
}).toThrowError(/insecurl/);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("should pass through $sce.trustAs() values in src properties", () => {
|
|
480
|
+
const element = $compile('<iframe ng-prop-src="testUrl"></iframe>')(
|
|
481
|
+
$rootScope,
|
|
482
|
+
);
|
|
483
|
+
$rootScope.testUrl = $sce.trustAsResourceUrl(
|
|
484
|
+
"javascript:doTrustedStuff()",
|
|
485
|
+
);
|
|
486
|
+
$rootScope.$apply();
|
|
487
|
+
|
|
488
|
+
expect(element.prop("src")).toEqual("javascript:doTrustedStuff()");
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
describe("base[href]", () => {
|
|
493
|
+
beforeEach(() => {
|
|
494
|
+
createInjector(["ng"]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
495
|
+
$compile = _$compile_;
|
|
496
|
+
$rootScope = _$rootScope_;
|
|
497
|
+
$sce = _$sce_;
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it("should be a RESOURCE_URL context", () => {
|
|
502
|
+
const element = $compile('<base ng-prop-href="testUrl"/>')($rootScope);
|
|
503
|
+
|
|
504
|
+
$rootScope.testUrl = $sce.trustAsResourceUrl("https://example.com/");
|
|
505
|
+
$rootScope.$apply();
|
|
506
|
+
expect(element.prop("href")).toContain("https://example.com/");
|
|
507
|
+
|
|
508
|
+
$rootScope.testUrl = "https://not.example.com/";
|
|
509
|
+
expect(() => {
|
|
510
|
+
$rootScope.$apply();
|
|
511
|
+
}).toThrowError(/insecurl/);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
describe("form[action]", () => {
|
|
516
|
+
beforeEach(() => {
|
|
517
|
+
createInjector(["ng"]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
518
|
+
$compile = _$compile_;
|
|
519
|
+
$rootScope = _$rootScope_;
|
|
520
|
+
$sce = _$sce_;
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it("should pass through action property for the same domain", () => {
|
|
525
|
+
const element = $compile('<form ng-prop-action="testUrl"></form>')(
|
|
526
|
+
$rootScope,
|
|
527
|
+
);
|
|
528
|
+
$rootScope.testUrl = "different_page";
|
|
529
|
+
$rootScope.$apply();
|
|
530
|
+
expect(element.prop("action")).toMatch(/\/different_page$/);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it("should clear out action property for a different domain", () => {
|
|
534
|
+
const element = $compile('<form ng-prop-action="testUrl"></form>')(
|
|
535
|
+
$rootScope,
|
|
536
|
+
);
|
|
537
|
+
$rootScope.testUrl = "http://a.different.domain.example.com";
|
|
538
|
+
expect(() => {
|
|
539
|
+
$rootScope.$apply();
|
|
540
|
+
}).toThrowError(/insecurl/);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it("should clear out JS action property", () => {
|
|
544
|
+
const element = $compile('<form ng-prop-action="testUrl"></form>')(
|
|
545
|
+
$rootScope,
|
|
546
|
+
);
|
|
547
|
+
$rootScope.testUrl = "javascript:alert(1);";
|
|
548
|
+
expect(() => {
|
|
549
|
+
$rootScope.$apply();
|
|
550
|
+
}).toThrowError(/insecurl/);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it("should clear out non-resource_url action property", () => {
|
|
554
|
+
const element = $compile('<form ng-prop-action="testUrl"></form>')(
|
|
555
|
+
$rootScope,
|
|
556
|
+
);
|
|
557
|
+
$rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
|
|
558
|
+
expect(() => {
|
|
559
|
+
$rootScope.$apply();
|
|
560
|
+
}).toThrowError(/insecurl/);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it("should pass through $sce.trustAsResourceUrl() values in action property", () => {
|
|
564
|
+
const element = $compile('<form ng-prop-action="testUrl"></form>')(
|
|
565
|
+
$rootScope,
|
|
566
|
+
);
|
|
567
|
+
$rootScope.testUrl = $sce.trustAsResourceUrl(
|
|
568
|
+
"javascript:doTrustedStuff()",
|
|
569
|
+
);
|
|
570
|
+
$rootScope.$apply();
|
|
571
|
+
|
|
572
|
+
expect(element.prop("action")).toEqual("javascript:doTrustedStuff()");
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe("link[href]", () => {
|
|
577
|
+
beforeEach(() => {
|
|
578
|
+
createInjector(["ng"]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
579
|
+
$compile = _$compile_;
|
|
580
|
+
$rootScope = _$rootScope_;
|
|
581
|
+
$sce = _$sce_;
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it("should reject invalid RESOURCE_URLs", () => {
|
|
586
|
+
const element = $compile(
|
|
587
|
+
'<link ng-prop-href="testUrl" rel="stylesheet" />',
|
|
588
|
+
)($rootScope);
|
|
589
|
+
$rootScope.testUrl = "https://evil.example.org/css.css";
|
|
590
|
+
expect(() => {
|
|
591
|
+
$rootScope.$apply();
|
|
592
|
+
}).toThrowError(/insecurl/);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it("should accept valid RESOURCE_URLs", () => {
|
|
596
|
+
const element = $compile(
|
|
597
|
+
'<link ng-prop-href="testUrl" rel="stylesheet" />',
|
|
598
|
+
)($rootScope);
|
|
599
|
+
|
|
600
|
+
$rootScope.testUrl = "./css1.css";
|
|
601
|
+
$rootScope.$apply();
|
|
602
|
+
expect(element.prop("href")).toContain("css1.css");
|
|
603
|
+
|
|
604
|
+
$rootScope.testUrl = $sce.trustAsResourceUrl(
|
|
605
|
+
"https://elsewhere.example.org/css2.css",
|
|
606
|
+
);
|
|
607
|
+
$rootScope.$apply();
|
|
608
|
+
expect(element.prop("href")).toContain(
|
|
609
|
+
"https://elsewhere.example.org/css2.css",
|
|
610
|
+
);
|
|
611
|
+
});
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
describe("*[innerHTML]", () => {
|
|
615
|
+
describe("SCE disabled", () => {
|
|
616
|
+
beforeEach(() => {
|
|
617
|
+
createInjector([
|
|
618
|
+
"ng",
|
|
619
|
+
($sceProvider) => {
|
|
620
|
+
$sceProvider.enabled(false);
|
|
621
|
+
},
|
|
622
|
+
]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
623
|
+
$compile = _$compile_;
|
|
624
|
+
$rootScope = _$rootScope_;
|
|
625
|
+
$sce = _$sce_;
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("should set html", () => {
|
|
630
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
631
|
+
$rootScope,
|
|
632
|
+
);
|
|
633
|
+
$rootScope.html = '<div onclick="">hello</div>';
|
|
634
|
+
$rootScope.$digest();
|
|
635
|
+
expect(element.html()).toEqual('<div onclick="">hello</div>');
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it("should update html", () => {
|
|
639
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
640
|
+
$rootScope,
|
|
641
|
+
);
|
|
642
|
+
$rootScope.html = "hello";
|
|
643
|
+
$rootScope.$digest();
|
|
644
|
+
expect(element.html()).toEqual("hello");
|
|
645
|
+
$rootScope.html = "goodbye";
|
|
646
|
+
$rootScope.$digest();
|
|
647
|
+
expect(element.html()).toEqual("goodbye");
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
it("should one-time bind if the expression starts with two colons", () => {
|
|
651
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="::html"></div>')(
|
|
652
|
+
$rootScope,
|
|
653
|
+
);
|
|
654
|
+
$rootScope.html = '<div onclick="">hello</div>';
|
|
655
|
+
expect($rootScope.$$watchers.length).toEqual(1);
|
|
656
|
+
$rootScope.$digest();
|
|
657
|
+
expect(element.text()).toEqual("hello");
|
|
658
|
+
expect($rootScope.$$watchers.length).toEqual(0);
|
|
659
|
+
$rootScope.html = '<div onclick="">hello</div>';
|
|
660
|
+
$rootScope.$digest();
|
|
661
|
+
expect(element.text()).toEqual("hello");
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
describe("SCE enabled", () => {
|
|
666
|
+
beforeEach(() => {
|
|
667
|
+
createInjector([
|
|
668
|
+
"ng",
|
|
669
|
+
($sceProvider) => {
|
|
670
|
+
$sceProvider.enabled(true);
|
|
671
|
+
},
|
|
672
|
+
]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
673
|
+
$compile = _$compile_;
|
|
674
|
+
$rootScope = _$rootScope_;
|
|
675
|
+
$sce = _$sce_;
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it("should NOT set html for untrusted values", () => {
|
|
680
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
681
|
+
$rootScope,
|
|
682
|
+
);
|
|
683
|
+
$rootScope.html = '<div onclick="">hello</div>';
|
|
684
|
+
expect(() => {
|
|
685
|
+
$rootScope.$digest();
|
|
686
|
+
}).toThrowError(/unsafe/);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
it("should NOT set html for wrongly typed values", () => {
|
|
690
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
691
|
+
$rootScope,
|
|
692
|
+
);
|
|
693
|
+
$rootScope.html = $sce.trustAsCss('<div onclick="">hello</div>');
|
|
694
|
+
expect(() => {
|
|
695
|
+
$rootScope.$digest();
|
|
696
|
+
}).toThrowError(/unsafe/);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it("should set html for trusted values", () => {
|
|
700
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
701
|
+
$rootScope,
|
|
702
|
+
);
|
|
703
|
+
$rootScope.html = $sce.trustAsHtml('<div onclick="">hello</div>');
|
|
704
|
+
$rootScope.$digest();
|
|
705
|
+
expect(element.html()).toEqual('<div onclick="">hello</div>');
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
it("should update html", () => {
|
|
709
|
+
const element = $compile('<div ng-prop-inner_h_t_m_l="html"></div>')(
|
|
710
|
+
$rootScope,
|
|
711
|
+
);
|
|
712
|
+
$rootScope.html = $sce.trustAsHtml("hello");
|
|
713
|
+
$rootScope.$digest();
|
|
714
|
+
expect(element.html()).toEqual("hello");
|
|
715
|
+
$rootScope.html = $sce.trustAsHtml("goodbye");
|
|
716
|
+
$rootScope.$digest();
|
|
717
|
+
expect(element.html()).toEqual("goodbye");
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
it("should not cause infinite recursion for trustAsHtml object watches", () => {
|
|
721
|
+
// Ref: https://github.com/angular/angular.js/issues/3932
|
|
722
|
+
// If the binding is a function that creates a new value on every call via trustAs, we'll
|
|
723
|
+
// trigger an infinite digest if we don't take care of it.
|
|
724
|
+
const element = $compile(
|
|
725
|
+
'<div ng-prop-inner_h_t_m_l="getHtml()"></div>',
|
|
726
|
+
)($rootScope);
|
|
727
|
+
$rootScope.getHtml = function () {
|
|
728
|
+
return $sce.trustAsHtml('<div onclick="">hello</div>');
|
|
729
|
+
};
|
|
730
|
+
$rootScope.$digest();
|
|
731
|
+
expect(element.html()).toEqual('<div onclick="">hello</div>');
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
it("should handle custom $sce objects", () => {
|
|
735
|
+
function MySafeHtml(val) {
|
|
736
|
+
this.val = val;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
createInjector([
|
|
740
|
+
"ng",
|
|
741
|
+
($provide) => {
|
|
742
|
+
$provide.decorator("$sce", ($delegate) => {
|
|
743
|
+
$delegate.trustAsHtml = function (html) {
|
|
744
|
+
return new MySafeHtml(html);
|
|
745
|
+
};
|
|
746
|
+
$delegate.getTrusted = function (type, mySafeHtml) {
|
|
747
|
+
return mySafeHtml && mySafeHtml.val;
|
|
748
|
+
};
|
|
749
|
+
$delegate.valueOf = function (v) {
|
|
750
|
+
return v instanceof MySafeHtml ? v.val : v;
|
|
751
|
+
};
|
|
752
|
+
return $delegate;
|
|
753
|
+
});
|
|
754
|
+
},
|
|
755
|
+
]).invoke((_$compile_, _$rootScope_, _$sce_) => {
|
|
756
|
+
$compile = _$compile_;
|
|
757
|
+
$rootScope = _$rootScope_;
|
|
758
|
+
$sce = _$sce_;
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// Ref: https://github.com/angular/angular.js/issues/14526
|
|
762
|
+
// Previous code used toString for change detection, which fails for custom objects
|
|
763
|
+
// that don't override toString.
|
|
764
|
+
const element = $compile(
|
|
765
|
+
'<div ng-prop-inner_h_t_m_l="getHtml()"></div>',
|
|
766
|
+
)($rootScope);
|
|
767
|
+
let html = "hello";
|
|
768
|
+
$rootScope.getHtml = function () {
|
|
769
|
+
return $sce.trustAsHtml(html);
|
|
770
|
+
};
|
|
771
|
+
$rootScope.$digest();
|
|
772
|
+
expect(element.html()).toEqual("hello");
|
|
773
|
+
html = "goodbye";
|
|
774
|
+
$rootScope.$digest();
|
|
775
|
+
expect(element.html()).toEqual("goodbye");
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
describe("*[style]", () => {
|
|
781
|
+
it("should NOT set style for untrusted values", () => {
|
|
782
|
+
const element = $compile('<div ng-prop-style="style"></div>')($rootScope);
|
|
783
|
+
$rootScope.style = "margin-left: 10px";
|
|
784
|
+
expect(() => {
|
|
785
|
+
$rootScope.$digest();
|
|
786
|
+
}).toThrowError(/unsafe/);
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
it("should NOT set style for wrongly typed values", () => {
|
|
790
|
+
const element = $compile('<div ng-prop-style="style"></div>')($rootScope);
|
|
791
|
+
$rootScope.style = $sce.trustAsHtml("margin-left: 10px");
|
|
792
|
+
expect(() => {
|
|
793
|
+
$rootScope.$digest();
|
|
794
|
+
}).toThrowError(/unsafe/);
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
it("should set style for trusted values", () => {
|
|
798
|
+
const element = $compile('<div ng-prop-style="style"></div>')($rootScope);
|
|
799
|
+
$rootScope.style = $sce.trustAsCss("margin-left: 10px");
|
|
800
|
+
$rootScope.$digest();
|
|
801
|
+
|
|
802
|
+
expect(element[0].style["margin-left"]).toEqual("10px");
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
});
|