fix(style_compiler): don’t touch urls in stylesheets and keep stylesheets with absolute urls in templates

We can’t resolve relative urls (e.g. for images) in the compiler as
these urls are meant to be loaded in the browser
(unless we would inline images as base64…).

Also, keep `<link rel=“stylesheet”>` in templates that
reference absolute urls with e.g. `http://`. This
behavior was already present for `@import` rules
within stylesheets.
Closes #4740
This commit is contained in:
Tobias Bosch
2015-10-14 09:39:40 -07:00
parent 2be9fef86d
commit 7dde18b181
7 changed files with 126 additions and 93 deletions

View File

@ -1,51 +1,26 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/testing_internal';
import {resolveStyleUrls} from 'angular2/src/core/compiler/style_url_resolver';
import {
extractStyleUrls,
isStyleUrlResolvable
} from 'angular2/src/core/compiler/style_url_resolver';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
export function main() {
describe('StyleUrlResolver', () => {
describe('extractStyleUrls', () => {
var urlResolver;
beforeEach(() => { urlResolver = new UrlResolver(); });
it('should resolve "url()" urls', () => {
it('should not resolve "url()" urls', () => {
var css = `
.foo {
background-image: url("double.jpg");
background-image: url('simple.jpg');
background-image: url(noquote.jpg);
}`;
var expectedCss = `
.foo {
background-image: url('http://ng.io/double.jpg');
background-image: url('http://ng.io/simple.jpg');
background-image: url('http://ng.io/noquote.jpg');
}`;
var resolvedCss = resolveStyleUrls(urlResolver, 'http://ng.io', css).style;
expect(resolvedCss).toEqual(expectedCss);
});
it('should not strip quotes from inlined SVG styles', () => {
var css = `
.selector {
background:rgb(55,71,79) url('data:image/svg+xml;utf8,<?xml version="1.0"?>');
background:rgb(55,71,79) url("data:image/svg+xml;utf8,<?xml version='1.0'?>");
background:rgb(55,71,79) url("/some/data:image");
}
`;
var expectedCss = `
.selector {
background:rgb(55,71,79) url('data:image/svg+xml;utf8,<?xml version="1.0"?>');
background:rgb(55,71,79) url("data:image/svg+xml;utf8,<?xml version='1.0'?>");
background:rgb(55,71,79) url('http://ng.io/some/data:image');
}
`;
var resolvedCss = resolveStyleUrls(urlResolver, 'http://ng.io', css).style;
expect(resolvedCss).toEqual(expectedCss);
var resolvedCss = extractStyleUrls(urlResolver, 'http://ng.io', css).style;
expect(resolvedCss).toEqual(css);
});
it('should extract "@import" urls', () => {
@ -53,7 +28,7 @@ export function main() {
@import '1.css';
@import "2.css";
`;
var styleWithImports = resolveStyleUrls(urlResolver, 'http://ng.io', css);
var styleWithImports = extractStyleUrls(urlResolver, 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual('');
expect(styleWithImports.styleUrls).toEqual(['http://ng.io/1.css', 'http://ng.io/2.css']);
});
@ -64,7 +39,7 @@ export function main() {
@import url("4.css");
@import url(5.css);
`;
var styleWithImports = resolveStyleUrls(urlResolver, 'http://ng.io', css);
var styleWithImports = extractStyleUrls(urlResolver, 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual('');
expect(styleWithImports.styleUrls)
.toEqual(['http://ng.io/3.css', 'http://ng.io/4.css', 'http://ng.io/5.css']);
@ -72,7 +47,7 @@ export function main() {
it('should extract "@import urls and keep rules in the same line', () => {
var css = `@import url('some.css');div {color: red};`;
var styleWithImports = resolveStyleUrls(urlResolver, 'http://ng.io', css);
var styleWithImports = extractStyleUrls(urlResolver, 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual('div {color: red};');
expect(styleWithImports.styleUrls).toEqual(['http://ng.io/some.css']);
});
@ -82,7 +57,7 @@ export function main() {
@import 'print1.css' print;
@import url(print2.css) print;
`;
var styleWithImports = resolveStyleUrls(urlResolver, 'http://ng.io', css);
var styleWithImports = extractStyleUrls(urlResolver, 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual('');
expect(styleWithImports.styleUrls)
.toEqual(['http://ng.io/print1.css', 'http://ng.io/print2.css']);
@ -90,19 +65,38 @@ export function main() {
it('should leave absolute non-package @import urls intact', () => {
var css = `@import url('http://server.com/some.css');`;
var styleWithImports = resolveStyleUrls(urlResolver, 'http://ng.io', css);
var styleWithImports = extractStyleUrls(urlResolver, 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual(`@import url('http://server.com/some.css');`);
expect(styleWithImports.styleUrls).toEqual([]);
});
it('should resolve package @import urls', () => {
var css = `@import url('package:a/b/some.css');`;
var styleWithImports = resolveStyleUrls(new FakeUrlResolver(), 'http://ng.io', css);
var styleWithImports = extractStyleUrls(new FakeUrlResolver(), 'http://ng.io', css);
expect(styleWithImports.style.trim()).toEqual(``);
expect(styleWithImports.styleUrls).toEqual(['fake_resolved_url']);
});
});
describe('isStyleUrlResolvable', () => {
it('should resolve relative urls',
() => { expect(isStyleUrlResolvable('someUrl.css')).toBe(true); });
it('should resolve package: urls',
() => { expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); });
it('should resolve asset: urls',
() => { expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); });
it('should not resolve empty urls', () => {
expect(isStyleUrlResolvable(null)).toBe(false);
expect(isStyleUrlResolvable('')).toBe(false);
});
it('should not resolve urls with other schema',
() => { expect(isStyleUrlResolvable('http://otherurl')).toBe(false); });
});
}
/// The real thing behaves differently between Dart and JS for package URIs.

View File

@ -242,6 +242,16 @@ export function main() {
expect(template.styleUrls).toEqual([]);
}));
it('should ignore link elements with absolute urls but non package: scheme',
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
var template = normalizer.normalizeLoadedTemplate(
dirType,
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
'<link href="http://some/external.css" rel="stylesheet"></link>',
'package:some/module/');
expect(template.styleUrls).toEqual([]);
}));
it('should extract @import style urls into styleAbsUrl',
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
var template = normalizer.normalizeLoadedTemplate(
@ -252,7 +262,7 @@ export function main() {
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
}));
it('should resolve relative urls in inline styles',
it('should not resolve relative urls in inline styles',
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
var template = normalizer.normalizeLoadedTemplate(
dirType, new CompileTemplateMetadata({
@ -261,8 +271,7 @@ export function main() {
styleUrls: []
}),
'', 'package:some/module/id');
expect(template.styles)
.toEqual(['.foo{background-image: url(\'package:some/module/double.jpg\');']);
expect(template.styles).toEqual(['.foo{background-image: url(\'double.jpg\');']);
}));
it('should resolve relative style urls in styleUrls',

View File

@ -845,9 +845,45 @@ Property binding a not used by any directive on an embedded template in TestComp
});
it('should ignore <link rel="stylesheet"> elements but include them for source info', () => {
expect(humanizeTemplateAsts(parse('<link rel="stylesheet"></link>a', [])))
.toEqual([[TextAst, 'a', 'TestComp > #text(a):nth-child(1)']]);
describe('<link rel="stylesheet">', () => {
it('should keep <link rel="stylesheet"> elements if they have an absolute non package: url',
() => {
expect(humanizeTemplateAsts(
parse('<link rel="stylesheet" href="http://someurl"></link>a', [])))
.toEqual([
[ElementAst, 'link', 'TestComp > link:nth-child(0)'],
[
AttrAst,
'href',
'http://someurl',
'TestComp > link:nth-child(0)[href=http://someurl]'
],
[AttrAst, 'rel', 'stylesheet', 'TestComp > link:nth-child(0)[rel=stylesheet]'],
[TextAst, 'a', 'TestComp > #text(a):nth-child(1)']
]);
});
it('should keep <link rel="stylesheet"> elements if they have no uri', () => {
expect(humanizeTemplateAsts(parse('<link rel="stylesheet"></link>a', [])))
.toEqual([
[ElementAst, 'link', 'TestComp > link:nth-child(0)'],
[AttrAst, 'rel', 'stylesheet', 'TestComp > link:nth-child(0)[rel=stylesheet]'],
[TextAst, 'a', 'TestComp > #text(a):nth-child(1)']
]);
});
it('should ignore <link rel="stylesheet"> elements if they have a relative uri', () => {
expect(
humanizeTemplateAsts(parse('<link rel="stylesheet" href="./other.css"></link>a', [])))
.toEqual([[TextAst, 'a', 'TestComp > #text(a):nth-child(1)']]);
});
it('should ignore <link rel="stylesheet"> elements if they have a package: uri', () => {
expect(humanizeTemplateAsts(
parse('<link rel="stylesheet" href="package:somePackage"></link>a', [])))
.toEqual([[TextAst, 'a', 'TestComp > #text(a):nth-child(1)']]);
});
});