Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y.Tree: An awesome generic tree data structure #429

Merged
merged 11 commits into from Feb 15, 2013
7 changes: 7 additions & 0 deletions src/tree/HISTORY.md
@@ -0,0 +1,7 @@
Tree Change History
===================

@VERSION@
-----

* Initial release.
17 changes: 17 additions & 0 deletions src/tree/README.md
@@ -0,0 +1,17 @@
Tree
====

Provides a generic tree data structure.

A tree has a root node, which may contain any number of child nodes, which may
themselves contain child nodes, ad infinitum.

Child nodes are lightweight function instances which delegate to the tree for
all significant functionality, so trees remain performant and memory-efficient
even with thousands and thousands of nodes.

The `Y.Tree` class doesn't expose any UI, but the following gallery modules are
examples of components that extend `Y.Tree` and provide a UI:

* [SmugMug Menu](https://github.com/smugmug/yui-gallery/src/sm-menu/)
* [SmugMug TreeView](https://github.com/smugmug/yui-gallery/src/sm-treeview/)
59 changes: 59 additions & 0 deletions src/tree/build.json
@@ -0,0 +1,59 @@
{
"name": "tree",

"builds": {
"tree": {
"jsfiles": [
"js/tree.js"
]
},

"tree-labelable": {
"jsfiles": [
"js/extensions/tree-labelable.js"
]
},

"tree-lazy": {
"jsfiles": [
"js/plugins/tree-lazy.js"
]
},

"tree-node": {
"jsfiles": [
"js/tree-node.js"
]
},

"tree-node-labelable": {
"jsfiles": [
"js/extensions/tree-node-labelable.js"
]
},

"tree-node-openable": {
"jsfiles": [
"js/extensions/tree-node-openable.js"
]
},

"tree-node-selectable": {
"jsfiles": [
"js/extensions/tree-node-selectable.js"
]
},

"tree-openable": {
"jsfiles": [
"js/extensions/tree-openable.js"
]
},

"tree-selectable": {
"jsfiles": [
"js/extensions/tree-selectable.js"
]
}
}
}
29 changes: 29 additions & 0 deletions src/tree/js/extensions/tree-labelable.js
@@ -0,0 +1,29 @@
/*jshint expr:true, onevar:false */

/**
Extension for `Tree` that adds baked-in support for node labels like you might
see in a treeview or menu.

@module tree
@submodule tree-labelable
@main tree-labelable
**/

/**
Extension for `Tree` that adds baked-in support for node labels like you might
see in a treeview or menu.

@class Tree.Labelable
@constructor
@extensionfor Tree
**/

function Labelable() {}

Labelable.prototype = {
initializer: function () {
this.nodeExtensions = this.nodeExtensions.concat(Y.Tree.Node.Labelable);
}
};

Y.Tree.Labelable = Labelable;
48 changes: 48 additions & 0 deletions src/tree/js/extensions/tree-node-labelable.js
@@ -0,0 +1,48 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge this class extension definition into the tree-labelable module? I don't see a need for them to be separate modules since they're close friends :)

Provides the `Tree.Node.Labelable` class, an extension for `Tree.Node` that
adds baked-in support for labels like you might see in a treeview or menu.

@module tree-labelable
@submodule tree-node-labelable
**/

/**
`Tree.Node` extension that adds baked in support for labels like you might see
in a treeview or menu.

**Security note:** The label is stored in raw, unescaped form. If you choose to
render the label as HTML, be sure to escape it first with `Y.Escape.html()`
unless you actually intend to render raw HTML contained in the label.

@class Tree.Node.Labelable
@constructor
@param {Tree} tree `Tree` instance with which this node should be associated.
@param {Object} [config] Configuration hash.
@param {String} [config.label=''] Label for this node.
@extensionfor Tree.Node
**/

function NodeLabelable(tree, config) {
this._serializable = this._serializable.concat('label');

if ('label' in config) {
this.label = config.label;
}
}

NodeLabelable.prototype = {
/**
Label for this node.

**Security note:** The label is stored in raw, unescaped form. If you choose
to render the label as HTML, be sure to escape it first with
`Y.Escape.html()` unless you actually intend to render raw HTML contained in
the label.

@property {String} label
@default ''
**/
label: ''
};

Y.Tree.Node.Labelable = NodeLabelable;
77 changes: 77 additions & 0 deletions src/tree/js/extensions/tree-node-openable.js
@@ -0,0 +1,77 @@
/**
Provides the `Tree.Node.Openable` class, an extension for `Tree.Node` that
adds methods useful for nodes in trees that use the `Tree.Openable` extension.

@module tree-openable
@submodule tree-node-openable
**/

/**
`Tree.Node` extension that adds methods useful for nodes in trees that use the
`Tree.Openable` extension.

@class Tree.Node.Openable
@constructor
@extensionfor Tree.Node
**/

function NodeOpenable() {}

NodeOpenable.prototype = {
/**
Closes this node if it's currently open.

@method close
@param {Object} [options] Options.
@param {Boolean} [options.silent=false] If `true`, the `close` event
will be suppressed.
@chainable
**/
close: function (options) {
this.tree.closeNode(this, options);
return this;
},

/**
Returns `true` if this node is currently open.

Note: the root node of a tree is always considered to be open.

@method isOpen
@return {Boolean} `true` if this node is currently open, `false` otherwise.
**/
isOpen: function () {
return !!this.state.open || this.isRoot();
},

/**
Opens this node if it's currently closed.

@method open
@param {Object} [options] Options.
@param {Boolean} [options.silent=false] If `true`, the `open` event
will be suppressed.
@chainable
**/
open: function (options) {
this.tree.openNode(this, options);
return this;
},

/**
Toggles the open/closed state of this node, closing it if it's currently
open or opening it if it's currently closed.

@method toggle
@param {Object} [options] Options.
@param {Boolean} [options.silent=false] If `true`, events will be
suppressed.
@chainable
**/
toggle: function (options) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too generic. I think toggleOpen() and toggleOpenNode() (for the Tree) will increase clarity and reduce collisions with other possible extensions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly. I'm not a huge fan of toggleOpen(), but I'll think about it.

this.tree.toggleNode(this, options);
return this;
}
};

Y.Tree.Node.Openable = NodeOpenable;
61 changes: 61 additions & 0 deletions src/tree/js/extensions/tree-node-selectable.js
@@ -0,0 +1,61 @@
/**
Provides the `Tree.Node.Selectable` class, an extension for `Tree.Node` that
adds methods useful for nodes in trees that use the `Tree.Selectable` extension.

@module tree-selectable
@submodule tree-node-selectable
**/

/**
`Tree.Node` extension that adds methods useful for nodes in trees that use the
`Tree.Selectable` extension.

@class Tree.Node.Selectable
@constructor
@extensionfor Tree.Node
**/

function NodeSelectable() {}

NodeSelectable.prototype = {
/**
Returns `true` if this node is currently selected.

@method isSelected
@return {Boolean} `true` if this node is currently selected, `false`
otherwise.
**/
isSelected: function () {
return !!this.state.selected;
},

/**
Selects this node.

@method select
@param {Object} [options] Options.
@param {Boolean} [options.silent=false] If `true`, the `select` event
will be suppressed.
@chainable
**/
select: function (options) {
this.tree.selectNode(this, options);
return this;
},

/**
Unselects this node.

@method unselect
@param {Object} [options] Options.
@param {Boolean} [options.silent=false] If `true`, the `unselect` event
will be suppressed.
@chainable
**/
unselect: function (options) {
this.tree.unselectNode(this, options);
return this;
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add toggleSelect()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selection isn't something you generally need to toggle. I've never had a case where I've needed that. It's typically something you're explicit about (which is why I gave toggle() to Openable).


Y.Tree.Node.Selectable = NodeSelectable;