📄 treeview.js
字号:
} } } break; case 'UL': case 'OL': build(node, el); break; } } } }; var markup = Dom.getChildrenBy(Dom.get(id),function (el) { var tag = el.tagName.toUpperCase(); return tag == 'UL' || tag == 'OL'; }); if (markup.length) { build(this.root, markup[0]); } else { } }, /** * Renders the tree boilerplate and visible nodes * @method render */ render: function() { var html = this.root.getHtml(); this.getEl().innerHTML = html; var getTarget = function (ev) { var target = Event.getTarget(ev); if (target.tagName.toUpperCase() != 'TD') { target = Dom.getAncestorByTagName(target,'td'); } if (Lang.isNull(target)) { return null; } if (target.className.length === 0) { target = target.previousSibling; if (Lang.isNull(target)) { return null; } } return target; }; if (!this._hasEvents) { Event.on( this.getEl(), 'click', function (ev) { var self = this, el = Event.getTarget(ev), node = this.getNodeByElement(el); if (!node) { return; } var toggle = function () { if (node.expanded) { node.collapse(); } else { node.expand(); } node.focus(); }; if (Dom.hasClass(el, node.labelStyle) || Dom.getAncestorByClassName(el,node.labelStyle)) { this.fireEvent('labelClick',node); } while (el && !Dom.hasClass(el.parentNode,'ygtvrow') && !/ygtv[tl][mp]h?h?/.test(el.className)) { el = Dom.getAncestorByTagName(el,'td'); } if (el) { // If it is a spacer cell, do nothing if (/ygtv(blank)?depthcell/.test(el.className)) { return;} // If it is a toggle cell, toggle if (/ygtv[tl][mp]h?h?/.test(el.className)) { toggle(); } else { if (this._dblClickTimer) { window.clearTimeout(this._dblClickTimer); this._dblClickTimer = null; } else { if (this._hasDblClickSubscriber) { this._dblClickTimer = window.setTimeout(function () { self._dblClickTimer = null; if (self.fireEvent('clickEvent', {event:ev,node:node}) !== false) { toggle(); } }, 200); } else { if (self.fireEvent('clickEvent', {event:ev,node:node}) !== false) { toggle(); } } } } } }, this, true ); Event.on( this.getEl(), 'dblclick', function (ev) { if (!this._hasDblClickSubscriber) { return; } var el = Event.getTarget(ev); while (!Dom.hasClass(el.parentNode,'ygtvrow')) { el = Dom.getAncestorByTagName(el,'td'); } if (/ygtv(blank)?depthcell/.test(el.className)) { return;} if (!(/ygtv[tl][mp]h?h?/.test(el.className))) { this.fireEvent('dblClickEvent', {event:ev, node:this.getNodeByElement(el)}); if (this._dblClickTimer) { window.clearTimeout(this._dblClickTimer); this._dblClickTimer = null; } } }, this, true ); Event.on( this.getEl(), 'mouseover', function (ev) { var target = getTarget(ev); if (target) {target.className = target.className.replace(/ygtv([lt])([mp])/gi, 'ygtv$1$2h').replace(/h+/, 'h'); } } ); Event.on( this.getEl(), 'mouseout', function (ev) { var target = getTarget(ev); if (target) { target.className = target.className.replace(/ygtv([lt])([mp])h/gi,'ygtv$1$2'); } } ); Event.on( this.getEl(), 'keydown', function (ev) { var target = Event.getTarget(ev), node = this.getNodeByElement(target), newNode = node, KEY = YAHOO.util.KeyListener.KEY; switch(ev.keyCode) { case KEY.UP: do { if (newNode.previousSibling) { newNode = newNode.previousSibling; } else { newNode = newNode.parent; } } while (newNode && !newNode.focus()); if (!newNode) { node.focus(); } Event.preventDefault(ev); break; case KEY.DOWN: do { if (newNode.nextSibling) { newNode = newNode.nextSibling; } else { newNode.expand(); newNode = (newNode.children.length || null) && newNode.children[0]; } } while (newNode && !newNode.focus()); if (!newNode) { node.focus(); } Event.preventDefault(ev); break; case KEY.LEFT: do { if (newNode.parent) { newNode = newNode.parent; } else { newNode = newNode.previousSibling; } } while (newNode && !newNode.focus()); if (!newNode) { node.focus(); } Event.preventDefault(ev); break; case KEY.RIGHT: do { newNode.expand(); if (newNode.children.length) { newNode = newNode.children[0]; } else { newNode = newNode.nextSibling; } } while (newNode && !newNode.focus()); if (!newNode) { node.focus(); } Event.preventDefault(ev); break; case KEY.ENTER: if (node.href) { if (node.target) { window.open(node.href,node.target); } else { window.location(node.href); } } else { node.toggle(); } this.fireEvent('enterKeyPressed',node); Event.preventDefault(ev); break; case KEY.HOME: newNode = this.getRoot(); if (newNode.children.length) {newNode = newNode.children[0];} if (!newNode.focus()) { node.focus(); } Event.preventDefault(ev); break; case KEY.END: newNode = newNode.parent.children; newNode = newNode[newNode.length -1]; if (!newNode.focus()) { node.focus(); } Event.preventDefault(ev); break; // case KEY.PAGE_UP: // break; // case KEY.PAGE_DOWN: // break; case 107: // plus key if (ev.shiftKey) { node.parent.expandAll(); } else { node.expand(); } break; case 109: // minus key if (ev.shiftKey) { node.parent.collapseAll(); } else { node.collapse(); } break; default: break; } }, this, true ); } this._hasEvents = true; }, /** * Returns the tree's host element * @method getEl * @return {HTMLElement} the host element */ getEl: function() { if (! this._el) { this._el = Dom.get(this.id); } return this._el; }, /** * Nodes register themselves with the tree instance when they are created. * @method regNode * @param node {Node} the node to register * @private */ regNode: function(node) { this._nodes[node.index] = node; }, /** * Returns the root node of this tree * @method getRoot * @return {Node} the root node */ getRoot: function() { return this.root; }, /** * Configures this tree to dynamically load all child data * @method setDynamicLoad * @param {function} fnDataLoader the function that will be called 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) { this.root.setDynamicLoad(fnDataLoader, iconMode); }, /** * Expands all child nodes. Note: this conflicts with the "multiExpand" * node property. If expand all is called in a tree with nodes that * do not allow multiple siblings to be displayed, only the last sibling * will be expanded. * @method expandAll */ expandAll: function() { if (!this.locked) { this.root.expandAll(); } }, /** * Collapses all expanded child nodes in the entire tree. * @method collapseAll */ collapseAll: function() { if (!this.locked) { this.root.collapseAll(); } }, /** * Returns a node in the tree that has the specified index (this index * is created internally, so this function probably will only be used * in html generated for a given node.) * @method getNodeByIndex * @param {int} nodeIndex the index of the node wanted * @return {Node} the node with index=nodeIndex, null if no match */ getNodeByIndex: function(nodeIndex) { var n = this._nodes[nodeIndex]; return (n) ? n : null; }, /** * Returns a node that has a matching property and value in the data * object that was passed into its constructor. * @method getNodeByProperty * @param {object} property the property to search (usually a string) * @param {object} value the value we want to find (usuall an int or string) * @return {Node} the matching node, null if no match */ getNodeByProperty: function(property, value) { for (var i in this._nodes) { if (this._nodes.hasOwnProperty(i)) { var n = this._nodes[i]; if (n.data && value == n.data[property]) { return n; } } } return null; }, /** * Returns a collection of nodes that have a matching property * and value in the data object that was passed into its constructor. * @method getNodesByProperty * @param {object} property the property to search (usually a string) * @param {object} value the value we want to find (usuall an int or string) * @return {Array} the matching collection of nodes, null if no match */ getNodesByProperty: function(property, value) { var values = []; for (var i in this._nodes) { if (this._nodes.hasOwnProperty(i)) { var n = this._nodes[i]; if (n.data && value == n.data[property]) { values.push(n); } } } return (values.length) ? values : null; }, /** * Returns the treeview node reference for an anscestor element * of the node, or null if it is not contained within any node * in this tree. * @method getNodeByElement * @param {HTMLElement} the element to test * @return {YAHOO.widget.Node} a node reference or null */ getNodeByElement: function(el) { var p=el, m, re=/ygtv([^\d]*)(.*)/; do { if (p && p.id) { m = p.id.match(re); if (m && m[2]) { return this.getNodeByIndex(m[2]); } } p = p.parentNode; if (!p || !p.tagName) { break; } } while (p.id !== this.id && p.tagName.toLowerCase() !== "body"); return null; }, /** * Removes the node and its children, and optionally refreshes the * branch of the tree that was affected. * @method removeNode * @param {Node} The node to remove * @param {boolean} autoRefresh automatically refreshes branch if true * @return {boolean} False is there was a problem, true otherwise. */ removeNode: function(node, autoRefresh) { // Don't delete the root node if (node.isRoot()) { return false; } // Get the branch that we may need to refresh var p = node.parent; if (p.parent) { p = p.parent; } // Delete the node and its children this._deleteNode(node); // Refresh the parent of the parent if (autoRefresh && p && p.childrenRendered) { p.refresh(); } return true; }, /** * wait until the animation is complete before deleting * to avoid javascript errors * @method _removeChildren_animComplete * @param o the custom event payload * @private */ _removeChildren_animComplete: function(o) { this.unsubscribe(this._removeChildren_animComplete); this.removeChildren(o.node); }, /** * Deletes this nodes child collection, recursively. Also collapses * the node, and resets the dynamic load flag. The primary use for * this method is to purge a node and allow it to fetch its data * dynamically again. * @method removeChildren * @param {Node} node the node to purge */ removeChildren: function(node) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -