313 lines
12 KiB
JavaScript
Executable File
313 lines
12 KiB
JavaScript
Executable File
/**
|
|
* 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 = ['<li class="x-tree-node"><div class="x-tree-node-el ', n.attributes.cls,'">',
|
|
'<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
|
|
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon">',
|
|
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
|
|
'<input class="l-tcb" '+ (n.disabled ? 'disabled="disabled" ' : '') +' type="checkbox" ', (a.checked ? "checked>" : '>'),
|
|
'<a hidefocus="on" href="',a.href ? a.href : "#",'" ',
|
|
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
|
|
'<span unselectable="on">',n.text,"</span></a></div>",
|
|
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
|
|
"</li>"];
|
|
|
|
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 <b>checked</b> (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 <b>unchecked</b> 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;
|
|
})
|
|
});
|