Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 2.8.2r1
*/
(function () {
var Dom = YAHOO.util.Dom,
Event = YAHOO.util.Event,
Lang = YAHOO.lang,
Widget = YAHOO.widget;
/**
* The treeview widget is a generic tree building tool.
* @module treeview
* @title TreeView Widget
* @requires yahoo, dom, event
* @optional animation, json, calendar
* @namespace YAHOO.widget
*/
/**
* Contains the tree view state data and the root node.
*
* @class TreeView
* @uses YAHOO.util.EventProvider
* @constructor
* @param {string|HTMLElement} id The id of the element, or the element itself that the tree will be inserted into.
* Existing markup in this element, if valid, will be used to build the tree
* @param {Array|Object|String} oConfig (optional) If present, it will be used to build the tree via method <a href="#method_buildTreeFromObject">buildTreeFromObject</a>
*
*/
YAHOO.widget.TreeView = function(id, oConfig) {
if (id) { this.init(id); }
if (oConfig) {
this.buildTreeFromObject(oConfig);
} else if (Lang.trim(this._el.innerHTML)) {
this.buildTreeFromMarkup(id);
}
};
var TV = Widget.TreeView;
TV.prototype = {
/**
* The id of tree container element
* @property id
* @type String
*/
id: null,
/**
* The host element for this tree
* @property _el
* @private
* @type HTMLelement
*/
_el: null,
/**
* Flat collection of all nodes in this tree. This is a sparse
* array, so the length property can't be relied upon for a
* node count for the tree.
* @property _nodes
* @type Node[]
* @private
*/
_nodes: null,
/**
* We lock the tree control while waiting for the dynamic loader to return
* @property locked
* @type boolean
*/
locked: false,
/**
* The animation to use for expanding children, if any
* @property _expandAnim
* @type string
* @private
*/
_expandAnim: null,
/**
* The animation to use for collapsing children, if any
* @property _collapseAnim
* @type string
* @private
*/
_collapseAnim: null,
/**
* The current number of animations that are executing
* @property _animCount
* @type int
* @private
*/
_animCount: 0,
/**
* The maximum number of animations to run at one time.
* @property maxAnim
* @type int
*/
maxAnim: 2,
/**
* Whether there is any subscriber to dblClickEvent
* @property _hasDblClickSubscriber
* @type boolean
* @private
*/
_hasDblClickSubscriber: false,
/**
* Stores the timer used to check for double clicks
* @property _dblClickTimer
* @type window.timer object
* @private
*/
_dblClickTimer: null,
/**
* A reference to the Node currently having the focus or null if none.
* @property currentFocus
* @type YAHOO.widget.Node
*/
currentFocus: null,
/**
* If true, only one Node can be highlighted at a time
* @property singleNodeHighlight
* @type boolean
* @default false
*/
singleNodeHighlight: false,
/**
* A reference to the Node that is currently highlighted.
* It is only meaningful if singleNodeHighlight is enabled
* @property _currentlyHighlighted
* @type YAHOO.widget.Node
* @default null
* @private
*/
_currentlyHighlighted: null,
/**
* Sets up the animation for expanding children
* @method setExpandAnim
* @param {string} type the type of animation (acceptable values defined
* in YAHOO.widget.TVAnim)
*/
setExpandAnim: function(type) {
this._expandAnim = (Widget.TVAnim.isValid(type)) ? type : null;
},
/**
* Sets up the animation for collapsing children
* @method setCollapseAnim
* @param {string} type of animation (acceptable values defined in
* YAHOO.widget.TVAnim)
*/
setCollapseAnim: function(type) {
this._collapseAnim = (Widget.TVAnim.isValid(type)) ? type : null;
},
/**
* Perform the expand animation if configured, or just show the
* element if not configured or too many animations are in progress
* @method animateExpand
* @param el {HTMLElement} the element to animate
* @param node {YAHOO.util.Node} the node that was expanded
* @return {boolean} true if animation could be invoked, false otherwise
*/
animateExpand: function(el, node) {
this.logger.log("animating expand");
if (this._expandAnim && this._animCount < this.maxAnim) {
// this.locked = true;
var tree = this;
var a = Widget.TVAnim.getAnim(this._expandAnim, el,
function() { tree.expandComplete(node); });
if (a) {
++this._animCount;
this.fireEvent("animStart", {
"node": node,
"type": "expand"
});
a.animate();
}
return true;
}
return false;
},
/**
* Perform the collapse animation if configured, or just show the
* element if not configured or too many animations are in progress
* @method animateCollapse
* @param el {HTMLElement} the element to animate
* @param node {YAHOO.util.Node} the node that was expanded
* @return {boolean} true if animation could be invoked, false otherwise
*/
animateCollapse: function(el, node) {
this.logger.log("animating collapse");
if (this._collapseAnim && this._animCount < this.maxAnim) {
// this.locked = true;
var tree = this;
var a = Widget.TVAnim.getAnim(this._collapseAnim, el,
function() { tree.collapseComplete(node); });
if (a) {
++this._animCount;
this.fireEvent("animStart", {
"node": node,
"type": "collapse"
});
a.animate();
}
return true;
}
return false;
},
/**
* Function executed when the expand animation completes
* @method expandComplete
*/
expandComplete: function(node) {
this.logger.log("expand complete: " + this.id);
--this._animCount;
this.fireEvent("animComplete", {
"node": node,
"type": "expand"
});
// this.locked = false;
},
/**
* Function executed when the collapse animation completes
* @method collapseComplete
*/
collapseComplete: function(node) {
this.logger.log("collapse complete: " + this.id);
--this._animCount;
this.fireEvent("animComplete", {
"node": node,
"type": "collapse"
});
// this.locked = false;
},
/**
* Initializes the tree
* @method init
* @parm {string|HTMLElement} id the id of the element that will hold the tree
* Finally displays the newly entered date in the tree.
* Overrides Node.displayEditedValue.
* @method displayEditedValue
* @param value {string} date to be displayed and stored in the node
* @param editorData {YAHOO.widget.TreeView.editorData} a shortcut to the static object holding editing information
*/
displayEditedValue: function (value,editorData) {
var node = editorData.node;
node.label = value;
node.getLabelEl().innerHTML = value;
},
/**
* Returns an object which could be used to build a tree out of this node and its children.
* It can be passed to the tree constructor to reproduce this node as a tree.
* It will return false if the node or any descendant loads dynamically, regardless of whether it is loaded or not.
* @method getNodeDefinition
* @return {Object | false} definition of the node or false if this node or any descendant is defined as dynamic
*/
getNodeDefinition: function() {
var def = YAHOO.widget.DateNode.superclass.getNodeDefinition.call(this);
if (def === false) { return false; }
if (this.calendarConfig) { def.calendarConfig = this.calendarConfig; }
return def;
}
});
})();
(function () {
var Dom = YAHOO.util.Dom,
Lang = YAHOO.lang,
Event = YAHOO.util.Event,
TV = YAHOO.widget.TreeView,
TVproto = TV.prototype;
/**
* An object to store information used for in-line editing
* for all Nodes of all TreeViews. It contains:
* <ul>
* <li>active {boolean}, whether there is an active cell editor </li>
* <li>whoHasIt {YAHOO.widget.TreeView} TreeView instance that is currently using the editor</li>
* <li>nodeType {string} value of static Node._type property, allows reuse of input element if node is of the same type.</li>
* <li>editorPanel {HTMLelement (<div>)} element holding the in-line editor</li>
* <li>inputContainer {HTMLelement (<div>)} element which will hold the type-specific input element(s) to be filled by the fillEditorContainer method</li>
* <li>buttonsContainer {HTMLelement (<div>)} element which holds the <button> elements for Ok/Cancel. If you don't want any of the buttons, hide it via CSS styles, don't destroy it</li>
* <li>node {YAHOO.widget.Node} reference to the Node being edited</li>
* <li>saveOnEnter {boolean}, whether the Enter key should be accepted as a Save command (Esc. is always taken as Cancel), disable for multi-line input elements </li>
* <li>oldValue {any} value before editing</li>
* </ul>
* Editors are free to use this object to store additional data.
* @property editorData
* @static
* @for YAHOO.widget.TreeView
*/
TV.editorData = {
active:false,
whoHasIt:null, // which TreeView has it
nodeType:null,
editorPanel:null,
inputContainer:null,
buttonsContainer:null,
node:null, // which Node is being edited
saveOnEnter:true,
oldValue:undefined
// Each node type is free to add its own properties to this as it sees fit.
};
/**
* Validator function for edited data, called from the TreeView instance scope,
* receives the arguments (newValue, oldValue, nodeInstance)
* and returns either the validated (or type-converted) value or undefined.
* An undefined return will prevent the editor from closing
* @property validator
* @type function
* @default null
* @for YAHOO.widget.TreeView
*/
TVproto.validator = null;
/**
* Entry point for initializing the editing plug-in.
* TreeView will call this method on initializing if it exists
* @method _initEditor
* @for YAHOO.widget.TreeView
* @private
*/
TVproto._initEditor = function () {
/**
* Fires when the user clicks on the ok button of a node editor
* @event editorSaveEvent
* @type CustomEvent
* @param oArgs.newValue {mixed} the new value just entered
* @param oArgs.oldValue {mixed} the value originally in the tree
* @param oArgs.node {YAHOO.widget.Node} the node that has the focus
* @for YAHOO.widget.TreeView
*/
this.createEvent("editorSaveEvent", this);
/**
* Fires when the user clicks on the cancel button of a node editor
* @event editorCancelEvent
* @type CustomEvent
* @param {YAHOO.widget.Node} node the node that has the focus
* @for YAHOO.widget.TreeView
*/
this.createEvent("editorCancelEvent", this);
};
/**
* Entry point of the editing plug-in.
* TreeView will call this method if it exists when a node label is clicked
* @method _nodeEditing
* @param node {YAHOO.widget.Node} the node to be edited
* @return {Boolean} true to indicate that the node is editable and prevent any further bubbling of the click.
* @for YAHOO.widget.TreeView
* @private
*/
TVproto._nodeEditing = function (node) {
if (node.fillEditorContainer && node.editable) {
var ed, topLeft, buttons, button, editorData = TV.editorData;
editorData.active = true;
editorData.whoHasIt = this;
if (!editorData.nodeType) {
editorData.editorPanel = ed = document.body.appendChild(document.createElement('div'));