Skip to content

Commit ee29397

Browse files
committed
refactor(renderer): replace doubly linked list with singly linked one
1 parent 063fe72 commit ee29397

File tree

3 files changed

+59
-38
lines changed

3 files changed

+59
-38
lines changed

nativescript-angular/element-registry.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ export interface ViewExtensions {
88
nodeType: number;
99
nodeName: string;
1010
templateParent: NgView;
11-
previousSibling: NgElement;
1211
nextSibling: NgElement;
1312
lastChild: NgElement;
1413
ngCssClasses: Map<string, boolean>;
1514
meta: ViewClassMeta;
1615
}
1716

17+
export interface ElementReference {
18+
previous: NgElement;
19+
next: NgElement;
20+
}
21+
1822
export interface ViewClass {
1923
new (): View;
2024
}
@@ -73,7 +77,7 @@ const getClassName = instance => instance.constructor.name;
7377

7478
export interface ViewClassMeta {
7579
skipAddToDom?: boolean;
76-
insertChild?: (parent: NgView, child: NgView, atIndex?: number) => void;
80+
insertChild?: (parent: NgView, child: NgView) => void;
7781
removeChild?: (parent: NgView, child: NgView) => void;
7882
}
7983

nativescript-angular/renderer.ts

Lines changed: 18 additions & 8 deletions
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, NgElement, InvisibleNode } from "./element-registry";
16+
import { NgView, NgElement, InvisibleNode, ElementReference, isDetachedElement } 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.
@@ -23,6 +23,7 @@ export const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
2323
export const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
2424
const ATTR_SANITIZER = /-/g;
2525

26+
2627
@Injectable()
2728
export class NativeScriptRendererFactory implements RendererFactory2 {
2829
private componentRenderers = new Map<string, NativeScriptRenderer>();
@@ -91,10 +92,10 @@ export class NativeScriptRenderer extends Renderer2 {
9192
}
9293

9394
@profile
94-
insertBefore(parent: NgView, newChild: NgView, refChild: NgElement): void {
95-
traceLog(`NativeScriptRenderer.insertBefore ` +
96-
`child: ${newChild} parent: ${parent} refChild: ${refChild}`);
97-
this.viewUtil.insertChild(parent, newChild, refChild);
95+
insertBefore(parent: NgView, newChild: NgView, { previous, next }: ElementReference): void {
96+
traceLog(`NativeScriptRenderer.insertBefore child: ${newChild} ` +
97+
`parent: ${parent} previous: ${previous} next: ${next}`);
98+
this.viewUtil.insertChild(parent, newChild, previous, next);
9899
}
99100

100101
@profile
@@ -116,9 +117,18 @@ export class NativeScriptRenderer extends Renderer2 {
116117
}
117118

118119
@profile
119-
nextSibling(node: NgView): NgElement {
120-
traceLog(`NativeScriptRenderer.nextSibling ${node}`);
121-
return node.nextSibling;
120+
nextSibling(node: NgView): ElementReference {
121+
traceLog(`NativeScriptRenderer.nextSibling of ${node} is ${node.nextSibling}`);
122+
123+
let next = node.nextSibling;
124+
while (next && isDetachedElement(next)) {
125+
next = next.nextSibling;
126+
}
127+
128+
return {
129+
previous: node,
130+
next,
131+
};
122132
}
123133

124134
@profile

nativescript-angular/view-util.ts

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ 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+
ElementReference,
89
InvisibleNode,
910
NgElement,
1011
NgView,
@@ -53,35 +54,35 @@ export class ViewUtil {
5354
this.isAndroid = device.os === platformNames.android;
5455
}
5556

56-
public insertChild(parent: NgView, child: NgElement, refChild?: NgElement) {
57+
public insertChild(parent: NgView, child: NgElement, previous?: NgElement, next?: NgElement) {
5758
// handle invisible nodes..
58-
if (child instanceof InvisibleNode) {
59-
child.templateParent = parent;
59+
if (!parent) {
60+
return;
6061
}
6162

62-
// add to queue
63-
const previousView = refChild || (parent && parent.lastChild);
64-
if (previousView) {
65-
previousView.nextSibling = child;
66-
child.previousSibling = previousView;
63+
if (child instanceof InvisibleNode) {
64+
child.templateParent = parent;
6765
}
6866

69-
if (!refChild && parent) {
67+
// add to end of queue if no next
68+
if (parent && !next) {
69+
if (parent.lastChild) {
70+
parent.lastChild.nextSibling = child;
71+
}
7072
parent.lastChild = child;
7173
}
7274

73-
// skip invisible elements ...
74-
while (isDetachedElement(refChild)) {
75-
refChild = refChild.previousSibling;
76-
previousView.nextSibling = child;
77-
child.previousSibling = previousView;
75+
// update queue if there is next
76+
if (next) {
77+
previous.nextSibling = child;
78+
child.nextSibling = next;
7879
}
7980

80-
// create actual view
81-
if (!parent || isDetachedElement(child)) {
81+
if (isDetachedElement(child)) {
8282
return;
8383
}
8484

85+
// create actual view
8586
if (parent.meta && parent.meta.insertChild) {
8687
parent.meta.insertChild(parent, child);
8788
} else if (isLayout(parent)) {
@@ -95,12 +96,13 @@ export class ViewUtil {
9596

9697
// insert child
9798

98-
if (refChild) {
99-
const atIndex = parent.getChildIndex(refChild);
99+
if (next) {
100+
const atIndex = parent.getChildIndex(next);
100101
parent.insertChild(child, atIndex);
101102
} else {
102103
parent.addChild(child);
103104
}
105+
104106
} else if (isContentView(parent)) {
105107
parent.content = child;
106108
} else if (parent && (<any>parent)._addChildFromBuilder) {
@@ -109,29 +111,34 @@ export class ViewUtil {
109111
}
110112

111113
public removeChild(parent: NgView, child: NgElement) {
112-
// remove from qeueue
113-
if (child.previousSibling) {
114-
child.previousSibling.nextSibling = child.nextSibling;
115-
}
116-
117-
if (child.nextSibling) {
118-
child.nextSibling.previousSibling = child.previousSibling;
119-
}
120-
121-
// actual desctructuring
122114
if (!parent || isDetachedElement(child)) {
115+
console.log("skip the removal of detached element")
123116
return;
124117
}
125118

126119
if (parent.meta && parent.meta.removeChild) {
127120
parent.meta.removeChild(parent, child);
128121
} else if (isLayout(parent)) {
122+
console.log("remove child from layout")
123+
const atIndex = parent.getChildIndex(child);
124+
if (atIndex === -1) {
125+
return;
126+
}
127+
128+
if (atIndex !== 0) {
129+
const previous = parent.getChildAt(atIndex - 1) as NgElement;
130+
previous.nextSibling = child.nextSibling;
131+
}
132+
129133
parent.removeChild(child);
134+
130135
} else if (isContentView(parent)) {
136+
console.log("remove child from content view");
131137
if (parent.content === child) {
132138
parent.content = null;
133139
}
134140
} else if (isView(parent)) {
141+
console.log("remove child from view element");
135142
parent._removeView(child);
136143
}
137144
}

0 commit comments

Comments
 (0)