📄 treeview.js
字号:
/**
* Returns the element that is being used for this node's spacer.
* @return {HTMLElement} this node's spacer html element
*/
/*
getSpacer: function() {
return document.getElementById( this.getSpacerId() ) || {};
},
*/
/*
getStateText: function() {
if (this.isLoading) {
return this.loadingText;
} else if (this.hasChildren(true)) {
if (this.expanded) {
return this.expandedText;
} else {
return this.collapsedText;
}
} else {
return "";
}
},
*/
/**
* Generates the link that will invoke this node's toggle method
* @return {string} the javascript url for toggling this node
*/
getToggleLink: function() {
return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," +
this.index + ").toggle()";
},
/**
* Hides this nodes children (creating them if necessary), changes the
* toggle style.
*/
collapse: function() {
// Only collapse if currently expanded
if (!this.expanded) { return; }
// fire the collapse event handler
var ret = this.tree.onCollapse(this);
if ("undefined" != typeof ret && !ret) {
return;
}
if (!this.getEl()) {
this.expanded = false;
return;
}
// hide the child div
this.hideChildren();
this.expanded = false;
if (this.hasIcon) {
this.getToggleEl().className = this.getStyle();
}
// this.getSpacer().title = this.getStateText();
},
/**
* Shows this nodes children (creating them if necessary), changes the
* toggle style, and collapses its siblings if multiExpand is not set.
*/
expand: function() {
// Only expand if currently collapsed.
if (this.expanded) { return; }
// fire the expand event handler
var ret = this.tree.onExpand(this);
if ("undefined" != typeof ret && !ret) {
return;
}
if (!this.getEl()) {
this.expanded = true;
return;
}
if (! this.childrenRendered) {
this.getChildrenEl().innerHTML = this.renderChildren();
} else {
}
this.expanded = true;
if (this.hasIcon) {
this.getToggleEl().className = this.getStyle();
}
// this.getSpacer().title = this.getStateText();
// We do an extra check for children here because the lazy
// load feature can expose nodes that have no children.
// if (!this.hasChildren()) {
if (this.isLoading) {
this.expanded = false;
return;
}
if (! this.multiExpand) {
var sibs = this.getSiblings();
for (var i=0; i<sibs.length; ++i) {
if (sibs[i] != this && sibs[i].expanded) {
sibs[i].collapse();
}
}
}
this.showChildren();
},
/**
* Returns the css style name for the toggle
*
* @return {string} the css class for this node's toggle
*/
getStyle: function() {
if (this.isLoading) {
return "ygtvloading";
} else {
// location top or bottom, middle nodes also get the top style
var loc = (this.nextSibling) ? "t" : "l";
// type p=plus(expand), m=minus(collapase), n=none(no children)
var type = "n";
if (this.hasChildren(true) || (this.isDynamic() && !this.getIconMode())) {
// if (this.hasChildren(true)) {
type = (this.expanded) ? "m" : "p";
}
return "ygtv" + loc + type;
}
},
/**
* Returns the hover style for the icon
* @return {string} the css class hover state
*/
getHoverStyle: function() {
var s = this.getStyle();
if (this.hasChildren(true) && !this.isLoading) {
s += "h";
}
return s;
},
/**
* Recursively expands all of this node's children.
*/
expandAll: function() {
for (var i=0;i<this.children.length;++i) {
var c = this.children[i];
if (c.isDynamic()) {
alert("Not supported (lazy load + expand all)");
break;
} else if (! c.multiExpand) {
alert("Not supported (no multi-expand + expand all)");
break;
} else {
c.expand();
c.expandAll();
}
}
},
/**
* Recursively collapses all of this node's children.
*/
collapseAll: function() {
for (var i=0;i<this.children.length;++i) {
this.children[i].collapse();
this.children[i].collapseAll();
}
},
/**
* Configures this node for dynamically obtaining the child data
* when the node is first expanded. Calling it without the callback
* will turn off dynamic load for the node.
*
* @param fmDataLoader {function} the function that will be used to get the data.
* @param iconMode {int} configures the icon that is displayed when a dynamic
* load node is expanded the first time without children. By default, the
* "collapse" icon will be used. If set to 1, the leaf node icon will be
* displayed.
*/
setDynamicLoad: function(fnDataLoader, iconMode) {
if (fnDataLoader) {
this.dataLoader = fnDataLoader;
this._dynLoad = true;
} else {
this.dataLoader = null;
this._dynLoad = false;
}
if (iconMode) {
this.iconMode = iconMode;
}
},
/**
* Evaluates if this node is the root node of the tree
*
* @return {boolean} true if this is the root node
*/
isRoot: function() {
return (this == this.tree.root);
},
/**
* Evaluates if this node's children should be loaded dynamically. Looks for
* the property both in this instance and the root node. If the tree is
* defined to load all children dynamically, the data callback function is
* defined in the root node
*
* @return {boolean} true if this node's children are to be loaded dynamically
*/
isDynamic: function() {
var lazy = (!this.isRoot() && (this._dynLoad || this.tree.root._dynLoad));
return lazy;
},
getIconMode: function() {
return (this.iconMode || this.tree.root.iconMode);
},
/**
* Checks if this node has children. If this node is lazy-loading and the
* children have not been rendered, we do not know whether or not there
* are actual children. In most cases, we need to assume that there are
* children (for instance, the toggle needs to show the expandable
* presentation state). In other times we want to know if there are rendered
* children. For the latter, "checkForLazyLoad" should be false.
*
* @param checkForLazyLoad {boolean} should we check for unloaded children?
* @return {boolean} true if this has children or if it might and we are
* checking for this condition.
*/
hasChildren: function(checkForLazyLoad) {
return ( this.children.length > 0 ||
(checkForLazyLoad && this.isDynamic() && !this.dynamicLoadComplete) );
},
/**
* Expands if node is collapsed, collapses otherwise.
*/
toggle: function() {
if (!this.tree.locked && ( this.hasChildren(true) || this.isDynamic()) ) {
if (this.expanded) { this.collapse(); } else { this.expand(); }
}
},
/**
* Returns the markup for this node and its children.
*
* @return {string} the markup for this node and its expanded children.
*/
getHtml: function() {
var sb = [];
sb[sb.length] = '<div class="ygtvitem" id="' + this.getElId() + '">';
sb[sb.length] = this.getNodeHtml();
sb[sb.length] = this.getChildrenHtml();
sb[sb.length] = '</div>';
return sb.join("");
},
/**
* Called when first rendering the tree. We always build the div that will
* contain this nodes children, but we don't render the children themselves
* unless this node is expanded.
*
* @return {string} the children container div html and any expanded children
* @private
*/
getChildrenHtml: function() {
var sb = [];
sb[sb.length] = '<div class="ygtvchildren"';
sb[sb.length] = ' id="' + this.getChildrenElId() + '"';
if (!this.expanded) {
sb[sb.length] = ' style="display:none;"';
}
sb[sb.length] = '>';
// Don't render the actual child node HTML unless this node is expanded.
if ( (this.hasChildren(true) && this.expanded) ||
(this.renderHidden && !this.isDynamic()) ) {
sb[sb.length] = this.renderChildren();
}
sb[sb.length] = '</div>';
return sb.join("");
},
/**
* Generates the markup for the child nodes. This is not done until the node
* is expanded.
*
* @return {string} the html for this node's children
* @private
*/
renderChildren: function() {
var node = this;
if (this.isDynamic() && !this.dynamicLoadComplete) {
this.isLoading = true;
this.tree.locked = true;
if (this.dataLoader) {
setTimeout(
function() {
node.dataLoader(node,
function() {
node.loadComplete();
});
}, 10);
} else if (this.tree.root.dataLoader) {
setTimeout(
function() {
node.tree.root.dataLoader(node,
function() {
node.loadComplete();
});
}, 10);
} else {
return "Error: data loader not found or not specified.";
}
return "";
} else {
return this.completeRender();
}
},
/**
* Called when we know we have all the child data.
* @return {string} children html
*/
completeRender: function() {
var sb = [];
for (var i=0; i < this.children.length; ++i) {
this.children[i].childrenRendered = false;
sb[sb.length] = this.children[i].getHtml();
}
this.childrenRendered = true;
return sb.join("");
},
/**
* Load complete is the callback function we pass to the data provider
* in dynamic load situations.
*/
loadComplete: function() {
this.getChildrenEl().innerHTML = this.completeRender();
this.dynamicLoadComplete = true;
this.isLoading = false;
this.expand();
this.tree.locked = false;
},
/**
* Returns this node's ancestor at the specified depth.
*
* @param {int} depth the depth of the ancestor.
* @return {Node} the ancestor
*/
getAncestor: function(depth) {
if (depth >= this.depth || depth < 0) {
return null;
}
var p = this.parent;
while (p.depth > depth) {
p = p.parent;
}
return p;
},
/**
* Returns the css class for the spacer at the specified depth for
* this node. If this node's ancestor at the specified depth
* has a next sibling the presentation is different than if it
* does not have a next sibling
*
* @param {int} depth the depth of the ancestor.
* @return {string} the css class for the spacer
*/
getDepthStyle: function(depth) {
return (this.getAncestor(depth).nextSibling) ?
"ygtvdepthcell" : "ygtvblankdepthcell";
},
/**
* Get the markup for the node. This is designed to be overrided so that we can
* support different types of nodes.
*
* @return {string} The HTML that will render this node.
*/
getNodeHtml: function() {
return "";
},
/**
* Regenerates the html for this node and its children. To be used when the
* node is expanded and new children have been added.
*/
refresh: function() {
// this.loadComplete();
this.getChildrenEl().innerHTML = this.completeRender();
if (this.hasIcon) {
var el = this.getToggleEl();
if (el) {
el.className = this.getStyle();
}
}
},
/**
* toString
* @return {string} string representation of the node
*/
toString: function() {
return "Node (" + this.index + ")";
}
};
/**
* A custom YAHOO.widget.Node that handles the unique nature of
* the virtual, presentationless root node.
*
* @extends YAHOO.widget.Node
* @constructor
*/
YAHOO.widget.RootNode = function(oTree) {
// Initialize the node with null params. The root node is a
// special case where the node has no presentation. So we have
// to alter the standard properties a bit.
this.init(null, null, true);
/**
* For the root node, we get the tree reference from as a param
* to the constructor instead of from the parent element.
*
* @type TreeView
*/
this.tree = oTree;
};
YAHOO.widget.RootNode.prototype = new YAHOO.widget.Node();
// overrides YAHOO.widget.Node
YAHOO.widget.RootNode.prototype.getNodeHtml = function() {
return "";
};
YAHOO.widget.RootNode.prototype.toString = function() {
return "RootNode";
};
YAHOO.widget.RootNode.prototype.loadComplete = function() {
this.tree.draw();
};
/**
* The default node presentation. The first parameter should be
* either a string that will be used as the node's label, or an object
* that has a string propery called label. By default, the clicking the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -