Skip to content

Commit

Permalink
fix(renderer): attach CommentNodes to visual tree (#888)
Browse files Browse the repository at this point in the history
fixes #872
  • Loading branch information
sis0k0 authored Jul 11, 2017
1 parent e6f8c3b commit 65359fa
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 83 deletions.
1 change: 1 addition & 0 deletions nativescript-angular/animations/animation-engine.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* tslint:disable */
import { ɵDomAnimationEngine as DomAnimationEngine } from "@angular/animations/browser";
import { AnimationEvent, AnimationPlayer } from "@angular/animations";

Expand Down
28 changes: 2 additions & 26 deletions nativescript-angular/directives/list-view-comp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import {
} from "@angular/core";
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view";
import { View, KeyedTemplate } from "tns-core-modules/ui/core/view";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { profile } from "tns-core-modules/profiling";

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

Expand Down Expand Up @@ -216,30 +216,6 @@ export class ListViewComponent implements DoCheck, OnDestroy, AfterContentInit {
}
}

function getSingleViewRecursive(nodes: Array<any>, nestLevel: number): View {
const actualNodes = nodes.filter(node => !(node instanceof CommentNode));

if (actualNodes.length === 0) {
throw new Error(`No suitable views found in list template! ` +
`Nesting level: ${nestLevel}`);
} else if (actualNodes.length > 1) {
throw new Error(`More than one view found in list template!` +
`Nesting level: ${nestLevel}`);
}

This comment has been minimized.

Copy link
@lxmanpai

lxmanpai Jun 21, 2018

Hi

const rootLayout = actualNodes[0];
if (!rootLayout) {
return getSingleViewRecursive(rootLayout.children, nestLevel + 1);
}

let parentLayout = rootLayout.parent;
if (parentLayout instanceof LayoutBase) {
parentLayout.removeChild(rootLayout);
}

return rootLayout;
}

export interface ComponentView {
rootNodes: Array<any>;
destroy(): void;
Expand Down
4 changes: 2 additions & 2 deletions nativescript-angular/directives/tab-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@angular/core";
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";

import { CommentNode } from "../element-registry";
import { InvisibleNode } from "../element-registry";

This comment has been minimized.

Copy link
@lxmanpai

lxmanpai Jun 21, 2018

Vidjaja

import { rendererLog } from "../trace";
import { isBlank } from "../lang-facade";

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

if (realViews.length > 0) {
this.item.view = realViews[0];
Expand Down
76 changes: 72 additions & 4 deletions nativescript-angular/element-registry.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { View } from "tns-core-modules/ui/core/view";
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";

export type NgView = (View & ViewExtensions);
export type NgElement = NgView | CommentNode;
export type NgElement = NgView | InvisibleNode;

export interface ViewExtensions {
nodeType: number;
Expand All @@ -15,12 +16,55 @@ export interface ViewClass {
new (): View;
}

// used for creating comments and text nodes in the renderer
export class CommentNode {
meta: { skipAddToDom: true };
export abstract class InvisibleNode extends View implements ViewExtensions {
meta: { skipAddToDom: boolean };
templateParent: NgView;
nodeType: number;
nodeName: string;
ngCssClasses: Map<string, boolean>;

constructor() {
super();

this.nodeType = 1;
this.nodeName = getClassName(this);
}

toString() {
return `${this.nodeName}(${this.id})`;
}
}

export class CommentNode extends InvisibleNode {
protected static id = 0;

constructor() {
super();

this.meta = {
skipAddToDom: false,
};
this.id = CommentNode.id.toString();
CommentNode.id += 1;
}
}

export class TextNode extends InvisibleNode {
protected static id = 0;

constructor() {
super();

this.meta = {
skipAddToDom: true,
};
this.id = TextNode.id.toString();
TextNode.id += 1;
}
}

const getClassName = instance => instance.constructor.name;

export interface ViewClassMeta {
skipAddToDom?: boolean;
insertChild?: (parent: NgView, child: NgView, atIndex: number) => void;
Expand Down Expand Up @@ -76,6 +120,30 @@ export function isKnownView(elementName: string): boolean {
elementMap.has(elementName.toLowerCase());
}

export function getSingleViewRecursive(nodes: Array<any>, nestLevel: number): View {
const actualNodes = nodes.filter(node => !(node instanceof InvisibleNode));

if (actualNodes.length === 0) {
throw new Error(`No suitable views found in list template! ` +
`Nesting level: ${nestLevel}`);
} else if (actualNodes.length > 1) {
throw new Error(`More than one view found in list template!` +
`Nesting level: ${nestLevel}`);
}

const rootLayout = actualNodes[0];
if (!rootLayout) {
return getSingleViewRecursive(rootLayout.children, nestLevel + 1);
}

const parentLayout = rootLayout.parent;
if (parentLayout instanceof LayoutBase) {
parentLayout.removeChild(rootLayout);
}

return rootLayout;
}

// Register default NativeScript components
// Note: ActionBar related components are registerd together with action-bar directives.
registerElement("AbsoluteLayout", () => require("tns-core-modules/ui/layouts/absolute-layout").AbsoluteLayout);
Expand Down
6 changes: 3 additions & 3 deletions nativescript-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@
"@angular/http": "~4.0.0 || ~4.1.0",
"@angular/platform-browser": "~4.0.0 || ~4.1.0",
"@angular/router": "~4.0.0 || ~4.1.0",
"codelyzer": "^3.0.1",
"rxjs": "^5.0.1",
"codelyzer": "^3.1.2",
"rxjs": "^5.4.2",
"tns-core-modules": "next",
"tslint": "^5.1.0",
"typescript": "~2.3.2",
"typescript": "^2.4.0",
"zone.js": "^0.8.4"
}
}
7 changes: 4 additions & 3 deletions nativescript-angular/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { profile } from "tns-core-modules/profiling";
import { APP_ROOT_VIEW, DEVICE, getRootPage } from "./platform-providers";
import { isBlank } from "./lang-facade";
import { ViewUtil } from "./view-util";
import { NgView, CommentNode } from "./element-registry";
import { NgView, InvisibleNode } from "./element-registry";
import { rendererLog as traceLog } from "./trace";

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

@profile
createComment(_value: any): CommentNode {
createComment(_value: any): InvisibleNode {
traceLog(`NativeScriptRenderer.createComment ${_value}`);
return this.viewUtil.createComment();
}
Expand All @@ -132,7 +132,7 @@ export class NativeScriptRenderer extends Renderer2 {
}

@profile
createText(_value: string): CommentNode {
createText(_value: string): InvisibleNode {
traceLog(`NativeScriptRenderer.createText ${_value}`);
return this.viewUtil.createText();
}
Expand Down Expand Up @@ -284,6 +284,7 @@ class EmulatedRenderer extends NativeScriptRenderer {
}
}

// tslint:disable-next-line
const addStyleToCss = profile('"renderer".addStyleToCss', function addStyleToCss(style: string): void {
addCss(style);
});
Expand Down
9 changes: 6 additions & 3 deletions nativescript-angular/router/ns-module-factory-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
SystemJsNgModuleLoader,
Type,
} from "@angular/core";
import { path, knownFolders } from "tns-core-modules/file-system";
import {
path as fileSystemPath,
knownFolders
} from "tns-core-modules/file-system";

const SEPARATOR = "#";

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

function getAbsolutePath(relativePath: string) {
const projectPath = knownFolders.currentApp().path;
const absolutePath = path.join(projectPath, relativePath);
const absolutePath = fileSystemPath.join(projectPath, relativePath);

return path.normalize(absolutePath);
return fileSystemPath.normalize(absolutePath);
}

function checkNotEmpty(value: any, modulePath: string, exportName: string): void {
Expand Down
2 changes: 0 additions & 2 deletions nativescript-angular/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
"declaration": true,
"removeComments": false,
"noEmitOnError": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitAny": false,
"lib": [
"dom",
Expand Down
1 change: 1 addition & 0 deletions nativescript-angular/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"no-string-literal": false,
"no-switch-case-fall-through": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-var-keyword": true,
"radix": false,
"switch-default": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ControlValueAccessor } from "@angular/forms";
import { View } from "tns-core-modules/ui/core/view";

export class BaseValueAccessor<TView extends View> implements ControlValueAccessor {
private pendingChangeNotification: number = 0;
private pendingChangeNotification: any = 0;
onChange = (_) => { };
onTouched = () => {};

Expand Down
22 changes: 7 additions & 15 deletions nativescript-angular/view-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { ContentView } from "tns-core-modules/ui/content-view";
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
import {
CommentNode,
InvisibleNode,
NgElement,
NgView,
TextNode,
ViewExtensions,
getViewClass,
getViewMeta,
Expand Down Expand Up @@ -52,9 +54,8 @@ export class ViewUtil {
}

public insertChild(parent: any, child: NgElement, atIndex: number = -1) {
if (child instanceof CommentNode) {
if (child instanceof InvisibleNode) {
child.templateParent = parent;
return;
}

if (!parent || isDetachedElement(child)) {
Expand All @@ -79,16 +80,11 @@ export class ViewUtil {
parent.content = child;
} else if (parent && parent._addChildFromBuilder) {
parent._addChildFromBuilder(child.nodeName, child);
} else {
// throw new Error("Parent can"t contain children: " + parent.nodeName + ", " + parent);
}
}

public removeChild(parent: any, child: NgElement) {
if (!parent ||
child instanceof CommentNode ||
isDetachedElement(child)) {

if (!parent || isDetachedElement(child)) {
return;
}

Expand All @@ -102,8 +98,6 @@ export class ViewUtil {
}
} else if (isView(parent)) {
parent._removeView(child);
} else {
// throw new Error("Unknown parent type: " + parent);
}
}

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

public createComment(): CommentNode {
public createComment(): InvisibleNode {
return new CommentNode();
}

public createText(): CommentNode {
return new CommentNode();
public createText(): InvisibleNode {
return new TextNode();
}

public createView(name: string): NgView {
Expand Down
Loading

0 comments on commit 65359fa

Please sign in to comment.