PDA

View Full Version : [solved] Style <li> of a tree node



Bulle Bas
11 Dec 2009, 7:47 AM
How can I acces the <li>-element of a tree node?
I want to add a class to the li element of a tree node. The following code adds a class to the node's text, but not the li itselves.




var tree = new Tree.TreePanel({

loader: new Ext.tree.TreeLoader({
url: '/my?format=json',
createNode: function (attr) {
if (attr.isVisible == '0') {
attr.cls = 'invisible';
}
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
}
}),
// more
});

Bulle Bas
11 Dec 2009, 8:37 AM
An update:

I thought that this might work, but it doesn't have any effect.


loader: new Ext.tree.TreeLoader({
url: '/my?format=json',
createNode: function (attr) {
var node = Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
if (attr.isVisible == '0') {
node.ui.addClass('invisible');
}
return node;
}
}),


Is this because changing the ui of the node needs to be done prior to Ext.tree.TreeLoader.prototype.createNode.call(this, attr);?

Animal
12 Dec 2009, 12:38 AM
It's the getEl() of the TreeNodeUI that you want to style.

That's private right now, but I cannot think of a good reason why. I'm going to add doc comments to make it public.

Bulle Bas
12 Dec 2009, 2:41 AM
Ah I was allready looking for it, beacuse most components provide a getEl()-method. I am happy you will improve this.

But one thing bugs me still, is that the TreeNodeUI does provide us an addClass()-method, but still doesn't have any effect. I am wondering what its purpose might be then and why TreeNodeUI.addClass() doesn't apply to a live dom element?

Bulle Bas
12 Dec 2009, 5:37 AM
This suggestion doesn't work too, since getEl is undefined yet.


loader: new Ext.tree.TreeLoader({
url: '/my?format=json',
createNode: function (attr) {
var node = Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
if (attr.isVisible == '0') {
node.ui.getEl().addClass('invisible'); // wrong getEl is undefined.
}
return node;
}
}),


It's the same with node.getEl(). This disturbs me, since I don't see a statement that getEl() is only defined at a certain condition.

How can I add a class to the node's li? I am lost now.:-/

Animal
12 Dec 2009, 9:03 AM
Try this



Ext.override(Ext.tree.TreeNodeIO, {
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.wrap.addClass(this.cls);

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;
}
});


Then configure it with a cls config

If that works for you I will post that as a Feature Request. It's quite normal to want to add your own class to stuff.

Bulle Bas
12 Dec 2009, 10:30 AM
Firebug tells me that


e is undefined
anonymous(Object name=e, Object)
/ext-js/ext-3.0.3/adapter/ext/ext-base.js Line 7


It has to do with renderElements() but I don't see what is going wrong here. I get this problem no matter if I disable my own line (red-colored).

You overide TreeNodeIO. How does my own value for cls 'reach' this class. Via node.cls?



Ext.override(Ext.tree.TreeNodeIO, {
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.wrap.addClass(this.cls);

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;
}
});



Ext.onReady(function () {
// shorthand
var Tree = Ext.tree;

var tree = new Tree.TreePanel({
useArrows: true,
autoScroll: true,
animate: true,
enableDD: true,
border: false,


treePanel: this,

loader: new Ext.tree.TreeLoader({
url: '/my?format=json',

createNode: function (attr) {
var node = Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
if (attr.isVisible == '0') {
node.cls = 'invisble';
}

return node;
}
}),

root: {
nodeType: 'async',
text: 'Ext JS',
draggable: false,
id: 'src'
}

});

// render the tree
tree.render('tree-div');
tree.getRootNode().expand();
});


Thanks for your help sofar. I agree it is a reasonable feature request.

On a sidenote, the api in this respect is highly confusing to me. At least behaviour ? api/documentation.

Animal
12 Dec 2009, 10:32 AM
I made a typo.

Bulle Bas
12 Dec 2009, 10:45 AM
Ah, do you know which?


Ext.override(Ext.tree.TreeNodeIO, {
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('');


I see that nel is not defined, but honestly I dont get the whole cb declaration.:P

Bulle Bas
12 Dec 2009, 11:46 AM
Ah, you meant Ext.tree.TreeNodeUI. I didn't saw it at first.
Still, this code does't work. Your addition (red line) is faulty

this.wrap.addClass(this.cls);
this.wrap seems to be a regular html-string. I am now looking for a way to add a class to this string using Ext (I don't know Ext thorougly yet).

UPDATE: this is fixed too. Correct solution.


Ext.override(Ext.tree.TreeNodeUI, {
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);
}
new Ext.Element(this.wrap).addClass(this.cls);

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;
}
});

Many thanks for your code, I wouldn't have figured this out on my own

Still, it might be better if there would be a working TreeNodeUI.getEl() method...:)