Skip to content

Commit b7f5da2

Browse files
sis0k0hdeshev
authored andcommitted
feat(renderer): use EmulatedRenderer to scope component styles
1 parent c2c56b3 commit b7f5da2

File tree

2 files changed

+92
-56
lines changed

2 files changed

+92
-56
lines changed

Diff for: nativescript-angular/renderer.ts

+89-44
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {
22
Inject, Injectable, Optional, NgZone,
33
RendererV2, RendererFactoryV2, RendererTypeV2,
4-
// ViewEncapsulation
5-
// ɵAnimationStyles, ɵAnimationKeyframe,
4+
ViewEncapsulation,
65
} from "@angular/core";
76

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

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

2730
@Injectable()
2831
export class NativeScriptRendererFactory implements RendererFactoryV2 {
@@ -34,7 +37,7 @@ export class NativeScriptRendererFactory implements RendererFactoryV2 {
3437
constructor(
3538
@Optional() @Inject(APP_ROOT_VIEW) rootView: View,
3639
@Inject(DEVICE) device: Device,
37-
zone: NgZone
40+
private zone: NgZone
3841
) {
3942
this.viewUtil = new ViewUtil(device);
4043
this.setRootNgView(rootView);
@@ -55,30 +58,19 @@ export class NativeScriptRendererFactory implements RendererFactoryV2 {
5558
}
5659

5760
let renderer: NativeScriptRenderer = this.componentRenderers.get(type.id);
58-
if (isBlank(renderer)) {
59-
renderer = this.defaultRenderer;
60-
61-
let stylesLength = type.styles.length;
62-
for (let i = 0; i < stylesLength; i++) {
63-
console.log(type.styles[i]);
64-
// this.hasComponentStyles = true;
65-
let cssString = type.styles[i] + "";
66-
const realCSS = this.replaceNgAttribute(cssString, type.id);
67-
addCss(realCSS);
68-
}
69-
this.componentRenderers.set(type.id, renderer);
61+
if (!isBlank(renderer)) {
62+
return renderer;
7063
}
7164

72-
return renderer;
73-
}
74-
75-
private attrReplacer = new RegExp(escapeRegexSymbols(CONTENT_ATTR), "g");
76-
private attrSanitizer = /-/g;
77-
65+
if (type.encapsulation === ViewEncapsulation.Emulated) {
66+
renderer = new EmulatedRenderer(type, this.rootNgView, this.zone, this.viewUtil);
67+
(<EmulatedRenderer>renderer).applyToHost(element);
68+
} else {
69+
renderer = this.defaultRenderer;
70+
}
7871

79-
private replaceNgAttribute(input: string, componentId: string): string {
80-
return input.replace(this.attrReplacer,
81-
"_ng_content_" + componentId.replace(this.attrSanitizer, "_"));
72+
this.componentRenderers.set(type.id, renderer);
73+
return renderer;
8274
}
8375
}
8476

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

97-
appendChild(parent: any, newChild: any): void {
89+
appendChild(parent: any, newChild: NgView): void {
9890
traceLog(`NativeScriptRenderer.appendChild child: ${newChild} parent: ${parent}`);
91+
console.log(typeof parent)
92+
console.log("appending child")
93+
console.log(newChild.id)
9994
this.viewUtil.insertChild(parent, newChild);
10095
}
10196

10297

103-
insertBefore(parent: any, newChild: any, refChild: any): void {
98+
insertBefore(parent: any, newChild: any, _refChild: any): void {
10499
traceLog(`NativeScriptRenderer.insertBefore child: ${newChild} parent: ${parent}`);
105100
if (parent) {
106-
parent.insertBefore(newChild, refChild);
101+
// Temporary solution until we implement nextSibling method
102+
this.appendChild(parent, newChild);
103+
// parent.insertBefore(newChild, refChild);
107104
}
108105
}
109106

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

120-
parentNode(node: NgView): NgView {
121-
return node.templateParent;
117+
parentNode(node: NgView): any {
118+
return node.parent;
122119
}
123120

124121
nextSibling(_node: NgView): void {
125122
traceLog(`NativeScriptRenderer.nextSibling ${_node}`);
126123
}
127124

128125
createViewRoot(hostElement: NgView): NgView {
129-
traceLog("CREATE VIEW ROOT: " + hostElement.nodeName);
126+
traceLog(`NativeScriptRenderer.createViewRoot ${hostElement.nodeName}`)
130127
return hostElement;
131128
}
132129

133130
projectNodes(parentElement: NgView, nodes: NgView[]): void {
134131
traceLog("NativeScriptRenderer.projectNodes");
135-
nodes.forEach((node) => {
136-
this.viewUtil.insertChild(parentElement, node);
137-
});
132+
nodes.forEach((node) => this.viewUtil.insertChild(parentElement, node));
138133
}
139134

140135
destroy() {
@@ -202,17 +197,7 @@ export class NativeScriptRenderer extends RendererV2 {
202197

203198
createElement(name: any, _namespace: string): NgView {
204199
traceLog(`NativeScriptRenderer.createElement: ${name}`);
205-
206-
return this.viewUtil.createView(name, view => {
207-
console.log(view);
208-
// Set an attribute to the view to scope component-specific css.
209-
// The property name is pre-generated by Angular.
210-
211-
// if (this.hasComponentStyles) {
212-
// const cssAttribute = this.replaceNgAttribute(CONTENT_ATTR, this.componentProtoId);
213-
// view[cssAttribute] = true;
214-
// }
215-
});
200+
return this.viewUtil.createView(name)
216201
}
217202

218203
createText(_value: string): NgView {
@@ -239,3 +224,63 @@ export class NativeScriptRenderer extends RendererV2 {
239224
}
240225
}
241226

227+
class EmulatedRenderer extends NativeScriptRenderer {
228+
private contentAttr: string;
229+
private hostAttr: string;
230+
231+
constructor(
232+
private component: RendererTypeV2,
233+
rootView: NgView,
234+
zone: NgZone,
235+
viewUtil: ViewUtil,
236+
) {
237+
super(rootView, zone, viewUtil);
238+
239+
this.addStyles();
240+
this.contentAttr = shimContentAttribute(component.id);
241+
this.hostAttr = shimHostAttribute(component.id);
242+
}
243+
244+
applyToHost(view: NgView) {
245+
super.setAttribute(view, this.hostAttr, "");
246+
}
247+
248+
appendChild(parent: any, newChild: NgView): void {
249+
// Set an attribute to the view to scope component-specific css.
250+
// The property name is pre-generated by Angular.
251+
const cssAttribute = this.replaceNgAttribute(CONTENT_ATTR);
252+
newChild[cssAttribute] = true;
253+
254+
super.appendChild(parent, newChild);
255+
}
256+
257+
createElement(parent: any, name: string): NgView {
258+
const view = super.createElement(parent, name);
259+
super.setAttribute(view, this.contentAttr, "");
260+
261+
return view;
262+
}
263+
264+
private addStyles() {
265+
this.component.styles
266+
.map(s => s.toString())
267+
.map(s => this.replaceNgAttribute(s))
268+
.forEach(addCss);
269+
}
270+
271+
private replaceNgAttribute(input: string): string {
272+
return input.replace(ATTR_REPLACER , `_ng_content_${this.componentId}`);
273+
}
274+
275+
private get componentId(): string {
276+
return this.component.id.replace(ATTR_SANITIZER , "_");
277+
}
278+
}
279+
280+
function shimContentAttribute(componentShortId: string): string {
281+
return CONTENT_ATTR.replace(COMPONENT_REGEX, componentShortId);
282+
}
283+
284+
function shimHostAttribute(componentShortId: string): string {
285+
return HOST_ATTR.replace(COMPONENT_REGEX, componentShortId);
286+
}

Diff for: nativescript-angular/view-util.ts

+3-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { rendererLog as traceLog } from "./trace";
1515

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

2021
export type ViewExtensions = ViewExtensions;
@@ -114,7 +115,7 @@ export class ViewUtil {
114115
}
115116
}
116117

117-
public createView(name: string, beforeAttach?: BeforeAttachAction): NgView {
118+
public createView(name: string): NgView {
118119
traceLog("Creating view:" + name);
119120

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

128-
if (beforeAttach) {
129-
beforeAttach(view);
130-
}
131-
132129
return view;
133130
}
134131

@@ -141,13 +138,7 @@ export class ViewUtil {
141138
}
142139

143140
private isXMLAttribute(name: string): boolean {
144-
switch (name) {
145-
case "style": return true;
146-
case "rows": return true;
147-
case "columns": return true;
148-
case "fontAttributes": return true;
149-
default: return false;
150-
}
141+
return XML_ATTRIBUTES.indexOf(name) !== -1;
151142
}
152143

153144
private platformFilter(attribute: string): string {

0 commit comments

Comments
 (0)