Skip to content

Commit 6b8ccb4

Browse files
committed
fix($sce): make trustAs watchable by caching its instances by type
Closes angular#3932, angular#3980
1 parent da3dc5c commit 6b8ccb4

File tree

2 files changed

+28
-20
lines changed

2 files changed

+28
-20
lines changed

src/ng/sce.js

+20-20
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,6 @@ function $SceDelegateProvider() {
131131
return resourceUrlBlacklist;
132132
};
133133

134-
// Helper functions for matching resource urls by policy.
135-
function isCompatibleProtocol(documentProtocol, resourceProtocol) {
136-
return ((documentProtocol === resourceProtocol) ||
137-
(documentProtocol === "http:" && resourceProtocol === "https:"));
138-
}
139-
140134
this.$get = ['$log', '$document', '$injector', '$$urlUtils', function(
141135
$log, $document, $injector, $$urlUtils) {
142136

@@ -179,32 +173,38 @@ function $SceDelegateProvider() {
179173
return allowed;
180174
}
181175

182-
function generateHolderType(base) {
176+
function generateHolderType(base, useCache) {
177+
var cacheInstances = {};
183178
var holderType = function TrustedValueHolderType(trustedValue) {
179+
if (cacheInstances[trustedValue] && useCache) {
180+
return cacheInstances[trustedValue];
181+
}
182+
183+
cacheInstances[trustedValue] = this;
184184
this.$$unwrapTrustedValue = function() {
185185
return trustedValue;
186186
};
187187
};
188188
if (base) {
189-
holderType.prototype = new base();
189+
holderType.prototype = new base('');
190190
}
191191
holderType.prototype.valueOf = function sceValueOf() {
192192
return this.$$unwrapTrustedValue();
193-
}
193+
};
194194
holderType.prototype.toString = function sceToString() {
195195
return this.$$unwrapTrustedValue().toString();
196-
}
196+
};
197197
return holderType;
198198
}
199199

200200
var trustedValueHolderBase = generateHolderType(),
201201
byType = {};
202202

203-
byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
204-
byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
205-
byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
206-
byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
207-
byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
203+
byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase, true);
204+
byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase, true);
205+
byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase, true);
206+
byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase, true);
207+
byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL], true);
208208

209209
/**
210210
* @ngdoc method
@@ -341,7 +341,7 @@ function $SceDelegateProvider() {
341341
* # Strict Contextual Escaping
342342
*
343343
* Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
344-
* contexts to result in a value that is marked as safe to use for that context One example of such
344+
* contexts to result in a value that is marked as safe to use for that context. One example of such
345345
* a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer to these
346346
* contexts as privileged or SCE contexts.
347347
*
@@ -419,7 +419,7 @@ function $SceDelegateProvider() {
419419
* By default, Angular only loads templates from the same domain and protocol as the application
420420
* document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
421421
* $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
422-
* protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
422+
* protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
423423
* them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
424424
*
425425
* *Please note*:
@@ -935,13 +935,13 @@ function $SceProvider() {
935935
var lName = lowercase(name);
936936
sce[camelCase("parse_as_" + lName)] = function (expr) {
937937
return parse(enumValue, expr);
938-
}
938+
};
939939
sce[camelCase("get_trusted_" + lName)] = function (value) {
940940
return getTrusted(enumValue, value);
941-
}
941+
};
942942
sce[camelCase("trust_as_" + lName)] = function (value) {
943943
return trustAs(enumValue, value);
944-
}
944+
};
945945
});
946946

947947
return sce;

test/ng/sceSpecs.js

+8
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ describe('SCE', function() {
173173
expect($sce.getTrustedHtml(wrappedValue)).toBe(originalValue);
174174
expect(wrappedValue.toString()).toBe(originalValue.toString());
175175
}));
176+
177+
it('should be watchable', inject(function ($rootScope, $sce) {
178+
$rootScope.$watch(function() { return $sce.trustAsHtml('<b></b>'); }, function(value) {
179+
expect($sce.getTrustedHtml(value)).toBe('<b></b>');
180+
});
181+
$rootScope.$apply();
182+
}));
183+
176184
});
177185

178186

0 commit comments

Comments
 (0)