diff --git a/modules/angular2/src/core/compiler/compiler.js b/modules/angular2/src/core/compiler/compiler.js index e3f20449a2..320a652e92 100644 --- a/modules/angular2/src/core/compiler/compiler.js +++ b/modules/angular2/src/core/compiler/compiler.js @@ -120,7 +120,6 @@ export class Compiler { } _compileTemplate(template: Element, cmpMetadata): Promise { - this._shadowDomStrategy.processTemplate(template, cmpMetadata); var pipeline = new CompilePipeline(this.createSteps(cmpMetadata)); var compileElements = pipeline.process(template); var protoView = compileElements[0].inheritedProtoView; diff --git a/modules/angular2/src/core/compiler/pipeline/compile_element.js b/modules/angular2/src/core/compiler/pipeline/compile_element.js index c8d6352c2b..8da921fce9 100644 --- a/modules/angular2/src/core/compiler/pipeline/compile_element.js +++ b/modules/angular2/src/core/compiler/pipeline/compile_element.js @@ -39,6 +39,8 @@ export class CompileElement { inheritedElementBinder:ElementBinder; distanceToParentInjector:number; compileChildren: boolean; + ignoreBindings: boolean; + constructor(element:Element) { this.element = element; this._attrs = null; @@ -64,6 +66,8 @@ export class CompileElement { this.inheritedElementBinder = null; this.distanceToParentInjector = 0; this.compileChildren = true; + // set to true to ignore all the bindings on the element + this.ignoreBindings = false; } refreshAttrs() { diff --git a/modules/angular2/src/core/compiler/pipeline/default_steps.js b/modules/angular2/src/core/compiler/pipeline/default_steps.js index 9b6c525f1d..e841c1a38c 100644 --- a/modules/angular2/src/core/compiler/pipeline/default_steps.js +++ b/modules/angular2/src/core/compiler/pipeline/default_steps.js @@ -1,5 +1,5 @@ import {ChangeDetection, Parser} from 'angular2/change_detection'; -import {List} from 'angular2/src/facade/collection'; +import {List, ListWrapper} from 'angular2/src/facade/collection'; import {PropertyBindingParser} from './property_binding_parser'; import {TextInterpolationParser} from './text_interpolation_parser'; @@ -9,9 +9,11 @@ import {ElementBindingMarker} from './element_binding_marker'; import {ProtoViewBuilder} from './proto_view_builder'; import {ProtoElementInjectorBuilder} from './proto_element_injector_builder'; import {ElementBinderBuilder} from './element_binder_builder'; +import {ShadowDomTransformer} from './shadow_dom_transformer'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; -import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {stringify} from 'angular2/src/facade/lang'; +import {DOM} from 'angular2/src/facade/dom'; /** * Default steps used for compiling a template. @@ -27,8 +29,14 @@ export function createDefaultSteps( var compilationUnit = stringify(compiledComponent.type); - return [ - new ViewSplitter(parser, compilationUnit), + var steps = [new ViewSplitter(parser, compilationUnit)]; + + if (!(shadowDomStrategy instanceof NativeShadowDomStrategy)) { + var step = new ShadowDomTransformer(compiledComponent, shadowDomStrategy, DOM.defaultDoc().head); + ListWrapper.push(steps, step); + } + + steps = ListWrapper.concat(steps,[ new PropertyBindingParser(parser, compilationUnit), new DirectiveParser(directives), new TextInterpolationParser(parser, compilationUnit), @@ -36,5 +44,7 @@ export function createDefaultSteps( new ProtoViewBuilder(changeDetection, shadowDomStrategy), new ProtoElementInjectorBuilder(), new ElementBinderBuilder(parser, compilationUnit) - ]; + ]); + + return steps; } diff --git a/modules/angular2/src/core/compiler/pipeline/element_binding_marker.js b/modules/angular2/src/core/compiler/pipeline/element_binding_marker.js index a5ad8844fa..686d3a47b3 100644 --- a/modules/angular2/src/core/compiler/pipeline/element_binding_marker.js +++ b/modules/angular2/src/core/compiler/pipeline/element_binding_marker.js @@ -26,6 +26,10 @@ const NG_BINDING_CLASS = 'ng-binding'; */ export class ElementBindingMarker extends CompileStep { process(parent:CompileElement, current:CompileElement, control:CompileControl) { + if (current.ignoreBindings) { + return; + } + var hasBindings = (isPresent(current.textNodeBindings) && MapWrapper.size(current.textNodeBindings)>0) || (isPresent(current.propertyBindings) && MapWrapper.size(current.propertyBindings)>0) || diff --git a/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js b/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js index 28c22b23c1..f93a47e667 100644 --- a/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js +++ b/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js @@ -38,6 +38,10 @@ export class PropertyBindingParser extends CompileStep { } process(parent:CompileElement, current:CompileElement, control:CompileControl) { + if (current.ignoreBindings) { + return; + } + var attrs = current.attrs(); MapWrapper.forEach(attrs, (attrValue, attrName) => { var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName); diff --git a/modules/angular2/src/core/compiler/pipeline/shadow_dom_transformer.js b/modules/angular2/src/core/compiler/pipeline/shadow_dom_transformer.js new file mode 100644 index 0000000000..7d90dd0d51 --- /dev/null +++ b/modules/angular2/src/core/compiler/pipeline/shadow_dom_transformer.js @@ -0,0 +1,79 @@ +import {CompileStep} from './compile_step'; +import {CompileElement} from './compile_element'; +import {CompileControl} from './compile_control'; + +import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; +import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {shimCssText} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_css'; + +import {DOM, Element} from 'angular2/src/facade/dom'; +import {isPresent, isBlank} from 'angular2/src/facade/lang'; +import {StringMapWrapper} from 'angular2/src/facade/collection'; + +var _cssCache = StringMapWrapper.create(); + +export class ShadowDomTransformer extends CompileStep { + _selector: string; + _strategy: ShadowDomStrategy; + _styleHost: Element; + _lastInsertedStyle: Element; + + constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy, styleHost: Element) { + super(); + this._strategy = strategy; + this._selector = cmpMetadata.annotation.selector; + this._styleHost = styleHost; + this._lastInsertedStyle = null; + } + + process(parent:CompileElement, current:CompileElement, control:CompileControl) { + // May be remove the styles + if (DOM.tagName(current.element) == 'STYLE') { + current.ignoreBindings = true; + if (this._strategy.extractStyles()) { + DOM.remove(current.element); + var css = DOM.getText(current.element); + if (this._strategy.shim()) { + // The css generated here is unique for the component (because of the shim). + // Then we do not need to cache it. + css = shimCssText(css, this._selector); + this._insertStyle(this._styleHost, css); + } else { + var seen = isPresent(StringMapWrapper.get(_cssCache, css)); + if (!seen) { + StringMapWrapper.set(_cssCache, css, true); + this._insertStyle(this._styleHost, css); + } + } + } + } else { + if (this._strategy.shim()) { + try { + DOM.setAttribute(current.element, this._selector, ''); + } catch(e) { + // TODO(vicb): for now only simple selector (tag name) are supported + } + } + } + } + + clearCache() { + _cssCache = StringMapWrapper.create(); + } + + _insertStyle(el: Element, css: string) { + var style = DOM.createStyleElement(css); + if (isBlank(this._lastInsertedStyle)) { + var firstChild = DOM.firstChild(el); + if (isPresent(firstChild)) { + DOM.insertBefore(firstChild, style); + } else { + DOM.appendChild(el, style); + } + } else { + DOM.insertAfter(this._lastInsertedStyle, style); + } + this._lastInsertedStyle = style; + } +} + diff --git a/modules/angular2/src/core/compiler/pipeline/text_interpolation_parser.js b/modules/angular2/src/core/compiler/pipeline/text_interpolation_parser.js index b412e69f6e..ec3474a9ae 100644 --- a/modules/angular2/src/core/compiler/pipeline/text_interpolation_parser.js +++ b/modules/angular2/src/core/compiler/pipeline/text_interpolation_parser.js @@ -23,7 +23,7 @@ export class TextInterpolationParser extends CompileStep { } process(parent:CompileElement, current:CompileElement, control:CompileControl) { - if (!current.compileChildren) { + if (!current.compileChildren || current.ignoreBindings) { return; } var element = current.element; diff --git a/modules/angular2/src/core/compiler/shadow_dom_strategy.js b/modules/angular2/src/core/compiler/shadow_dom_strategy.js index 232df53858..2cf6c9d89e 100644 --- a/modules/angular2/src/core/compiler/shadow_dom_strategy.js +++ b/modules/angular2/src/core/compiler/shadow_dom_strategy.js @@ -1,28 +1,22 @@ import {Type, isBlank, isPresent} from 'angular2/src/facade/lang'; -import {DOM, Element, StyleElement} from 'angular2/src/facade/dom'; +import {DOM, Element} from 'angular2/src/facade/dom'; import {List, ListWrapper} from 'angular2/src/facade/collection'; import {View} from './view'; import {Content} from './shadow_dom_emulation/content_tag'; import {LightDom} from './shadow_dom_emulation/light_dom'; import {DirectiveMetadata} from './directive_metadata'; -import {shimCssText} from './shadow_dom_emulation/shim_css'; export class ShadowDomStrategy { attachTemplate(el:Element, view:View){} constructLightDom(lightDomView:View, shadowDomView:View, el:Element){} polyfillDirectives():List{ return null; } - processTemplate(template: Element, cmpMetadata: DirectiveMetadata) { return null; } + shim(): boolean { return false; } + extractStyles(): boolean { return false; } } export class EmulatedShadowDomStrategy extends ShadowDomStrategy { - _styleHost: Element; - - constructor(styleHost: Element = null) { + constructor() { super(); - if (isBlank(styleHost)) { - styleHost = DOM.defaultDoc().head; - } - this._styleHost = styleHost; } attachTemplate(el:Element, view:View){ @@ -38,25 +32,20 @@ export class EmulatedShadowDomStrategy extends ShadowDomStrategy { return [Content]; } - processTemplate(template: Element, cmpMetadata: DirectiveMetadata) { - var templateRoot = DOM.templateAwareRoot(template); - var attrName = cmpMetadata.annotation.selector; + shim(): boolean { + return true; + } - // Shim CSS for emulated shadow DOM and attach the styles do the document head - var styles = _detachStyles(templateRoot); - for (var i = 0; i < styles.length; i++) { - var style = styles[i]; - var processedCss = shimCssText(DOM.getText(style), attrName); - DOM.setText(style, processedCss); - } - _attachStyles(this._styleHost, styles); - - // Update the DOM to trigger the CSS - _addAttributeToChildren(templateRoot, attrName); + extractStyles(): boolean { + return true; } } export class NativeShadowDomStrategy extends ShadowDomStrategy { + constructor() { + super(); + } + attachTemplate(el:Element, view:View){ moveViewNodesIntoParent(el.createShadowRoot(), view); } @@ -69,8 +58,12 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy { return []; } - processTemplate(template: Element, cmpMetadata: DirectiveMetadata) { - return template; + shim(): boolean { + return false; + } + + extractStyles(): boolean { + return false; } } @@ -79,38 +72,3 @@ function moveViewNodesIntoParent(parent, view) { DOM.appendChild(parent, view.nodes[i]); } } - -// TODO(vicb): union types: el is an Element or a Document Fragment -function _detachStyles(el): List { - var nodeList = DOM.querySelectorAll(el, 'style'); - var styles = []; - for (var i = 0; i < nodeList.length; i++) { - var style = DOM.remove(nodeList[i]); - ListWrapper.push(styles, style); - } - return styles; -} - -// Move the styles as the first children of the template -function _attachStyles(el: Element, styles: List) { - var firstChild = DOM.firstChild(el); - for (var i = styles.length - 1; i >= 0; i--) { - var style = styles[i]; - if (isPresent(firstChild)) { - DOM.insertBefore(firstChild, style); - } else { - DOM.appendChild(el, style); - } - firstChild = style; - } -} - -// TODO(vicb): union types: el is an Element or a Document Fragment -function _addAttributeToChildren(el, attrName:string) { - // TODO(vicb): currently the code crashes when the attrName is not an el selector - var children = DOM.querySelectorAll(el, "*"); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - DOM.setAttribute(child, attrName, ''); - } -} diff --git a/modules/angular2/src/facade/dom.dart b/modules/angular2/src/facade/dom.dart index c250ec5017..47f8e3b48c 100644 --- a/modules/angular2/src/facade/dom.dart +++ b/modules/angular2/src/facade/dom.dart @@ -103,6 +103,12 @@ class DOM { el.setAttribute(attrName, attrValue); return el; } + static StyleElement createStyleElement(String css, [HtmlDocument doc = null]) { + if (doc == null) doc = document; + var el = doc.createElement("STYLE"); + el.text = css; + return el; + } static clone(Node node) => node.clone(true); static bool hasProperty(Element element, String name) => new JsObject.fromBrowserObject(element).hasProperty(name); diff --git a/modules/angular2/test/core/compiler/compiler_spec.js b/modules/angular2/test/core/compiler/compiler_spec.js index 4ddc9a7b57..0850a4064a 100644 --- a/modules/angular2/test/core/compiler/compiler_spec.js +++ b/modules/angular2/test/core/compiler/compiler_spec.js @@ -70,23 +70,6 @@ export function main() { }); }); - it('should use the shadow dom strategy to process the template', (done) => { - // TODO(vicb) test in Dart when the bug is fixed - // https://code.google.com/p/dart/issues/detail?id=18249 - if (IS_DARTIUM) { - done(); - return; - } - var templateHtml = 'processed template'; - var compiler = createCompiler((parent, current, control) => { - current.inheritedProtoView = new ProtoView(current.element, null, null); - }, new FakeShadowDomStrategy(templateHtml)); - compiler.compile(MainComponent, null).then( (protoView) => { - expect(DOM.getInnerHTML(protoView.element)).toEqual('processed template'); - done(); - }); - }); - it('should load nested components', (done) => { var mainEl = el('
'); var compiler = createCompiler( (parent, current, control) => { @@ -244,15 +227,3 @@ class MockStep extends CompileStep { this.processClosure(parent, current, control); } } - -class FakeShadowDomStrategy extends NativeShadowDomStrategy { - templateHtml: string; - constructor(templateHtml: string) { - super(); - this.templateHtml = templateHtml; - } - - processTemplate(template: Element, cmpMetadata: DirectiveMetadata) { - DOM.setInnerHTML(template, this.templateHtml); - } -} diff --git a/modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js b/modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js index 89213dc7ff..4af2707b80 100644 --- a/modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js +++ b/modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js @@ -14,7 +14,8 @@ import {Template, Decorator, Component} from 'angular2/src/core/annotations/anno export function main() { describe('ElementBindingMarker', () => { - function createPipeline({textNodeBindings, propertyBindings, variableBindings, eventBindings, directives}={}) { + function createPipeline({textNodeBindings, propertyBindings, variableBindings, eventBindings, + directives, ignoreBindings}={}) { var reader = new DirectiveMetadataReader(); return new CompilePipeline([ new MockStep((parent, current, control) => { @@ -30,6 +31,9 @@ export function main() { if (isPresent(eventBindings)) { current.eventBindings = eventBindings; } + if (isPresent(ignoreBindings)) { + current.ignoreBindings = ignoreBindings; + } if (isPresent(directives)) { for (var i=0; i { + var textNodeBindings = MapWrapper.create(); + MapWrapper.set(textNodeBindings, 0, 'expr'); + var results = createPipeline({textNodeBindings: textNodeBindings, + ignoreBindings: true}).process(el('
')); + assertBinding(results[0], false); + }); + it('should mark elements with text node bindings', () => { var textNodeBindings = MapWrapper.create(); MapWrapper.set(textNodeBindings, 0, 'expr'); diff --git a/modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js b/modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js index f51a0396b6..c57e72eb30 100644 --- a/modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js +++ b/modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js @@ -3,15 +3,24 @@ import {PropertyBindingParser} from 'angular2/src/core/compiler/pipeline/propert import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline'; import {DOM} from 'angular2/src/facade/dom'; import {MapWrapper} from 'angular2/src/facade/collection'; - +import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element'; +import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step' +import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control'; import {Lexer, Parser} from 'angular2/change_detection'; export function main() { describe('PropertyBindingParser', () => { - function createPipeline() { - return new CompilePipeline([new PropertyBindingParser(new Parser(new Lexer()), null)]); + function createPipeline(ignoreBindings = false) { + return new CompilePipeline([ + new MockStep((parent, current, control) => { current.ignoreBindings = ignoreBindings; }), + new PropertyBindingParser(new Parser(new Lexer()), null)]); } + it('should not parse bindings when ignoreBindings is true', () => { + var results = createPipeline(true).process(el('
')); + expect(results[0].propertyBindings).toBe(null); + }); + it('should detect [] syntax', () => { var results = createPipeline().process(el('
')); expect(MapWrapper.get(results[0].propertyBindings, 'a').source).toEqual('b'); @@ -69,3 +78,14 @@ export function main() { }); }); } + +class MockStep extends CompileStep { + processClosure:Function; + constructor(process) { + super(); + this.processClosure = process; + } + process(parent:CompileElement, current:CompileElement, control:CompileControl) { + this.processClosure(parent, current, control); + } +} diff --git a/modules/angular2/test/core/compiler/pipeline/shadow_dom_transformer_spec.js b/modules/angular2/test/core/compiler/pipeline/shadow_dom_transformer_spec.js new file mode 100644 index 0000000000..8eabb5ad93 --- /dev/null +++ b/modules/angular2/test/core/compiler/pipeline/shadow_dom_transformer_spec.js @@ -0,0 +1,128 @@ +import {describe, beforeEach, expect, it, iit, ddescribe, el} from 'angular2/test_lib'; + +import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline'; +import {ShadowDomTransformer} from 'angular2/src/core/compiler/pipeline/shadow_dom_transformer'; +import {Component} from 'angular2/src/core/annotations/annotations'; +import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; +import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {shimCssText} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_css'; + +import {DOM} from 'angular2/src/facade/dom'; +import {MapWrapper} from 'angular2/src/facade/collection'; + +export function main() { + describe('ShadowDomTransformer', () => { + function createPipeline(selector, strategy:ShadowDomStrategy, styleHost) { + var component = new Component({selector: selector}); + var meta = new DirectiveMetadata(null, component, null); + var transformer = new ShadowDomTransformer(meta, strategy, styleHost); + transformer.clearCache(); + return new CompilePipeline([transformer]); + } + + it('it should set ignoreBindings to true for style elements', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(false, false), host); + var results = pipeline.process(el('
')); + expect(results[0].ignoreBindings).toBe(false); + expect(results[1].ignoreBindings).toBe(true); + }); + + describe('css', () => { + it('should not extract the styles when extractStyles() is false', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(false, false), host); + var template = el(''); + pipeline.process(template); + expect(template).toHaveText('.s{}'); + }); + + it('should move the styles to the host when extractStyles() is true', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(true, false), host); + var template = el('
'); + pipeline.process(template); + expect(template).toHaveText(''); + expect(host).toHaveText('.s{}'); + }); + + it('should preserve original content when moving styles', () => { + var host = el('
original content
'); + var pipeline = createPipeline('foo', new FakeStrategy(true, false), host); + var template = el('
'); + pipeline.process(template); + expect(template).toHaveText(''); + expect(host).toHaveText('.s{}original content'); + }); + + it('should move the styles to the host in the original order', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(true, false), host); + var template = el('
'); + pipeline.process(template); + expect(host).toHaveText('.s1{}.s2{}'); + }); + + it('should shim the styles when shim() and extractStyles() are true', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(true, true), host); + var template = el('
'); + pipeline.process(template); + expect(host).toHaveText(shimCssText('.s1{}', 'foo')); + }); + + it('should deduplicate styles before moving them when shim() is false', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(true, false), host); + var template = el('
'); + pipeline.process(template); + expect(host).toHaveText('.s1{}'); + }); + }); + + describe('html', () => { + it('should add an attribute to all children when shim() is true', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(false, true), host); + var template = el('
'); + pipeline.process(template); + expect(DOM.getOuterHTML(template)).toEqual('
') + }); + + it('should not modify the template when shim() is false', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo', new FakeStrategy(false, false), host); + var template = el('
'); + pipeline.process(template); + expect(DOM.getOuterHTML(template)).toEqual('
') + }); + + it('should not throw with complex selectors', () => { + var host = DOM.createElement('div'); + var pipeline = createPipeline('foo[bar]', new FakeStrategy(false, true), host); + var template = el('
'); + expect(() => pipeline.process(template)).not.toThrow(); + }); + + }); + }); +} + +class FakeStrategy extends ShadowDomStrategy { + _extractStyles: boolean; + _shim: boolean; + + constructor(extractStyles: boolean, shim: boolean) { + super(); + this._extractStyles = extractStyles; + this._shim = shim; + } + + extractStyles(): boolean { + return this._extractStyles; + } + + shim(): boolean { + return this._shim; + } +} diff --git a/modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js b/modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js index 7053f0cbdc..e460dc8a9d 100644 --- a/modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js +++ b/modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js @@ -3,19 +3,27 @@ import {TextInterpolationParser} from 'angular2/src/core/compiler/pipeline/text_ import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline'; import {DOM} from 'angular2/src/facade/dom'; import {MapWrapper} from 'angular2/src/facade/collection'; - import {Lexer, Parser} from 'angular2/change_detection'; +import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element'; +import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step' +import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control'; import {IgnoreChildrenStep} from './pipeline_spec'; export function main() { describe('TextInterpolationParser', () => { - function createPipeline() { + function createPipeline(ignoreBindings = false) { return new CompilePipeline([ + new MockStep((parent, current, control) => { current.ignoreBindings = ignoreBindings; }), new IgnoreChildrenStep(), new TextInterpolationParser(new Parser(new Lexer()), null) ]); } + it('should not look for text interpolation when ignoreBindings is true', () => { + var results = createPipeline(true).process(el('
{{expr1}}{{expr2}}
')); + expect(results[0].textNodeBindings).toBe(null); + }); + it('should find text interpolation in normal elements', () => { var results = createPipeline().process(el('
{{expr1}}{{expr2}}
')); var bindings = results[0].textNodeBindings; @@ -55,3 +63,14 @@ export function main() { }); }); } + +class MockStep extends CompileStep { + processClosure:Function; + constructor(process) { + super(); + this.processClosure = process; + } + process(parent:CompileElement, current:CompileElement, control:CompileControl) { + this.processClosure(parent, current, control); + } +} diff --git a/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js b/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js deleted file mode 100644 index f6116a8afb..0000000000 --- a/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js +++ /dev/null @@ -1,62 +0,0 @@ -import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; -import {NativeShadowDomStrategy, EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; -import {DOM} from 'angular2/src/facade/dom'; -import {Component} from 'angular2/src/core/annotations/annotations'; -import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; - -export function main() { - describe('Shadow DOM strategy', () => { - var strategy, - component = new Component({selector: 'mycmp'}), - metadata = new DirectiveMetadata(null, component, null); - - describe('Native', () => { - beforeEach(() => { - strategy = new NativeShadowDomStrategy(); - }); - - it('should leave the styles in the template', () => { - var tpl = DOM.createTemplate('
content
'); - strategy.processTemplate(tpl, metadata); - expect(tpl.content).toHaveText('.s1{}content'); - }); - - it('should not modify the content of the template', () => { - var html = '

content

'; - var tpl = DOM.createTemplate(html); - strategy.processTemplate(tpl, metadata); - expect(DOM.getInnerHTML(tpl)).toEqual(html); - }); - }); - - describe('Emulated', () => { - var root; - beforeEach(() => { - root = el('
'); - strategy = new EmulatedShadowDomStrategy(root); - }); - - it('should move the styles from the template to the root', () => { - var tpl = DOM.createTemplate('
content
'); - strategy.processTemplate(tpl, metadata); - expect(root).toHaveText('.s1[mycmp] {}.s2[mycmp] {}'); - expect(tpl.content).toHaveText('content'); - }); - - it('should insert the styles as the first children of the host', () => { - DOM.setInnerHTML(root, '

root content

') - var tpl = DOM.createTemplate(''); - strategy.processTemplate(tpl, metadata); - expect(root).toHaveText('.s1[mycmp] {}.s2[mycmp] {}root content'); - }); - - it('should add the component selector to all template children', () => { - var html = '

content

'; - var processedHtml = '

content

'; - var tpl = DOM.createTemplate(html); - strategy.processTemplate(tpl, metadata); - expect(DOM.getInnerHTML(tpl)).toEqual(processedHtml); - }); - }); - }); -}