-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix(compile): do not create directives for constant media URL attributes #16737
Conversation
|
src/ng/compile.js
Outdated
@@ -3871,6 +3871,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { | |||
compile: function() { | |||
return { | |||
pre: function attrInterpolatePreLinkFn(scope, element, attr) { | |||
if (trustedContext === $sce.MEDIA_URL && isConstantInterpolation(interpolateFn)) { | |||
// Constant MEDIA_URL attributes should just be sanitized and not watched. | |||
attr[name] = interpolateFn(scope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this assignment? I thought to go back to the previous behavior we'd want to do no assignments.
I thought we'd just update this condition to return early like it previously did...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the only way to keep all the tests passing. If you change the condition you linked to then a load of other ngSrc
etc related tests fail. This is due to the fact that the url sanitization has moved to the interpolation rather than being done in the compiler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh :/
And we can't do this if + return
outside the directive? Before doing directives.push
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No because we need to set the sanitized value to the attribute at least once.
When I run the fix locally, it seems that the The original reported bug was fixed though :) |
@fbrandel - I don't think what you are suggesting ever worked with Angular. The following variants on |
@petebacondarwin With the PR applied this stopped working, as no |
Ahah! Let me see if I can reproduce in a unit test... |
@fbrandel I added unit tests for this case but I cannot reproduce your issue. Please can you take a look and see if you can do so? |
@petebacondarwin After building the project with the PR applied, I can see the tests pass. |
@petebacondarwin Sorry to come up with more investigation ;) It seems that the combination of Plunkr: https://next.plnkr.co/edit/mMn0sv47O81Hi0FJ Unit Test: it('should compile img with constant [src]-attribute and [ng-attr-data-src] attribute', inject(function() {
$rootScope.name = 'some-image.png';
element = $compile('<img src="constant.png" ng-attr-data-src="{{name}}">')($rootScope);
expect(element.attr('data-src')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('src')).toBe('constant.png');
expect(element.attr('data-src')).toBe('some-image.png');
$rootScope.name = 'other-image.png';
$rootScope.$digest();
expect(element.attr('src')).toBe('constant.png');
expect(element.attr('data-src')).toBe('other-image.png');
})); |
Hmm, oh dear. This is a can of worms... |
774a336
to
fbf5eb3
Compare
fbf5eb3
to
ab77738
Compare
@fbrandel - can you take a look at this alternative approach? See if you can break this one :-) |
ab77738
to
4a3f356
Compare
@petebacondarwin Looking good with my scenarios! Thank you so far for taking care! |
test/ng/compileSpec.js
Outdated
@@ -12109,6 +12118,47 @@ describe('$compile', function() { | |||
expect(element.attr('dash-test4')).toBe('JamieMason'); | |||
})); | |||
|
|||
it('should work with img[src]', inject(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It tests ng-attr-src, not src. The same remark for the next test.
We are now setting the attribute twice, even for interpolated attributes, which is not that great imo. Can we detect if the attribute value has not been interpolated? |
@@ -422,6 +422,10 @@ forEach(['src', 'srcset', 'href'], function(attrName) { | |||
propName = null; | |||
} | |||
|
|||
// We need to sanitize the url at least once, in case it is a constant | |||
// non-interpolated attribute. | |||
attr.$set(normalized, $sce.getTrustedMediaUrl(attr[normalized])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could check the current value and only call $set()
if getTrustedMediaUrl()
return a different value.
…ributes By creating attribute directives that watch the value of media url attributes (e.g. `img[src]`) we caused a conflict when both `src` and `data-src` were appearing on the same element. As each directive was trying to write to the attributes on the element, where AngularJS treats `src` and `data-src` as synonymous. This commit ensures that we do not create create such directives when the media url attribute is a constant (no interpolation). Because of this (and because we no longer sanitize URLs in the `$attr.$set()` method, this commit also updates `ngHref` and `ngSrc` to do a preliminary sanitization of URLs in case there is no interpolation in the attribute value. Fixes angular#16734
6393def
to
0687a4f
Compare
By creating attribute directives that watch the value of
media url attributes (e.g.
img[src]
) we caused a conflictwhen both
src
anddata-src
were appearing on thesame element. As each directive was trying to write to the
attributes on the element, where AngularJS treats
src
anddata-src
as synonymous.This commit ensures that we do not create create such directives
when the media url attribute is a constant (no interpolation).
Because of this (and because we no longer sanitize URLs in the
$attr.$set()
method, this commit also updatesngHref
andngSrc
to do a preliminary sanitization of URLs in case thereis no interpolation in the attribute value.