pkg-tree-debug.js
资源名称:ext-3.1.0.zip [点击查看]
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:150k
源码类别:
JavaScript
开发平台:
JavaScript
- if(fn.call(scope||cs[i], cs[i]) === true){
- return cs[i];
- }
- }
- return null;
- },
- /**
- * Sorts this nodes children using the supplied sort function.
- * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.
- * @param {Object} scope (optional)The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
- */
- sort : function(fn, scope){
- var cs = this.childNodes;
- var len = cs.length;
- if(len > 0){
- var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
- cs.sort(sortFn);
- for(var i = 0; i < len; i++){
- var n = cs[i];
- n.previousSibling = cs[i-1];
- n.nextSibling = cs[i+1];
- if(i === 0){
- this.setFirstChild(n);
- }
- if(i == len-1){
- this.setLastChild(n);
- }
- }
- }
- },
- /**
- * Returns true if this node is an ancestor (at any point) of the passed node.
- * @param {Node} node
- * @return {Boolean}
- */
- contains : function(node){
- return node.isAncestor(this);
- },
- /**
- * Returns true if the passed node is an ancestor (at any point) of this node.
- * @param {Node} node
- * @return {Boolean}
- */
- isAncestor : function(node){
- var p = this.parentNode;
- while(p){
- if(p == node){
- return true;
- }
- p = p.parentNode;
- }
- return false;
- },
- toString : function(){
- return "[Node"+(this.id?" "+this.id:"")+"]";
- }
- });/**
- * @class Ext.tree.TreeNode
- * @extends Ext.data.Node
- * @cfg {String} text The text for this node
- * @cfg {Boolean} expanded true to start the node expanded
- * @cfg {Boolean} allowDrag False to make this node undraggable if {@link #draggable} = true (defaults to true)
- * @cfg {Boolean} allowDrop False if this node cannot have child nodes dropped on it (defaults to true)
- * @cfg {Boolean} disabled true to start the node disabled
- * @cfg {String} icon The path to an icon for the node. The preferred way to do this
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.
- * @cfg {String} cls A css class to be added to the node
- * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
- * @cfg {String} href URL of the link used for the node (defaults to #)
- * @cfg {String} hrefTarget target frame for the link
- * @cfg {Boolean} hidden True to render hidden. (Defaults to false).
- * @cfg {String} qtip An Ext QuickTip for the node
- * @cfg {Boolean} expandable If set to true, the node will always show a plus/minus icon, even when empty
- * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
- * @cfg {Boolean} singleClickExpand True for single click expand on this node
- * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Ext.tree.TreeNodeUI)
- * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
- * (defaults to undefined with no checkbox rendered)
- * @cfg {Boolean} draggable True to make this node draggable (defaults to false)
- * @cfg {Boolean} isTarget False to not allow this node to act as a drop target (defaults to true)
- * @cfg {Boolean} allowChildren False to not allow this node to have child nodes (defaults to true)
- * @cfg {Boolean} editable False to not allow this node to be edited by an {@link Ext.tree.TreeEditor} (defaults to true)
- * @constructor
- * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
- */
- Ext.tree.TreeNode = function(attributes){
- attributes = attributes || {};
- if(Ext.isString(attributes)){
- attributes = {text: attributes};
- }
- this.childrenRendered = false;
- this.rendered = false;
- Ext.tree.TreeNode.superclass.constructor.call(this, attributes);
- this.expanded = attributes.expanded === true;
- this.isTarget = attributes.isTarget !== false;
- this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
- this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
- /**
- * Read-only. The text for this node. To change it use <code>{@link #setText}</code>.
- * @type String
- */
- this.text = attributes.text;
- /**
- * True if this node is disabled.
- * @type Boolean
- */
- this.disabled = attributes.disabled === true;
- /**
- * True if this node is hidden.
- * @type Boolean
- */
- this.hidden = attributes.hidden === true;
- this.addEvents(
- /**
- * @event textchange
- * Fires when the text for this node is changed
- * @param {Node} this This node
- * @param {String} text The new text
- * @param {String} oldText The old text
- */
- 'textchange',
- /**
- * @event beforeexpand
- * Fires before this node is expanded, return false to cancel.
- * @param {Node} this This node
- * @param {Boolean} deep
- * @param {Boolean} anim
- */
- 'beforeexpand',
- /**
- * @event beforecollapse
- * Fires before this node is collapsed, return false to cancel.
- * @param {Node} this This node
- * @param {Boolean} deep
- * @param {Boolean} anim
- */
- 'beforecollapse',
- /**
- * @event expand
- * Fires when this node is expanded
- * @param {Node} this This node
- */
- 'expand',
- /**
- * @event disabledchange
- * Fires when the disabled status of this node changes
- * @param {Node} this This node
- * @param {Boolean} disabled
- */
- 'disabledchange',
- /**
- * @event collapse
- * Fires when this node is collapsed
- * @param {Node} this This node
- */
- 'collapse',
- /**
- * @event beforeclick
- * Fires before click processing. Return false to cancel the default action.
- * @param {Node} this This node
- * @param {Ext.EventObject} e The event object
- */
- 'beforeclick',
- /**
- * @event click
- * Fires when this node is clicked
- * @param {Node} this This node
- * @param {Ext.EventObject} e The event object
- */
- 'click',
- /**
- * @event checkchange
- * Fires when a node with a checkbox's checked property changes
- * @param {Node} this This node
- * @param {Boolean} checked
- */
- 'checkchange',
- /**
- * @event beforedblclick
- * Fires before double click processing. Return false to cancel the default action.
- * @param {Node} this This node
- * @param {Ext.EventObject} e The event object
- */
- 'beforedblclick',
- /**
- * @event dblclick
- * Fires when this node is double clicked
- * @param {Node} this This node
- * @param {Ext.EventObject} e The event object
- */
- 'dblclick',
- /**
- * @event contextmenu
- * Fires when this node is right clicked
- * @param {Node} this This node
- * @param {Ext.EventObject} e The event object
- */
- 'contextmenu',
- /**
- * @event beforechildrenrendered
- * Fires right before the child nodes for this node are rendered
- * @param {Node} this This node
- */
- 'beforechildrenrendered'
- );
- var uiClass = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI;
- /**
- * Read-only. The UI for this node
- * @type TreeNodeUI
- */
- this.ui = new uiClass(this);
- };
- Ext.extend(Ext.tree.TreeNode, Ext.data.Node, {
- preventHScroll : true,
- /**
- * Returns true if this node is expanded
- * @return {Boolean}
- */
- isExpanded : function(){
- return this.expanded;
- },
- /**
- * Returns the UI object for this node.
- * @return {TreeNodeUI} The object which is providing the user interface for this tree
- * node. Unless otherwise specified in the {@link #uiProvider}, this will be an instance
- * of {@link Ext.tree.TreeNodeUI}
- */
- getUI : function(){
- return this.ui;
- },
- getLoader : function(){
- var owner;
- return this.loader || ((owner = this.getOwnerTree()) && owner.loader ? owner.loader : (this.loader = new Ext.tree.TreeLoader()));
- },
- // private override
- setFirstChild : function(node){
- var of = this.firstChild;
- Ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
- if(this.childrenRendered && of && node != of){
- of.renderIndent(true, true);
- }
- if(this.rendered){
- this.renderIndent(true, true);
- }
- },
- // private override
- setLastChild : function(node){
- var ol = this.lastChild;
- Ext.tree.TreeNode.superclass.setLastChild.call(this, node);
- if(this.childrenRendered && ol && node != ol){
- ol.renderIndent(true, true);
- }
- if(this.rendered){
- this.renderIndent(true, true);
- }
- },
- // these methods are overridden to provide lazy rendering support
- // private override
- appendChild : function(n){
- if(!n.render && !Ext.isArray(n)){
- n = this.getLoader().createNode(n);
- }
- var node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);
- if(node && this.childrenRendered){
- node.render();
- }
- this.ui.updateExpandIcon();
- return node;
- },
- // private override
- removeChild : function(node, destroy){
- this.ownerTree.getSelectionModel().unselect(node);
- Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
- // if it's been rendered remove dom node
- if(node.ui.rendered){
- node.ui.remove();
- }
- if(this.childNodes.length < 1){
- this.collapse(false, false);
- }else{
- this.ui.updateExpandIcon();
- }
- if(!this.firstChild && !this.isHiddenRoot()) {
- this.childrenRendered = false;
- }
- return node;
- },
- // private override
- insertBefore : function(node, refNode){
- if(!node.render){
- node = this.getLoader().createNode(node);
- }
- var newNode = Ext.tree.TreeNode.superclass.insertBefore.call(this, node, refNode);
- if(newNode && refNode && this.childrenRendered){
- node.render();
- }
- this.ui.updateExpandIcon();
- return newNode;
- },
- /**
- * Sets the text for this node
- * @param {String} text
- */
- setText : function(text){
- var oldText = this.text;
- this.text = this.attributes.text = text;
- if(this.rendered){ // event without subscribing
- this.ui.onTextChange(this, text, oldText);
- }
- this.fireEvent('textchange', this, text, oldText);
- },
- /**
- * Triggers selection of this node
- */
- select : function(){
- var t = this.getOwnerTree();
- if(t){
- t.getSelectionModel().select(this);
- }
- },
- /**
- * Triggers deselection of this node
- * @param {Boolean} silent (optional) True to stop selection change events from firing.
- */
- unselect : function(silent){
- var t = this.getOwnerTree();
- if(t){
- t.getSelectionModel().unselect(this, silent);
- }
- },
- /**
- * Returns true if this node is selected
- * @return {Boolean}
- */
- isSelected : function(){
- var t = this.getOwnerTree();
- return t ? t.getSelectionModel().isSelected(this) : false;
- },
- /**
- * Expand this node.
- * @param {Boolean} deep (optional) True to expand all children as well
- * @param {Boolean} anim (optional) false to cancel the default animation
- * @param {Function} callback (optional) A callback to be called when
- * expanding this node completes (does not wait for deep expand to complete).
- * Called with 1 parameter, this node.
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
- */
- expand : function(deep, anim, callback, scope){
- if(!this.expanded){
- if(this.fireEvent('beforeexpand', this, deep, anim) === false){
- return;
- }
- if(!this.childrenRendered){
- this.renderChildren();
- }
- this.expanded = true;
- if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
- this.ui.animExpand(function(){
- this.fireEvent('expand', this);
- this.runCallback(callback, scope || this, [this]);
- if(deep === true){
- this.expandChildNodes(true);
- }
- }.createDelegate(this));
- return;
- }else{
- this.ui.expand();
- this.fireEvent('expand', this);
- this.runCallback(callback, scope || this, [this]);
- }
- }else{
- this.runCallback(callback, scope || this, [this]);
- }
- if(deep === true){
- this.expandChildNodes(true);
- }
- },
- runCallback : function(cb, scope, args){
- if(Ext.isFunction(cb)){
- cb.apply(scope, args);
- }
- },
- isHiddenRoot : function(){
- return this.isRoot && !this.getOwnerTree().rootVisible;
- },
- /**
- * Collapse this node.
- * @param {Boolean} deep (optional) True to collapse all children as well
- * @param {Boolean} anim (optional) false to cancel the default animation
- * @param {Function} callback (optional) A callback to be called when
- * expanding this node completes (does not wait for deep expand to complete).
- * Called with 1 parameter, this node.
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
- */
- collapse : function(deep, anim, callback, scope){
- if(this.expanded && !this.isHiddenRoot()){
- if(this.fireEvent('beforecollapse', this, deep, anim) === false){
- return;
- }
- this.expanded = false;
- if((this.getOwnerTree().animate && anim !== false) || anim){
- this.ui.animCollapse(function(){
- this.fireEvent('collapse', this);
- this.runCallback(callback, scope || this, [this]);
- if(deep === true){
- this.collapseChildNodes(true);
- }
- }.createDelegate(this));
- return;
- }else{
- this.ui.collapse();
- this.fireEvent('collapse', this);
- this.runCallback(callback, scope || this, [this]);
- }
- }else if(!this.expanded){
- this.runCallback(callback, scope || this, [this]);
- }
- if(deep === true){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- cs[i].collapse(true, false);
- }
- }
- },
- // private
- delayedExpand : function(delay){
- if(!this.expandProcId){
- this.expandProcId = this.expand.defer(delay, this);
- }
- },
- // private
- cancelExpand : function(){
- if(this.expandProcId){
- clearTimeout(this.expandProcId);
- }
- this.expandProcId = false;
- },
- /**
- * Toggles expanded/collapsed state of the node
- */
- toggle : function(){
- if(this.expanded){
- this.collapse();
- }else{
- this.expand();
- }
- },
- /**
- * Ensures all parent nodes are expanded, and if necessary, scrolls
- * the node into view.
- * @param {Function} callback (optional) A function to call when the node has been made visible.
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
- */
- ensureVisible : function(callback, scope){
- var tree = this.getOwnerTree();
- tree.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function(){
- var node = tree.getNodeById(this.id); // Somehow if we don't do this, we lose changes that happened to node in the meantime
- tree.getTreeEl().scrollChildIntoView(node.ui.anchor);
- this.runCallback(callback, scope || this, [this]);
- }.createDelegate(this));
- },
- /**
- * Expand all child nodes
- * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
- */
- expandChildNodes : function(deep){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- cs[i].expand(deep);
- }
- },
- /**
- * Collapse all child nodes
- * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
- */
- collapseChildNodes : function(deep){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- cs[i].collapse(deep);
- }
- },
- /**
- * Disables this node
- */
- disable : function(){
- this.disabled = true;
- this.unselect();
- if(this.rendered && this.ui.onDisableChange){ // event without subscribing
- this.ui.onDisableChange(this, true);
- }
- this.fireEvent('disabledchange', this, true);
- },
- /**
- * Enables this node
- */
- enable : function(){
- this.disabled = false;
- if(this.rendered && this.ui.onDisableChange){ // event without subscribing
- this.ui.onDisableChange(this, false);
- }
- this.fireEvent('disabledchange', this, false);
- },
- // private
- renderChildren : function(suppressEvent){
- if(suppressEvent !== false){
- this.fireEvent('beforechildrenrendered', this);
- }
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++){
- cs[i].render(true);
- }
- this.childrenRendered = true;
- },
- // private
- sort : function(fn, scope){
- Ext.tree.TreeNode.superclass.sort.apply(this, arguments);
- if(this.childrenRendered){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++){
- cs[i].render(true);
- }
- }
- },
- // private
- render : function(bulkRender){
- this.ui.render(bulkRender);
- if(!this.rendered){
- // make sure it is registered
- this.getOwnerTree().registerNode(this);
- this.rendered = true;
- if(this.expanded){
- this.expanded = false;
- this.expand(false, false);
- }
- }
- },
- // private
- renderIndent : function(deep, refresh){
- if(refresh){
- this.ui.childIndent = null;
- }
- this.ui.renderIndent();
- if(deep === true && this.childrenRendered){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++){
- cs[i].renderIndent(true, refresh);
- }
- }
- },
- beginUpdate : function(){
- this.childrenRendered = false;
- },
- endUpdate : function(){
- if(this.expanded && this.rendered){
- this.renderChildren();
- }
- },
- destroy : function(){
- this.unselect(true);
- Ext.tree.TreeNode.superclass.destroy.call(this);
- Ext.destroy(this.ui, this.loader);
- this.ui = this.loader = null;
- },
- // private
- onIdChange : function(id){
- this.ui.onIdChange(id);
- }
- });
- Ext.tree.TreePanel.nodeTypes.node = Ext.tree.TreeNode;/**
- * @class Ext.tree.AsyncTreeNode
- * @extends Ext.tree.TreeNode
- * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
- * @constructor
- * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
- */
- Ext.tree.AsyncTreeNode = function(config){
- this.loaded = config && config.loaded === true;
- this.loading = false;
- Ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
- /**
- * @event beforeload
- * Fires before this node is loaded, return false to cancel
- * @param {Node} this This node
- */
- this.addEvents('beforeload', 'load');
- /**
- * @event load
- * Fires when this node is loaded
- * @param {Node} this This node
- */
- /**
- * The loader used by this node (defaults to using the tree's defined loader)
- * @type TreeLoader
- * @property loader
- */
- };
- Ext.extend(Ext.tree.AsyncTreeNode, Ext.tree.TreeNode, {
- expand : function(deep, anim, callback, scope){
- if(this.loading){ // if an async load is already running, waiting til it's done
- var timer;
- var f = function(){
- if(!this.loading){ // done loading
- clearInterval(timer);
- this.expand(deep, anim, callback, scope);
- }
- }.createDelegate(this);
- timer = setInterval(f, 200);
- return;
- }
- if(!this.loaded){
- if(this.fireEvent("beforeload", this) === false){
- return;
- }
- this.loading = true;
- this.ui.beforeLoad(this);
- var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
- if(loader){
- loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback, scope]), this);
- return;
- }
- }
- Ext.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback, scope);
- },
- /**
- * Returns true if this node is currently loading
- * @return {Boolean}
- */
- isLoading : function(){
- return this.loading;
- },
- loadComplete : function(deep, anim, callback, scope){
- this.loading = false;
- this.loaded = true;
- this.ui.afterLoad(this);
- this.fireEvent("load", this);
- this.expand(deep, anim, callback, scope);
- },
- /**
- * Returns true if this node has been loaded
- * @return {Boolean}
- */
- isLoaded : function(){
- return this.loaded;
- },
- hasChildNodes : function(){
- if(!this.isLeaf() && !this.loaded){
- return true;
- }else{
- return Ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
- }
- },
- /**
- * Trigger a reload for this node
- * @param {Function} callback
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Node.
- */
- reload : function(callback, scope){
- this.collapse(false, false);
- while(this.firstChild){
- this.removeChild(this.firstChild).destroy();
- }
- this.childrenRendered = false;
- this.loaded = false;
- if(this.isHiddenRoot()){
- this.expanded = false;
- }
- this.expand(false, false, callback, scope);
- }
- });
- Ext.tree.TreePanel.nodeTypes.async = Ext.tree.AsyncTreeNode;/**
- * @class Ext.tree.TreeNodeUI
- * This class provides the default UI implementation for Ext TreeNodes.
- * The TreeNode UI implementation is separate from the
- * tree implementation, and allows customizing of the appearance of
- * tree nodes.<br>
- * <p>
- * If you are customizing the Tree's user interface, you
- * may need to extend this class, but you should never need to instantiate this class.<br>
- * <p>
- * This class provides access to the user interface components of an Ext TreeNode, through
- * {@link Ext.tree.TreeNode#getUI}
- */
- Ext.tree.TreeNodeUI = function(node){
- this.node = node;
- this.rendered = false;
- this.animating = false;
- this.wasLeaf = true;
- this.ecc = 'x-tree-ec-icon x-tree-elbow';
- this.emptyIcon = Ext.BLANK_IMAGE_URL;
- };
- Ext.tree.TreeNodeUI.prototype = {
- // private
- removeChild : function(node){
- if(this.rendered){
- this.ctNode.removeChild(node.ui.getEl());
- }
- },
- // private
- beforeLoad : function(){
- this.addClass("x-tree-node-loading");
- },
- // private
- afterLoad : function(){
- this.removeClass("x-tree-node-loading");
- },
- // private
- onTextChange : function(node, text, oldText){
- if(this.rendered){
- this.textNode.innerHTML = text;
- }
- },
- // private
- onDisableChange : function(node, state){
- this.disabled = state;
- if (this.checkbox) {
- this.checkbox.disabled = state;
- }
- if(state){
- this.addClass("x-tree-node-disabled");
- }else{
- this.removeClass("x-tree-node-disabled");
- }
- },
- // private
- onSelectedChange : function(state){
- if(state){
- this.focus();
- this.addClass("x-tree-selected");
- }else{
- //this.blur();
- this.removeClass("x-tree-selected");
- }
- },
- // private
- onMove : function(tree, node, oldParent, newParent, index, refNode){
- this.childIndent = null;
- if(this.rendered){
- var targetNode = newParent.ui.getContainer();
- if(!targetNode){//target not rendered
- this.holder = document.createElement("div");
- this.holder.appendChild(this.wrap);
- return;
- }
- var insertBefore = refNode ? refNode.ui.getEl() : null;
- if(insertBefore){
- targetNode.insertBefore(this.wrap, insertBefore);
- }else{
- targetNode.appendChild(this.wrap);
- }
- this.node.renderIndent(true, oldParent != newParent);
- }
- },
- /**
- * Adds one or more CSS classes to the node's UI element.
- * Duplicate classes are automatically filtered out.
- * @param {String/Array} className The CSS class to add, or an array of classes
- */
- addClass : function(cls){
- if(this.elNode){
- Ext.fly(this.elNode).addClass(cls);
- }
- },
- /**
- * Removes one or more CSS classes from the node's UI element.
- * @param {String/Array} className The CSS class to remove, or an array of classes
- */
- removeClass : function(cls){
- if(this.elNode){
- Ext.fly(this.elNode).removeClass(cls);
- }
- },
- // private
- remove : function(){
- if(this.rendered){
- this.holder = document.createElement("div");
- this.holder.appendChild(this.wrap);
- }
- },
- // private
- fireEvent : function(){
- return this.node.fireEvent.apply(this.node, arguments);
- },
- // private
- initEvents : function(){
- this.node.on("move", this.onMove, this);
- if(this.node.disabled){
- this.onDisableChange(this.node, true);
- }
- if(this.node.hidden){
- this.hide();
- }
- var ot = this.node.getOwnerTree();
- var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
- if(dd && (!this.node.isRoot || ot.rootVisible)){
- Ext.dd.Registry.register(this.elNode, {
- node: this.node,
- handles: this.getDDHandles(),
- isHandle: false
- });
- }
- },
- // private
- getDDHandles : function(){
- return [this.iconNode, this.textNode, this.elNode];
- },
- /**
- * Hides this node.
- */
- hide : function(){
- this.node.hidden = true;
- if(this.wrap){
- this.wrap.style.display = "none";
- }
- },
- /**
- * Shows this node.
- */
- show : function(){
- this.node.hidden = false;
- if(this.wrap){
- this.wrap.style.display = "";
- }
- },
- // private
- onContextMenu : function(e){
- if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
- e.preventDefault();
- this.focus();
- this.fireEvent("contextmenu", this.node, e);
- }
- },
- // private
- onClick : function(e){
- if(this.dropping){
- e.stopEvent();
- return;
- }
- if(this.fireEvent("beforeclick", this.node, e) !== false){
- var a = e.getTarget('a');
- if(!this.disabled && this.node.attributes.href && a){
- this.fireEvent("click", this.node, e);
- return;
- }else if(a && e.ctrlKey){
- e.stopEvent();
- }
- e.preventDefault();
- if(this.disabled){
- return;
- }
- if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
- this.node.toggle();
- }
- this.fireEvent("click", this.node, e);
- }else{
- e.stopEvent();
- }
- },
- // private
- onDblClick : function(e){
- e.preventDefault();
- if(this.disabled){
- return;
- }
- if(this.fireEvent("beforedblclick", this.node, e) !== false){
- if(this.checkbox){
- this.toggleCheck();
- }
- if(!this.animating && this.node.isExpandable()){
- this.node.toggle();
- }
- this.fireEvent("dblclick", this.node, e);
- }
- },
- onOver : function(e){
- this.addClass('x-tree-node-over');
- },
- onOut : function(e){
- this.removeClass('x-tree-node-over');
- },
- // private
- onCheckChange : function(){
- var checked = this.checkbox.checked;
- // fix for IE6
- this.checkbox.defaultChecked = checked;
- this.node.attributes.checked = checked;
- this.fireEvent('checkchange', this.node, checked);
- },
- // private
- ecClick : function(e){
- if(!this.animating && this.node.isExpandable()){
- this.node.toggle();
- }
- },
- // private
- startDrop : function(){
- this.dropping = true;
- },
- // delayed drop so the click event doesn't get fired on a drop
- endDrop : function(){
- setTimeout(function(){
- this.dropping = false;
- }.createDelegate(this), 50);
- },
- // private
- expand : function(){
- this.updateExpandIcon();
- this.ctNode.style.display = "";
- },
- // private
- focus : function(){
- if(!this.node.preventHScroll){
- try{this.anchor.focus();
- }catch(e){}
- }else{
- try{
- var noscroll = this.node.getOwnerTree().getTreeEl().dom;
- var l = noscroll.scrollLeft;
- this.anchor.focus();
- noscroll.scrollLeft = l;
- }catch(e){}
- }
- },
- /**
- * Sets the checked status of the tree node to the passed value, or, if no value was passed,
- * toggles the checked status. If the node was rendered with no checkbox, this has no effect.
- * @param {Boolean} (optional) The new checked status.
- */
- toggleCheck : function(value){
- var cb = this.checkbox;
- if(cb){
- cb.checked = (value === undefined ? !cb.checked : value);
- this.onCheckChange();
- }
- },
- // private
- blur : function(){
- try{
- this.anchor.blur();
- }catch(e){}
- },
- // private
- animExpand : function(callback){
- var ct = Ext.get(this.ctNode);
- ct.stopFx();
- if(!this.node.isExpandable()){
- this.updateExpandIcon();
- this.ctNode.style.display = "";
- Ext.callback(callback);
- return;
- }
- this.animating = true;
- this.updateExpandIcon();
- ct.slideIn('t', {
- callback : function(){
- this.animating = false;
- Ext.callback(callback);
- },
- scope: this,
- duration: this.node.ownerTree.duration || .25
- });
- },
- // private
- highlight : function(){
- var tree = this.node.getOwnerTree();
- Ext.fly(this.wrap).highlight(
- tree.hlColor || "C3DAF9",
- {endColor: tree.hlBaseColor}
- );
- },
- // private
- collapse : function(){
- this.updateExpandIcon();
- this.ctNode.style.display = "none";
- },
- // private
- animCollapse : function(callback){
- var ct = Ext.get(this.ctNode);
- ct.enableDisplayMode('block');
- ct.stopFx();
- this.animating = true;
- this.updateExpandIcon();
- ct.slideOut('t', {
- callback : function(){
- this.animating = false;
- Ext.callback(callback);
- },
- scope: this,
- duration: this.node.ownerTree.duration || .25
- });
- },
- // private
- getContainer : function(){
- return this.ctNode;
- },
- /**
- * Returns the element which encapsulates this node.
- * @return {HtmlElement} The DOM element. The default implementation uses a <code><li></code>.
- */
- getEl : function(){
- return this.wrap;
- },
- // private
- appendDDGhost : function(ghostNode){
- ghostNode.appendChild(this.elNode.cloneNode(true));
- },
- // private
- getDDRepairXY : function(){
- return Ext.lib.Dom.getXY(this.iconNode);
- },
- // private
- onRender : function(){
- this.render();
- },
- // private
- render : function(bulkRender){
- var n = this.node, a = n.attributes;
- var targetNode = n.parentNode ?
- n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
- if(!this.rendered){
- this.rendered = true;
- this.renderElements(n, a, targetNode, bulkRender);
- if(a.qtip){
- if(this.textNode.setAttributeNS){
- this.textNode.setAttributeNS("ext", "qtip", a.qtip);
- if(a.qtipTitle){
- this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
- }
- }else{
- this.textNode.setAttribute("ext:qtip", a.qtip);
- if(a.qtipTitle){
- this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
- }
- }
- }else if(a.qtipCfg){
- a.qtipCfg.target = Ext.id(this.textNode);
- Ext.QuickTips.register(a.qtipCfg);
- }
- this.initEvents();
- if(!this.node.expanded){
- this.updateExpandIcon(true);
- }
- }else{
- if(bulkRender === true) {
- targetNode.appendChild(this.wrap);
- }
- }
- },
- // private
- renderElements : function(n, a, targetNode, bulkRender){
- // add some indent caching, this helps performance when rendering a large tree
- this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
- var cb = Ext.isBoolean(a.checked),
- nel,
- href = a.href ? a.href : Ext.isGecko ? "" : "#",
- buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
- '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
- '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
- '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
- cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
- '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
- a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
- '<ul class="x-tree-node-ct" style="display:none;"></ul>',
- "</li>"].join('');
- if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
- this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
- }else{
- this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
- }
- this.elNode = this.wrap.childNodes[0];
- this.ctNode = this.wrap.childNodes[1];
- var cs = this.elNode.childNodes;
- this.indentNode = cs[0];
- this.ecNode = cs[1];
- this.iconNode = cs[2];
- var index = 3;
- if(cb){
- this.checkbox = cs[3];
- // fix for IE6
- this.checkbox.defaultChecked = this.checkbox.checked;
- index++;
- }
- this.anchor = cs[index];
- this.textNode = cs[index].firstChild;
- },
- /**
- * Returns the <a> element that provides focus for the node's UI.
- * @return {HtmlElement} The DOM anchor element.
- */
- getAnchor : function(){
- return this.anchor;
- },
- /**
- * Returns the text node.
- * @return {HtmlNode} The DOM text node.
- */
- getTextEl : function(){
- return this.textNode;
- },
- /**
- * Returns the icon <img> element.
- * @return {HtmlElement} The DOM image element.
- */
- getIconEl : function(){
- return this.iconNode;
- },
- /**
- * Returns the checked status of the node. If the node was rendered with no
- * checkbox, it returns false.
- * @return {Boolean} The checked flag.
- */
- isChecked : function(){
- return this.checkbox ? this.checkbox.checked : false;
- },
- // private
- updateExpandIcon : function(){
- if(this.rendered){
- var n = this.node,
- c1,
- c2,
- cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow",
- hasChild = n.hasChildNodes();
- if(hasChild || n.attributes.expandable){
- if(n.expanded){
- cls += "-minus";
- c1 = "x-tree-node-collapsed";
- c2 = "x-tree-node-expanded";
- }else{
- cls += "-plus";
- c1 = "x-tree-node-expanded";
- c2 = "x-tree-node-collapsed";
- }
- if(this.wasLeaf){
- this.removeClass("x-tree-node-leaf");
- this.wasLeaf = false;
- }
- if(this.c1 != c1 || this.c2 != c2){
- Ext.fly(this.elNode).replaceClass(c1, c2);
- this.c1 = c1; this.c2 = c2;
- }
- }else{
- if(!this.wasLeaf){
- Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
- delete this.c1;
- delete this.c2;
- this.wasLeaf = true;
- }
- }
- var ecc = "x-tree-ec-icon "+cls;
- if(this.ecc != ecc){
- this.ecNode.className = ecc;
- this.ecc = ecc;
- }
- }
- },
- // private
- onIdChange: function(id){
- if(this.rendered){
- this.elNode.setAttribute('ext:tree-node-id', id);
- }
- },
- // private
- getChildIndent : function(){
- if(!this.childIndent){
- var buf = [],
- p = this.node;
- while(p){
- if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
- if(!p.isLast()) {
- buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
- } else {
- buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
- }
- }
- p = p.parentNode;
- }
- this.childIndent = buf.join("");
- }
- return this.childIndent;
- },
- // private
- renderIndent : function(){
- if(this.rendered){
- var indent = "",
- p = this.node.parentNode;
- if(p){
- indent = p.ui.getChildIndent();
- }
- if(this.indentMarkup != indent){ // don't rerender if not required
- this.indentNode.innerHTML = indent;
- this.indentMarkup = indent;
- }
- this.updateExpandIcon();
- }
- },
- destroy : function(){
- if(this.elNode){
- Ext.dd.Registry.unregister(this.elNode.id);
- }
- Ext.each(['textnode', 'anchor', 'checkbox', 'indentNode', 'ecNode', 'iconNode', 'elNode', 'ctNode', 'wrap', 'holder'], function(el){
- if(this[el]){
- Ext.fly(this[el]).remove();
- delete this[el];
- }
- }, this);
- delete this.node;
- }
- };
- /**
- * @class Ext.tree.RootTreeNodeUI
- * This class provides the default UI implementation for <b>root</b> Ext TreeNodes.
- * The RootTreeNode UI implementation allows customizing the appearance of the root tree node.<br>
- * <p>
- * If you are customizing the Tree's user interface, you
- * may need to extend this class, but you should never need to instantiate this class.<br>
- */
- Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
- // private
- render : function(){
- if(!this.rendered){
- var targetNode = this.node.ownerTree.innerCt.dom;
- this.node.expanded = true;
- targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
- this.wrap = this.ctNode = targetNode.firstChild;
- }
- },
- collapse : Ext.emptyFn,
- expand : Ext.emptyFn
- });/**
- * @class Ext.tree.TreeLoader
- * @extends Ext.util.Observable
- * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child
- * nodes from a specified URL. The response must be a JavaScript Array definition
- * whose elements are node definition objects. e.g.:
- * <pre><code>
- [{
- id: 1,
- text: 'A leaf Node',
- leaf: true
- },{
- id: 2,
- text: 'A folder Node',
- children: [{
- id: 3,
- text: 'A child Node',
- leaf: true
- }]
- }]
- </code></pre>
- * <br><br>
- * A server request is sent, and child nodes are loaded only when a node is expanded.
- * The loading node's id is passed to the server under the parameter name "node" to
- * enable the server to produce the correct child nodes.
- * <br><br>
- * To pass extra parameters, an event handler may be attached to the "beforeload"
- * event, and the parameters specified in the TreeLoader's baseParams property:
- * <pre><code>
- myTreeLoader.on("beforeload", function(treeLoader, node) {
- this.baseParams.category = node.attributes.category;
- }, this);
- </code></pre>
- * This would pass an HTTP parameter called "category" to the server containing
- * the value of the Node's "category" attribute.
- * @constructor
- * Creates a new Treeloader.
- * @param {Object} config A config object containing config properties.
- */
- Ext.tree.TreeLoader = function(config){
- this.baseParams = {};
- Ext.apply(this, config);
- this.addEvents(
- /**
- * @event beforeload
- * Fires before a network request is made to retrieve the Json text which specifies a node's children.
- * @param {Object} This TreeLoader object.
- * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
- * @param {Object} callback The callback function specified in the {@link #load} call.
- */
- "beforeload",
- /**
- * @event load
- * Fires when the node has been successfuly loaded.
- * @param {Object} This TreeLoader object.
- * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
- * @param {Object} response The response object containing the data from the server.
- */
- "load",
- /**
- * @event loadexception
- * Fires if the network request failed.
- * @param {Object} This TreeLoader object.
- * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
- * @param {Object} response The response object containing the data from the server.
- */
- "loadexception"
- );
- Ext.tree.TreeLoader.superclass.constructor.call(this);
- if(Ext.isString(this.paramOrder)){
- this.paramOrder = this.paramOrder.split(/[s,|]/);
- }
- };
- Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
- /**
- * @cfg {String} dataUrl The URL from which to request a Json string which
- * specifies an array of node definition objects representing the child nodes
- * to be loaded.
- */
- /**
- * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
- */
- /**
- * @cfg {String} url Equivalent to {@link #dataUrl}.
- */
- /**
- * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.
- */
- /**
- * @cfg {Object} baseParams (optional) An object containing properties which
- * specify HTTP parameters to be passed to each request for child nodes.
- */
- /**
- * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
- * created by this loader. If the attributes sent by the server have an attribute in this object,
- * they take priority.
- */
- /**
- * @cfg {Object} uiProviders (optional) An object containing properties which
- * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional
- * <i>uiProvider</i> attribute of a returned child node is a string rather
- * than a reference to a TreeNodeUI implementation, then that string value
- * is used as a property name in the uiProviders object.
- */
- uiProviders : {},
- /**
- * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
- * child nodes before loading.
- */
- clearOnLoad : true,
- /**
- * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.
- * A list of params to be executed
- * server side. Specify the params in the order in which they must be executed on the server-side
- * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
- * comma, or pipe. For example,
- * any of the following would be acceptable:<pre><code>
- paramOrder: ['param1','param2','param3']
- paramOrder: 'param1 param2 param3'
- paramOrder: 'param1,param2,param3'
- paramOrder: 'param1|param2|param'
- </code></pre>
- */
- paramOrder: undefined,
- /**
- * @cfg {Boolean} paramsAsHash Only used when using directFn.
- * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
- * <tt>{@link #paramOrder}</tt> nullifies this configuration.
- */
- paramsAsHash: false,
- /**
- * @cfg {String} nodeParameter The name of the parameter sent to the server which contains
- * the identifier of the node. Defaults to <tt>'node'</tt>.
- */
- nodeParameter: 'node',
- /**
- * @cfg {Function} directFn
- * Function to call when executing a request.
- */
- directFn : undefined,
- /**
- * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.
- * This is called automatically when a node is expanded, but may be used to reload
- * a node (or append new children if the {@link #clearOnLoad} option is false.)
- * @param {Ext.tree.TreeNode} node
- * @param {Function} callback Function to call after the node has been loaded. The
- * function is passed the TreeNode which was requested to be loaded.
- * @param (Object) scope The cope (<code>this</code> reference) in which the callback is executed.
- * defaults to the loaded TreeNode.
- */
- load : function(node, callback, scope){
- if(this.clearOnLoad){
- while(node.firstChild){
- node.removeChild(node.firstChild);
- }
- }
- if(this.doPreload(node)){ // preloaded json children
- this.runCallback(callback, scope || node, [node]);
- }else if(this.directFn || this.dataUrl || this.url){
- this.requestData(node, callback, scope || node);
- }
- },
- doPreload : function(node){
- if(node.attributes.children){
- if(node.childNodes.length < 1){ // preloaded?
- var cs = node.attributes.children;
- node.beginUpdate();
- for(var i = 0, len = cs.length; i < len; i++){
- var cn = node.appendChild(this.createNode(cs[i]));
- if(this.preloadChildren){
- this.doPreload(cn);
- }
- }
- node.endUpdate();
- }
- return true;
- }
- return false;
- },
- getParams: function(node){
- var buf = [], bp = this.baseParams;
- if(this.directFn){
- buf.push(node.id);
- if(bp){
- if(this.paramOrder){
- for(var i = 0, len = this.paramOrder.length; i < len; i++){
- buf.push(bp[this.paramOrder[i]]);
- }
- }else if(this.paramsAsHash){
- buf.push(bp);
- }
- }
- return buf;
- }else{
- var o = Ext.apply({}, bp);
- o[this.nodeParameter] = node.id;
- return o;
- }
- },
- requestData : function(node, callback, scope){
- if(this.fireEvent("beforeload", this, node, callback) !== false){
- if(this.directFn){
- var args = this.getParams(node);
- args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));
- this.directFn.apply(window, args);
- }else{
- this.transId = Ext.Ajax.request({
- method:this.requestMethod,
- url: this.dataUrl||this.url,
- success: this.handleResponse,
- failure: this.handleFailure,
- scope: this,
- argument: {callback: callback, node: node, scope: scope},
- params: this.getParams(node)
- });
- }
- }else{
- // if the load is cancelled, make sure we notify
- // the node that we are done
- this.runCallback(callback, scope || node, []);
- }
- },
- processDirectResponse: function(result, response, args){
- if(response.status){
- this.handleResponse({
- responseData: Ext.isArray(result) ? result : null,
- responseText: result,
- argument: args
- });
- }else{
- this.handleFailure({
- argument: args
- });
- }
- },
- // private
- runCallback: function(cb, scope, args){
- if(Ext.isFunction(cb)){
- cb.apply(scope, args);
- }
- },
- isLoading : function(){
- return !!this.transId;
- },
- abort : function(){
- if(this.isLoading()){
- Ext.Ajax.abort(this.transId);
- }
- },
- /**
- * <p>Override this function for custom TreeNode node implementation, or to
- * modify the attributes at creation time.</p>
- * Example:<pre><code>
- new Ext.tree.TreePanel({
- ...
- loader: new Ext.tree.TreeLoader({
- url: 'dataUrl',
- createNode: function(attr) {
- // Allow consolidation consignments to have
- // consignments dropped into them.
- if (attr.isConsolidation) {
- attr.iconCls = 'x-consol',
- attr.allowDrop = true;
- }
- return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
- }
- }),
- ...
- });
- </code></pre>
- * @param attr {Object} The attributes from which to create the new node.
- */
- createNode : function(attr){
- // apply baseAttrs, nice idea Corey!
- if(this.baseAttrs){
- Ext.applyIf(attr, this.baseAttrs);
- }
- if(this.applyLoader !== false && !attr.loader){
- attr.loader = this;
- }
- if(Ext.isString(attr.uiProvider)){
- attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
- }
- if(attr.nodeType){
- return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
- }else{
- return attr.leaf ?
- new Ext.tree.TreeNode(attr) :
- new Ext.tree.AsyncTreeNode(attr);
- }
- },
- processResponse : function(response, node, callback, scope){
- var json = response.responseText;
- try {
- var o = response.responseData || Ext.decode(json);
- node.beginUpdate();
- for(var i = 0, len = o.length; i < len; i++){
- var n = this.createNode(o[i]);
- if(n){
- node.appendChild(n);
- }
- }
- node.endUpdate();
- this.runCallback(callback, scope || node, [node]);
- }catch(e){
- this.handleFailure(response);
- }
- },
- handleResponse : function(response){
- this.transId = false;
- var a = response.argument;
- this.processResponse(response, a.node, a.callback, a.scope);
- this.fireEvent("load", this, a.node, response);
- },
- handleFailure : function(response){
- this.transId = false;
- var a = response.argument;
- this.fireEvent("loadexception", this, a.node, response);
- this.runCallback(a.callback, a.scope || a.node, [a.node]);
- },
- destroy : function(){
- this.purgeListeners();
- }
- });/** * @class Ext.tree.TreeFilter * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes * @param {TreePanel} tree * @param {Object} config (optional) */ Ext.tree.TreeFilter = function(tree, config){ this.tree = tree; this.filtered = {}; Ext.apply(this, config); }; Ext.tree.TreeFilter.prototype = { clearBlank:false, reverse:false, autoClear:false, remove:false, /** * Filter the data by a specific attribute. * @param {String/RegExp} value Either string that the attribute value * should start with or a RegExp to test against the attribute * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text". * @param {TreeNode} startNode (optional) The node to start the filter at. */ filter : function(value, attr, startNode){ attr = attr || "text"; var f; if(typeof value == "string"){ var vlen = value.length; // auto clear empty filter if(vlen == 0 && this.clearBlank){ this.clear(); return; } value = value.toLowerCase(); f = function(n){ return n.attributes[attr].substr(0, vlen).toLowerCase() == value; }; }else if(value.exec){ // regex? f = function(n){ return value.test(n.attributes[attr]); }; }else{ throw 'Illegal filter type, must be string or regex'; } this.filterBy(f, null, startNode); }, /** * Filter by a function. The passed function will be called with each * node in the tree (or from the startNode). If the function returns true, the node is kept * otherwise it is filtered. If a node is filtered, its children are also filtered. * @param {Function} fn The filter function * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node. */ filterBy : function(fn, scope, startNode){ startNode = startNode || this.tree.root; if(this.autoClear){ this.clear(); } var af = this.filtered, rv = this.reverse; var f = function(n){ if(n == startNode){ return true; } if(af[n.id]){ return false; } var m = fn.call(scope || n, n); if(!m || rv){ af[n.id] = n; n.ui.hide(); return false; } return true; }; startNode.cascade(f); if(this.remove){ for(var id in af){ if(typeof id != "function"){ var n = af[id]; if(n && n.parentNode){ n.parentNode.removeChild(n); } } } } }, /** * Clears the current filter. Note: with the "remove" option * set a filter cannot be cleared. */ clear : function(){ var t = this.tree; var af = this.filtered; for(var id in af){ if(typeof id != "function"){ var n = af[id]; if(n){ n.ui.show(); } } } this.filtered = {}; } }; /**
- * @class Ext.tree.TreeSorter
- * Provides sorting of nodes in a {@link Ext.tree.TreePanel}. The TreeSorter automatically monitors events on the
- * associated TreePanel that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
- * Example usage:<br />
- * <pre><code>
- new Ext.tree.TreeSorter(myTree, {
- folderSort: true,
- dir: "desc",
- sortType: function(node) {
- // sort by a custom, typed attribute:
- return parseInt(node.id, 10);
- }
- });
- </code></pre>
- * @constructor
- * @param {TreePanel} tree
- * @param {Object} config
- */
- Ext.tree.TreeSorter = function(tree, config){
- /**
- * @cfg {Boolean} folderSort True to sort leaf nodes under non-leaf nodes (defaults to false)
- */
- /**
- * @cfg {String} property The named attribute on the node to sort by (defaults to "text"). Note that this
- * property is only used if no {@link #sortType} function is specified, otherwise it is ignored.
- */
- /**
- * @cfg {String} dir The direction to sort ("asc" or "desc," case-insensitive, defaults to "asc")
- */
- /**
- * @cfg {String} leafAttr The attribute used to determine leaf nodes when {@link #folderSort} = true (defaults to "leaf")
- */
- /**
- * @cfg {Boolean} caseSensitive true for case-sensitive sort (defaults to false)
- */
- /**
- * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting. The function
- * will be called with a single parameter (the {@link Ext.tree.TreeNode} being evaluated) and is expected to return
- * the node's sort value cast to the specific data type required for sorting. This could be used, for example, when
- * a node's text (or other attribute) should be sorted as a date or numeric value. See the class description for
- * example usage. Note that if a sortType is specified, any {@link #property} config will be ignored.
- */
- Ext.apply(this, config);
- tree.on("beforechildrenrendered", this.doSort, this);
- tree.on("append", this.updateSort, this);
- tree.on("insert", this.updateSort, this);
- tree.on("textchange", this.updateSortParent, this);
- var dsc = this.dir && this.dir.toLowerCase() == "desc";
- var p = this.property || "text";
- var sortType = this.sortType;
- var fs = this.folderSort;
- var cs = this.caseSensitive === true;
- var leafAttr = this.leafAttr || 'leaf';
- this.sortFn = function(n1, n2){
- if(fs){
- if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
- return 1;
- }
- if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
- return -1;
- }
- }
- var v1 = sortType ? sortType(n1.attributes[p]) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
- var v2 = sortType ? sortType(n2.attributes[p]) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
- if(v1 < v2){
- return dsc ? +1 : -1;
- }else if(v1 > v2){
- return dsc ? -1 : +1;
- }else{
- return 0;
- }
- };
- };
- Ext.tree.TreeSorter.prototype = {
- doSort : function(node){
- node.sort(this.sortFn);
- },
- compareNodes : function(n1, n2){
- return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
- },
- updateSort : function(tree, node){
- if(node.childrenRendered){
- this.doSort.defer(1, this, [node]);
- }
- },
- updateSortParent : function(node){
- var p = node.parentNode;
- if(p && p.childrenRendered){
- this.doSort.defer(1, this, [p]);
- }
- }
- };/**
- * @class Ext.tree.TreeDropZone
- * @extends Ext.dd.DropZone
- * @constructor
- * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping
- * @param {Object} config
- */
- if(Ext.dd.DropZone){
- Ext.tree.TreeDropZone = function(tree, config){
- /**
- * @cfg {Boolean} allowParentInsert
- * Allow inserting a dragged node between an expanded parent node and its first child that will become a
- * sibling of the parent when dropped (defaults to false)
- */
- this.allowParentInsert = config.allowParentInsert || false;
- /**
- * @cfg {String} allowContainerDrop
- * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
- */
- this.allowContainerDrop = config.allowContainerDrop || false;
- /**
- * @cfg {String} appendOnly
- * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
- */
- this.appendOnly = config.appendOnly || false;
- Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);
- /**
- * The TreePanel for this drop zone
- * @type Ext.tree.TreePanel
- * @property
- */
- this.tree = tree;
- /**
- * Arbitrary data that can be associated with this tree and will be included in the event object that gets
- * passed to any nodedragover event handler (defaults to {})
- * @type Ext.tree.TreePanel
- * @property
- */
- this.dragOverData = {};
- // private
- this.lastInsertClass = "x-tree-no-status";
- };
- Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {
- /**
- * @cfg {String} ddGroup
- * A named drag drop group to which this object belongs. If a group is specified, then this object will only
- * interact with other drag drop objects in the same group (defaults to 'TreeDD').
- */
- ddGroup : "TreeDD",
- /**
- * @cfg {String} expandDelay
- * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
- * over the target (defaults to 1000)
- */
- expandDelay : 1000,
- // private
- expandNode : function(node){
- if(node.hasChildNodes() && !node.isExpanded()){
- node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
- }
- },
- // private
- queueExpand : function(node){
- this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
- },
- // private
- cancelExpand : function(){
- if(this.expandProcId){
- clearTimeout(this.expandProcId);
- this.expandProcId = false;
- }
- },
- // private
- isValidDropPoint : function(n, pt, dd, e, data){
- if(!n || !data){ return false; }
- var targetNode = n.node;
- var dropNode = data.node;
- // default drop rules
- if(!(targetNode && targetNode.isTarget && pt)){
- return false;
- }
- if(pt == "append" && targetNode.allowChildren === false){
- return false;
- }
- if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
- return false;
- }
- if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
- return false;
- }
- // reuse the object
- var overEvent = this.dragOverData;
- overEvent.tree = this.tree;
- overEvent.target = targetNode;
- overEvent.data = data;
- overEvent.point = pt;
- overEvent.source = dd;
- overEvent.rawEvent = e;
- overEvent.dropNode = dropNode;
- overEvent.cancel = false;
- var result = this.tree.fireEvent("nodedragover", overEvent);
- return overEvent.cancel === false && result !== false;
- },
- // private
- getDropPoint : function(e, n, dd){
- var tn = n.node;
- if(tn.isRoot){
- return tn.allowChildren !== false ? "append" : false; // always append for root
- }
- var dragEl = n.ddel;
- var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
- var y = Ext.lib.Event.getPageY(e);
- var noAppend = tn.allowChildren === false || tn.isLeaf();
- if(this.appendOnly || tn.parentNode.allowChildren === false){
- return noAppend ? false : "append";
- }
- var noBelow = false;
- if(!this.allowParentInsert){
- noBelow = tn.hasChildNodes() && tn.isExpanded();
- }
- var q = (b - t) / (noAppend ? 2 : 3);
- if(y >= t && y < (t + q)){
- return "above";
- }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
- return "below";
- }else{
- return "append";
- }
- },
- // private
- onNodeEnter : function(n, dd, e, data){
- this.cancelExpand();
- },
- onContainerOver : function(dd, e, data) {
- if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
- return this.dropAllowed;
- }
- return this.dropNotAllowed;
- },
- // private
- onNodeOver : function(n, dd, e, data){
- var pt = this.getDropPoint(e, n, dd);
- var node = n.node;
- // auto node expand check
- if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
- this.queueExpand(node);
- }else if(pt != "append"){
- this.cancelExpand();
- }
- // set the insert point style on the target node
- var returnCls = this.dropNotAllowed;
- if(this.isValidDropPoint(n, pt, dd, e, data)){
- if(pt){
- var el = n.ddel;
- var cls;
- if(pt == "above"){
- returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
- cls = "x-tree-drag-insert-above";
- }else if(pt == "below"){
- returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
- cls = "x-tree-drag-insert-below";
- }else{
- returnCls = "x-tree-drop-ok-append";
- cls = "x-tree-drag-append";
- }
- if(this.lastInsertClass != cls){
- Ext.fly(el).replaceClass(this.lastInsertClass, cls);
- this.lastInsertClass = cls;
- }
- }
- }
- return returnCls;
- },
- // private
- onNodeOut : function(n, dd, e, data){
- this.cancelExpand();
- this.removeDropIndicators(n);
- },
- // private
- onNodeDrop : function(n, dd, e, data){
- var point = this.getDropPoint(e, n, dd);
- var targetNode = n.node;
- targetNode.ui.startDrop();
- if(!this.isValidDropPoint(n, point, dd, e, data)){
- targetNode.ui.endDrop();
- return false;
- }
- // first try to find the drop node
- var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
- return this.processDrop(targetNode, data, point, dd, e, dropNode);
- },
- onContainerDrop : function(dd, e, data){
- if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
- var targetNode = this.tree.getRootNode();
- targetNode.ui.startDrop();
- var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);
- return this.processDrop(targetNode, data, 'append', dd, e, dropNode);
- }
- return false;
- },
- // private
- processDrop: function(target, data, point, dd, e, dropNode){
- var dropEvent = {
- tree : this.tree,
- target: target,
- data: data,
- point: point,
- source: dd,
- rawEvent: e,
- dropNode: dropNode,
- cancel: !dropNode,
- dropStatus: false
- };
- var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
- if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
- target.ui.endDrop();
- return dropEvent.dropStatus;
- }
- target = dropEvent.target;
- if(point == 'append' && !target.isExpanded()){
- target.expand(false, null, function(){
- this.completeDrop(dropEvent);
- }.createDelegate(this));
- }else{
- this.completeDrop(dropEvent);
- }
- return true;
- },
- // private
- completeDrop : function(de){
- var ns = de.dropNode, p = de.point, t = de.target;
- if(!Ext.isArray(ns)){
- ns = [ns];
- }
- var n;
- for(var i = 0, len = ns.length; i < len; i++){
- n = ns[i];
- if(p == "above"){
- t.parentNode.insertBefore(n, t);
- }else if(p == "below"){
- t.parentNode.insertBefore(n, t.nextSibling);
- }else{
- t.appendChild(n);
- }
- }
- n.ui.focus();
- if(Ext.enableFx && this.tree.hlDrop){
- n.ui.highlight();
- }
- t.ui.endDrop();
- this.tree.fireEvent("nodedrop", de);
- },
- // private
- afterNodeMoved : function(dd, data, e, targetNode, dropNode){
- if(Ext.enableFx && this.tree.hlDrop){
- dropNode.ui.focus();
- dropNode.ui.highlight();
- }
- this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
- },
- // private
- getTree : function(){
- return this.tree;
- },
- // private
- removeDropIndicators : function(n){
- if(n && n.ddel){
- var el = n.ddel;
- Ext.fly(el).removeClass([
- "x-tree-drag-insert-above",
- "x-tree-drag-insert-below",
- "x-tree-drag-append"]);
- this.lastInsertClass = "_noclass";
- }
- },
- // private
- beforeDragDrop : function(target, e, id){
- this.cancelExpand();
- return true;
- },
- // private
- afterRepair : function(data){
- if(data && Ext.enableFx){
- data.node.ui.highlight();
- }
- this.hideProxy();
- }
- });
- }/**
- * @class Ext.tree.TreeDragZone
- * @extends Ext.dd.DragZone
- * @constructor
- * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dragging
- * @param {Object} config
- */
- if(Ext.dd.DragZone){
- Ext.tree.TreeDragZone = function(tree, config){
- Ext.tree.TreeDragZone.superclass.constructor.call(this, tree.innerCt, config);
- /**
- * The TreePanel for this drag zone
- * @type Ext.tree.TreePanel
- * @property
- */
- this.tree = tree;
- };
- Ext.extend(Ext.tree.TreeDragZone, Ext.dd.DragZone, {
- /**
- * @cfg {String} ddGroup
- * A named drag drop group to which this object belongs. If a group is specified, then this object will only
- * interact with other drag drop objects in the same group (defaults to 'TreeDD').
- */
- ddGroup : "TreeDD",
- // private
- onBeforeDrag : function(data, e){
- var n = data.node;
- return n && n.draggable && !n.disabled;
- },
- // private
- onInitDrag : function(e){
- var data = this.dragData;
- this.tree.getSelectionModel().select(data.node);
- this.tree.eventModel.disable();
- this.proxy.update("");
- data.node.ui.appendDDGhost(this.proxy.ghost.dom);
- this.tree.fireEvent("startdrag", this.tree, data.node, e);
- },
- // private
- getRepairXY : function(e, data){
- return data.node.ui.getDDRepairXY();
- },
- // private
- onEndDrag : function(data, e){
- this.tree.eventModel.enable.defer(100, this.tree.eventModel);
- this.tree.fireEvent("enddrag", this.tree, data.node, e);
- },
- // private
- onValidDrop : function(dd, e, id){
- this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
- this.hideProxy();
- },
- // private
- beforeInvalidDrop : function(e, id){
- // this scrolls the original position back into view
- var sm = this.tree.getSelectionModel();
- sm.clearSelections();
- sm.select(this.dragData.node);
- },
- // private
- afterRepair : function(){
- if (Ext.enableFx && this.tree.hlDrop) {
- Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
- }
- this.dragging = false;
- }
- });
- }/** * @class Ext.tree.TreeEditor * @extends Ext.Editor * Provides editor functionality for inline tree node editing. Any valid {@link Ext.form.Field} subclass can be used * as the editor field. * @constructor * @param {TreePanel} tree * @param {Object} fieldConfig (optional) Either a prebuilt {@link Ext.form.Field} instance or a Field config object * that will be applied to the default field instance (defaults to a {@link Ext.form.TextField}). * @param {Object} config (optional) A TreeEditor config object */ Ext.tree.TreeEditor = function(tree, fc, config){ fc = fc || {}; var field = fc.events ? fc : new Ext.form.TextField(fc); Ext.tree.TreeEditor.superclass.constructor.call(this, field, config); this.tree = tree; if(!tree.rendered){ tree.on('render', this.initEditor, this); }else{ this.initEditor(tree); } }; Ext.extend(Ext.tree.TreeEditor, Ext.Editor, { /** * @cfg {String} alignment * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "l-l"). */ alignment: "l-l", // inherit autoSize: false, /** * @cfg {Boolean} hideEl * True to hide the bound element while the editor is displayed (defaults to false) */ hideEl : false, /** * @cfg {String} cls * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor") */ cls: "x-small-editor x-tree-editor", /** * @cfg {Boolean} shim * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false) */ shim:false, // inherit shadow:"frame", /** * @cfg {Number} maxWidth * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed * the containing tree element's size, it will be automatically limited for you to the container width, taking * scroll and client offsets into account prior to each edit. */ maxWidth: 250, /** * @cfg {Number} editDelay The number of milliseconds between clicks to register a double-click that will trigger * editing on the current node (defaults to 350). If two clicks occur on the same node within this time span, * the editor for the node will display, otherwise it will be processed as a regular click. */ editDelay : 350, initEditor : function(tree){ tree.on({ scope: this, beforeclick: this.beforeNodeClick, dblclick: this.onNodeDblClick }); this.on({ scope: this, complete: this.updateNode, beforestartedit: this.fitToTree, specialkey: this.onSpecialKey }); this.on('startedit', this.bindScroll, this, {delay:10}); }, // private fitToTree : function(ed, el){ var td = this.tree.getTreeEl().dom, nd = el.dom; if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible td.scrollLeft = nd.offsetLeft; } var w = Math.min( this.maxWidth, (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5); this.setSize(w, ''); }, /** * Edit the text of the passed {@link Ext.tree.TreeNode TreeNode}. * @param node {Ext.tree.TreeNode} The TreeNode to edit. The TreeNode must be {@link Ext.tree.TreeNode#editable editable}. */ triggerEdit : function(node, defer){ this.completeEdit(); if(node.attributes.editable !== false){ /** * The {@link Ext.tree.TreeNode TreeNode} this editor is bound to. Read-only. * @type Ext.tree.TreeNode * @property editNode */ this.editNode = node; if(this.tree.autoScroll){ Ext.fly(node.ui.getEl()).scrollIntoView(this.tree.body); } var value = node.text || ''; if (!Ext.isGecko && Ext.isEmpty(node.text)){ node.setText(' '); } this.autoEditTimer = this.startEdit.defer(this.editDelay, this, [node.ui.textNode, value]); return false; } }, // private bindScroll : function(){ this.tree.getTreeEl().on('scroll', this.cancelEdit, this); }, // private beforeNodeClick : function(node, e){ clearTimeout(this.autoEditTimer); if(this.tree.getSelectionModel().isSelected(node)){ e.stopEvent(); return this.triggerEdit(node); } }, onNodeDblClick : function(node, e){ clearTimeout(this.autoEditTimer); }, // private updateNode : function(ed, value){ this.tree.getTreeEl().un('scroll', this.cancelEdit, this); this.editNode.setText(value); }, // private onHide : function(){ Ext.tree.TreeEditor.superclass.onHide.call(this); if(this.editNode){ this.editNode.ui.focus.defer(50, this.editNode.ui); } }, // private onSpecialKey : function(field, e){ var k = e.getKey(); if(k == e.ESC){ e.stopEvent(); this.cancelEdit(); }else if(k == e.ENTER && !e.hasModifier()){ e.stopEvent(); this.completeEdit(); } }, onDestroy : function(){ clearTimeout(this.autoEditTimer); Ext.tree.TreeEditor.superclass.onDestroy.call(this); var tree = this.tree; tree.un('beforeclick', this.beforeNodeClick, this); tree.un('dblclick', this.onNodeDblClick, this); } });