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
Changes from 2 commits
fc36c18
703e1b8
e56aad4
c171e27
2f867d6
f94707e
cdfe909
e4888fc
2f1aa05
c6b90bd
0387ccb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Tree Change History | ||
=================== | ||
|
||
@VERSION@ | ||
----- | ||
|
||
* Initial release. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
] | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
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; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Too generic. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly. I'm not a huge fan of |
||
this.tree.toggleNode(this, options); | ||
return this; | ||
} | ||
}; | ||
|
||
Y.Tree.Node.Openable = NodeOpenable; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
||
Y.Tree.Node.Selectable = NodeSelectable; |
There was a problem hiding this comment.
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 :)