/** * Retrieve an array of ids of checked nodes * @return {Array} array of ids of checked nodes */ Ext.tree.TreePanel.prototype.getChecked = function(node){ var checked = [], i; if( typeof node == 'undefined' ) { //node = this.rootVisible ? this.getRootNode() : this.getRootNode().firstChild; node = this.getRootNode(); } if( node.attributes.checked ) { checked.push(node.id); } if( node.childNodes.length ) { for( i = 0; i < node.childNodes.length; i++ ) { checked = checked.concat( this.getChecked(node.childNodes[i]) ); } } return checked; }; /** * @class Ext.tree.CustomUITreeLoader * @extends Ext.tree.TreeLoader * Overrides createNode to force uiProvider to be an arbitrary TreeNodeUI to save bandwidth */ Ext.tree.CustomUITreeLoader = function() { Ext.tree.CustomUITreeLoader.superclass.constructor.apply(this, arguments); }; Ext.extend(Ext.tree.CustomUITreeLoader, Ext.tree.TreeLoader, { createNode : function(attr){ Ext.apply(attr, this.baseAttr || {}); if(this.applyLoader !== false){ attr.loader = this; } if(typeof attr.uiProvider == 'string'){ attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider); } return(attr.leaf ? new Ext.tree.TreeNode(attr) : new Ext.tree.AsyncTreeNode(attr)); } }); /** * @class Ext.tree.CheckboxNodeUI * @extends Ext.tree.TreeNodeUI * Adds a checkbox to all nodes */ Ext.tree.CheckboxNodeUI = function() { Ext.tree.CheckboxNodeUI.superclass.constructor.apply(this, arguments); }; Ext.extend(Ext.tree.CheckboxNodeUI, Ext.tree.TreeNodeUI, { /** * This is virtually identical to Ext.tree.TreeNodeUI.render, modifications are indicated inline */ render : function(bulkRender){ var n = this.node; var targetNode = n.parentNode ? n.parentNode.ui.getContainer() : n.ownerTree.container.dom; /* in later svn builds this changes to n.ownerTree.innerCt.dom */ if(!this.rendered){ this.rendered = true; var a = n.attributes; // add some indent caching, this helps performance when rendering a large tree this.indentMarkup = ""; if(n.parentNode){ this.indentMarkup = n.parentNode.ui.getChildIndent(); } // modification: added checkbox var buf = ['
  • ', '',this.indentMarkup,"", '', '', '" : '>'), '', '',n.text,"
    ", '', "
  • "]; if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){ this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join("")); }else{ this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join("")); } 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]; this.checkbox = cs[3]; // modification: inserted checkbox this.anchor = cs[4]; this.textNode = cs[4].firstChild; 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(); // modification: Add additional handlers here to avoid modifying Ext.tree.TreeNodeUI Ext.fly(this.checkbox).on('click', this.check.createDelegate(this, [null])); n.on('dblclick', function(e) { if( this.isLeaf() ) { this.getUI().toggleCheck(); } }); if(!this.node.expanded){ this.updateExpandIcon(); } }else{ if(bulkRender === true) { targetNode.appendChild(this.wrap); } } }, checked : function() { return this.checkbox.checked; }, /** * Sets a checkbox appropriately. By default only walks down through child nodes * if called with no arguments (onchange event from the checkbox), otherwise * it's assumed the call is being made programatically and the correct arguments are provided. * @param {Boolean} state true to check the checkbox, false to clear it. (defaults to the opposite of the checkbox.checked) * @param {Boolean} descend true to walk through the nodes children and set their checkbox values. (defaults to false) */ check : function(state, descend, bulk) { if (this.node.disabled) { return; } var n = this.node; var tree = n.getOwnerTree(); var parentNode = n.parentNode;n if( !n.expanded && !n.childrenRendered ) { n.expand(false, false, this.check.createDelegate(this, arguments)); } if( typeof bulk == 'undefined' ) { bulk = false; } if( typeof state == 'undefined' || state === null ) { state = this.checkbox.checked; descend = !state; if( state ) { n.expand(false, false); } } else { this.checkbox.checked = state; } n.attributes.checked = state; // do we have parents? if( parentNode !== null && state ) { // if we're checking the box, check it all the way up if( parentNode.getUI().check ) { //parentNode.getUI().check(state, false, true); } } if( descend && !n.isLeaf() ) { var cs = n.childNodes; for(var i = 0; i < cs.length; i++) { //cs[i].getUI().check(state, true, true); } } if( !bulk ) { tree.fireEvent('check', n, state); } }, toggleCheck : function(state) { this.check(!this.checkbox.checked, true); } }); /** * @class Ext.tree.CheckNodeMultiSelectionModel * @extends Ext.tree.MultiSelectionModel * Multi selection for a TreePanel containing Ext.tree.CheckboxNodeUI. * Adds enhanced selection routines for selecting multiple items * and key processing to check/clear checkboxes. */ Ext.tree.CheckNodeMultiSelectionModel = function(){ Ext.tree.CheckNodeMultiSelectionModel.superclass.constructor.call(this); }; Ext.extend(Ext.tree.CheckNodeMultiSelectionModel, Ext.tree.MultiSelectionModel, { init : function(tree){ this.tree = tree; tree.el.on("keydown", this.onKeyDown, this); tree.on("click", this.onNodeClick, this); }, /** * Handle a node click * If ctrl key is down and node is selected will unselect the node. * If the shift key is down it will create a contiguous selection * (see {@link Ext.tree.CheckNodeMultiSelectionModel#extendSelection} for the limitations) */ onNodeClick : function(node, e){ if (node.disabled) { return; } if( e.shiftKey && this.extendSelection(node) ) { return true; } if( e.ctrlKey && this.isSelected(node) ) { this.unselect(node); } else { this.select(node, e, e.ctrlKey); } }, /** * Selects all nodes between the previously selected node and the one that the user has just selected. * Will not span multiple depths, so only children of the same parent will be selected. */ extendSelection : function(node) { var last = this.lastSelNode; if( node == last || !last ) { return false; /* same selection, process normally normally */ } if( node.parentNode == last.parentNode ) { var cs = node.parentNode.childNodes; var i = 0, attr='id', selecting=false, lastSelect=false; this.clearSelections(true); for( i = 0; i < cs.length; i++ ) { // We have to traverse the entire tree b/c don't know of a way to find // a numerical representation of a nodes position in a tree. if( cs[i].attributes[attr] == last.attributes[attr] || cs[i].attributes[attr] == node.attributes[attr] ) { // lastSelect ensures that we select the final node in the list lastSelect = selecting; selecting = !selecting; } if( selecting || lastSelect ) { this.select(cs[i], null, true); // if we're selecting the last node break to avoid traversing the entire tree if( lastSelect ) { break; } } } return true; } else { return false; } }, /** * Traps the press of the SPACE bar and sets the check state of selected nodes to the opposite state of * the selected or last selected node. Assume you have the following five Ext.tree.CheckboxNodeUIs: * [X] One, [X] Two, [X] Three, [ ] Four, [ ] Five * If you select them in this order: One, Two, Three, Four, Five and press the space bar they all * will be checked (the opposite of the checkbox state of Five). * If you select them in this order: Five, Four, Three, Two, One and press the space bar they all * will be unchecked which is the opposite of the checkbox state of One. */ onKeyDown : Ext.tree.DefaultSelectionModel.prototype.onKeyDown.createInterceptor(function(e) { var s = this.selNode || this.lastSelNode; // undesirable, but required var sm = this; if(!s){ return; } var k = e.getKey(); switch(k){ case e.SPACE: e.stopEvent(); var sel = this.getSelectedNodes(); var state = !s.getUI().checked(); if( sel.length == 1 ) { s.getUI().check(state, !s.isLeaf()); } else { for( var i = 0; i < sel.length; i++ ) { sel[i].getUI().check(state, !sel[i].isLeaf() ); } } break; } return true; }) });