Skip to content

Commit

Permalink
fix(core): keep styles for ViewEncapsulation.Native isolated per co…
Browse files Browse the repository at this point in the history
…mponent

BREAKING CHANGE:
- `Renderer.registerComponent` now takes an additional argument.

Fixes #4513
Closes #4524
  • Loading branch information
tbosch committed Oct 5, 2015
1 parent a9aef8e commit 0299d4a
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 22 deletions.
2 changes: 1 addition & 1 deletion modules/angular2/src/core/linker/proto_view_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class ProtoViewFactory {
var compiledTemplateData = cmd.template.getData(this._appId);

this._renderer.registerComponentTemplate(cmd.templateId, compiledTemplateData.commands,
compiledTemplateData.styles);
compiledTemplateData.styles, cmd.nativeShadow);
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));

nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
Expand Down
3 changes: 2 additions & 1 deletion modules/angular2/src/core/render/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ export class Renderer {
* Once a template is registered it can be referenced via {@link RenderBeginComponentCmd} when
* {@link #createProtoView creating Render ProtoView}.
*/
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {}
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
nativeShadow: boolean) {}

/**
* Creates a {@link RenderProtoViewRef} from an array of {@link RenderTemplateCmd}`s.
Expand Down
19 changes: 16 additions & 3 deletions modules/angular2/src/core/render/dom/dom_renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {camelCaseToDashCase} from './util';
@Injectable()
export class DomRenderer implements Renderer, NodeFactory<Node> {
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
private _nativeShadowStyles: Map<number, string[]> = new Map<number, string[]>();
private _document;

/**
Expand All @@ -46,9 +47,14 @@ export class DomRenderer implements Renderer, NodeFactory<Node> {
this._document = document;
}

registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
nativeShadow: boolean) {
this._componentCmds.set(templateId, commands);
this._domSharedStylesHost.addStyles(styles);
if (nativeShadow) {
this._nativeShadowStyles.set(templateId, styles);
} else {
this._domSharedStylesHost.addStyles(styles);
}
}

resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
Expand Down Expand Up @@ -193,7 +199,14 @@ export class DomRenderer implements Renderer, NodeFactory<Node> {
DOM.setAttribute(node, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
}
}
createShadowRoot(host: Node): Node { return DOM.createShadowRoot(host); }
createShadowRoot(host: Node, templateId: number): Node {
var sr = DOM.createShadowRoot(host);
var styles = this._nativeShadowStyles.get(templateId);
for (var i = 0; i < styles.length; i++) {
DOM.appendChild(sr, DOM.createStyleElement(styles[i]));
}
return sr;
}
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
on(element: Node, eventName: string, callback: Function) {
Expand Down
4 changes: 2 additions & 2 deletions modules/angular2/src/core/render/view_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export interface NodeFactory<N> {
createTemplateAnchor(attrNameAndValues: string[]): N;
createElement(name: string, attrNameAndValues: string[]): N;
mergeElement(existing: N, attrNameAndValues: string[]);
createShadowRoot(host: N): N;
createShadowRoot(host: N, templateId: number): N;
createText(value: string): N;
appendChild(parent: N, child: N);
on(element: N, eventName: string, callback: Function);
Expand Down Expand Up @@ -125,7 +125,7 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
var el = this._beginElement(cmd);
var root = el;
if (cmd.nativeShadow) {
root = this.factory.createShadowRoot(el);
root = this.factory.createShadowRoot(el, cmd.templateId);
this.nativeShadowRoots.push(root);
}
var component = new Component(el, root, cmd, this.factory, this.allBuilders);
Expand Down
3 changes: 2 additions & 1 deletion modules/angular2/src/web_workers/ui/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export class MessageBasedRenderer {
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
this._bus.initChannel(EVENT_CHANNEL);

broker.registerMethod("registerComponentTemplate", [PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE],
broker.registerMethod("registerComponentTemplate",
[PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE, PRIMITIVE],
bind(this._renderer.registerComponentTemplate, this._renderer));
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
bind(this._createProtoView, this));
Expand Down
6 changes: 4 additions & 2 deletions modules/angular2/src/web_workers/worker/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ export class WebWorkerRenderer implements Renderer {
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
}

registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
nativeShadow: boolean) {
var fnArgs = [
new FnArg(templateId, null),
new FnArg(commands, WebWorkerTemplateCmd),
new FnArg(styles, null)
new FnArg(styles, null),
new FnArg(nativeShadow, null)
];
var args = new UiArguments("registerComponentTemplate", fnArgs);
this._messageBroker.runOnService(args, null);
Expand Down
33 changes: 22 additions & 11 deletions modules/angular2/test/core/linker/projection_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,18 +423,18 @@ export function main() {
}));

if (DOM.supportsNativeShadowDOM()) {
it('should support native content projection',
it('should support native content projection and isolate styles per component',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<simple-native>' +
'<div>A</div>' +
'</simple-native>',
directives: [SimpleNative]
template: '<simple-native1><div>A</div></simple-native1>' +
'<simple-native2><div>B</div></simple-native2>',
directives: [SimpleNative1, SimpleNative2]
}))
.createAsync(MainComp)
.then((main) => {

expect(main.debugElement.nativeElement).toHaveText('SIMPLE(A)');
var childNodes = DOM.childNodes(main.debugElement.nativeElement);
expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)');
expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)');
async.done();
});
}));
Expand Down Expand Up @@ -485,13 +485,24 @@ class Simple {
stringProp: string = '';
}

@Component({selector: 'simple-native'})
@Component({selector: 'simple-native1'})
@View({
template: 'SIMPLE1(<content></content>)',
directives: [],
encapsulation: ViewEncapsulation.Native,
styles: ['div {color: red}']
})
class SimpleNative1 {
}

@Component({selector: 'simple-native2'})
@View({
template: 'SIMPLE(<content></content>)',
template: 'SIMPLE2(<content></content>)',
directives: [],
encapsulation: ViewEncapsulation.Native
encapsulation: ViewEncapsulation.Native,
styles: ['div {color: blue}']
})
class SimpleNative {
class SimpleNative2 {
}

@Component({selector: 'empty'})
Expand Down
2 changes: 1 addition & 1 deletion modules/angular2/test/core/render/view_factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ class DomNodeFactory implements NodeFactory<Node> {
DOM.setAttribute(el, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
}
}
createShadowRoot(host: Node): Node {
createShadowRoot(host: Node, templateId: number): Node {
var root = DOM.createElement('shadow-root');
DOM.appendChild(host, root);
return root;
Expand Down

0 comments on commit 0299d4a

Please sign in to comment.