Skip to content

Commit

Permalink
feat(renderer): use EmulatedRenderer to scope component styles
Browse files Browse the repository at this point in the history
  • Loading branch information
sis0k0 authored and hdeshev committed Mar 28, 2017
1 parent 366e98e commit 70603c4
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 56 deletions.
133 changes: 89 additions & 44 deletions nativescript-angular/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {
Inject, Injectable, Optional, NgZone,
RendererV2, RendererFactoryV2, RendererTypeV2,
// ViewEncapsulation
// ɵAnimationStyles, ɵAnimationKeyframe,
ViewEncapsulation,
} from "@angular/core";

import { escapeRegexSymbols } from "tns-core-modules/utils/utils";
Expand All @@ -21,8 +20,12 @@ import { Device } from "tns-core-modules/platform";
import { getRootPage } from "./platform-providers";

// CONTENT_ATTR not exported from NativeScript_renderer - we need it for styles application.
const COMPONENT_REGEX = /%COMP%/g;
export const COMPONENT_VARIABLE = "%COMP%";
export const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
export const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
const ATTR_REPLACER = new RegExp(escapeRegexSymbols(CONTENT_ATTR), "g");
const ATTR_SANITIZER = /-/g;

@Injectable()
export class NativeScriptRendererFactory implements RendererFactoryV2 {
Expand All @@ -34,7 +37,7 @@ export class NativeScriptRendererFactory implements RendererFactoryV2 {
constructor(
@Optional() @Inject(APP_ROOT_VIEW) rootView: View,
@Inject(DEVICE) device: Device,
zone: NgZone
private zone: NgZone
) {
this.viewUtil = new ViewUtil(device);
this.setRootNgView(rootView);
Expand All @@ -55,30 +58,19 @@ export class NativeScriptRendererFactory implements RendererFactoryV2 {
}

let renderer: NativeScriptRenderer = this.componentRenderers.get(type.id);
if (isBlank(renderer)) {
renderer = this.defaultRenderer;

let stylesLength = type.styles.length;
for (let i = 0; i < stylesLength; i++) {
console.log(type.styles[i]);
// this.hasComponentStyles = true;
let cssString = type.styles[i] + "";
const realCSS = this.replaceNgAttribute(cssString, type.id);
addCss(realCSS);
}
this.componentRenderers.set(type.id, renderer);
if (!isBlank(renderer)) {
return renderer;
}

return renderer;
}

private attrReplacer = new RegExp(escapeRegexSymbols(CONTENT_ATTR), "g");
private attrSanitizer = /-/g;

if (type.encapsulation === ViewEncapsulation.Emulated) {
renderer = new EmulatedRenderer(type, this.rootNgView, this.zone, this.viewUtil);
(<EmulatedRenderer>renderer).applyToHost(element);
} else {
renderer = this.defaultRenderer;
}

private replaceNgAttribute(input: string, componentId: string): string {
return input.replace(this.attrReplacer,
"_ng_content_" + componentId.replace(this.attrSanitizer, "_"));
this.componentRenderers.set(type.id, renderer);
return renderer;
}
}

Expand All @@ -94,16 +86,21 @@ export class NativeScriptRenderer extends RendererV2 {
traceLog("NativeScriptRenderer created");
}

appendChild(parent: any, newChild: any): void {
appendChild(parent: any, newChild: NgView): void {
traceLog(`NativeScriptRenderer.appendChild child: ${newChild} parent: ${parent}`);
console.log(typeof parent)
console.log("appending child")
console.log(newChild.id)
this.viewUtil.insertChild(parent, newChild);
}


insertBefore(parent: any, newChild: any, refChild: any): void {
insertBefore(parent: any, newChild: any, _refChild: any): void {
traceLog(`NativeScriptRenderer.insertBefore child: ${newChild} parent: ${parent}`);
if (parent) {
parent.insertBefore(newChild, refChild);
// Temporary solution until we implement nextSibling method
this.appendChild(parent, newChild);
// parent.insertBefore(newChild, refChild);
}
}

Expand All @@ -117,24 +114,22 @@ export class NativeScriptRenderer extends RendererV2 {
return this.rootView;
}

parentNode(node: NgView): NgView {
return node.templateParent;
parentNode(node: NgView): any {
return node.parent;
}

nextSibling(_node: NgView): void {
traceLog(`NativeScriptRenderer.nextSibling ${_node}`);
}

createViewRoot(hostElement: NgView): NgView {
traceLog("CREATE VIEW ROOT: " + hostElement.nodeName);
traceLog(`NativeScriptRenderer.createViewRoot ${hostElement.nodeName}`)
return hostElement;
}

projectNodes(parentElement: NgView, nodes: NgView[]): void {
traceLog("NativeScriptRenderer.projectNodes");
nodes.forEach((node) => {
this.viewUtil.insertChild(parentElement, node);
});
nodes.forEach((node) => this.viewUtil.insertChild(parentElement, node));
}

destroy() {
Expand Down Expand Up @@ -202,17 +197,7 @@ export class NativeScriptRenderer extends RendererV2 {

createElement(name: any, _namespace: string): NgView {
traceLog(`NativeScriptRenderer.createElement: ${name}`);

return this.viewUtil.createView(name, view => {
console.log(view);
// Set an attribute to the view to scope component-specific css.
// The property name is pre-generated by Angular.

// if (this.hasComponentStyles) {
// const cssAttribute = this.replaceNgAttribute(CONTENT_ATTR, this.componentProtoId);
// view[cssAttribute] = true;
// }
});
return this.viewUtil.createView(name)
}

createText(_value: string): NgView {
Expand All @@ -239,3 +224,63 @@ export class NativeScriptRenderer extends RendererV2 {
}
}

class EmulatedRenderer extends NativeScriptRenderer {
private contentAttr: string;
private hostAttr: string;

constructor(
private component: RendererTypeV2,
rootView: NgView,
zone: NgZone,
viewUtil: ViewUtil,
) {
super(rootView, zone, viewUtil);

this.addStyles();
this.contentAttr = shimContentAttribute(component.id);
this.hostAttr = shimHostAttribute(component.id);
}

applyToHost(view: NgView) {
super.setAttribute(view, this.hostAttr, "");
}

appendChild(parent: any, newChild: NgView): void {
// Set an attribute to the view to scope component-specific css.
// The property name is pre-generated by Angular.
const cssAttribute = this.replaceNgAttribute(CONTENT_ATTR);
newChild[cssAttribute] = true;

super.appendChild(parent, newChild);
}

createElement(parent: any, name: string): NgView {
const view = super.createElement(parent, name);
super.setAttribute(view, this.contentAttr, "");

return view;
}

private addStyles() {
this.component.styles
.map(s => s.toString())
.map(s => this.replaceNgAttribute(s))
.forEach(addCss);
}

private replaceNgAttribute(input: string): string {
return input.replace(ATTR_REPLACER , `_ng_content_${this.componentId}`);
}

private get componentId(): string {
return this.component.id.replace(ATTR_SANITIZER , "_");
}
}

function shimContentAttribute(componentShortId: string): string {
return CONTENT_ATTR.replace(COMPONENT_REGEX, componentShortId);
}

function shimHostAttribute(componentShortId: string): string {
return HOST_ATTR.replace(COMPONENT_REGEX, componentShortId);
}
15 changes: 3 additions & 12 deletions nativescript-angular/view-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { rendererLog as traceLog } from "./trace";

const IOS_PREFX: string = ":ios:";
const ANDROID_PREFX: string = ":android:";
const XML_ATTRIBUTES = Object.freeze([ "style", "row", "columns", "fontAttributes"]);
const whiteSpaceSplitter = /\s+/;

export type ViewExtensions = ViewExtensions;
Expand Down Expand Up @@ -114,7 +115,7 @@ export class ViewUtil {
}
}

public createView(name: string, beforeAttach?: BeforeAttachAction): NgView {
public createView(name: string): NgView {
traceLog("Creating view:" + name);

if (!isKnownView(name)) {
Expand All @@ -125,10 +126,6 @@ export class ViewUtil {
view.nodeName = name;
view.meta = getViewMeta(name);

if (beforeAttach) {
beforeAttach(view);
}

return view;
}

Expand All @@ -141,13 +138,7 @@ export class ViewUtil {
}

private isXMLAttribute(name: string): boolean {
switch (name) {
case "style": return true;
case "rows": return true;
case "columns": return true;
case "fontAttributes": return true;
default: return false;
}
return XML_ATTRIBUTES.indexOf(name) !== -1;
}

private platformFilter(attribute: string): string {
Expand Down

0 comments on commit 70603c4

Please sign in to comment.