From f1593ebca591cf6bb23e7f8d15a35037f1b65b8d Mon Sep 17 00:00:00 2001 From: Rado Kirov Date: Tue, 10 Mar 2015 12:30:50 -0700 Subject: [PATCH] feat(shadowdom): turn on ShadowDom Emulated Mode by default. Closes: #526 --- modules/angular2/src/core/application.js | 6 ++-- .../shadow_dom_emulation/light_dom.js | 1 + .../src/core/compiler/shadow_dom_strategy.js | 2 +- modules/angular2/src/dom/browser_adapter.es6 | 4 ++- .../angular2/test/core/application_spec.js | 28 ++++++++++++++----- .../e2e_test/naive_infinite_scroll_spec.es6 | 8 +++--- .../src/naive_infinite_scroll/index.js | 18 ++++++++++-- modules/benchmarks/src/tree/tree_benchmark.js | 18 ++++++++++-- .../e2e_test/hello_world/hello_world_spec.es6 | 4 +-- .../examples/src/hello_world/index_static.js | 16 ++++++++++- 10 files changed, 83 insertions(+), 22 deletions(-) diff --git a/modules/angular2/src/core/application.js b/modules/angular2/src/core/application.js index cca8518ad8..137b830e8f 100644 --- a/modules/angular2/src/core/application.js +++ b/modules/angular2/src/core/application.js @@ -14,7 +14,7 @@ import {List, ListWrapper} from 'angular2/src/facade/collection'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; -import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl'; import {EventManager, DomEventsPlugin} from 'angular2/src/core/events/event_manager'; @@ -84,7 +84,9 @@ function _injectorBindings(appComponentType): List { var plugins = [new HammerGesturesPlugin(), new DomEventsPlugin()]; return new EventManager(plugins, zone); }, [VmTurnZone]), - bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy), + bind(ShadowDomStrategy).toFactory( + (styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head), + [StyleUrlResolver, appDocumentToken]), Compiler, CompilerCache, TemplateResolver, diff --git a/modules/angular2/src/core/compiler/shadow_dom_emulation/light_dom.js b/modules/angular2/src/core/compiler/shadow_dom_emulation/light_dom.js index 56e00e996d..f090f066a6 100644 --- a/modules/angular2/src/core/compiler/shadow_dom_emulation/light_dom.js +++ b/modules/angular2/src/core/compiler/shadow_dom_emulation/light_dom.js @@ -36,6 +36,7 @@ export class LightDom { this.lightDomView = lightDomView; this.shadowDomView = shadowDomView; this.nodes = DOM.childNodesAsList(element); + this.roots = null; } diff --git a/modules/angular2/src/core/compiler/shadow_dom_strategy.js b/modules/angular2/src/core/compiler/shadow_dom_strategy.js index ab4c02380a..d1748985bd 100644 --- a/modules/angular2/src/core/compiler/shadow_dom_strategy.js +++ b/modules/angular2/src/core/compiler/shadow_dom_strategy.js @@ -78,7 +78,7 @@ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy { this._styleHost = styleHost; } - attachTemplate(el, view:viewModule.View){ + attachTemplate(el, view:viewModule.View) { DOM.clearNodes(el); _moveViewNodesIntoParent(el, view); } diff --git a/modules/angular2/src/dom/browser_adapter.es6 b/modules/angular2/src/dom/browser_adapter.es6 index 8bccb22ec6..29bc14b145 100644 --- a/modules/angular2/src/dom/browser_adapter.es6 +++ b/modules/angular2/src/dom/browser_adapter.es6 @@ -80,7 +80,9 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { return res; } clearNodes(el) { - el.innerHTML = ''; + for (var i = 0; i < el.childNodes.length; i++) { + this.remove(el.childNodes[i]); + } } appendChild(el, node) { el.appendChild(node); diff --git a/modules/angular2/test/core/application_spec.js b/modules/angular2/test/core/application_spec.js index ff84455f14..db2568e5b9 100644 --- a/modules/angular2/test/core/application_spec.js +++ b/modules/angular2/test/core/application_spec.js @@ -18,6 +18,12 @@ class HelloRootCmp { } } +@Component({selector: 'hello-app'}) +@Template({inline: 'before: after: done'}) +class HelloRootCmpContent { + constructor() { } +} + @Component({selector: 'hello-app-2'}) @Template({inline: '{{greeting}} world, again!'}) class HelloRootCmp2 { @@ -48,14 +54,17 @@ class HelloRootCmp4 { } export function main() { - var fakeDoc, el, el2, testBindings; + var fakeDoc, el, el2, testBindings, lightDom; beforeEach(() => { fakeDoc = DOM.createHtmlDocument(); el = DOM.createElement('hello-app', fakeDoc); el2 = DOM.createElement('hello-app-2', fakeDoc); + lightDom = DOM.createElement('light-dom-el', fakeDoc); DOM.appendChild(fakeDoc.body, el); DOM.appendChild(fakeDoc.body, el2); + DOM.appendChild(el, lightDom); + DOM.setText(lightDom, 'loading'); testBindings = [bind(appDocumentToken).toValue(fakeDoc)]; }); @@ -93,8 +102,7 @@ export function main() { it('should display hello world', (done) => { var injectorPromise = bootstrap(HelloRootCmp, testBindings); injectorPromise.then((injector) => { - expect(injector.get(appElementToken) - .shadowRoot.childNodes[0].nodeValue).toEqual('hello world!'); + expect(injector.get(appElementToken)).toHaveText('hello world!'); done(); }); }); @@ -103,10 +111,8 @@ export function main() { var injectorPromise1 = bootstrap(HelloRootCmp, testBindings); var injectorPromise2 = bootstrap(HelloRootCmp2, testBindings); PromiseWrapper.all([injectorPromise1, injectorPromise2]).then((injectors) => { - expect(injectors[0].get(appElementToken) - .shadowRoot.childNodes[0].nodeValue).toEqual('hello world!'); - expect(injectors[1].get(appElementToken) - .shadowRoot.childNodes[0].nodeValue).toEqual('hello world, again!'); + expect(injectors[0].get(appElementToken)).toHaveText('hello world!'); + expect(injectors[1].get(appElementToken)).toHaveText('hello world, again!'); done(); }); }); @@ -131,5 +137,13 @@ export function main() { done(); }); }); + + it("should support shadow dom content tag", (done) => { + var injectorPromise = bootstrap(HelloRootCmpContent, testBindings); + injectorPromise.then((injector) => { + expect(injector.get(appElementToken)).toHaveText('before: loading after: done'); + done(); + }); + }); }); } diff --git a/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6 b/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6 index a15a431e06..7411cee33b 100644 --- a/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6 +++ b/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6 @@ -9,11 +9,11 @@ describe('ng2 naive infinite scroll benchmark', function () { it('should not throw errors', function() { browser.get(URL); var expectedRowCount = 18; - var expectedCellsPerRow = 11; - var allScrollItems = 'scroll-app /deep/ #testArea /deep/ scroll-item'; - var cells = `${ allScrollItems } /deep/ .row *`; + var expectedCellsPerRow = 28; + var allScrollItems = 'scroll-app #testArea scroll-item'; + var cells = `${ allScrollItems } .row *`; var stageButtons = - `${ allScrollItems } /deep/ .row stage-buttons /deep/ button`; + `${ allScrollItems } .row stage-buttons button`; var count = function(selector) { return browser.executeScript( diff --git a/modules/benchmarks/src/naive_infinite_scroll/index.js b/modules/benchmarks/src/naive_infinite_scroll/index.js index 726bee0088..d47db26721 100644 --- a/modules/benchmarks/src/naive_infinite_scroll/index.js +++ b/modules/benchmarks/src/naive_infinite_scroll/index.js @@ -6,12 +6,14 @@ import {Parser, Lexer, ChangeDetector, ChangeDetection} from 'angular2/change_detection'; import {ExceptionHandler} from 'angular2/src/core/exception_handler'; import { - bootstrap, Component, Viewport, Template, ViewContainer, Compiler, onChange + bootstrap, Component, Viewport, Template, ViewContainer, Compiler, onChange, NgElement, Decorator } from 'angular2/angular2'; import {Reflector, reflector} from 'angular2/src/reflection/reflection'; import {CompilerCache} from 'angular2/src/core/compiler/compiler'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; -import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag'; +import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; @@ -256,6 +258,12 @@ export function setupReflectorForAngular() { "annotations": [] }); + reflector.registerType(EmulatedUnscopedShadowDomStrategy, { + "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null), + "parameters": [[StyleUrlResolver]], + "annotations": [] + }); + reflector.registerType(StyleUrlResolver, { "factory": (urlResolver) => new StyleUrlResolver(urlResolver), "parameters": [[UrlResolver]], @@ -274,6 +282,12 @@ export function setupReflectorForAngular() { "annotations": [] }); + reflector.registerType(Content, { + "factory": (lightDom, el) => new Content(lightDom, el), + "parameters": [[DestinationLightDom], [NgElement]], + "annotations" : [new Decorator({selector: '[content]'})] + }); + reflector.registerType(StyleInliner, { "factory": (xhr, styleUrlResolver, urlResolver) => new StyleInliner(xhr, styleUrlResolver, urlResolver), diff --git a/modules/benchmarks/src/tree/tree_benchmark.js b/modules/benchmarks/src/tree/tree_benchmark.js index dacfb47218..625a0564ab 100644 --- a/modules/benchmarks/src/tree/tree_benchmark.js +++ b/modules/benchmarks/src/tree/tree_benchmark.js @@ -2,13 +2,15 @@ import {Parser, Lexer, ChangeDetector, ChangeDetection, jitChangeDetection} from 'angular2/change_detection'; import {ExceptionHandler} from 'angular2/src/core/exception_handler'; -import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler} from 'angular2/angular2'; +import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler, NgElement, Decorator} from 'angular2/angular2'; import {CompilerCache} from 'angular2/src/core/compiler/compiler'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; -import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag'; +import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {UrlResolver} from 'angular2/src/core/compiler/url_resolver'; import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver'; @@ -127,12 +129,24 @@ function setupReflector() { "annotations": [] }); + reflector.registerType(EmulatedUnscopedShadowDomStrategy, { + "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null), + "parameters": [[StyleUrlResolver]], + "annotations": [] + }); + reflector.registerType(StyleUrlResolver, { "factory": (urlResolver) => new StyleUrlResolver(urlResolver), "parameters": [[UrlResolver]], "annotations": [] }); + reflector.registerType(Content, { + "factory": (lightDom, el) => new Content(lightDom, el), + "parameters": [[DestinationLightDom], [NgElement]], + "annotations" : [new Decorator({selector: '[content]'})] + }); + reflector.registerType(UrlResolver, { "factory": () => new UrlResolver(), "parameters": [], diff --git a/modules/examples/e2e_test/hello_world/hello_world_spec.es6 b/modules/examples/e2e_test/hello_world/hello_world_spec.es6 index 1bdcf97e39..a5f8c8bbf3 100644 --- a/modules/examples/e2e_test/hello_world/hello_world_spec.es6 +++ b/modules/examples/e2e_test/hello_world/hello_world_spec.es6 @@ -40,9 +40,9 @@ describe('hello world', function () { }); function getComponentText(selector, innerSelector) { - return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.querySelector("'+innerSelector+'").textContent'); + return browser.executeScript('return document.querySelector("'+selector+'").querySelector("'+innerSelector+'").textContent'); } function clickComponentButton(selector, innerSelector) { - return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.querySelector("'+innerSelector+'").click()'); + return browser.executeScript('return document.querySelector("'+selector+'").querySelector("'+innerSelector+'").click()'); } diff --git a/modules/examples/src/hello_world/index_static.js b/modules/examples/src/hello_world/index_static.js index 6973b0f393..c4f198efe0 100644 --- a/modules/examples/src/hello_world/index_static.js +++ b/modules/examples/src/hello_world/index_static.js @@ -7,7 +7,9 @@ import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; -import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag'; +import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; @@ -125,6 +127,12 @@ function setup() { "annotations": [] }); + reflector.registerType(EmulatedUnscopedShadowDomStrategy, { + "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null), + "parameters": [[StyleUrlResolver]], + "annotations": [] + }); + reflector.registerType(StyleUrlResolver, { "factory": (urlResolver) => new StyleUrlResolver(urlResolver), "parameters": [[UrlResolver]], @@ -143,6 +151,12 @@ function setup() { "annotations": [] }); + reflector.registerType(Content, { + "factory": (lightDom, el) => new Content(lightDom, el), + "parameters": [[DestinationLightDom], [NgElement]], + "annotations" : [new Decorator({selector: '[content]'})] + }); + reflector.registerType(StyleInliner, { "factory": (xhr, styleUrlResolver, urlResolver) => new StyleInliner(xhr, styleUrlResolver, urlResolver),