Skip to content

Commit 65359fa

Browse files
authored
fix(renderer): attach CommentNodes to visual tree (#888)
fixes #872
1 parent e6f8c3b commit 65359fa

File tree

12 files changed

+187
-83
lines changed

12 files changed

+187
-83
lines changed

Diff for: nativescript-angular/animations/animation-engine.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* tslint:disable */
12
import { ɵDomAnimationEngine as DomAnimationEngine } from "@angular/animations/browser";
23
import { AnimationEvent, AnimationPlayer } from "@angular/animations";
34

Diff for: nativescript-angular/directives/list-view-comp.ts

+2-26
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ import {
2121
} from "@angular/core";
2222
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view";
2323
import { View, KeyedTemplate } from "tns-core-modules/ui/core/view";
24-
import { ObservableArray } from "tns-core-modules/data/observable-array";
2524
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
25+
import { ObservableArray } from "tns-core-modules/data/observable-array";
2626
import { profile } from "tns-core-modules/profiling";
2727

28-
import { CommentNode } from "../element-registry";
28+
import { getSingleViewRecursive } from "../element-registry";
2929
import { isListLikeIterable } from "../collection-facade";
3030
import { listViewLog, listViewError } from "../trace";
3131

@@ -216,30 +216,6 @@ export class ListViewComponent implements DoCheck, OnDestroy, AfterContentInit {
216216
}
217217
}
218218

219-
function getSingleViewRecursive(nodes: Array<any>, nestLevel: number): View {
220-
const actualNodes = nodes.filter(node => !(node instanceof CommentNode));
221-
222-
if (actualNodes.length === 0) {
223-
throw new Error(`No suitable views found in list template! ` +
224-
`Nesting level: ${nestLevel}`);
225-
} else if (actualNodes.length > 1) {
226-
throw new Error(`More than one view found in list template!` +
227-
`Nesting level: ${nestLevel}`);
228-
}
229-
230-
const rootLayout = actualNodes[0];
231-
if (!rootLayout) {
232-
return getSingleViewRecursive(rootLayout.children, nestLevel + 1);
233-
}
234-
235-
let parentLayout = rootLayout.parent;
236-
if (parentLayout instanceof LayoutBase) {
237-
parentLayout.removeChild(rootLayout);
238-
}
239-
240-
return rootLayout;
241-
}
242-
243219
export interface ComponentView {
244220
rootNodes: Array<any>;
245221
destroy(): void;

Diff for: nativescript-angular/directives/tab-view.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from "@angular/core";
1010
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";
1111

12-
import { CommentNode } from "../element-registry";
12+
import { InvisibleNode } from "../element-registry";
1313
import { rendererLog } from "../trace";
1414
import { isBlank } from "../lang-facade";
1515

@@ -105,7 +105,7 @@ export class TabViewItemDirective implements OnInit {
105105
const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
106106
// Filter out text nodes and comments
107107
const realViews = viewRef.rootNodes.filter(node =>
108-
!(node instanceof CommentNode));
108+
!(node instanceof InvisibleNode));
109109

110110
if (realViews.length > 0) {
111111
this.item.view = realViews[0];

Diff for: nativescript-angular/element-registry.ts

+72-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { View } from "tns-core-modules/ui/core/view";
2+
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
23

34
export type NgView = (View & ViewExtensions);
4-
export type NgElement = NgView | CommentNode;
5+
export type NgElement = NgView | InvisibleNode;
56

67
export interface ViewExtensions {
78
nodeType: number;
@@ -15,12 +16,55 @@ export interface ViewClass {
1516
new (): View;
1617
}
1718

18-
// used for creating comments and text nodes in the renderer
19-
export class CommentNode {
20-
meta: { skipAddToDom: true };
19+
export abstract class InvisibleNode extends View implements ViewExtensions {
20+
meta: { skipAddToDom: boolean };
2121
templateParent: NgView;
22+
nodeType: number;
23+
nodeName: string;
24+
ngCssClasses: Map<string, boolean>;
25+
26+
constructor() {
27+
super();
28+
29+
this.nodeType = 1;
30+
this.nodeName = getClassName(this);
31+
}
32+
33+
toString() {
34+
return `${this.nodeName}(${this.id})`;
35+
}
36+
}
37+
38+
export class CommentNode extends InvisibleNode {
39+
protected static id = 0;
40+
41+
constructor() {
42+
super();
43+
44+
this.meta = {
45+
skipAddToDom: false,
46+
};
47+
this.id = CommentNode.id.toString();
48+
CommentNode.id += 1;
49+
}
50+
}
51+
52+
export class TextNode extends InvisibleNode {
53+
protected static id = 0;
54+
55+
constructor() {
56+
super();
57+
58+
this.meta = {
59+
skipAddToDom: true,
60+
};
61+
this.id = TextNode.id.toString();
62+
TextNode.id += 1;
63+
}
2264
}
2365

66+
const getClassName = instance => instance.constructor.name;
67+
2468
export interface ViewClassMeta {
2569
skipAddToDom?: boolean;
2670
insertChild?: (parent: NgView, child: NgView, atIndex: number) => void;
@@ -76,6 +120,30 @@ export function isKnownView(elementName: string): boolean {
76120
elementMap.has(elementName.toLowerCase());
77121
}
78122

123+
export function getSingleViewRecursive(nodes: Array<any>, nestLevel: number): View {
124+
const actualNodes = nodes.filter(node => !(node instanceof InvisibleNode));
125+
126+
if (actualNodes.length === 0) {
127+
throw new Error(`No suitable views found in list template! ` +
128+
`Nesting level: ${nestLevel}`);
129+
} else if (actualNodes.length > 1) {
130+
throw new Error(`More than one view found in list template!` +
131+
`Nesting level: ${nestLevel}`);
132+
}
133+
134+
const rootLayout = actualNodes[0];
135+
if (!rootLayout) {
136+
return getSingleViewRecursive(rootLayout.children, nestLevel + 1);
137+
}
138+
139+
const parentLayout = rootLayout.parent;
140+
if (parentLayout instanceof LayoutBase) {
141+
parentLayout.removeChild(rootLayout);
142+
}
143+
144+
return rootLayout;
145+
}
146+
79147
// Register default NativeScript components
80148
// Note: ActionBar related components are registerd together with action-bar directives.
81149
registerElement("AbsoluteLayout", () => require("tns-core-modules/ui/layouts/absolute-layout").AbsoluteLayout);

Diff for: nativescript-angular/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@
6464
"@angular/http": "~4.0.0 || ~4.1.0",
6565
"@angular/platform-browser": "~4.0.0 || ~4.1.0",
6666
"@angular/router": "~4.0.0 || ~4.1.0",
67-
"codelyzer": "^3.0.1",
68-
"rxjs": "^5.0.1",
67+
"codelyzer": "^3.1.2",
68+
"rxjs": "^5.4.2",
6969
"tns-core-modules": "next",
7070
"tslint": "^5.1.0",
71-
"typescript": "~2.3.2",
71+
"typescript": "^2.4.0",
7272
"zone.js": "^0.8.4"
7373
}
7474
}

Diff for: nativescript-angular/renderer.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { profile } from "tns-core-modules/profiling";
1313
import { APP_ROOT_VIEW, DEVICE, getRootPage } from "./platform-providers";
1414
import { isBlank } from "./lang-facade";
1515
import { ViewUtil } from "./view-util";
16-
import { NgView, CommentNode } from "./element-registry";
16+
import { NgView, InvisibleNode } from "./element-registry";
1717
import { rendererLog as traceLog } from "./trace";
1818

1919
// CONTENT_ATTR not exported from NativeScript_renderer - we need it for styles application.
@@ -120,7 +120,7 @@ export class NativeScriptRenderer extends Renderer2 {
120120
}
121121

122122
@profile
123-
createComment(_value: any): CommentNode {
123+
createComment(_value: any): InvisibleNode {
124124
traceLog(`NativeScriptRenderer.createComment ${_value}`);
125125
return this.viewUtil.createComment();
126126
}
@@ -132,7 +132,7 @@ export class NativeScriptRenderer extends Renderer2 {
132132
}
133133

134134
@profile
135-
createText(_value: string): CommentNode {
135+
createText(_value: string): InvisibleNode {
136136
traceLog(`NativeScriptRenderer.createText ${_value}`);
137137
return this.viewUtil.createText();
138138
}
@@ -284,6 +284,7 @@ class EmulatedRenderer extends NativeScriptRenderer {
284284
}
285285
}
286286

287+
// tslint:disable-next-line
287288
const addStyleToCss = profile('"renderer".addStyleToCss', function addStyleToCss(style: string): void {
288289
addCss(style);
289290
});

Diff for: nativescript-angular/router/ns-module-factory-loader.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import {
66
SystemJsNgModuleLoader,
77
Type,
88
} from "@angular/core";
9-
import { path, knownFolders } from "tns-core-modules/file-system";
9+
import {
10+
path as fileSystemPath,
11+
knownFolders
12+
} from "tns-core-modules/file-system";
1013

1114
const SEPARATOR = "#";
1215

@@ -51,9 +54,9 @@ function splitPath(path: string): {modulePath: string, exportName: string} {
5154

5255
function getAbsolutePath(relativePath: string) {
5356
const projectPath = knownFolders.currentApp().path;
54-
const absolutePath = path.join(projectPath, relativePath);
57+
const absolutePath = fileSystemPath.join(projectPath, relativePath);
5558

56-
return path.normalize(absolutePath);
59+
return fileSystemPath.normalize(absolutePath);
5760
}
5861

5962
function checkNotEmpty(value: any, modulePath: string, exportName: string): void {

Diff for: nativescript-angular/tsconfig.json

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
"declaration": true,
1212
"removeComments": false,
1313
"noEmitOnError": true,
14-
"noUnusedLocals": true,
15-
"noUnusedParameters": true,
1614
"noImplicitAny": false,
1715
"lib": [
1816
"dom",

Diff for: nativescript-angular/tslint.json

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"no-string-literal": false,
6262
"no-switch-case-fall-through": true,
6363
"no-unused-expression": true,
64+
"no-unused-variable": true,
6465
"no-var-keyword": true,
6566
"radix": false,
6667
"switch-default": true,

Diff for: nativescript-angular/value-accessors/base-value-accessor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ControlValueAccessor } from "@angular/forms";
22
import { View } from "tns-core-modules/ui/core/view";
33

44
export class BaseValueAccessor<TView extends View> implements ControlValueAccessor {
5-
private pendingChangeNotification: number = 0;
5+
private pendingChangeNotification: any = 0;
66
onChange = (_) => { };
77
onTouched = () => {};
88

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

+7-15
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import { ContentView } from "tns-core-modules/ui/content-view";
55
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
66
import {
77
CommentNode,
8+
InvisibleNode,
89
NgElement,
910
NgView,
11+
TextNode,
1012
ViewExtensions,
1113
getViewClass,
1214
getViewMeta,
@@ -52,9 +54,8 @@ export class ViewUtil {
5254
}
5355

5456
public insertChild(parent: any, child: NgElement, atIndex: number = -1) {
55-
if (child instanceof CommentNode) {
57+
if (child instanceof InvisibleNode) {
5658
child.templateParent = parent;
57-
return;
5859
}
5960

6061
if (!parent || isDetachedElement(child)) {
@@ -79,16 +80,11 @@ export class ViewUtil {
7980
parent.content = child;
8081
} else if (parent && parent._addChildFromBuilder) {
8182
parent._addChildFromBuilder(child.nodeName, child);
82-
} else {
83-
// throw new Error("Parent can"t contain children: " + parent.nodeName + ", " + parent);
8483
}
8584
}
8685

8786
public removeChild(parent: any, child: NgElement) {
88-
if (!parent ||
89-
child instanceof CommentNode ||
90-
isDetachedElement(child)) {
91-
87+
if (!parent || isDetachedElement(child)) {
9288
return;
9389
}
9490

@@ -102,8 +98,6 @@ export class ViewUtil {
10298
}
10399
} else if (isView(parent)) {
104100
parent._removeView(child);
105-
} else {
106-
// throw new Error("Unknown parent type: " + parent);
107101
}
108102
}
109103

@@ -112,17 +106,15 @@ export class ViewUtil {
112106
return parent.getChildIndex(child);
113107
} else if (isContentView(parent)) {
114108
return child === parent.content ? 0 : -1;
115-
} else {
116-
// throw new Error("Parent can"t contain children: " + parent);
117109
}
118110
}
119111

120-
public createComment(): CommentNode {
112+
public createComment(): InvisibleNode {
121113
return new CommentNode();
122114
}
123115

124-
public createText(): CommentNode {
125-
return new CommentNode();
116+
public createText(): InvisibleNode {
117+
return new TextNode();
126118
}
127119

128120
public createView(name: string): NgView {

0 commit comments

Comments
 (0)