refactor(render): move services to render folder

property_setter_factory
selector
style_inliner
style_url_resolver
shadow_css
This commit is contained in:
Tobias Bosch
2015-04-02 14:40:49 -07:00
parent be5ccf6957
commit c1aa65239e
34 changed files with 50 additions and 167 deletions

View File

@ -28,7 +28,7 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {ComponentUrlMapper, RuntimeComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {CssProcessor} from 'angular2/src/core/compiler/css_processor';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';

View File

@ -29,7 +29,7 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {CssProcessor} from 'angular2/src/core/compiler/css_processor';
import {EventManager} from 'angular2/src/render/dom/events/event_manager';

View File

@ -1,78 +0,0 @@
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib';
import {setterFactory} from 'angular2/src/core/compiler/property_setter_factory';
import {DOM} from 'angular2/src/dom/dom_adapter';
export function main() {
var div;
beforeEach( () => {
div = el('<div></div>');
});
describe('property setter factory', () => {
it('should return a setter for a property', () => {
var setterFn = setterFactory('title');
setterFn(div, 'Hello');
expect(div.title).toEqual('Hello');
var otherSetterFn = setterFactory('title');
expect(setterFn).toBe(otherSetterFn);
});
it('should return a setter for an attribute', () => {
var setterFn = setterFactory('attr.role');
setterFn(div, 'button');
expect(DOM.getAttribute(div, 'role')).toEqual('button');
setterFn(div, null);
expect(DOM.getAttribute(div, 'role')).toEqual(null);
expect(() => {
setterFn(div, 4);
}).toThrowError("Invalid role attribute, only string values are allowed, got '4'");
var otherSetterFn = setterFactory('attr.role');
expect(setterFn).toBe(otherSetterFn);
});
it('should return a setter for a class', () => {
var setterFn = setterFactory('class.active');
setterFn(div, true);
expect(DOM.hasClass(div, 'active')).toEqual(true);
setterFn(div, false);
expect(DOM.hasClass(div, 'active')).toEqual(false);
var otherSetterFn = setterFactory('class.active');
expect(setterFn).toBe(otherSetterFn);
});
it('should return a setter for a style', () => {
var setterFn = setterFactory('style.width');
setterFn(div, '40px');
expect(DOM.getStyle(div, 'width')).toEqual('40px');
setterFn(div, null);
expect(DOM.getStyle(div, 'width')).toEqual('');
var otherSetterFn = setterFactory('style.width');
expect(setterFn).toBe(otherSetterFn);
});
it('should return a setter for a style with a unit', () => {
var setterFn = setterFactory('style.height.px');
setterFn(div, 40);
expect(DOM.getStyle(div, 'height')).toEqual('40px');
setterFn(div, null);
expect(DOM.getStyle(div, 'height')).toEqual('');
var otherSetterFn = setterFactory('style.height.px');
expect(setterFn).toBe(otherSetterFn);
});
it('should return a setter for innerHtml', () => {
var setterFn = setterFactory('innerHtml');
setterFn(div, '<span></span>');
expect(DOM.getInnerHTML(div)).toEqual('<span></span>');
var otherSetterFn = setterFactory('innerHtml');
expect(setterFn).toBe(otherSetterFn);
});
});
}

View File

@ -1,282 +0,0 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {SelectorMatcher} from 'angular2/src/core/compiler/selector';
import {CssSelector} from 'angular2/src/core/compiler/selector';
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
export function main() {
describe('SelectorMatcher', () => {
var matcher, matched, selectableCollector, s1, s2, s3, s4;
function reset() {
matched = ListWrapper.create();
}
beforeEach(() => {
reset();
s1 = s2 = s3 = s4 = null;
selectableCollector = (selector, context) => {
ListWrapper.push(matched, selector);
ListWrapper.push(matched, context);
}
matcher = new SelectorMatcher();
});
it('should select by element name case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('someTag'), 1);
expect(matcher.match(CssSelector.parse('SOMEOTHERTAG')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('SOMETAG')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
});
it('should select by class name case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('.someClass'), 1);
matcher.addSelectables(s2 = CssSelector.parse('.someClass.class2'), 2);
expect(matcher.match(CssSelector.parse('.SOMEOTHERCLASS')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('.SOMECLASS')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
reset();
expect(matcher.match(CssSelector.parse('.someClass.class2')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
});
it('should select by attr name case insensitive independent of the value', () => {
matcher.addSelectables(s1 = CssSelector.parse('[someAttr]'), 1);
matcher.addSelectables(s2 = CssSelector.parse('[someAttr][someAttr2]'), 2);
expect(matcher.match(CssSelector.parse('[SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('[SOMEATTR]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
reset();
expect(matcher.match(CssSelector.parse('[SOMEATTR=someValue]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
reset();
expect(matcher.match(CssSelector.parse('[someAttr][someAttr2]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
});
it('should select by attr name only once if the value is from the DOM', () => {
matcher.addSelectables(s1 = CssSelector.parse('[some-decor]'), 1);
var elementSelector = new CssSelector();
var element = el('<div attr></div>');
var empty = DOM.getAttribute(element, 'attr');
elementSelector.addAttribute('some-decor', empty);
matcher.match(elementSelector, selectableCollector);
expect(matched).toEqual([s1[0],1]);
});
it('should select by attr name and value case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('[someAttr=someValue]'), 1);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEVALUE]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
});
it('should select by element name, class name and attribute name with value', () => {
matcher.addSelectables(s1 = CssSelector.parse('someTag.someClass[someAttr=someValue]'), 1);
expect(matcher.match(CssSelector.parse('someOtherTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr=someValue]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
});
it('should select by many attributes and independent of the value', () => {
matcher.addSelectables(s1 = CssSelector.parse('input[type=text][control]'), 1);
var cssSelector = new CssSelector();
cssSelector.setElement('input');
cssSelector.addAttribute('type', 'text');
cssSelector.addAttribute('control', 'one');
expect(matcher.match(cssSelector, selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0], 1]);
});
it('should select independent of the order in the css selector', () => {
matcher.addSelectables(s1 = CssSelector.parse('[someAttr].someClass'), 1);
matcher.addSelectables(s2 = CssSelector.parse('.someClass[someAttr]'), 2);
matcher.addSelectables(s3 = CssSelector.parse('.class1.class2'), 3);
matcher.addSelectables(s4 = CssSelector.parse('.class2.class1'), 4);
expect(matcher.match(CssSelector.parse('[someAttr].someClass')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
reset();
expect(matcher.match(CssSelector.parse('.someClass[someAttr]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
reset();
expect(matcher.match(CssSelector.parse('.class1.class2')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s3[0],3,s4[0],4]);
reset();
expect(matcher.match(CssSelector.parse('.class2.class1')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s4[0],4,s3[0],3]);
});
it('should not select with a matching :not selector', () => {
matcher.addSelectables(CssSelector.parse('p:not(.someClass)'), 1);
matcher.addSelectables(CssSelector.parse('p:not([someAttr])'), 2);
matcher.addSelectables(CssSelector.parse(':not(.someClass)'), 3);
matcher.addSelectables(CssSelector.parse(':not(p)'), 4);
matcher.addSelectables(CssSelector.parse(':not(p[someAttr])'), 5);
expect(matcher.match(CssSelector.parse('p.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
expect(matched).toEqual([]);
});
it('should select with a non matching :not selector', () => {
matcher.addSelectables(s1 = CssSelector.parse('p:not(.someClass)'), 1);
matcher.addSelectables(s2 = CssSelector.parse('p:not(.someOtherClass[someAttr])'), 2);
matcher.addSelectables(s3 = CssSelector.parse(':not(.someClass)'), 3);
matcher.addSelectables(s4 = CssSelector.parse(':not(.someOtherClass[someAttr])'), 4);
expect(matcher.match(CssSelector.parse('p[someOtherAttr].someOtherClass')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2,s3[0],3,s4[0],4]);
});
it('should select with one match in a list', () => {
matcher.addSelectables(s1 = CssSelector.parse('input[type=text], textbox'), 1);
expect(matcher.match(CssSelector.parse('textbox')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[1],1]);
reset();
expect(matcher.match(CssSelector.parse('input[type=text]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
});
it('should not select twice with two matches in a list', () => {
matcher.addSelectables(s1 = CssSelector.parse('input, .someClass'), 1);
expect(matcher.match(CssSelector.parse('input.someclass')[0], selectableCollector)).toEqual(true);
expect(matched.length).toEqual(2);
expect(matched).toEqual([s1[0],1]);
});
});
describe('CssSelector.parse', () => {
it('should detect element names', () => {
var cssSelector = CssSelector.parse('sometag')[0];
expect(cssSelector.element).toEqual('sometag');
expect(cssSelector.toString()).toEqual('sometag');
});
it('should detect class names', () => {
var cssSelector = CssSelector.parse('.someClass')[0];
expect(cssSelector.classNames).toEqual(['someclass']);
expect(cssSelector.toString()).toEqual('.someclass');
});
it('should detect attr names', () => {
var cssSelector = CssSelector.parse('[attrname]')[0];
expect(cssSelector.attrs).toEqual(['attrname', '']);
expect(cssSelector.toString()).toEqual('[attrname]');
});
it('should detect attr values', () => {
var cssSelector = CssSelector.parse('[attrname=attrvalue]')[0];
expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
expect(cssSelector.toString()).toEqual('[attrname=attrvalue]');
});
it('should detect multiple parts', () => {
var cssSelector = CssSelector.parse('sometag[attrname=attrvalue].someclass')[0];
expect(cssSelector.element).toEqual('sometag');
expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
expect(cssSelector.classNames).toEqual(['someclass']);
expect(cssSelector.toString()).toEqual('sometag.someclass[attrname=attrvalue]');
});
it('should detect multiple attributes', () => {
var cssSelector = CssSelector.parse('input[type=text][control]')[0];
expect(cssSelector.element).toEqual('input');
expect(cssSelector.attrs).toEqual(['type', 'text', 'control', '']);
expect(cssSelector.toString()).toEqual('input[type=text][control]');
});
it('should detect :not', () => {
var cssSelector = CssSelector.parse('sometag:not([attrname=attrvalue].someclass)')[0];
expect(cssSelector.element).toEqual('sometag');
expect(cssSelector.attrs.length).toEqual(0);
expect(cssSelector.classNames.length).toEqual(0);
var notSelector = cssSelector.notSelector;
expect(notSelector.element).toEqual(null);
expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
expect(notSelector.classNames).toEqual(['someclass']);
expect(cssSelector.toString()).toEqual('sometag:not(.someclass[attrname=attrvalue])');
});
it('should detect :not without truthy', () => {
var cssSelector = CssSelector.parse(':not([attrname=attrvalue].someclass)')[0];
expect(cssSelector.element).toEqual("*");
var notSelector = cssSelector.notSelector;
expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
expect(notSelector.classNames).toEqual(['someclass']);
expect(cssSelector.toString()).toEqual('*:not(.someclass[attrname=attrvalue])');
});
it('should throw when nested :not', () => {
expect(() => {
CssSelector.parse('sometag:not(:not([attrname=attrvalue].someclass))')[0];
}).toThrowError('Nesting :not is not allowed in a selector');
});
it('should detect lists of selectors', () => {
var cssSelectors = CssSelector.parse('.someclass,[attrname=attrvalue], sometag');
expect(cssSelectors.length).toEqual(3);
expect(cssSelectors[0].classNames).toEqual(['someclass']);
expect(cssSelectors[1].attrs).toEqual(['attrname', 'attrvalue']);
expect(cssSelectors[2].element).toEqual('sometag');
});
it('should detect lists of selectors with :not', () => {
var cssSelectors = CssSelector.parse('input[type=text], :not(textarea), textbox:not(.special)');
expect(cssSelectors.length).toEqual(3);
expect(cssSelectors[0].element).toEqual('input');
expect(cssSelectors[0].attrs).toEqual(['type', 'text']);
expect(cssSelectors[1].element).toEqual('*');
expect(cssSelectors[1].notSelector.element).toEqual('textarea');
expect(cssSelectors[2].element).toEqual('textbox');
expect(cssSelectors[2].notSelector.classNames).toEqual(['special']);
});
});
}

View File

@ -1,117 +0,0 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {ShadowCss} from 'angular2/src/core/compiler/shadow_dom_emulation/shadow_css';
import {RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
export function main() {
describe('ShadowCss', function() {
function s(css: string, contentAttr:string, hostAttr:string = '') {
var shadowCss = new ShadowCss();
var shim = shadowCss.shimCssText(css, contentAttr, hostAttr);
var nlRegexp = RegExpWrapper.create('\\n');
return StringWrapper.replaceAll(shim, nlRegexp, '');
}
it('should handle empty string', () => {
expect(s('', 'a')).toEqual('');
});
it('should add an attribute to every rule', () => {
var css = 'one {color: red;}two {color: red;}';
var expected = 'one[a] {color: red;}two[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should hanlde invalid css', () => {
var css = 'one {color: red;}garbage';
var expected = 'one[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should add an attribute to every selector', () => {
var css = 'one, two {color: red;}';
var expected = 'one[a], two[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle media rules', () => {
var css = '@media screen and (max-width: 800px) {div {font-size: 50px;}}';
var expected = '@media screen and (max-width: 800px) {div[a] {font-size: 50px;}}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle media rules with simple rules', () => {
var css = '@media screen and (max-width: 800px) {div {font-size: 50px;}} div {}';
var expected = '@media screen and (max-width: 800px) {div[a] {font-size: 50px;}}div[a] {}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle complicated selectors', () => {
expect(s('one::before {}', 'a')).toEqual('one[a]::before {}');
expect(s('one two {}', 'a')).toEqual('one[a] two[a] {}');
expect(s('one>two {}', 'a')).toEqual('one[a] > two[a] {}');
expect(s('one+two {}', 'a')).toEqual('one[a] + two[a] {}');
expect(s('one~two {}', 'a')).toEqual('one[a] ~ two[a] {}');
expect(s('.one.two > three {}', 'a')).toEqual('.one.two[a] > three[a] {}');
expect(s('one[attr="value"] {}', 'a')).toEqual('one[attr="value"][a] {}');
expect(s('one[attr=value] {}', 'a')).toEqual('one[attr="value"][a] {}');
expect(s('one[attr^="value"] {}', 'a')).toEqual('one[attr^="value"][a] {}');
expect(s('one[attr$="value"] {}', 'a')).toEqual('one[attr$="value"][a] {}');
expect(s('one[attr*="value"] {}', 'a')).toEqual('one[attr*="value"][a] {}');
expect(s('one[attr|="value"] {}', 'a')).toEqual('one[attr|="value"][a] {}');
expect(s('one[attr] {}', 'a')).toEqual('one[attr][a] {}');
expect(s('[is="one"] {}', 'a')).toEqual('[is="one"][a] {}');
});
it('should handle :host', () => {
expect(s(':host {}', 'a', 'a-host')).toEqual('[a-host] {}');
expect(s(':host(.x,.y) {}', 'a', 'a-host')).toEqual('[a-host].x, [a-host].y {}');
expect(s(':host(.x,.y) > .z {}', 'a', 'a-host')).toEqual('[a-host].x > .z, [a-host].y > .z {}');
});
it('should handle :host-context', () => {
expect(s(':host-context(.x) {}', 'a', 'a-host')).toEqual('[a-host].x, .x [a-host] {}');
expect(s(':host-context(.x) > .y {}', 'a', 'a-host')).toEqual('[a-host].x > .y, .x [a-host] > .y {}');
});
it('should support polyfill-next-selector', () => {
var css = s("polyfill-next-selector {content: 'x > y'} z {}", 'a');
expect(css).toEqual('x[a] > y[a] {}');
css = s('polyfill-next-selector {content: "x > y"} z {}', 'a');
expect(css).toEqual('x[a] > y[a] {}');
});
it('should support polyfill-unscoped-rule', () => {
var css = s("polyfill-unscoped-rule {content: '#menu > .bar';background: blue;}", 'a');
expect(StringWrapper.contains(css, '#menu > .bar {;background: blue;}')).toBeTruthy();
css = s('polyfill-unscoped-rule {content: "#menu > .bar";background: blue;}', 'a');
expect(StringWrapper.contains(css, '#menu > .bar {;background: blue;}')).toBeTruthy();
});
it('should support polyfill-rule', () => {
var css = s("polyfill-rule {content: ':host.foo .bar';background: blue;}", 'a', 'a-host');
expect(css).toEqual('[a-host].foo .bar {background: blue;}');
css = s('polyfill-rule {content: ":host.foo .bar";background: blue;}', 'a', 'a-host');
expect(css).toEqual('[a-host].foo .bar {background: blue;}');
});
it('should handle ::shadow', () => {
var css = s('x::shadow > y {}', 'a');
expect(css).toEqual('x[a] > y[a] {}');
});
it('should handle /deep/', () => {
var css = s('x /deep/ y {}', 'a');
expect(css).toEqual('x[a] y[a] {}');
});
it('should handle >>>', () => {
var css = s('x >>> y {}', 'a');
expect(css).toEqual('x[a] y[a] {}');
});
});
}

View File

@ -30,8 +30,8 @@ import {ShadowDomStrategy,
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {CssProcessor} from 'angular2/src/core/compiler/css_processor';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';

View File

@ -18,8 +18,8 @@ import {
resetShadowDomCache,
} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {ProtoView} from 'angular2/src/core/compiler/view';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';

View File

@ -1,235 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
beforeEachBindings,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/test_lib';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {isBlank} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/services/xhr';
import {bind} from 'angular2/di';
export function main() {
describe('StyleInliner', () => {
beforeEachBindings(() => [
bind(XHR).toClass(FakeXHR),
]);
describe('loading', () => {
it('should return a string when there is no import statement', inject([StyleInliner], (inliner) => {
var css = '.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).not.toBePromise();
expect(loadedCss).toEqual(css);
}));
it('should inline @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should support url([unquoted url]) in @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle @import error gracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should inline multiple @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.two {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should inline nested @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle circular dependencies gracefuly',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle invalid @import fracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
describe('media query', () => {
it('should wrap inlined content in media query',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
describe('url rewritting', () => {
it('should rewrite url in inlined content',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css', '@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";'
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(
".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n"
);
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
});
}
class FakeXHR extends XHR {
_responses: Map;
constructor() {
super();
this._responses = MapWrapper.create();
}
get(url: string): Promise<string> {
var response = MapWrapper.get(this._responses, url);
if (isBlank(response)) {
return PromiseWrapper.reject('xhr error');
}
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) {
MapWrapper.set(this._responses, url, response);
}
}

View File

@ -1,80 +0,0 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {UrlResolver} from 'angular2/src/services/url_resolver';
export function main() {
describe('StyleUrlResolver', () => {
it('should resolve "url()" urls', () => {
var styleUrlResolver = new StyleUrlResolver(new FakeUrlResolver());
var css = `
.foo {
background-image: url("double.jpg");
background-image: url('simple.jpg');
background-image: url(noquote.jpg);
}`;
var expectedCss = `
.foo {
background-image: url('base/double.jpg');
background-image: url('base/simple.jpg');
background-image: url('base/noquote.jpg');
}`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');
expect(resolvedCss).toEqual(expectedCss);
});
it('should resolve "@import" urls', () => {
var styleUrlResolver = new StyleUrlResolver(new FakeUrlResolver());
var css = `
@import '1.css';
@import "2.css";
`;
var expectedCss = `
@import 'base/1.css';
@import 'base/2.css';
`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');
expect(resolvedCss).toEqual(expectedCss);
});
it('should resolve "@import url()" urls', () => {
var styleUrlResolver = new StyleUrlResolver(new FakeUrlResolver());
var css = `
@import url('3.css');
@import url("4.css");
@import url(5.css);
`;
var expectedCss = `
@import url('base/3.css');
@import url('base/4.css');
@import url('base/5.css');
`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');
expect(resolvedCss).toEqual(expectedCss);
});
it('should support media query in "@import"', () => {
var styleUrlResolver = new StyleUrlResolver(new FakeUrlResolver());
var css = `
@import 'print.css' print;
@import url(print.css) print;
`;
var expectedCss = `
@import 'base/print.css' print;
@import url('base/print.css') print;
`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');
expect(resolvedCss).toEqual(expectedCss);
});
});
}
class FakeUrlResolver extends UrlResolver {
resolve(baseUrl: string, url: string): string {
return baseUrl + '/' + url;
}
}