Skip to content

Commit

Permalink
Fixes dojo#739, tree.expand now returns a promise.
Browse files Browse the repository at this point in the history
  • Loading branch information
edhager committed Oct 17, 2013
1 parent 576f69e commit c8f200f
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 15 deletions.
1 change: 1 addition & 0 deletions test/intern/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ define([
'intern/node_modules/dojo/has!host-browser?./core/stores',
'intern/node_modules/dojo/has!host-browser?./core/_StoreMixin',
'intern/node_modules/dojo/has!host-browser?./core/OnDemand-removeRow',
'intern/node_modules/dojo/has!host-browser?./core/tree-expand-promise',
'intern/node_modules/dojo/has!host-browser?./extensions/Pagination'
], function(){});
216 changes: 216 additions & 0 deletions test/intern/core/tree-expand-promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
define([
"intern!tdd",
"intern/chai!assert",
"dgrid/OnDemandGrid",
"dgrid/tree",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/store/Memory",
"dojo/store/util/QueryResults",
"dojo/dom-construct",
"dojo/query",
"dojo/Deferred"
], function(test, assert, OnDemandGrid, tree, declare, lang, Memory, QueryResults, domConstruct, query, Deferred){

test.suite("tree (expand + promise)", function(){
var grid;
var SyncTreeStore = declare(Memory, {
// A memory store with methods to support a tree
getChildren: function(parent, options){
// Support persisting the original query via options.originalQuery
// so that child levels will filter the same way as the root level
return this.query(
lang.mixin({}, options && options.originalQuery || null,
{ parent: parent.id }),
options);
},
mayHaveChildren: function(parent){
return true;
},
query: function(query, options){
query = query || {};
options = options || {};

if(!query.parent && !options.deep){
// Default to a single-level query for root items (no parent)
query.parent = undefined;
}
return this.queryEngine(query, options)(this.data);
}
});
var AsyncTreeStore = declare(SyncTreeStore, {
// SyncTreeStore with an asynchronous query method.
query: function(query, options){
this.dfd = new Deferred();
var promise = this.dfd.promise;
this.queryResults = this.inherited(arguments);
return QueryResults(promise);
},
resolve: function(){
// Allows the test to control when the store query is resolved.
this.dfd.resolve(this.queryResults);
}
});

function createData(){
return [
{ id: 1, node: "Node 1", value: "Value 1"},
{ id: 2, node: "Node 2", value: "Value 2", parent: 1},
{ id: 3, node: "Node 3", value: "Value 3", parent: 2},
{ id: 4, node: "Node 4", value: "Value 4", parent: 2},
{ id: 5, node: "Node 5", value: "Value 5"}
];
}

function createGrid(store){
grid = new OnDemandGrid({
store: store,
columns: [
tree({field: "node", label: "Node"}),
{field: "value", label: "Value"}
]
});
domConstruct.place(grid.domNode, document.body);
grid.startup();
}

function destroyGrid(){
if(grid){
grid.destroy();
grid = null;
}
}

test.suite("tree with sync store", function(){
test.beforeEach(function(){
var data = createData();
var store = new SyncTreeStore({
data: data
});
createGrid(store);
});
test.afterEach(function(){
destroyGrid();
});

// Tests
test.test("expand + no callback", function(){
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1);
// The memory store is asynchronous
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
});

test.test("expand + callback", function(){
var dfd = this.async(1000);
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
}));
});

test.test("expand + multiple callback", function(){
var dfd = this.async(1000);
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
grid.expand(2).then(dfd.callback(function(){
assert.strictEqual(5, query(".dgrid-row", grid.domNode).length, "Grid has 5 rows");
grid.expand(4).then(dfd.callback(function(){
assert.strictEqual(5, query(".dgrid-row", grid.domNode).length, "Grid has 5 rows");
}));
}));
}));
});

test.test("duplicate expand + callback", function(){
var dfd = this.async(1000);
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
}));
}));
});
});

test.suite("tree with async store", function(){
test.beforeEach(function(){
var data = createData();
var store = new AsyncTreeStore({
data: data
});
createGrid(store);
});
test.afterEach(function(){
destroyGrid();
});

test.test("expand + callback", function(){
var dfd = this.async(1000);
grid.on("dgrid-refresh-complete", dfd.callback(function(){
// Start testing when the grid is ready.
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
}));
// The expand has not occurred yet.
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.store.resolve();
}));
assert.strictEqual(0, query(".dgrid-row", grid.domNode).length, "Grid has 0 rows");
// Resolve the grid's initial store query.
grid.store.resolve();
});

test.test("expand + multiple callback", function(){
var dfd = this.async(1000);
grid.on("dgrid-refresh-complete", dfd.callback(function(){
// Start testing when the grid is ready.
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
grid.expand(2).then(dfd.callback(function(){
assert.strictEqual(5, query(".dgrid-row", grid.domNode).length, "Grid has 5 rows");
grid.expand(4).then(dfd.callback(function(){
assert.strictEqual(5, query(".dgrid-row", grid.domNode).length, "Grid has 5 rows");
}));
// Resolve expand(4) query
grid.store.resolve();
}));
// The expand has not occurred yet.
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
// Resolve expand(2) query
grid.store.resolve();
}));
// The expand has not occurred yet.
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
// Resolve expand(1) query
grid.store.resolve();
}));
// Resolve the grid's initial store query.
grid.store.resolve();
});

test.test("duplicate expand + callback", function(){
var dfd = this.async(1000);
grid.on("dgrid-refresh-complete", dfd.callback(function(){
// Start testing when the grid is ready.
assert.strictEqual(2, query(".dgrid-row", grid.domNode).length, "Grid has 2 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
grid.expand(1).then(dfd.callback(function(){
assert.strictEqual(3, query(".dgrid-row", grid.domNode).length, "Grid has 3 rows");
}));
}));
grid.store.resolve();
}));
// Resolve the grid's initial store query.
grid.store.resolve();
});
});

// TODO make the query throw an error.
});
});
37 changes: 22 additions & 15 deletions tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ function tree(column){
// if unspecified, toggles the current state.

var row = target.element ? target : grid.row(target),
hasTransitionend = has("transitionend");
hasTransitionend = has("transitionend"),
dfd = new Deferred(),
promise = dfd.promise;

target = row.element;
target = target.className.indexOf("dgrid-expando-icon") > -1 ? target :
Expand Down Expand Up @@ -217,21 +219,24 @@ function tree(column){
if("level" in target){
query.level = target.level;
}
Deferred.when(
grid.renderQuery ?
grid._trackError(function(){
return grid.renderQuery(query, preloadNode, options);
}) :
grid.renderArray(query(options), preloadNode,
"level" in query ? { queryLevel: query.level } : {}),
function(){
// Expand once results are retrieved, if the row is still expanded.
if(grid._expanded[row.id] && hasTransitionend){
var scrollHeight = container.scrollHeight;
container.style.height = scrollHeight ? scrollHeight + "px" : "auto";
// Add the query to the promise chain.
promise = promise.then(function(){
return Deferred.when(
grid.renderQuery ?
grid._trackError(function(){
return grid.renderQuery(query, preloadNode, options);
}) :
grid.renderArray(query(options), preloadNode,
"level" in query ? { queryLevel: query.level } : {}),
function(){
// Expand once results are retrieved, if the row is still expanded.
if(grid._expanded[row.id] && hasTransitionend){
var scrollHeight = container.scrollHeight;
container.style.height = scrollHeight ? scrollHeight + "px" : "auto";
}
}
}
);
);
});

if(hasTransitionend){
on(container, hasTransitionend, ontransitionend);
Expand Down Expand Up @@ -277,6 +282,8 @@ function tree(column){
delete this._expanded[row.id];
}
}
dfd.resolve();
return promise;
}; // end function grid.expand

// Set up a destroy function on column to tear down the listeners/aspects
Expand Down

0 comments on commit c8f200f

Please sign in to comment.