Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Apr 7, 2016
2 parents 7b0931d + dae99d9 commit 93b7d26
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 36 deletions.
47 changes: 46 additions & 1 deletion dist/infinite-tree.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! infinite-tree v0.6.3 | (c) 2016 Cheton Wu <[email protected]> | MIT | https://github.com/cheton/infinite-tree */
/*! infinite-tree v0.7.0 | (c) 2016 Cheton Wu <[email protected]> | MIT | https://github.com/cheton/infinite-tree */
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
Expand Down Expand Up @@ -149,6 +149,7 @@ return /******/ (function(modules) { // webpackBootstrap
autoOpen: false,
droppable: false,
el: null,
loadNodes: null,
rowRenderer: _renderer.defaultRowRenderer,
selectable: true,
shouldSelectNode: null
Expand Down Expand Up @@ -708,6 +709,42 @@ return /******/ (function(modules) { // webpackBootstrap
return false;
}

if (!node.hasChildren() && node.loadOnDemand) {
if (typeof this.options.loadNodes !== 'function') {
return false;
}

// Set loading state to true
node.state.loading = true;
this.rows[nodeIndex] = this.options.rowRenderer(node, this.options);

// Updates list with new data
this.update();

this.options.loadNodes(node, function (err, nodes) {
// Set loading state to false
node.state.loading = false;
_this5.rows[nodeIndex] = _this5.options.rowRenderer(node, _this5.options);

// Updates list with new data
_this5.update();

if (err) {
return;
}

// Append child nodes
nodes.forEach(function (childNode) {
_this5.appendChildNode(childNode, node);
});

// Call openNode again
_this5.openNode(node);
});

return false;
}

node.state.open = true; // Set node.state.open to true
var openNodes = [node].concat(this.state.openNodes); // the most recently used items first
this.state.openNodes = openNodes;
Expand Down Expand Up @@ -2201,6 +2238,8 @@ return /******/ (function(modules) { // webpackBootstrap
var defaultRowRenderer = function defaultRowRenderer(node, treeOptions) {
var id = node.id;
var label = node.label;
var _node$loadOnDemand = node.loadOnDemand;
var loadOnDemand = _node$loadOnDemand === undefined ? false : _node$loadOnDemand;
var children = node.children;
var state = node.state;
var depth = state.depth;
Expand All @@ -2220,6 +2259,9 @@ return /******/ (function(modules) { // webpackBootstrap
if (more && !open) {
togglerContent = '►';
}
if (!more && loadOnDemand) {
togglerContent = '►';
}
var toggler = (0, _helper.buildHTML)('a', togglerContent, {
'class': function () {
if (more && open) {
Expand All @@ -2228,6 +2270,9 @@ return /******/ (function(modules) { // webpackBootstrap
if (more && !open) {
return (0, _helper.classNames)('tree-toggler', 'tree-closed');
}
if (!more && loadOnDemand) {
return (0, _helper.classNames)('tree-toggler', 'tree-closed');
}
return '';
}()
});
Expand Down
6 changes: 3 additions & 3 deletions dist/infinite-tree.min.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions examples/animation.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// http://stackoverflow.com/questions/6410730/webkit-css-endless-rotation-animation-how
//
@-webkit-keyframes rotating /* Safari and Chrome */ {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.rotating {
animation: rotating 2s linear infinite;
}
4 changes: 2 additions & 2 deletions examples/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/bundle.js.map

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion examples/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import InfiniteTree from '../src';
import rowRenderer from './renderer';
import '../src/index.styl';
import './animation.styl';
import { addEventListener, preventDefault, stopPropagation, quoteattr } from '../src/helper';

const data = [];
const source = '{"id":"<root>","label":"<root>","props":{"droppable":true},"children":[{"id":"alpha","label":"Alpha","props":{"droppable":true}},{"id":"bravo","label":"Bravo","props":{"droppable":true},"children":[{"id":"charlie","label":"Charlie","props":{"droppable":true},"children":[{"id":"delta","label":"Delta","props":{"droppable":true},"children":[{"id":"echo","label":"Echo","props":{"droppable":true}},{"id":"foxtrot","label":"Foxtrot","props":{"droppable":true}}]},{"id":"golf","label":"Golf","props":{"droppable":true}}]},{"id":"hotel","label":"Hotel","props":{"droppable":true},"children":[{"id":"india","label":"India","props":{"droppable":true},"children":[{"id":"juliet","label":"Juliet","props":{"droppable":true}}]}]},{"id":"kilo","label":"Kilo","props":{"droppable":true}}]}]}';
const source = '{"id":"<root>","label":"<root>","props":{"droppable":true},"children":[{"id":"alpha","label":"Alpha","props":{"droppable":true}},{"id":"bravo","label":"Bravo","props":{"droppable":true},"children":[{"id":"charlie","label":"Charlie","props":{"droppable":true},"children":[{"id":"delta","label":"Delta","props":{"droppable":true},"children":[{"id":"echo","label":"Echo","props":{"droppable":true}},{"id":"foxtrot","label":"Foxtrot","props":{"droppable":true}}]},{"id":"golf","label":"Golf","props":{"droppable":true}}]},{"id":"hotel","label":"Hotel","props":{"droppable":true},"children":[{"id":"india","label":"India","props":{"droppable":true},"children":[{"id":"juliet","label":"Juliet","props":{"droppable":true}}]}]},{"id":"kilo","label":"(Load On Demand) Kilo","loadOnDemand":true,"props":{"droppable":true}}]}]}';

for (let i = 0; i < 1000; ++i) {
data.push(JSON.parse(source.replace(/"(id|label)":"([^"]*)"/g, '"$1": "$2.' + i + '"')));
Expand All @@ -29,6 +30,22 @@ const tree = new InfiniteTree({
autoOpen: true, // Defaults to false
droppable: true, // Defaults to false
el: document.querySelector('#tree'),
loadNodes: (parentNode, done) => {
const suffix = parentNode.id.replace(/(\w)+/, '');
const nodes = [
{
id: 'node1' + suffix,
label: 'Node 1'
},
{
id: 'node2' + suffix,
label: 'Node 2'
}
];
setTimeout(() => {
done(null, nodes);
}, 1000);
},
rowRenderer: rowRenderer,
selectable: true, // Defaults to true
shouldSelectNode: (node) => { // Defaults to null
Expand Down
66 changes: 40 additions & 26 deletions examples/renderer.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
import { buildHTML, classNames, quoteattr } from '../src/helper';

const rowRenderer = (node, treeOptions) => {
const { id, label, children, state, props } = node;
const { id, label, loadOnDemand = false, children, state, props = {} } = node;
const droppable = (treeOptions.droppable) && (props.droppable);
const { depth, open, path, total, selected = false } = state;
const { depth, open, path, total, loading = false, selected = false } = state;
const childrenLength = Object.keys(children).length;
const more = node.hasChildren();

let toggler = '';
if (more) {
let togglerContent = '';
if (open) {
togglerContent = buildHTML('i', '', {
'class': classNames('glyphicon', 'glyphicon-triangle-bottom')
});
}
if (!open) {
togglerContent = buildHTML('i', '', {
'class': classNames('glyphicon', 'glyphicon-triangle-right')
});
}
toggler = buildHTML('a', togglerContent, {
'class': (() => {
if (more && open) {
return classNames('tree-toggler');
}
if (more && !open) {
return classNames('tree-toggler', 'tree-closed');
}
return '';
})()
let togglerContent = '';
if (!more && loadOnDemand) {
togglerContent = buildHTML('i', '', {
'class': classNames('glyphicon', 'glyphicon-triangle-right')
});
}
if (more && open) {
togglerContent = buildHTML('i', '', {
'class': classNames('glyphicon', 'glyphicon-triangle-bottom')
});
}
if (more && !open) {
togglerContent = buildHTML('i', '', {
'class': classNames('glyphicon', 'glyphicon-triangle-right')
});
}
const toggler = buildHTML('a', togglerContent, {
'class': (() => {
if (!more && loadOnDemand) {
return classNames('tree-toggler', 'tree-closed');
}
if (more && open) {
return classNames('tree-toggler');
}
if (more && !open) {
return classNames('tree-toggler', 'tree-closed');
}
return '';
})()
});

const icon = buildHTML('i', '', {
'class': classNames(
Expand All @@ -45,10 +50,19 @@ const rowRenderer = (node, treeOptions) => {
const title = buildHTML('span', quoteattr(label), {
'class': classNames('tree-title')
});
const loadingIcon = buildHTML('i', '', {
'style': 'margin-left: 5px',
'class': classNames(
{ 'hidden': !loading },
'glyphicon',
'glyphicon-refresh',
{ 'rotating': loading }
)
});
const count = buildHTML('span', childrenLength, {
'class': 'count'
});
const treeNode = buildHTML('div', toggler + icon + title + count, {
const treeNode = buildHTML('div', toggler + icon + title + loadingIcon + count, {
'class': 'tree-node',
'style': 'margin-left: ' + depth * 18 + 'px'
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "infinite-tree",
"version": "0.6.3",
"version": "0.7.0",
"description": "A browser-ready tree library that can efficiently display a large tree with smooth scrolling.",
"homepage": "https://github.com/cheton/infinite-tree",
"main": "lib/index.js",
Expand Down
37 changes: 37 additions & 0 deletions src/infinite-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class InfiniteTree extends events.EventEmitter {
autoOpen: false,
droppable: false,
el: null,
loadNodes: null,
rowRenderer: defaultRowRenderer,
selectable: true,
shouldSelectNode: null
Expand Down Expand Up @@ -561,6 +562,42 @@ class InfiniteTree extends events.EventEmitter {
return false;
}

if (!node.hasChildren() && node.loadOnDemand) {
if (typeof this.options.loadNodes !== 'function') {
return false;
}

// Set loading state to true
node.state.loading = true;
this.rows[nodeIndex] = this.options.rowRenderer(node, this.options);

// Updates list with new data
this.update();

this.options.loadNodes(node, (err, nodes) => {
// Set loading state to false
node.state.loading = false;
this.rows[nodeIndex] = this.options.rowRenderer(node, this.options);

// Updates list with new data
this.update();

if (err) {
return;
}

// Append child nodes
nodes.forEach((childNode) => {
this.appendChildNode(childNode, node);
});

// Call openNode again
this.openNode(node);
});

return false;
}

node.state.open = true; // Set node.state.open to true
const openNodes = [node].concat(this.state.openNodes); // the most recently used items first
this.state.openNodes = openNodes;
Expand Down
8 changes: 7 additions & 1 deletion src/renderer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { buildHTML, classNames, quoteattr } from './helper';

const defaultRowRenderer = (node, treeOptions) => {
const { id, label, children, state } = node;
const { id, label, loadOnDemand = false, children, state } = node;
const { depth, open, path, total, selected = false } = state;
const childrenLength = Object.keys(children).length;
const more = node.hasChildren();
Expand All @@ -13,6 +13,9 @@ const defaultRowRenderer = (node, treeOptions) => {
if (more && !open) {
togglerContent = '►';
}
if (!more && loadOnDemand) {
togglerContent = '►';
}
const toggler = buildHTML('a', togglerContent, {
'class': (() => {
if (more && open) {
Expand All @@ -21,6 +24,9 @@ const defaultRowRenderer = (node, treeOptions) => {
if (more && !open) {
return classNames('tree-toggler', 'tree-closed');
}
if (!more && loadOnDemand) {
return classNames('tree-toggler', 'tree-closed');
}
return '';
})()
});
Expand Down

0 comments on commit 93b7d26

Please sign in to comment.