/*!
* Ext JS Library 3.4.0
* Copyright(c) 2006-2011 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
/**
* @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.
*
* 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.
*
* This class provides access to the user interface components of an Ext TreeNode, through
* {@link Ext.tree.TreeNode#getUI}
*/
Ext.tree.TreeNodeUI = Ext.extend(Object, {
constructor : function(node){
Ext.apply(this, {
node: node,
rendered: false,
animating: false,
wasLeaf: true,
ecc: 'x-tree-ec-icon x-tree-elbow',
emptyIcon: Ext.BLANK_IMAGE_URL
});
},
// 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
onIconClsChange : function(node, cls, oldCls){
if(this.rendered){
Ext.fly(this.iconNode).replaceClass(oldCls, cls);
}
},
// private
onIconChange : function(node, icon){
if(this.rendered){
//'',
var empty = Ext.isEmpty(icon);
this.iconNode.src = empty ? this.emptyIcon : icon;
Ext.fly(this.iconNode)[empty ? 'removeClass' : 'addClass']('x-tree-node-inline-icon');
}
},
// private
onTipChange : function(node, tip, title){
if(this.rendered){
var hasTitle = Ext.isDefined(title);
if(this.textNode.setAttributeNS){
this.textNode.setAttributeNS("ext", "qtip", tip);
if(hasTitle){
this.textNode.setAttributeNS("ext", "qtitle", title);
}
}else{
this.textNode.setAttribute("ext:qtip", tip);
if(hasTitle){
this.textNode.setAttribute("ext:qtitle", title);
}
}
}
},
// private
onHrefChange : function(node, href, target){
if(this.rendered){
this.anchor.href = this.getHref(href);
if(Ext.isDefined(target)){
this.anchor.target = target;
}
}
},
// private
onClsChange : function(node, cls, oldCls){
if(this.rendered){
Ext.fly(this.elNode).replaceClass(oldCls, cls);
}
},
// private
onDisableChange : function(node, state){
this.disabled = state;
if (this.checkbox) {
this.checkbox.disabled = state;
}
this[state ? 'addClass' : '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} value (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 <li>
.
*/
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){
this.onTipChange(n, a.qtip, 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 = this.getHref(a.href),
buf = ['
* 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.
*/
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 = '