From 3ea655918ee200e5d9d1ad0410e4b2f52608b437 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 15 Jun 2015 15:57:42 +0200 Subject: [PATCH] refactor(Compiler): inline styles before compiling the template --- modules/angular2/src/core/application.ts | 8 +- .../src/core/compiler/template_resolver.ts | 2 +- modules/angular2/src/dom/html_adapter.dart | 12 +- modules/angular2/src/render/api.ts | 2 +- .../dom/compiler/compile_step_factory.ts | 10 +- .../src/render/dom/compiler/compiler.ts | 20 +-- .../{shadow_dom => compiler}/style_inliner.ts | 0 .../style_url_resolver.ts | 0 .../render/dom/compiler/template_loader.ts | 121 ++++++++++++++---- .../emulated_scoped_shadow_dom_strategy.ts | 37 ++---- .../emulated_unscoped_shadow_dom_strategy.ts | 25 +--- .../shadow_dom/native_shadow_dom_strategy.ts | 24 ---- .../src/render/dom/shadow_dom/shadow_css.ts | 2 +- .../dom/shadow_dom/shadow_dom_compile_step.ts | 15 +-- .../dom/shadow_dom/shadow_dom_strategy.ts | 20 +-- .../angular2/src/test_lib/test_injector.ts | 8 +- .../compile_step_factory.dart | 4 +- .../template_compiler/generator.dart | 22 ++-- .../test/core/compiler/compiler_spec.ts | 40 +++--- .../angular2/test/directives/ng_if_spec.ts | 2 +- .../dom/compiler/compiler_common_tests.ts | 44 ++----- .../style_inliner_spec.ts | 2 +- .../style_url_resolver_spec.ts | 2 +- .../dom/compiler/template_loader_spec.ts | 98 ++++++++++++-- ...mulated_scoped_shadow_dom_strategy_spec.ts | 74 +---------- ...lated_unscoped_shadow_dom_strategy_spec.ts | 59 +-------- .../native_shadow_dom_strategy_spec.ts | 60 +-------- .../shadow_dom_emulation_integration_spec.ts | 26 +--- .../src/compiler/compiler_benchmark.ts | 9 +- modules/examples/src/material/demo_common.ts | 8 +- 30 files changed, 288 insertions(+), 468 deletions(-) rename modules/angular2/src/render/dom/{shadow_dom => compiler}/style_inliner.ts (100%) rename modules/angular2/src/render/dom/{shadow_dom => compiler}/style_url_resolver.ts (100%) rename modules/angular2/test/render/dom/{shadow_dom => compiler}/style_inliner_spec.ts (99%) rename modules/angular2/test/render/dom/{shadow_dom => compiler}/style_url_resolver_spec.ts (96%) diff --git a/modules/angular2/src/core/application.ts b/modules/angular2/src/core/application.ts index 12b827d127..7202e9d061 100644 --- a/modules/angular2/src/core/application.ts +++ b/modules/angular2/src/core/application.ts @@ -25,6 +25,8 @@ import { } from 'angular2/change_detection'; import {ExceptionHandler} from './exception_handler'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; +import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; +import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; import {TemplateResolver} from './compiler/template_resolver'; import {DirectiveResolver} from './compiler/directive_resolver'; import {List, ListWrapper} from 'angular2/src/facade/collection'; @@ -42,8 +44,6 @@ import {KeyEventsPlugin} from 'angular2/src/render/dom/events/key_events'; import {HammerGesturesPlugin} from 'angular2/src/render/dom/events/hammer_gestures'; import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; import {UrlResolver} from 'angular2/src/services/url_resolver'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; import {AppRootUrl} from 'angular2/src/services/app_root_url'; import { ComponentRef, @@ -105,9 +105,7 @@ function _injectorBindings(appComponentType): List> { }, [NgZone]), bind(ShadowDomStrategy) - .toFactory((styleInliner, styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy( - styleInliner, styleUrlResolver, doc.head), - [StyleInliner, StyleUrlResolver, DOCUMENT_TOKEN]), + .toFactory((doc) => new EmulatedUnscopedShadowDomStrategy(doc.head), [DOCUMENT_TOKEN]), DomRenderer, DefaultDomCompiler, bind(Renderer).toAlias(DomRenderer), diff --git a/modules/angular2/src/core/compiler/template_resolver.ts b/modules/angular2/src/core/compiler/template_resolver.ts index 6125f632d6..4b0376ac21 100644 --- a/modules/angular2/src/core/compiler/template_resolver.ts +++ b/modules/angular2/src/core/compiler/template_resolver.ts @@ -22,7 +22,7 @@ export class TemplateResolver { return view; } - _resolve(component: Type) { + _resolve(component: Type): View { var annotations = reflector.annotations(component); for (var i = 0; i < annotations.length; i++) { var annotation = annotations[i]; diff --git a/modules/angular2/src/dom/html_adapter.dart b/modules/angular2/src/dom/html_adapter.dart index 049dd46f70..28de7a1782 100644 --- a/modules/angular2/src/dom/html_adapter.dart +++ b/modules/angular2/src/dom/html_adapter.dart @@ -67,10 +67,10 @@ class Html5LibDomAdapter implements DomAdapter { throw 'not implemented'; } querySelector(el, String selector) { - throw 'not implemented'; + return el.querySelector(selector); } List querySelectorAll(el, String selector) { - throw 'not implemented'; + return el.querySelectorAll(selector); } on(el, evt, listener) { throw 'not implemented'; @@ -94,7 +94,7 @@ class Html5LibDomAdapter implements DomAdapter { return el.innerHtml; } getOuterHTML(el) { - throw 'not implemented'; + return el.outerHtml; } String nodeName(node) { switch (node.nodeType) { @@ -130,12 +130,12 @@ class Html5LibDomAdapter implements DomAdapter { } parentElement(el) { - throw 'not implemented'; + return el.parent; } List childNodes(el) => el.nodes; List childNodesAsList(el) => el.nodes; clearNodes(el) { - throw 'not implemented'; + el.nodes.forEach((e) => e.remove()); } appendChild(el, node) => el.append(node.remove()); removeChild(el, node) { @@ -153,7 +153,7 @@ class Html5LibDomAdapter implements DomAdapter { throw 'not implemented'; } setInnerHTML(el, value) { - throw 'not implemented'; + el.innerHtml = value; } getText(el) { return el.text; diff --git a/modules/angular2/src/render/api.ts b/modules/angular2/src/render/api.ts index 176a03ed34..6de107424e 100644 --- a/modules/angular2/src/render/api.ts +++ b/modules/angular2/src/render/api.ts @@ -303,7 +303,7 @@ export class RenderCompiler { * we don't need to serialize all possible components over the wire, * but only the needed ones based on previous calls. */ - compile(template: ViewDefinition): Promise { return null; } + compile(view: ViewDefinition): Promise { return null; } } export interface RenderElementRef { diff --git a/modules/angular2/src/render/dom/compiler/compile_step_factory.ts b/modules/angular2/src/render/dom/compiler/compile_step_factory.ts index 4dd8c3a669..7fe7015922 100644 --- a/modules/angular2/src/render/dom/compiler/compile_step_factory.ts +++ b/modules/angular2/src/render/dom/compiler/compile_step_factory.ts @@ -1,6 +1,4 @@ import {List} from 'angular2/src/facade/collection'; -import {Promise} from 'angular2/src/facade/async'; - import {Parser} from 'angular2/change_detection'; import {ViewDefinition} from '../../api'; import {CompileStep} from './compile_step'; @@ -12,21 +10,19 @@ import {ShadowDomCompileStep} from '../shadow_dom/shadow_dom_compile_step'; import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy'; export class CompileStepFactory { - createSteps(template: ViewDefinition, subTaskPromises: List>): List { - return null; - } + createSteps(template: ViewDefinition): List { return null; } } export class DefaultStepFactory extends CompileStepFactory { constructor(public _parser: Parser, public _shadowDomStrategy: ShadowDomStrategy) { super(); } - createSteps(template: ViewDefinition, subTaskPromises: List>) { + createSteps(template: ViewDefinition): List { return [ new ViewSplitter(this._parser), new PropertyBindingParser(this._parser), new DirectiveParser(this._parser, template.directives), new TextInterpolationParser(this._parser), - new ShadowDomCompileStep(this._shadowDomStrategy, template, subTaskPromises) + new ShadowDomCompileStep(this._shadowDomStrategy, template) ]; } } diff --git a/modules/angular2/src/render/dom/compiler/compiler.ts b/modules/angular2/src/render/dom/compiler/compiler.ts index 2a42fdec10..ca774deb8f 100644 --- a/modules/angular2/src/render/dom/compiler/compiler.ts +++ b/modules/angular2/src/render/dom/compiler/compiler.ts @@ -28,12 +28,11 @@ export class DomCompiler extends RenderCompiler { super(); } - compile(template: ViewDefinition): Promise { - var tplPromise = this._templateLoader.load(template); + compile(view: ViewDefinition): Promise { + var tplPromise = this._templateLoader.load(view); return PromiseWrapper.then( - tplPromise, (el) => this._compileTemplate(template, el, ViewType.COMPONENT), (e) => { - throw new BaseException( - `Failed to load the template for "${template.componentId}" : ${e}`); + tplPromise, (el) => this._compileTemplate(view, el, ViewType.COMPONENT), (e) => { + throw new BaseException(`Failed to load the template for "${view.componentId}" : ${e}`); }); } @@ -51,17 +50,10 @@ export class DomCompiler extends RenderCompiler { _compileTemplate(viewDef: ViewDefinition, tplElement, protoViewType: ViewType): Promise { - var subTaskPromises = []; - var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises)); + var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef)); var compileElements = pipeline.process(tplElement, protoViewType, viewDef.componentId); - var protoView = compileElements[0].inheritedProtoView.build(); - - if (subTaskPromises.length > 0) { - return PromiseWrapper.all(subTaskPromises).then((_) => protoView); - } else { - return PromiseWrapper.resolve(protoView); - } + return PromiseWrapper.resolve(compileElements[0].inheritedProtoView.build()); } } diff --git a/modules/angular2/src/render/dom/shadow_dom/style_inliner.ts b/modules/angular2/src/render/dom/compiler/style_inliner.ts similarity index 100% rename from modules/angular2/src/render/dom/shadow_dom/style_inliner.ts rename to modules/angular2/src/render/dom/compiler/style_inliner.ts diff --git a/modules/angular2/src/render/dom/shadow_dom/style_url_resolver.ts b/modules/angular2/src/render/dom/compiler/style_url_resolver.ts similarity index 100% rename from modules/angular2/src/render/dom/shadow_dom/style_url_resolver.ts rename to modules/angular2/src/render/dom/compiler/style_url_resolver.ts diff --git a/modules/angular2/src/render/dom/compiler/template_loader.ts b/modules/angular2/src/render/dom/compiler/template_loader.ts index 4d79bb1758..5e0c5b8c7a 100644 --- a/modules/angular2/src/render/dom/compiler/template_loader.ts +++ b/modules/angular2/src/render/dom/compiler/template_loader.ts @@ -1,13 +1,15 @@ import {Injectable} from 'angular2/di'; -import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang'; -import {Map, MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; +import {isBlank, isPresent, BaseException, stringify, isPromise} from 'angular2/src/facade/lang'; +import {Map, MapWrapper, ListWrapper, List} from 'angular2/src/facade/collection'; import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; import {DOM} from 'angular2/src/dom/dom_adapter'; import {XHR} from 'angular2/src/render/xhr'; import {ViewDefinition} from '../../api'; -import {UrlResolver} from 'angular2/src/services/url_resolver'; + +import {StyleInliner} from './style_inliner'; +import {StyleUrlResolver} from './style_url_resolver'; /** * Strategy to load component templates. @@ -17,37 +19,36 @@ import {UrlResolver} from 'angular2/src/services/url_resolver'; export class TemplateLoader { _cache: Map> = new Map(); - constructor(private _xhr: XHR, urlResolver: UrlResolver) {} + constructor(private _xhr: XHR, private _styleInliner: StyleInliner, + private _styleUrlResolver: StyleUrlResolver) {} load(view: ViewDefinition): Promise { - let html; - let fetchedStyles; + let tplElAndStyles: List> = [this._loadHtml(view)]; - // Load the HTML - if (isPresent(view.template)) { - html = PromiseWrapper.resolve(view.template); - } else if (isPresent(view.templateAbsUrl)) { - html = this._loadText(view.templateAbsUrl); - } else { - throw new BaseException('View should have either the templateUrl or template property set'); + if (isPresent(view.styles)) { + view.styles.forEach((cssText: string) => { + let textOrPromise = this._resolveAndInlineCssText(cssText, view.templateAbsUrl); + tplElAndStyles.push(textOrPromise); + }); } - // Load the styles - if (isPresent(view.styleAbsUrls) && view.styleAbsUrls.length > 0) { - fetchedStyles = ListWrapper.map(view.styleAbsUrls, url => this._loadText(url)); - } else { - fetchedStyles = []; + if (isPresent(view.styleAbsUrls)) { + view.styleAbsUrls.forEach(url => { + let promise = this._loadText(url).then( + cssText => this._resolveAndInlineCssText(cssText, view.templateAbsUrl)); + tplElAndStyles.push(promise); + }); } - // Inline the styles and return a template element - return PromiseWrapper.all(ListWrapper.concat([html], fetchedStyles)) + // Inline the styles from the @View annotation and return a template element + return PromiseWrapper.all(tplElAndStyles) .then((res: List) => { - let html = res[0]; - let fetchedStyles = ListWrapper.slice(res, 1); + let tplEl = res[0]; + let cssTexts = ListWrapper.slice(res, 1); - html = _createStyleTags(view.styles) + _createStyleTags(fetchedStyles) + html; + _insertCssTexts(DOM.content(tplEl), cssTexts); - return DOM.createTemplate(html); + return tplEl; }); } @@ -67,10 +68,74 @@ export class TemplateLoader { return response; } + + // Load the html and inline any style tags + private _loadHtml(view: ViewDefinition): Promise { + let html; + + // Load the HTML + if (isPresent(view.template)) { + html = PromiseWrapper.resolve(view.template); + } else if (isPresent(view.templateAbsUrl)) { + html = this._loadText(view.templateAbsUrl); + } else { + throw new BaseException('View should have either the templateUrl or template property set'); + } + + // Inline the style tags from the html + return html.then(html => { + var tplEl = DOM.createTemplate(html); + let styleEls = DOM.querySelectorAll(DOM.content(tplEl), 'STYLE'); + + let promises: List> = []; + for (let i = 0; i < styleEls.length; i++) { + let promise = this._resolveAndInlineElement(styleEls[i], view.templateAbsUrl); + if (isPromise(promise)) { + promises.push(promise); + } + } + + return promises.length > 0 ? PromiseWrapper.all(promises).then(_ => tplEl) : tplEl; + }); + } + + /** + * Inlines a style element. + * + * @param styleEl The style element + * @param baseUrl The base url + * @returns {Promise} null when no @import rule exist in the css or a Promise + * @private + */ + private _resolveAndInlineElement(styleEl, baseUrl: string): Promise { + let textOrPromise = this._resolveAndInlineCssText(DOM.getText(styleEl), baseUrl); + + if (isPromise(textOrPromise)) { + return (>textOrPromise).then(css => { DOM.setText(styleEl, css); }); + } else { + DOM.setText(styleEl, textOrPromise); + return null; + } + } + + private _resolveAndInlineCssText(cssText: string, baseUrl: string): string | Promise { + cssText = this._styleUrlResolver.resolveUrls(cssText, baseUrl); + return this._styleInliner.inlineImports(cssText, baseUrl); + } } -function _createStyleTags(styles?: List): string { - return isBlank(styles) ? - '' : - ListWrapper.map(styles, css => ``).join(''); +function _insertCssTexts(element, cssTexts: List): void { + if (cssTexts.length == 0) return; + + let insertBefore = DOM.firstChild(element); + + for (let i = cssTexts.length - 1; i >= 0; i--) { + let styleEl = DOM.createStyleElement(cssTexts[i]); + if (isPresent(insertBefore)) { + DOM.insertBefore(insertBefore, styleEl); + } else { + DOM.appendChild(element, styleEl); + } + insertBefore = styleEl; + } } diff --git a/modules/angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy.ts b/modules/angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy.ts index 616253e4f6..1fab2275a4 100644 --- a/modules/angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy.ts +++ b/modules/angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy.ts @@ -1,10 +1,7 @@ -import {isBlank, isPresent, isPromise} from 'angular2/src/facade/lang'; -import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; +import {isBlank, isPresent} from 'angular2/src/facade/lang'; import {DOM} from 'angular2/src/dom/dom_adapter'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; import {EmulatedUnscopedShadowDomStrategy} from './emulated_unscoped_shadow_dom_strategy'; import { getContentAttribute, @@ -27,39 +24,21 @@ import { * - see `ShadowCss` for more information and limitations. */ export class EmulatedScopedShadowDomStrategy extends EmulatedUnscopedShadowDomStrategy { - constructor(styleInliner: StyleInliner, styleUrlResolver: StyleUrlResolver, styleHost) { - super(styleInliner, styleUrlResolver, styleHost); - } - - processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise { - var cssText = DOM.getText(styleEl); - - cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); - var inlinedCss = this.styleInliner.inlineImports(cssText, templateUrl); - - var ret = null; - if (isPromise(inlinedCss)) { - DOM.setText(styleEl, ''); - ret = (>inlinedCss) - .then((css) => { - css = shimCssForComponent(css, hostComponentId); - DOM.setText(styleEl, css); - }); - } else { - var css = shimCssForComponent(inlinedCss, hostComponentId); - DOM.setText(styleEl, css); - } + constructor(styleHost) { super(styleHost); } + processStyleElement(hostComponentId: string, templateUrl: string, styleEl): void { + let cssText = DOM.getText(styleEl); + cssText = shimCssForComponent(cssText, hostComponentId); + DOM.setText(styleEl, cssText); this._moveToStyleHost(styleEl); - return ret; } - _moveToStyleHost(styleEl) { + _moveToStyleHost(styleEl): void { DOM.remove(styleEl); insertStyleElement(this.styleHost, styleEl); } - processElement(hostComponentId: string, elementComponentId: string, element) { + processElement(hostComponentId: string, elementComponentId: string, element): void { // Shim the element as a child of the compiled component if (isPresent(hostComponentId)) { var contentAttribute = getContentAttribute(getComponentId(hostComponentId)); diff --git a/modules/angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy.ts b/modules/angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy.ts index e724726b18..f9b69b2718 100644 --- a/modules/angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy.ts +++ b/modules/angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy.ts @@ -1,14 +1,9 @@ -import {isPromise} from 'angular2/src/facade/lang'; -import {Promise} from 'angular2/src/facade/async'; - import {DOM} from 'angular2/src/dom/dom_adapter'; import * as viewModule from '../view/view'; import {LightDom} from './light_dom'; import {ShadowDomStrategy} from './shadow_dom_strategy'; -import {StyleUrlResolver} from './style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; import {insertSharedStyleText} from './util'; /** @@ -21,10 +16,7 @@ import {insertSharedStyleText} from './util'; * - you can **not** use shadow DOM specific selectors in the styles */ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy { - constructor(public styleInliner: StyleInliner, public styleUrlResolver: StyleUrlResolver, - public styleHost) { - super(); - } + constructor(public styleHost) { super(); } hasNativeContentElement(): boolean { return false; } @@ -34,21 +26,8 @@ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy { return new LightDom(lightDomView, el); } - processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise { + processStyleElement(hostComponentId: string, templateUrl: string, styleEl): void { var cssText = DOM.getText(styleEl); - - cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); - var inlinedCss = this.styleInliner.inlineImports(cssText, templateUrl); - - var ret = null; - if (isPromise(inlinedCss)) { - DOM.setText(styleEl, ''); - ret = (>inlinedCss).then(css => { DOM.setText(styleEl, css); }); - } else { - DOM.setText(styleEl, inlinedCss); - } - insertSharedStyleText(cssText, this.styleHost, styleEl); - return ret; } } diff --git a/modules/angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy.ts b/modules/angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy.ts index 0904cf4945..67c36ad965 100644 --- a/modules/angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy.ts +++ b/modules/angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy.ts @@ -1,12 +1,6 @@ -import {isPromise} from 'angular2/src/facade/lang'; -import {Promise} from 'angular2/src/facade/async'; import {Injectable} from 'angular2/di'; - import {DOM} from 'angular2/src/dom/dom_adapter'; - -import {StyleUrlResolver} from './style_url_resolver'; import {ShadowDomStrategy} from './shadow_dom_strategy'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; /** * This strategies uses the native Shadow DOM support. @@ -16,23 +10,5 @@ import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; */ @Injectable() export class NativeShadowDomStrategy extends ShadowDomStrategy { - constructor(public styleInliner: StyleInliner, public styleUrlResolver: StyleUrlResolver) { - super(); - } - prepareShadowRoot(el) { return DOM.createShadowRoot(el); } - - processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise { - var cssText = DOM.getText(styleEl); - - cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); - var inlinedCss = this.styleInliner.inlineImports(cssText, templateUrl); - - if (isPromise(inlinedCss)) { - return (>inlinedCss).then(css => { DOM.setText(styleEl, css); }); - } else { - DOM.setText(styleEl, inlinedCss); - return null; - } - } } diff --git a/modules/angular2/src/render/dom/shadow_dom/shadow_css.ts b/modules/angular2/src/render/dom/shadow_dom/shadow_css.ts index 6a13c3e145..68ea0d20be 100644 --- a/modules/angular2/src/render/dom/shadow_dom/shadow_css.ts +++ b/modules/angular2/src/render/dom/shadow_dom/shadow_css.ts @@ -11,7 +11,7 @@ import { } from 'angular2/src/facade/lang'; /** - * This file is a port of shadowCSS from webcomponents.js to AtScript. + * This file is a port of shadowCSS from webcomponents.js to TypeScript. * * Please make sure to keep to edits in sync with the source file. * diff --git a/modules/angular2/src/render/dom/shadow_dom/shadow_dom_compile_step.ts b/modules/angular2/src/render/dom/shadow_dom/shadow_dom_compile_step.ts index 094337d155..3f439eca69 100644 --- a/modules/angular2/src/render/dom/shadow_dom/shadow_dom_compile_step.ts +++ b/modules/angular2/src/render/dom/shadow_dom/shadow_dom_compile_step.ts @@ -1,6 +1,4 @@ import {isBlank, isPresent, assertionsEnabled, isPromise} from 'angular2/src/facade/lang'; -import {MapWrapper, List, ListWrapper} from 'angular2/src/facade/collection'; -import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {DOM} from 'angular2/src/dom/dom_adapter'; @@ -11,8 +9,7 @@ import {ViewDefinition} from '../../api'; import {ShadowDomStrategy} from './shadow_dom_strategy'; export class ShadowDomCompileStep implements CompileStep { - constructor(public _shadowDomStrategy: ShadowDomStrategy, public _template: ViewDefinition, - public _subTaskPromises: List>) {} + constructor(public _shadowDomStrategy: ShadowDomStrategy, public _view: ViewDefinition) {} process(parent: CompileElement, current: CompileElement, control: CompileControl) { var tagName = DOM.tagName(current.element).toUpperCase(); @@ -22,17 +19,13 @@ export class ShadowDomCompileStep implements CompileStep { this._processContentElement(current); } else { var componentId = current.isBound() ? current.inheritedElementBinder.componentId : null; - this._shadowDomStrategy.processElement(this._template.componentId, componentId, - current.element); + this._shadowDomStrategy.processElement(this._view.componentId, componentId, current.element); } } _processStyleElement(current: CompileElement, control: CompileControl) { - var stylePromise = this._shadowDomStrategy.processStyleElement( - this._template.componentId, this._template.templateAbsUrl, current.element); - if (isPresent(stylePromise) && isPromise(stylePromise)) { - this._subTaskPromises.push(stylePromise); - } + this._shadowDomStrategy.processStyleElement(this._view.componentId, this._view.templateAbsUrl, + current.element); // Style elements should not be further processed by the compiler, as they can not contain // bindings. Skipping further compiler steps allow speeding up the compilation process. diff --git a/modules/angular2/src/render/dom/shadow_dom/shadow_dom_strategy.ts b/modules/angular2/src/render/dom/shadow_dom/shadow_dom_strategy.ts index 976f7c9f9c..cdfdf91352 100644 --- a/modules/angular2/src/render/dom/shadow_dom/shadow_dom_strategy.ts +++ b/modules/angular2/src/render/dom/shadow_dom/shadow_dom_strategy.ts @@ -1,28 +1,20 @@ import {isBlank, isPresent} from 'angular2/src/facade/lang'; -import {Promise} from 'angular2/src/facade/async'; import * as viewModule from '../view/view'; import {LightDom} from './light_dom'; export class ShadowDomStrategy { + // Whether the strategy understands the native tag hasNativeContentElement(): boolean { return true; } - /** - * Prepares and returns the shadow root for the given element. - */ + // Prepares and returns the (emulated) shadow root for the given element. prepareShadowRoot(el): any { return null; } constructLightDom(lightDomView: viewModule.DomView, el): LightDom { return null; } - /** - * An optional step that can modify the template style elements. - */ - processStyleElement(hostComponentId: string, templateUrl: string, styleElement): Promise { - return null; - } + // An optional step that can modify the template style elements. + processStyleElement(hostComponentId: string, templateUrl: string, styleElement): void {} - /** - * An optional step that can modify the template elements (style elements exlcuded). - */ - processElement(hostComponentId: string, elementComponentId: string, element) {} + // An optional step that can modify the template elements (style elements exlcuded). + processElement(hostComponentId: string, elementComponentId: string, element): void {} } diff --git a/modules/angular2/src/test_lib/test_injector.ts b/modules/angular2/src/test_lib/test_injector.ts index 7b5efe247e..eba8ab9bc4 100644 --- a/modules/angular2/src/test_lib/test_injector.ts +++ b/modules/angular2/src/test_lib/test_injector.ts @@ -23,8 +23,8 @@ import {XHR} from 'angular2/src/render/xhr'; import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; import {UrlResolver} from 'angular2/src/services/url_resolver'; import {AppRootUrl} from 'angular2/src/services/app_root_url'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; +import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; +import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; import {NgZone} from 'angular2/src/core/zone/ng_zone'; import {DOM} from 'angular2/src/dom/dom_adapter'; @@ -88,9 +88,7 @@ function _getAppBindings() { bind(DOCUMENT_TOKEN) .toValue(appDoc), bind(ShadowDomStrategy) - .toFactory((styleInliner, styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy( - styleInliner, styleUrlResolver, doc.head), - [StyleInliner, StyleUrlResolver, DOCUMENT_TOKEN]), + .toFactory((doc) => new EmulatedUnscopedShadowDomStrategy(doc.head), [DOCUMENT_TOKEN]), DomRenderer, DefaultDomCompiler, bind(Renderer).toAlias(DomRenderer), diff --git a/modules/angular2/src/transform/template_compiler/compile_step_factory.dart b/modules/angular2/src/transform/template_compiler/compile_step_factory.dart index 72e0dc7366..c665cbdcd5 100644 --- a/modules/angular2/src/transform/template_compiler/compile_step_factory.dart +++ b/modules/angular2/src/transform/template_compiler/compile_step_factory.dart @@ -1,6 +1,5 @@ library angular2.transform.template_compiler.compile_step_factory; -import 'dart:async'; import 'package:angular2/src/change_detection/parser/parser.dart' as ng; import 'package:angular2/src/render/api.dart'; import 'package:angular2/src/render/dom/compiler/compile_step.dart'; @@ -15,8 +14,7 @@ class CompileStepFactory implements base.CompileStepFactory { final ng.Parser _parser; CompileStepFactory(this._parser); - List createSteps( - ViewDefinition template, List subTaskPromises) { + List createSteps(ViewDefinition template) { return [ new ViewSplitter(_parser), new PropertyBindingParser(_parser), diff --git a/modules/angular2/src/transform/template_compiler/generator.dart b/modules/angular2/src/transform/template_compiler/generator.dart index c53d69a8e8..e91835d1f4 100644 --- a/modules/angular2/src/transform/template_compiler/generator.dart +++ b/modules/angular2/src/transform/template_compiler/generator.dart @@ -7,6 +7,8 @@ import 'package:angular2/src/change_detection/parser/parser.dart' as ng; import 'package:angular2/src/core/compiler/proto_view_factory.dart'; import 'package:angular2/src/render/api.dart'; import 'package:angular2/src/render/dom/compiler/compile_pipeline.dart'; +import 'package:angular2/src/render/dom/compiler/style_inliner.dart'; +import 'package:angular2/src/render/dom/compiler/style_url_resolver.dart'; import 'package:angular2/src/render/dom/compiler/template_loader.dart'; import 'package:angular2/src/render/xhr.dart' show XHR; import 'package:angular2/src/reflection/reflection.dart'; @@ -79,11 +81,17 @@ Future processTemplates(AssetReader reader, AssetId entryPoint, /// reflectively accessed from that template. class _TemplateExtractor { final CompileStepFactory _factory; - final TemplateLoader _loader; + TemplateLoader _loader; _TemplateExtractor(XHR xhr) - : _factory = new CompileStepFactory(new ng.Parser(new ng.Lexer())), - _loader = new TemplateLoader(xhr, new UrlResolver()); + : _factory = new CompileStepFactory(new ng.Parser(new ng.Lexer())) { + + var urlResolver = new UrlResolver(); + var styleUrlResolver = new StyleUrlResolver(urlResolver); + var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); + + _loader = new TemplateLoader(xhr, styleInliner, styleUrlResolver); + } Future<_ExtractResult> extractTemplates(ViewDefinition viewDef) async { // Check for "imperative views". @@ -98,9 +106,7 @@ class _TemplateExtractor { var recordingCapabilities = new RecordingReflectionCapabilities(); reflector.reflectionCapabilities = recordingCapabilities; - var subtaskPromises = []; - var pipeline = - new CompilePipeline(_factory.createSteps(viewDef, subtaskPromises)); + var pipeline = new CompilePipeline(_factory.createSteps(viewDef)); var compileElements = pipeline.process(templateEl, ViewType.COMPONENT, viewDef.componentId); @@ -109,9 +115,7 @@ class _TemplateExtractor { reflector.reflectionCapabilities = savedReflectionCapabilities; - return Future - .wait(subtaskPromises) - .then((_) => new _ExtractResult(recordingCapabilities, protoViewDto)); + return new _ExtractResult(recordingCapabilities, protoViewDto); } } diff --git a/modules/angular2/test/core/compiler/compiler_spec.ts b/modules/angular2/test/core/compiler/compiler_spec.ts index 293fdf2454..7b20657b4b 100644 --- a/modules/angular2/test/core/compiler/compiler_spec.ts +++ b/modules/angular2/test/core/compiler/compiler_spec.ts @@ -62,8 +62,8 @@ export function main() { protoViewFactoryResults: List>) { var urlResolver = new FakeUrlResolver(); renderCompileRequests = []; - renderCompiler.spy('compile').andCallFake((template) => { - renderCompileRequests.push(template); + renderCompiler.spy('compile').andCallFake((view) => { + renderCompileRequests.push(view); return PromiseWrapper.resolve(ListWrapper.removeAt(renderCompileResults, 0)); }); @@ -467,12 +467,12 @@ export function main() { }); } -function createDirectiveBinding(directiveResolver, type) { +function createDirectiveBinding(directiveResolver, type): DirectiveBinding { var annotation = directiveResolver.resolve(type); return DirectiveBinding.createFromType(type, annotation); } -function createProtoView(elementBinders = null) { +function createProtoView(elementBinders = null): AppProtoView { var pv = new AppProtoView(null, null, new Map(), null); if (isBlank(elementBinders)) { elementBinders = []; @@ -481,18 +481,19 @@ function createProtoView(elementBinders = null) { return pv; } -function createComponentElementBinder(directiveResolver, type) { +function createComponentElementBinder(directiveResolver, type): ElementBinder { var binding = createDirectiveBinding(directiveResolver, type); return new ElementBinder(0, null, 0, null, binding); } -function createViewportElementBinder(nestedProtoView) { +function createViewportElementBinder(nestedProtoView): ElementBinder { var elBinder = new ElementBinder(0, null, 0, null, null); elBinder.nestedProtoView = nestedProtoView; return elBinder; } -function createRenderProtoView(elementBinders = null, type: renderApi.ViewType = null) { +function createRenderProtoView(elementBinders = null, + type: renderApi.ViewType = null): renderApi.ProtoViewDto { if (isBlank(type)) { type = renderApi.ViewType.COMPONENT; } @@ -502,16 +503,16 @@ function createRenderProtoView(elementBinders = null, type: renderApi.ViewType = return new renderApi.ProtoViewDto({elementBinders: elementBinders, type: type}); } -function createRenderComponentElementBinder(directiveIndex) { +function createRenderComponentElementBinder(directiveIndex): renderApi.ElementBinder { return new renderApi.ElementBinder( {directives: [new renderApi.DirectiveBinder({directiveIndex: directiveIndex})]}); } -function createRenderViewportElementBinder(nestedProtoView) { +function createRenderViewportElementBinder(nestedProtoView): renderApi.ElementBinder { return new renderApi.ElementBinder({nestedProtoView: nestedProtoView}); } -function createRootProtoView(directiveResolver, type) { +function createRootProtoView(directiveResolver, type): AppProtoView { return createProtoView([createComponentElementBinder(directiveResolver, type)]); } @@ -577,23 +578,18 @@ class FakeAppRootUrl extends AppRootUrl { class FakeTemplateResolver extends TemplateResolver { - _cmpTemplates: Map; + _cmpViews: Map = new Map(); - constructor() { - super(); - this._cmpTemplates = new Map(); - } + constructor() { super(); } resolve(component: Type): viewAnn.View { - var template = this._cmpTemplates.get(component); - if (isBlank(template)) { - // dynamic component - return null; - } - return template; + // returns null for dynamic components + return this._cmpViews.has(component) ? this._cmpViews.get(component) : null; } - setView(component: Type, template: viewAnn.View) { this._cmpTemplates.set(component, template); } + setView(component: Type, template: viewAnn.View): void { + this._cmpViews.set(component, template); + } } class FakeProtoViewFactory extends ProtoViewFactory { diff --git a/modules/angular2/test/directives/ng_if_spec.ts b/modules/angular2/test/directives/ng_if_spec.ts index 6894148372..b7a18a3fc5 100644 --- a/modules/angular2/test/directives/ng_if_spec.ts +++ b/modules/angular2/test/directives/ng_if_spec.ts @@ -21,7 +21,7 @@ import {Component, View} from 'angular2/angular2'; import {NgIf} from 'angular2/src/directives/ng_if'; export function main() { - describe('if directive', () => { + describe('ng-if directive', () => { it('should work in a template attribute', inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => { var html = '
hello
'; diff --git a/modules/angular2/test/render/dom/compiler/compiler_common_tests.ts b/modules/angular2/test/render/dom/compiler/compiler_common_tests.ts index bfb5be6567..db99e2f97c 100644 --- a/modules/angular2/test/render/dom/compiler/compiler_common_tests.ts +++ b/modules/angular2/test/render/dom/compiler/compiler_common_tests.ts @@ -24,8 +24,6 @@ import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_ import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; -import {UrlResolver} from 'angular2/src/services/url_resolver'; - import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view'; export function runCompilerCommonTests() { @@ -111,30 +109,6 @@ export function runCompilerCommonTests() { }); })); - it('should wait for async subtasks to be resolved', inject([AsyncTestCompleter], (async) => { - var subTasksCompleted = false; - - var completer = PromiseWrapper.completer(); - - var compiler = createCompiler((parent, current, control) => { - mockStepFactory.subTaskPromises.push( - completer.promise.then((_) => { subTasksCompleted = true; })); - }); - - // It should always return a Promise because the subtask is async - var pvPromise = compiler.compile( - new ViewDefinition({componentId: 'someId', template: 'some component'})); - expect(pvPromise).toBePromise(); - expect(subTasksCompleted).toEqual(false); - - // The Promise should resolve after the subtask is ready - completer.resolve(null); - pvPromise.then((protoView) => { - expect(subTasksCompleted).toEqual(true); - async.done(); - }); - })); - it('should return ProtoViews of type COMPONENT_VIEW_TYPE', inject([AsyncTestCompleter], (async) => { var compiler = createCompiler(EMPTY_STEP); @@ -174,10 +148,8 @@ class MockStepFactory extends CompileStepFactory { super(); this.steps = steps; } - createSteps(viewDef, subTaskPromises) { + createSteps(viewDef): List { this.viewDef = viewDef; - this.subTaskPromises = subTaskPromises; - ListWrapper.forEach(this.subTaskPromises, (p) => this.subTaskPromises.push(p)); return this.steps; } } @@ -199,20 +171,20 @@ var EMPTY_STEP = (parent, current, control) => { class FakeTemplateLoader extends TemplateLoader { _urlData: Map; constructor(urlData) { - super(null, new UrlResolver()); + super(null, null, null); this._urlData = urlData; } - load(template: ViewDefinition) { - if (isPresent(template.template)) { - return PromiseWrapper.resolve(DOM.createTemplate(template.template)); + load(view: ViewDefinition): Promise { + if (isPresent(view.template)) { + return PromiseWrapper.resolve(DOM.createTemplate(view.template)); } - if (isPresent(template.templateAbsUrl)) { - var content = this._urlData.get(template.templateAbsUrl); + if (isPresent(view.templateAbsUrl)) { + var content = this._urlData.get(view.templateAbsUrl); return isPresent(content) ? PromiseWrapper.resolve(DOM.createTemplate(content)) : - PromiseWrapper.reject(`Failed to fetch url "${template.templateAbsUrl}"`, null); + PromiseWrapper.reject(`Failed to fetch url "${view.templateAbsUrl}"`, null); } throw new BaseException('View should have either the templateUrl or template property set'); diff --git a/modules/angular2/test/render/dom/shadow_dom/style_inliner_spec.ts b/modules/angular2/test/render/dom/compiler/style_inliner_spec.ts similarity index 99% rename from modules/angular2/test/render/dom/shadow_dom/style_inliner_spec.ts rename to modules/angular2/test/render/dom/compiler/style_inliner_spec.ts index db7cedd386..0f8b81eac0 100644 --- a/modules/angular2/test/render/dom/shadow_dom/style_inliner_spec.ts +++ b/modules/angular2/test/render/dom/compiler/style_inliner_spec.ts @@ -11,7 +11,7 @@ import { it, xit, } from 'angular2/test_lib'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; +import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; import {isBlank} from 'angular2/src/facade/lang'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; diff --git a/modules/angular2/test/render/dom/shadow_dom/style_url_resolver_spec.ts b/modules/angular2/test/render/dom/compiler/style_url_resolver_spec.ts similarity index 96% rename from modules/angular2/test/render/dom/shadow_dom/style_url_resolver_spec.ts rename to modules/angular2/test/render/dom/compiler/style_url_resolver_spec.ts index d1da831d79..f4616feaa2 100644 --- a/modules/angular2/test/render/dom/shadow_dom/style_url_resolver_spec.ts +++ b/modules/angular2/test/render/dom/compiler/style_url_resolver_spec.ts @@ -1,5 +1,5 @@ import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; +import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; import {UrlResolver} from 'angular2/src/services/url_resolver'; diff --git a/modules/angular2/test/render/dom/compiler/template_loader_spec.ts b/modules/angular2/test/render/dom/compiler/template_loader_spec.ts index 35eb1830d2..61b07a108b 100644 --- a/modules/angular2/test/render/dom/compiler/template_loader_spec.ts +++ b/modules/angular2/test/render/dom/compiler/template_loader_spec.ts @@ -12,19 +12,27 @@ import { } from 'angular2/test_lib'; import {DOM} from 'angular2/src/dom/dom_adapter'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; +import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; +import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; import {UrlResolver} from 'angular2/src/services/url_resolver'; import {ViewDefinition} from 'angular2/src/render/api'; -import {PromiseWrapper} from 'angular2/src/facade/async'; +import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; +import {StringWrapper, isBlank, isPresent} from 'angular2/src/facade/lang'; +import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; +import {XHR} from 'angular2/src/render/xhr'; import {MockXHR} from 'angular2/src/render/xhr_mock'; export function main() { describe('TemplateLoader', () => { - var loader, xhr; + var loader, xhr, styleUrlResolver, urlResolver; beforeEach(() => { xhr = new MockXHR(); - loader = new TemplateLoader(xhr, new FakeUrlResolver()); + urlResolver = new FakeUrlResolver(); + styleUrlResolver = new StyleUrlResolver(urlResolver); + let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); + loader = new TemplateLoader(xhr, styleInliner, styleUrlResolver); }); describe('html', () => { @@ -46,6 +54,33 @@ export function main() { xhr.flush(); })); + it('should resolve urls in styles', inject([AsyncTestCompleter], (async) => { + xhr.expect('base/foo.html', + ''); + var template = new ViewDefinition({templateAbsUrl: 'base/foo.html'}); + loader.load(template).then((el) => { + expect(DOM.content(el)) + .toHaveText(".foo { background-image: url('/base/double.jpg'); }"); + async.done(); + }); + xhr.flush(); + })); + + it('should inline styles', inject([AsyncTestCompleter], (async) => { + let xhr = new FakeXHR(); + xhr.reply('base/foo.html', ''); + xhr.reply('/base/foo.css', '/* foo.css */'); + + let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); + let loader = new TemplateLoader(xhr, styleInliner, styleUrlResolver); + + var template = new ViewDefinition({templateAbsUrl: 'base/foo.html'}); + loader.load(template).then((el) => { + expect(DOM.getInnerHTML(el)).toEqual(""); + async.done(); + }); + })); + it('should return a new template element on each call', inject([AsyncTestCompleter], (async) => { var firstEl; @@ -91,8 +126,17 @@ export function main() { var template = new ViewDefinition({template: 'html', styles: ['style 1', 'style 2']}); loader.load(template).then((el) => { expect(DOM.getInnerHTML(el)) - .toEqual( - 'html'); + .toEqual('html'); + async.done(); + }); + })); + + it('should resolve urls in inline styles', inject([AsyncTestCompleter], (async) => { + var template = new ViewDefinition( + {template: 'html', styles: ['.foo { background-image: url("double.jpg"); }']}); + loader.load(template).then((el) => { + expect(DOM.getInnerHTML(el)) + .toEqual("html"); async.done(); }); })); @@ -108,13 +152,29 @@ export function main() { }); loader.load(template).then((el) => { expect(DOM.getInnerHTML(el)) - .toEqual( - 'xhr template'); + .toEqual('xhr template'); async.done(); }); xhr.flush(); })); + it('should inline styles', inject([AsyncTestCompleter], (async) => { + let xhr = new FakeXHR(); + xhr.reply('base/foo.html', '

template

'); + xhr.reply('/base/foo.css', '/* foo.css */'); + + let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); + let loader = new TemplateLoader(xhr, styleInliner, styleUrlResolver); + + var template = new ViewDefinition( + {templateAbsUrl: 'base/foo.html', styles: ['@import "foo.css";']}); + loader.load(template).then((el) => { + expect(DOM.getInnerHTML(el)).toEqual("

template

"); + async.done(); + }); + })); + + it('should return a rejected Promise when XHR loading fails', inject([AsyncTestCompleter], (async) => { xhr.expect('base/foo.css', null); @@ -136,5 +196,27 @@ class SomeComponent {} class FakeUrlResolver extends UrlResolver { constructor() { super(); } - resolve(baseUrl: string, url: string): string { return baseUrl + url; } + resolve(baseUrl: string, url: string): string { + if (url.length > 0 && url[0] == '/') return url; + if (!isPresent(baseUrl)) return `/${url}`; + var parts: List = baseUrl.split('/'); + if (parts.length > 1) { + ListWrapper.removeLast(parts); + } + parts.push(url); + return '/' + parts.join('/'); + } +} + +class FakeXHR extends XHR { + _responses: Map = new Map(); + + constructor() { super(); } + + get(url: string): Promise { + return this._responses.has(url) ? PromiseWrapper.resolve(this._responses.get(url)) : + PromiseWrapper.reject('xhr error', null); + } + + reply(url: string, response: string): void { this._responses.set(url, response); } } diff --git a/modules/angular2/test/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy_spec.ts b/modules/angular2/test/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy_spec.ts index ae7cae8acf..e975d2120f 100644 --- a/modules/angular2/test/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy_spec.ts +++ b/modules/angular2/test/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy_spec.ts @@ -13,12 +13,7 @@ import { normalizeCSS } from 'angular2/test_lib'; -import {isPresent, isBlank} from 'angular2/src/facade/lang'; import {DOM} from 'angular2/src/dom/dom_adapter'; -import {Map, MapWrapper} from 'angular2/src/facade/collection'; -import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; - -import {XHR} from 'angular2/src/render/xhr'; import { EmulatedScopedShadowDomStrategy, @@ -26,21 +21,14 @@ import { import { resetShadowDomCache, } from 'angular2/src/render/dom/shadow_dom/util'; -import {UrlResolver} from 'angular2/src/services/url_resolver'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; export function main() { describe('EmulatedScopedShadowDomStrategy', () => { - var xhr, styleHost, strategy; + var styleHost, strategy; beforeEach(() => { - var urlResolver = new UrlResolver(); - var styleUrlResolver = new StyleUrlResolver(urlResolver); - xhr = new FakeXHR(); - var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); styleHost = el('
'); - strategy = new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost); + strategy = new EmulatedScopedShadowDomStrategy(styleHost); resetShadowDomCache(); }); @@ -49,34 +37,12 @@ export function main() { expect(strategy.prepareShadowRoot(host)).toBe(host); }); - it('should rewrite style urls', () => { - var styleElement = el(''); - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(normalizeCSS(DOM.getText(styleElement))) - .toEqual(".foo[_ngcontent-0] { background-image:url(http://base/img.jpg); }"); - }); - it('should scope styles', () => { var styleElement = el(''); strategy.processStyleElement('someComponent', 'http://base', styleElement); expect(styleElement).toHaveText(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}"); }); - it('should inline @import rules', inject([AsyncTestCompleter], (async) => { - xhr.reply('http://base/one.css', '.one {}'); - - var styleElement = el(''); - var stylePromise = - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(stylePromise).toBePromise(); - expect(styleElement).toHaveText(''); - - stylePromise.then((_) => { - expect(styleElement).toHaveText('.one[_ngcontent-0] {\n\n}'); - async.done(); - }); - })); - it('should return the same style given the same component', () => { var styleElement = el(''); strategy.processStyleElement('someComponent', 'http://base', styleElement); @@ -97,22 +63,6 @@ export function main() { expect(DOM.getText(styleElement)).not.toEqual(DOM.getText(styleElement2)); }); - it('should move the style element to the style host when @imports are present', - inject([AsyncTestCompleter], (async) => { - xhr.reply('http://base/one.css', '.one {}'); - - var compileElement = el('
'); - var styleElement = DOM.firstChild(compileElement); - var stylePromise = - strategy.processStyleElement('someComponent', 'http://base', styleElement); - - stylePromise.then((_) => { - expect(compileElement).toHaveText(''); - expect(styleHost).toHaveText('.one[_ngcontent-0] {\n\n}'); - async.done(); - }); - })); - it('should move the style element to the style host', () => { var compileElement = el('
'); var styleElement = DOM.firstChild(compileElement); @@ -136,23 +86,3 @@ export function main() { }); } - -class FakeXHR extends XHR { - _responses: Map; - - constructor() { - super(); - this._responses = new Map(); - } - - get(url: string): Promise { - var response = this._responses.get(url); - if (isBlank(response)) { - return PromiseWrapper.reject('xhr error', null); - } - - return PromiseWrapper.resolve(response); - } - - reply(url: string, response: string) { this._responses.set(url, response); } -} diff --git a/modules/angular2/test/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy_spec.ts b/modules/angular2/test/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy_spec.ts index 6d501e96c7..ccb98419c6 100644 --- a/modules/angular2/test/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy_spec.ts +++ b/modules/angular2/test/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy_spec.ts @@ -13,7 +13,7 @@ import { } from 'angular2/test_lib'; import {DOM} from 'angular2/src/dom/dom_adapter'; -import {Map, ListWrapper} from 'angular2/src/facade/collection'; +import {ListWrapper} from 'angular2/src/facade/collection'; import { EmulatedUnscopedShadowDomStrategy, @@ -21,28 +21,16 @@ import { import { resetShadowDomCache, } from 'angular2/src/render/dom/shadow_dom/util'; -import {UrlResolver} from 'angular2/src/services/url_resolver'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; - -import {isBlank} from 'angular2/src/facade/lang'; -import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; - -import {XHR} from 'angular2/src/render/xhr'; export function main() { var strategy; describe('EmulatedUnscopedShadowDomStrategy', () => { - var xhr, styleHost; + var styleHost; beforeEach(() => { - var urlResolver = new UrlResolver(); - var styleUrlResolver = new StyleUrlResolver(urlResolver); - xhr = new FakeXHR(); - var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); styleHost = el('
'); - strategy = new EmulatedUnscopedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost); + strategy = new EmulatedUnscopedShadowDomStrategy(styleHost); resetShadowDomCache(); }); @@ -51,27 +39,6 @@ export function main() { expect(strategy.prepareShadowRoot(host)).toBe(host); }); - it('should rewrite style urls', () => { - var styleElement = el(''); - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(styleElement).toHaveText(".foo {background-image: url('http://base/img.jpg');}"); - }); - - it('should inline @import rules', inject([AsyncTestCompleter], (async) => { - xhr.reply('http://base/one.css', '.one {}'); - - var styleElement = el(''); - var stylePromise = - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(stylePromise).toBePromise(); - expect(styleElement).toHaveText(''); - - stylePromise.then((_) => { - expect(styleElement).toHaveText('.one {}\n'); - async.done(); - }); - })); - it('should move the style element to the style host', () => { var compileElement = el('
'); var styleElement = DOM.firstChild(compileElement); @@ -96,23 +63,3 @@ export function main() { }); } - -class FakeXHR extends XHR { - _responses: Map; - - constructor() { - super(); - this._responses = >{}; - } - - get(url: string): Promise { - var response = this._responses[url]; - if (isBlank(response)) { - return PromiseWrapper.reject('xhr error', null); - } - - return PromiseWrapper.resolve(response); - } - - reply(url: string, response: string) { this._responses[url] = response; } -} diff --git a/modules/angular2/test/render/dom/shadow_dom/native_shadow_dom_strategy_spec.ts b/modules/angular2/test/render/dom/shadow_dom/native_shadow_dom_strategy_spec.ts index 758f9e53a5..48b0256656 100644 --- a/modules/angular2/test/render/dom/shadow_dom/native_shadow_dom_strategy_spec.ts +++ b/modules/angular2/test/render/dom/shadow_dom/native_shadow_dom_strategy_spec.ts @@ -15,15 +15,6 @@ import { import { NativeShadowDomStrategy } from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy'; -import {UrlResolver} from 'angular2/src/services/url_resolver'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; - -import {XHR} from 'angular2/src/render/xhr'; - -import {isBlank} from 'angular2/src/facade/lang'; -import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; -import {Map} from 'angular2/src/facade/collection'; import {DOM} from 'angular2/src/dom/dom_adapter'; @@ -31,14 +22,7 @@ export function main() { var strategy; describe('NativeShadowDomStrategy', () => { - var xhr; - beforeEach(() => { - var urlResolver = new UrlResolver(); - var styleUrlResolver = new StyleUrlResolver(urlResolver); - xhr = new FakeXHR(); - var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); - strategy = new NativeShadowDomStrategy(styleInliner, styleUrlResolver); - }); + beforeEach(() => { strategy = new NativeShadowDomStrategy(); }); if (DOM.supportsNativeShadowDOM()) { it('should use the native shadow root', () => { @@ -46,47 +30,5 @@ export function main() { expect(strategy.prepareShadowRoot(host)).toBe(DOM.getShadowRoot(host)); }); } - - it('should rewrite style urls', () => { - var styleElement = el(''); - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(styleElement) - .toHaveText(".foo {" + "background-image: url('http://base/img.jpg');" + "}"); - }); - - it('should inline @import rules', inject([AsyncTestCompleter], (async) => { - xhr.reply('http://base/one.css', '.one {}'); - - var styleElement = el(''); - var stylePromise = - strategy.processStyleElement('someComponent', 'http://base', styleElement); - expect(stylePromise).toBePromise(); - - stylePromise.then((_) => { - expect(styleElement).toHaveText('.one {}\n'); - async.done(); - }); - })); - }); } - -class FakeXHR extends XHR { - _responses: Map; - - constructor() { - super(); - this._responses = >{}; - } - - get(url: string): Promise { - var response = this._responses[url]; - if (isBlank(response)) { - return PromiseWrapper.reject('xhr error', null); - } - - return PromiseWrapper.resolve(response); - } - - reply(url: string, response: string) { this._responses[url] = response; } -} diff --git a/modules/angular2/test/render/dom/shadow_dom_emulation_integration_spec.ts b/modules/angular2/test/render/dom/shadow_dom_emulation_integration_spec.ts index 36ea9dacaa..9c2c12743b 100644 --- a/modules/angular2/test/render/dom/shadow_dom_emulation_integration_spec.ts +++ b/modules/angular2/test/render/dom/shadow_dom_emulation_integration_spec.ts @@ -29,35 +29,21 @@ import { import { NativeShadowDomStrategy } from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; import {DomTestbed, elRef} from './dom_testbed'; export function main() { describe('ShadowDom integration tests', function() { - var styleHost; + var styleHost = DOM.createElement('div'); + var strategies = { - "scoped": - bind(ShadowDomStrategy) - .toFactory((styleInliner, styleUrlResolver) => new EmulatedScopedShadowDomStrategy( - styleInliner, styleUrlResolver, styleHost), - [StyleInliner, StyleUrlResolver]), - "unscoped": - bind(ShadowDomStrategy) - .toFactory((styleInliner, styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy( - styleInliner, styleUrlResolver, null), - [StyleInliner, StyleUrlResolver]) + "scoped": bind(ShadowDomStrategy).toValue(new EmulatedScopedShadowDomStrategy(styleHost)), + "unscoped": bind(ShadowDomStrategy).toValue(new EmulatedUnscopedShadowDomStrategy(styleHost)) }; if (DOM.supportsNativeShadowDOM()) { - StringMapWrapper.set( - strategies, "native", - bind(ShadowDomStrategy) - .toFactory((styleInliner, styleUrlResolver) => - new NativeShadowDomStrategy(styleInliner, styleUrlResolver), - [StyleInliner, StyleUrlResolver])); + StringMapWrapper.set(strategies, "native", + bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy())); } - beforeEach(() => { styleHost = el('
'); }); StringMapWrapper.forEach(strategies, (strategyBinding, name) => { describe(`${name} shadow dom strategy`, () => { diff --git a/modules/benchmarks/src/compiler/compiler_benchmark.ts b/modules/benchmarks/src/compiler/compiler_benchmark.ts index eb749dffaf..17b85032e0 100644 --- a/modules/benchmarks/src/compiler/compiler_benchmark.ts +++ b/modules/benchmarks/src/compiler/compiler_benchmark.ts @@ -16,10 +16,7 @@ import {Component, Directive, View} from 'angular2/angular2'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {UrlResolver} from 'angular2/src/services/url_resolver'; -import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; -import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner'; import {AppRootUrl} from 'angular2/src/services/app_root_url'; - import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; import {reflector} from 'angular2/src/reflection/reflection'; @@ -39,11 +36,9 @@ export function main() { var templateResolver = new MultipleTemplateResolver( count, [BenchmarkComponentNoBindings, BenchmarkComponentWithBindings]); var urlResolver = new UrlResolver(); - var styleUrlResolver = new StyleUrlResolver(urlResolver); - var styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver); - var shadowDomStrategy = new NativeShadowDomStrategy(styleInliner, styleUrlResolver); + var shadowDomStrategy = new NativeShadowDomStrategy(); var renderCompiler = new rc.DefaultDomCompiler(new Parser(new Lexer()), shadowDomStrategy, - new TemplateLoader(null, urlResolver)); + new TemplateLoader(null, null, null)); var compiler = new Compiler( reader, cache, templateResolver, new ComponentUrlMapper(), urlResolver, renderCompiler, new ProtoViewFactory(new DynamicChangeDetection(null)), new FakeAppRootUrl()); diff --git a/modules/examples/src/material/demo_common.ts b/modules/examples/src/material/demo_common.ts index 9c105d1aa4..4e3a2ad288 100644 --- a/modules/examples/src/material/demo_common.ts +++ b/modules/examples/src/material/demo_common.ts @@ -27,16 +27,16 @@ export class DemoUrlResolver extends UrlResolver { constructor() { super(); - if (isBlank(UrlResolver.a)) { - UrlResolver.a = DOM.createElement('a'); + if (isBlank(DemoUrlResolver.a)) { + DemoUrlResolver.a = DOM.createElement('a'); } this.isInPubServe = _isInPubServe(); } resolve(baseUrl: string, url: string): string { if (isBlank(baseUrl)) { - DOM.resolveAndSetHref(UrlResolver.a, url, null); - return DOM.getHref(UrlResolver.a); + DOM.resolveAndSetHref(DemoUrlResolver.a, url, null); + return DOM.getHref(DemoUrlResolver.a); } if (isBlank(url) || url == '') {