Skip to content

Commit

Permalink
Add virtual root (#10)
Browse files Browse the repository at this point in the history
In current behavior, we have root of linked list tree as an element to display in the table. This assumes that the table has one row that is the ancestor of every other row and this is how the demo app mocks its data.

However, in many table, we do not have one row at the top level but multiple rows at top level. To handle this case, we should have a root node that's the parent of all top level row but does not display in the table. This PR adds a virtual root to the linked list tree to support that.
  • Loading branch information
billy-addepar authored Aug 10, 2017
1 parent 7cffd57 commit 419646d
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 83 deletions.
17 changes: 11 additions & 6 deletions addon/utils/linked-list-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ import { property } from '../utils/class';
import Ember from 'ember';

export default class LinkedListTree extends Ember.Object {
@property root = null;
@property pointerNode = null;
@property pointerIndex = -1;

constructor(root) {
super();

this.root = root;
this.pointerNode = root;
root.updateNext(null);
root.updateNodeCountAndIndex(-1);

this.pointerIndex = 0;
this.set('length', root.nodeCount);
// Root is a virtual node and will not be used for display
if (root.children.length > 0) {
this.pointerNode = root.children[0];
}

this.set('length', root.nodeCount - 1);
}

objectAt(index) {
Expand Down Expand Up @@ -70,9 +75,9 @@ export default class LinkedListTree extends Ember.Object {
// Update next & previous link.
const newNextNode = row.next;
if (newNextNode != null) {
newNextNode.previous = newNextNode.previousOriginal;
newNextNode.previous = newNextNode.originalPrevious;
}
row.next = row.nextOriginal;
row.next = row.originalNext;

row.collapse = false;
this.updateParentNodeCount(row, (row.nodeCount + row.nodeCountDelta) - 1);
Expand Down
8 changes: 4 additions & 4 deletions addon/utils/tree-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class TreeNode {
/**
* Original next node when tree is fully expanded.
*/
@property nextOriginal = null;
@property originalNext = null;

/**
* Current previous node (apply for both case expand & collapse).
Expand All @@ -31,7 +31,7 @@ export default class TreeNode {
/**
* Original previous node when the tree is fully expanded.
*/
@property previousOriginal = null;
@property originalPrevious = null;

/**
* Total number of node in this subtree (including this node).
Expand Down Expand Up @@ -63,11 +63,11 @@ export default class TreeNode {

_setNextNode(node) {
this.next = node;
this.nextOriginal = node;
this.originalNext = node;

if (node != null) {
node.previous = this;
node.previousOriginal = this;
node.originalPrevious = this;
}
}

Expand Down
13 changes: 5 additions & 8 deletions tests/dummy/app/controllers/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ export default Ember.Controller.extend({
},

rows: Ember.computed(function() {
const root = new TreeNode(null, this.getRow("Root"));

console.log(root.value.get('id'));

const topRow = new TreeNode(null, this.getRow("Top Row"));
for (let i = 0; i < 10; i++) {
const header = new TreeNode(root, this.getRow("Header " + i));
const header = new TreeNode(topRow, this.getRow("Header " + i));
for (let j = 0; j < 10; j++) {
const group = new TreeNode(header, this.getRow("Group " + j));
for (let k = 0; k < 10; k++) {
Expand All @@ -34,11 +31,11 @@ export default Ember.Controller.extend({
header.addChild(group);
}

root.addChild(header);
topRow.addChild(header);
}

root.updateNext(null);
const nodeCount = root.updateNodeCountAndIndex(0);
const root = new TreeNode(null, null);
root.addChild(topRow);

return new LinkedListTree(root);
}),
Expand Down
11 changes: 7 additions & 4 deletions tests/helpers/tree-generator.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import TreeNode from 'dummy/utils/tree-node';

const generateBasicRoot = () => {
const root = new TreeNode(null, 'Root');
const topRow = new TreeNode(null, 'Top Row');

for (let i = 0; i < 10; i++) {
const header = new TreeNode(root, `Header ${i}`);
const header = new TreeNode(topRow, `Header ${i}`);
for (let j = 0; j < 10; j++) {
const group = new TreeNode(header, `Group ${j}`);
for (let k = 0; k < 10; k++) {
Expand All @@ -14,11 +14,14 @@ const generateBasicRoot = () => {
header.addChild(group);
}

root.addChild(header);
topRow.addChild(header);
}

const root = new TreeNode(null, 'Root');
root.addChild(topRow);

root.updateNext(null);
root.updateNodeCountAndIndex(0);
root.updateNodeCountAndIndex(-1);

return root;
};
Expand Down
10 changes: 0 additions & 10 deletions tests/unit/utils/fixed-column-test.js

This file was deleted.

4 changes: 2 additions & 2 deletions tests/unit/utils/linked-list-tree-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ test('Test objectAt', function(assert) {

let node = tree.objectAt(359);
assert.equal(tree.pointerIndex, 359);
verifyTreePath(assert, node, ['Leaf 1', 'Group 2', 'Header 3', 'Root']);
verifyTreePath(assert, node, ['Leaf 1', 'Group 2', 'Header 3', 'Top Row']);

node = tree.objectAt(67);
assert.equal(tree.pointerIndex, 67);
verifyTreePath(assert, node, ['Leaf 9', 'Group 5', 'Header 0', 'Root']);
verifyTreePath(assert, node, ['Leaf 9', 'Group 5', 'Header 0', 'Top Row']);
});

test('Test expanding and collapsing rows', function(assert) {
Expand Down
9 changes: 5 additions & 4 deletions tests/unit/utils/tree-node-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ module('Unit | Utility | tree node');
// Replace this with your real tests.
test('Test next and preivous nodes', function(assert) {
const root = generateBasicRoot();
assert.equal(root.nodeCount, 1111, 'Root has 1111 nodes including self');
const firstRow = root.next;
assert.equal(firstRow.nodeCount, 1111, 'Root has 1111 nodes, not including root');

let node = root.next.next; // Group 0
let node = firstRow.next.next; // Group 0
assert.equal(node.value, 'Group 0', 'Next node is correct');

// Test next nodes of the 10 leaf
Expand All @@ -26,11 +27,11 @@ test('Test next and preivous nodes', function(assert) {
assert.equal(node.value, 'Group 0', 'Previous node of leaf 0 is correct');

// Test next node on collapse of Header 0.
const header0 = root.next;
const header0 = firstRow.next;
assert.equal(header0.nextOnCollapse.value, 'Header 1',
'Next node on collapse of Header 0 is Header 1');

assert.equal(header0.nextWithDirection(-1).value, 'Root',
assert.equal(header0.nextWithDirection(-1).value, 'Top Row',
'Next node with negative direction of header 0 is Root');

assert.equal(header0.nextWithDirection(1).value, 'Group 0',
Expand Down
54 changes: 9 additions & 45 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@
dependencies:
"@glimmer/util" "^0.22.3"

"@html-next/vertical-collection@1.0.0-beta.5":
version "1.0.0-beta.5"
resolved "https://registry.yarnpkg.com/@html-next/vertical-collection/-/vertical-collection-1.0.0-beta.5.tgz#fd6e3130beeafb80d2735c5644cf5ccb0ff884e2"
"@html-next/vertical-collection@1.0.0-beta.6":
version "1.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@html-next/vertical-collection/-/vertical-collection-1.0.0-beta.6.tgz#854f10ebee73a003664236fcfeca607be8bf5178"
dependencies:
babel-plugin-filter-imports "^0.3.1"
babel-plugin-transform-es2015-block-scoping "^6.24.1"
Expand Down Expand Up @@ -305,10 +305,6 @@ ast-types@0.8.12:
version "0.8.12"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc"

ast-types@0.8.15:
version "0.8.15"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52"

ast-types@0.9.6:
version "0.9.6"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
Expand Down Expand Up @@ -3194,7 +3190,7 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"

glob@7.1.1:
glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5:
version "7.1.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
Expand All @@ -3215,17 +3211,6 @@ glob@^5.0.10, glob@^5.0.15:
once "^1.3.0"
path-is-absolute "^1.0.0"

glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"

global-modules@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
Expand Down Expand Up @@ -4178,7 +4163,7 @@ mime@^1.2.11:
version "1.3.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0"

"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
Expand All @@ -4190,18 +4175,14 @@ minimatch@^2.0.3:
dependencies:
brace-expansion "^1.0.0"

minimist@0.0.8:
minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"

minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"

minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"

mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
Expand Down Expand Up @@ -4651,14 +4632,10 @@ q@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"

qs@6.4.0, qs@~6.4.0:
qs@6.4.0, qs@^6.4.0, qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"

qs@^6.4.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49"

quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408"
Expand Down Expand Up @@ -4763,7 +4740,7 @@ readline2@^1.0.1:
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"

recast@0.10.33:
recast@0.10.33, recast@^0.10.10:
version "0.10.33"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697"
dependencies:
Expand All @@ -4772,15 +4749,6 @@ recast@0.10.33:
private "~0.1.5"
source-map "~0.5.0"

recast@^0.10.10:
version "0.10.43"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f"
dependencies:
ast-types "0.8.15"
esprima-fb "~15001.1001.0-dev-harmony-fb"
private "~0.1.5"
source-map "~0.5.0"

recast@^0.11.17, recast@^0.11.3:
version "0.11.23"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
Expand Down Expand Up @@ -5258,11 +5226,7 @@ spdx-license-ids@^1.0.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"

sprintf-js@^1.0.3:
version "1.1.1"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"

sprintf-js@~1.0.2:
sprintf-js@^1.0.3, sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"

Expand Down

0 comments on commit 419646d

Please sign in to comment.