fix(core): keep styles for ViewEncapsulation.Native
isolated per component
BREAKING CHANGE: - `Renderer.registerComponent` now takes an additional argument. Fixes #4513 Closes #4524
This commit is contained in:
parent
a9aef8e5e6
commit
0299d4af00
@ -71,7 +71,7 @@ export class ProtoViewFactory {
|
|||||||
var compiledTemplateData = cmd.template.getData(this._appId);
|
var compiledTemplateData = cmd.template.getData(this._appId);
|
||||||
|
|
||||||
this._renderer.registerComponentTemplate(cmd.templateId, compiledTemplateData.commands,
|
this._renderer.registerComponentTemplate(cmd.templateId, compiledTemplateData.commands,
|
||||||
compiledTemplateData.styles);
|
compiledTemplateData.styles, cmd.nativeShadow);
|
||||||
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
||||||
|
|
||||||
nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
|
nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
|
||||||
|
@ -230,7 +230,8 @@ export class Renderer {
|
|||||||
* Once a template is registered it can be referenced via {@link RenderBeginComponentCmd} when
|
* Once a template is registered it can be referenced via {@link RenderBeginComponentCmd} when
|
||||||
* {@link #createProtoView creating Render ProtoView}.
|
* {@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.
|
* Creates a {@link RenderProtoViewRef} from an array of {@link RenderTemplateCmd}`s.
|
||||||
|
@ -35,6 +35,7 @@ import {camelCaseToDashCase} from './util';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomRenderer implements Renderer, NodeFactory<Node> {
|
export class DomRenderer implements Renderer, NodeFactory<Node> {
|
||||||
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
|
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
|
||||||
|
private _nativeShadowStyles: Map<number, string[]> = new Map<number, string[]>();
|
||||||
private _document;
|
private _document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,9 +47,14 @@ export class DomRenderer implements Renderer, NodeFactory<Node> {
|
|||||||
this._document = document;
|
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._componentCmds.set(templateId, commands);
|
||||||
this._domSharedStylesHost.addStyles(styles);
|
if (nativeShadow) {
|
||||||
|
this._nativeShadowStyles.set(templateId, styles);
|
||||||
|
} else {
|
||||||
|
this._domSharedStylesHost.addStyles(styles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
|
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
|
||||||
@ -193,7 +199,14 @@ export class DomRenderer implements Renderer, NodeFactory<Node> {
|
|||||||
DOM.setAttribute(node, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
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 : ''); }
|
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
|
||||||
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
|
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
|
||||||
on(element: Node, eventName: string, callback: Function) {
|
on(element: Node, eventName: string, callback: Function) {
|
||||||
|
@ -70,7 +70,7 @@ export interface NodeFactory<N> {
|
|||||||
createTemplateAnchor(attrNameAndValues: string[]): N;
|
createTemplateAnchor(attrNameAndValues: string[]): N;
|
||||||
createElement(name: string, attrNameAndValues: string[]): N;
|
createElement(name: string, attrNameAndValues: string[]): N;
|
||||||
mergeElement(existing: N, attrNameAndValues: string[]);
|
mergeElement(existing: N, attrNameAndValues: string[]);
|
||||||
createShadowRoot(host: N): N;
|
createShadowRoot(host: N, templateId: number): N;
|
||||||
createText(value: string): N;
|
createText(value: string): N;
|
||||||
appendChild(parent: N, child: N);
|
appendChild(parent: N, child: N);
|
||||||
on(element: N, eventName: string, callback: Function);
|
on(element: N, eventName: string, callback: Function);
|
||||||
@ -125,7 +125,7 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
|||||||
var el = this._beginElement(cmd);
|
var el = this._beginElement(cmd);
|
||||||
var root = el;
|
var root = el;
|
||||||
if (cmd.nativeShadow) {
|
if (cmd.nativeShadow) {
|
||||||
root = this.factory.createShadowRoot(el);
|
root = this.factory.createShadowRoot(el, cmd.templateId);
|
||||||
this.nativeShadowRoots.push(root);
|
this.nativeShadowRoots.push(root);
|
||||||
}
|
}
|
||||||
var component = new Component(el, root, cmd, this.factory, this.allBuilders);
|
var component = new Component(el, root, cmd, this.factory, this.allBuilders);
|
||||||
|
@ -31,7 +31,8 @@ export class MessageBasedRenderer {
|
|||||||
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
this._bus.initChannel(EVENT_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));
|
bind(this._renderer.registerComponentTemplate, this._renderer));
|
||||||
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
|
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
|
||||||
bind(this._createProtoView, this));
|
bind(this._createProtoView, this));
|
||||||
|
@ -35,11 +35,13 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {
|
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
|
||||||
|
nativeShadow: boolean) {
|
||||||
var fnArgs = [
|
var fnArgs = [
|
||||||
new FnArg(templateId, null),
|
new FnArg(templateId, null),
|
||||||
new FnArg(commands, WebWorkerTemplateCmd),
|
new FnArg(commands, WebWorkerTemplateCmd),
|
||||||
new FnArg(styles, null)
|
new FnArg(styles, null),
|
||||||
|
new FnArg(nativeShadow, null)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
||||||
this._messageBroker.runOnService(args, null);
|
this._messageBroker.runOnService(args, null);
|
||||||
|
@ -423,18 +423,18 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (DOM.supportsNativeShadowDOM()) {
|
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) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MainComp, new ViewMetadata({
|
tcb.overrideView(MainComp, new ViewMetadata({
|
||||||
template: '<simple-native>' +
|
template: '<simple-native1><div>A</div></simple-native1>' +
|
||||||
'<div>A</div>' +
|
'<simple-native2><div>B</div></simple-native2>',
|
||||||
'</simple-native>',
|
directives: [SimpleNative1, SimpleNative2]
|
||||||
directives: [SimpleNative]
|
|
||||||
}))
|
}))
|
||||||
.createAsync(MainComp)
|
.createAsync(MainComp)
|
||||||
.then((main) => {
|
.then((main) => {
|
||||||
|
var childNodes = DOM.childNodes(main.debugElement.nativeElement);
|
||||||
expect(main.debugElement.nativeElement).toHaveText('SIMPLE(A)');
|
expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)');
|
||||||
|
expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
@ -485,13 +485,24 @@ class Simple {
|
|||||||
stringProp: string = '';
|
stringProp: string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'simple-native'})
|
@Component({selector: 'simple-native1'})
|
||||||
@View({
|
@View({
|
||||||
template: 'SIMPLE(<content></content>)',
|
template: 'SIMPLE1(<content></content>)',
|
||||||
directives: [],
|
directives: [],
|
||||||
encapsulation: ViewEncapsulation.Native
|
encapsulation: ViewEncapsulation.Native,
|
||||||
|
styles: ['div {color: red}']
|
||||||
})
|
})
|
||||||
class SimpleNative {
|
class SimpleNative1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'simple-native2'})
|
||||||
|
@View({
|
||||||
|
template: 'SIMPLE2(<content></content>)',
|
||||||
|
directives: [],
|
||||||
|
encapsulation: ViewEncapsulation.Native,
|
||||||
|
styles: ['div {color: blue}']
|
||||||
|
})
|
||||||
|
class SimpleNative2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'empty'})
|
@Component({selector: 'empty'})
|
||||||
|
@ -521,7 +521,7 @@ class DomNodeFactory implements NodeFactory<Node> {
|
|||||||
DOM.setAttribute(el, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
DOM.setAttribute(el, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createShadowRoot(host: Node): Node {
|
createShadowRoot(host: Node, templateId: number): Node {
|
||||||
var root = DOM.createElement('shadow-root');
|
var root = DOM.createElement('shadow-root');
|
||||||
DOM.appendChild(host, root);
|
DOM.appendChild(host, root);
|
||||||
return root;
|
return root;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user