PDA

View Full Version : [2.2]Ext.ux.tree.PagingTreeLoader



xiexueze
24 Aug 2008, 9:47 PM
Ext.ux.tree.PagingTreeLoader class extends Ext.tree.TreeLoader class
suport client paging and server paging

1.client paging uages:


var tree = new Ext.tree.TreePanel({
applyTo:'tree-ct',
width:300,
height:400,
autoScroll:true,
plugins: new Ext.ux.tree.TreeNodeMouseoverPlugin(), //must use the plugin
loader: new Ext.ux.tree.PagingTreeLoader({ //use the extend TreeLoader
dataUrl:'getNodes.jsp',
pageSize:10, //the count of the childnode to show every time
enableTextPaging:true, //whether to show the pagination's text
pagingModel:'local' //local means client paging ,remote means server paging
}),
root: new Ext.tree.AsyncTreeNode({ id:'0',text:'root' })
});

the server just get the 'node' paramenter value,and return the JSON like this:


[{id:1,text:'node1',leaf:false,children:[{...},...{...}]},{id:1,text:'node2',leaf:true},...,{id:100,text:'node100',leaf:true}]


2.server paging uages:
the js just change the pagingModel value to 'remote'.
the server will receive some parameters:

node : the id of the node which is expending or paging
start : the start index of the children,when the node first expends,the start value is 0
limit : equals the jscode's pageSize,means the count of the node to show ervery time
total : the total count of the node's children,when the node first expends,the total parameter dosen't exist


the server return the JSON like this:


{total:200,nodes:[{id:1,text:'node1',leaf:false},...,{id:100,text:'node100',leaf:false}]}


Update 2009-4-28
I had rewrote this extension to fix some bugs,and had upload to the attachment name PagingTreeLoader(2009-4-28).zip

the PagingTreeLoader had been tested in IE6/firefox3/chrome1/safari4, and support the ext2.x , thanks !

Emblem Parade
24 Sep 2008, 10:08 PM
I'm getting a "D.firstChild is null" error.

Any chance you can post a non-JSMin-ed version of the source, so I can help debug?

This seems like an ingenious way to handle the "very large tree" problem. I hope we can get it to work!

juststrings
13 Oct 2008, 6:31 AM
xiexueze,

I think your post is extremely useful since pagination is required many a time... I am trying to implement the same paging functionality in EXT 1.1... Could you pl.post the non minified version so that many users like myself could benefit from this? I think I am getting an error in the Toolbar constructor because I am using EXt 1.1 but nevertheless I think I might be able to use your class as a very useful starting point and build from there..

Thanks!

crashedsnow
26 Jan 2009, 8:09 PM
Hi,

I've just implemented this extension, and it's exactly what I needed! I have a tree with some branches owning thousands of nodes. Very good solution.

I do have some display issues though.

1. I had to modify the source code to change the style of the text displayed after the textbox (the source has a hard coded <font>) tag which I changed to a span with a style

2. I get a strange "wobble" when I mouse over the paging toolbar within the tree. It's only about a 1 pixel vertical wobble as the mouse is moved, but it makes the control look a bit strange. (hard to explain this one)

3. When operating within a bordered layout with a scrollbar, we get two weird behaviors (see attached)

A) When paging to the next page, the call to "reload()" the node causes the tree to close the node for reloading (normal tree behavior). If however, closing the node causes the scroll in the containing panel to change, the paging toolbar is left "floating" in mid-air until the node is loaded. We solved this by adding the following:



reload : function() {
this.hide(); <-- Added this
this.updateField();
this.treeNode.reload()
},



This just makes sure the toolbar is hidden while the reload happens.

B ) When the width of the containing panel is not sufficient to contain the toolbar, it is rendered ABOVE the scrollbar/split of the layout. See attachments for this.

Any ideas on solutions to 2, and 3B?

Thanks

crashedsnow
26 Jan 2009, 8:20 PM
I just added this "hack" to fix the toolbar "wobble" (mentioned in previous post).

In Ext.ux.tree.PagingTreeLoader#showToolbar, changed the "move" behaviour




// add a fudge factor to keep toolbar stable
var currentA = this.pagingTreeToolbar.getEl().getX();
var currentG = this.pagingTreeToolbar.getEl().getY();
if(Math.abs(currentA - A) > 5 && Math.abs(currentG - G) > 5) {
this.pagingTreeToolbar.getEl().moveTo(A, G);
}

superDuke
26 Feb 2009, 7:18 AM
If you have your root node paged, when you move out of the treepanel, the pager toolbar remains. This is problamatic if your tree is inside a tab panel. When switching tabs, the pager is on top of all other items. Has anyone else had this issue?

superDuke
26 Feb 2009, 8:23 AM
Got it.. thanks to Animal in http://extjs.com/forum/showthread.php?p=180375#post180375


Ext.ux.tree.TreeNodeMouseoverPlugin = Ext.extend(Object, {
init: function(_tree) {
if (!_tree.rendered) {
_tree.on('render', function() {this.init(_tree)}, this);
return;
}
this.tree = _tree;
_tree.body.on('mouseover', this.onTreeMouseover, this, {delegate: 'a.x-tree-node-anchor'});
_tree.body.on('mouseout', this.onTreeMouseout, this, {delegate: 'div.x-tree-node-el'});
},

onTreeMouseover: function(e, t) {
var nodeEl = Ext.fly(t).up('div.x-tree-node-el');
if (nodeEl) {
var nodeId = nodeEl.getAttributeNS('ext', 'tree-node-id');
if (nodeId) {
this.tree.fireEvent('mouseover', this.tree.getNodeById(nodeId), e);
}
}
},

onTreeMouseout: function(e, t) {
var nodeEl = Ext.fly(t);
if (nodeEl) {
var nodeId = nodeEl.getAttributeNS('ext', 'tree-node-id');
if (nodeId) {
this.tree.fireEvent('mouseout', this.tree.getNodeById(nodeId), e);
}
}
},
});

binod dokania
21 Apr 2009, 1:10 PM
I tried using this plugin but I am not getting any pagination buttons (next,previous etc.) although I am able to get the desired number of nodes. I am assuming that by the side of node to expand these buttons should appear.

Am I missing any images or any css to include. I have included

pagingTreeLoader.js
pagingTreeLoader.css
TreeNodeMouseoverPlugin.js

superDuke
21 Apr 2009, 1:13 PM
Have you tried using firebug to see if the mouseout / mouseover events are firing? Firebug should also tell you if you are including resources but the paths are bad.

binod dokania
21 Apr 2009, 1:52 PM
Following is the snapshot from firebug which says that mouseover event is fired.
I am also not getting any resources not fround exception

superDuke
21 Apr 2009, 1:57 PM
Step through the showToolbar function in the pagingtreeloader, see what F has:



if (!F.isLoaded)
{
return;
}

if ((F.isLeaf() || !F.isLoaded()) && E !== true)
{
this.pagingTreeToolbar.hide();
return
}

binod dokania
21 Apr 2009, 2:14 PM
Going through that function does not hide the toolbar as those conditions are not met.
Please refer the snapshot

binod dokania
21 Apr 2009, 2:15 PM
Do we need to override the treemouseOverPlugin provided by Animal. I saw that it is already included in the main PagingTreeLoader.js

superDuke
21 Apr 2009, 2:38 PM
Should work without it. Can you post the code or a stripped down example?

binod dokania
21 Apr 2009, 2:44 PM
Actually I am using tree inside a complex layout. So it won't be easy for you to debug through that. I will try to mimic the same in a prototype and let u know. In the mean time if you have any sample working code any where, can you please post that.

Thanks

superDuke
21 Apr 2009, 3:17 PM
Try this. Put it in the examples/tree directory. Root will get a toolbar once it loads.

binod dokania
22 Apr 2009, 10:59 AM
Thanks SuperDuke,

Your example is working fine. But when I tried to get it work in my scenario it is not working. I tried to modify your html only to mimic my scenario.Please refer the attached file. My tree panel, along with a grid on the right hand side, is inside a panel. This panel is inside a Window.

What I noticed that pagingTreeToolbar is rendered in document.body. So it might be due to this it is not visible while we hover the mouse. Can't we specify toolbar to render inside treePanel (e.g. top/bottom toolbar etc..)

liqingzhu
22 Apr 2009, 5:26 PM
SuperDuke:
How are you!:) I tried to get the Parameter("start","limit") at Server,but the value is null?
Please tell me why and how to use the remote ?
My code is like this

var root = new Ext.tree.AsyncTreeNode({
text:'HEADOFFICE',
expanded:true,
id:'0'
});
/*var loader = new Ext.tree.TreeLoader({
baseAttrs:{cust:'client'},

dataUrl:'/apollo/back/Companyaction_getallcompanyinfos.action'
});*/
var loader = new Ext.ux.tree.PagingTreeLoader({ TreeLoader
dataUrl:'/apollo/back/Companyaction_getallcompanyinfos.action',
pageSize:10,
enableTextPaging:true,
pagingModel:'remote', //local is client,remote is server
params:{start:0,limit:10} //the paramter
});

loader.on("beforeload",function(treeloader,node)
{
treeloader.baseParams = {
id : node.id,
fzr: node.attributes.fzr
};
},this);

var tree = new Ext.tree.TreePanel({
plugins: new Ext.ux.tree.TreeNodeMouseoverPlugin(),
loader:loader,
title:'Company Info',
width:280,
autoHeight:true,
autoScroll: true,
height:400,
tbar:[
{text:'add',tooltip:'addinfo',iconCls:'add',handler:addcompany}
listeners: {
'render': function(tp){
tp.getSelectionModel().on('selectionchange', function(tree, node){
var el = Ext.getCmp('details-panel').body;
tpl.overwrite(el, node.attributes);

})
}
},
root:root
});

superDuke
22 Apr 2009, 6:23 PM
Hi liqingzhu, override the getParameters method for the loader to include parsing the node.attributes.pagingInfo and appending to the buffer.

superDuke
22 Apr 2009, 6:40 PM
binod dokania, the toolbar is rendered but needs a high z-index to be shown on top of the other components. When I set the z-index:15000, the toolbar shows on top of the window.

binod dokania
22 Apr 2009, 7:49 PM
Superduke,
I solved that issue by modifying pagingTreeLoader.js and passing pagingToolbar from treePanel itself. I will try your option as well..your's one is easy enough...

binod dokania
24 Apr 2009, 12:36 PM
Today I moved to latest3.0 release. There example posted is throwing exception:

this.field is null.

did u encountered same issue?

binod dokania
27 Apr 2009, 11:20 AM
I am able to integrate it to ext3.0RC1.
but I am facing issue with reload of tree. After some update i want to relaod the tree but call itself does not fire, which used to fire with normal treeLoader

xiexueze
27 Apr 2009, 11:09 PM
I am so sorry to forget about this thread .

yes I have rewrote and uploaded the PagingTreeLoader(2009-4-28) (http://extjs.com/forum/showthread.php?p=213913) to fix some bugs,and had tested in IE6/firefox3/chrome1/safari4, support ext2.x ,of course it is not to be compressed.

Additional,I also have rewrote this extention to support the latest Ext3.0 RC1
http://extjs.com/forum/showthread.php?p=322438
thanks!

binod dokania
28 Apr 2009, 10:42 AM
xiexueze (http://extjs.com/forum/member.php?u=7927),

Thanks! I wish I could find that thread which could saved my effort . I tried with your new files as well but with this one does not remove the paging toolbar after taking out the mouse.
With ext 2.2 when you hover your mouse then only you see the paging tree toolbar otherwise not.

xiexueze
28 Apr 2009, 7:01 PM
yes, cause I think the user would might ignore the paging toolbar when hide the toolbar.
but if you want ,you can just change the method onMouseOver like this:


onMouseOver : function(node){
var ptb = node.attributes.ptb;
if(node.isLeaf() || !node.isLoaded() || !ptb){
if(this.ptb){
this.ptb.hide();
}
return;
}
if(this.ptb !== ptb){
if(this.ptb){
this.ptb.hide();
}
this.ptb = ptb;
}
this.ptb.show();
},

binod dokania
29 Apr 2009, 2:57 PM
Thanks xiexueze (http://extjs.com/forum/member.php?u=7927),

One more thing now we need to hover the mouse over the node only then toolbar appears.
Previously even if hover the mouse anywhere in area by the side of node then also toolbar use to appear.

I need this for other feature e.g. click etc which is i think got overridden by this pagingtoolbar. vbmenu_register("postmenu_322862", true);

lionking_twx
3 Jun 2009, 3:18 PM
great work!thanks to you!
but when there is a node newly added without leaf:true/false configured an error might occured,which says:property or method not supported

navaro_81
8 Sep 2009, 3:37 AM
Hi,
I tested your nice code but it`s contain small bugs, therefore I decided to review your code and make it more efficient with less bugs and more flexibility.
I hope your enjoy


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ext.ns("Ext.ux.tree");

Ext.ux.tree.PagingTreeLoader = function(config) {

this.pagingModel = config.pagingModel || "local";
this.pageSize = config.pageSize || 20;
this.ptb = false;
this.ptbConfig = {enableTextPaging:config.enableTextPaging,hideMode:'visibility1'};

Ext.ux.tree.PagingTreeLoader.superclass.constructor.apply(this, arguments);
};

Ext.extend(Ext.ux.tree.PagingTreeLoader, Ext.tree.TreeLoader, {
doPreload : function(node){
var pi = node.attributes.pagingInfo;
if(pi == undefined){
node.attributes.pagingInfo = pi = {limit: this.pageSize,start: 0};
}
if(this.pagingModel == "local"){
var children = node.attributes.children;
if(children){
var limit = pi.limit;
var start = pi.start;
var total = pi.total = children.length;

node.beginUpdate();
for(var len = (start + limit); start < len && start < total; start++){
var cn = node.appendChild(this.createNode(children[start]));
if(this.preloadChildren){
this.doPreload(cn);
}
}
node.endUpdate();

if(limit < total){
this.createToolbar(node);
}

return true;
}
}

Ext.apply(this.baseParams,pi);

return false;
},

processResponse : function(response, node, callback){
var json = response.responseText;
try {
var o = eval("("+json+")");
var pi = node.attributes.pagingInfo;
if(this.isArray(o)){
pi.total = o.length;
}else{
pi.total = o.total || o.nodes.length;
o = o.nodes;
}
if(this.pagingModel == 'local'){
node.attributes.children = o;
}
node.beginUpdate();
for(var i = 0, len = o.length; i < len && i < pi.limit; i++){
var cn = this.createNode(o[i]);
if(cn){
cn = node.appendChild(cn);
}
}
node.endUpdate();

if(pi.limit < pi.total){
this.createToolbar(node);
}

if(typeof callback == "function"){
callback(this, node);
}
}catch(e){
this.handleFailure(response);
}
},

isArray : function(v){
return v && typeof v.length == 'number' && typeof v.splice == 'function';
},

handleResponse : function(response){
this.transId = false;
var arg = response.argument;
this.processResponse(response, arg.node, arg.callback);
this.fireEvent("load", this, arg.node, response);

this.addMouseOverEvent(arg.node);
},

addMouseOverEvent : function(node){
var tree = node.ownerTree;
if(!tree.hasListener('mouseover')){
tree.on('mouseover',this.onMouseOver,this);
}
},

onMouseOver : function(node){
if(node.isLeaf() || !node.isLoaded()){
return;
}
var ptb = node.attributes.ptb;
if(ptb){
if(this.ptb !== ptb){
if(this.ptb)
this.ptb.hide();
this.ptb = ptb;
}
ptb.show();
}
},


createToolbar : function(node){
var ptb = node.attributes.ptb;
var tree = node.ownerTree;

if(this.ptb !== ptb){
if(this.ptb){
this.ptb.hide();
}
var showTop = (!tree.rootVisible && node.isRoot);
if(ptb == undefined){
node.attributes.ptb = ptb = new Ext.ux.tree.PagingTreeToolbar(this.ptbConfig);

var el = node.getUI().getEl();
if(!showTop){
el = Ext.get(el.firstChild);
if(Ext.isIE){
el.addClass('x-tree-paging-nowrap');
el = Ext.DomHelper.append(el,{tag:'div',cls:'x-tree-paging-inline'},true);
}else{
el.addClass('x-tree-paging-float');
el = Ext.DomHelper.insertAfter(el,{tag:'div',cls:'x-tree-paging-inline'},true);
}
}
ptb.render(el);
}
this.ptb = showTop ? this.ptb : ptb;
}
ptb.setTreeNode(node);
}

});

Ext.ux.tree.TreeNodeMouseoverPlugin = Ext.extend(Object, {
init: function(tree) {
if (!tree.rendered) {
tree.on('render', function() {this.init(tree)}, this);
}else{
this.tree = tree;
tree.body.on('mouseover', this.onTreeMouseover, this, {delegate: 'div.x-tree-node-el'});
}
},
onTreeMouseover: function(e, t) {
var nodeEl = Ext.fly(t);
if (nodeEl) {
var nodeId = nodeEl.getAttributeNS('ext', 'tree-node-id');
if (nodeId) {
this.tree.fireEvent('mouseover', this.tree.getNodeById(nodeId), e);
}
}
}
});


Ext.ux.tree.PagingTreeToolbar = Ext.extend(Ext.Toolbar, {

firstText : Ext.PagingToolbar.prototype.firstText,
prevText : Ext.PagingToolbar.prototype.prevText,
nextText : Ext.PagingToolbar.prototype.nextText,
lastText : Ext.PagingToolbar.prototype.lastText,
afterPageText : "<font size=2> / {0}</font>",

autoCreate: {
cls:'x-tree-paging-toolbar x-small-editor x-tree-paging-inline',
style:'vertical-align:middle',
html:'<table cellspacing="0"><tr></tr></table>'
},

// private
onRender : function(ct, position){
this.height = Ext.isIE ? 10 : 18;
this.width = 50;
Ext.PagingToolbar.superclass.onRender.call(this, ct, position);

this.first = this.addButton({
tooltip: this.firstText,
cls:"x-tree-paging-btn-icon",
iconCls: "x-tbar-page-first",
disabled: true,
handler: this.onClick.createDelegate(this, ["first"])
});
this.prev = this.addButton({
tooltip: this.prevText,
cls:"x-tree-paging-btn-icon",
iconCls: "x-tbar-page-prev",
disabled: true,
handler: this.onClick.createDelegate(this, ["prev"])
});
if(this.enableTextPaging == true){
this.addText('&nbsp;');
this.field = new Ext.form.TextField({
enableKeyEvents:true,
selectOnFocus : true,
cls: "x-tbar-page-number"
})
this.add(this.field);
this.addText('&nbsp');
this.field.on("keydown", this.onPagingKeydown, this);
this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
};
this.next = this.addButton({
tooltip: this.nextText,
cls:"x-tree-paging-btn-icon",
iconCls: "x-tbar-page-next",
disabled: true,
handler: this.onClick.createDelegate(this, ["next"])
});
this.last = this.addButton({
tooltip: this.lastText,
cls:"x-tree-paging-btn-icon",
iconCls: "x-tbar-page-last",
disabled: true,
handler: this.onClick.createDelegate(this, ["last"])
});
if(true){
this.addText('&nbsp;&nbsp;<span style="font-size:10">Search:</span>');
this.fieldSearch = new Ext.form.TextField({
enableKeyEvents:true,
width:90
})
this.fieldSearch.on("keydown",
function(t, e)
{
if (e.getKey() == e.RETURN)
{
e.stopEvent();
this.pi.query = t.getValue();
this.treeNode.reload();
}
}
, this);
this.add(this.fieldSearch);
};

},

// private
onClick : function(which){
switch(which){
case "first":
this.pi.start = 0;
break;
case "prev":
this.pi.start = Math.max(0, this.pi.start-this.pi.limit);
break;
case "next":
this.pi.start = this.pi.start+this.pi.limit;
break;
case "last":
var total = this.pi.total;
var extra = total % this.pi.limit;
var lastStart = extra ? (total - extra) : (total-this.pi.limit);
this.pi.start = lastStart;
break;
}
this.updateField();
this.treeNode.reload();
},

// private
updateField : function(){
if(this.enableTextPaging === true){
var d = this.getPageData(), ap = d.activePage, ps = d.pages;
this.afterTextEl.setText(String.format(this.afterPageText, d.pages));
this.field.setValue(ap);
}

},

// private
onPagingKeydown : function(t, e){

var k = e.getKey(), d = this.getPageData(), pageNum;
if (k == e.RETURN) {
e.stopEvent();
pageNum = this.readPage(d);
if(pageNum !== false){
pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
this.pi.start = pageNum * this.pi.limit;
this.treeNode.reload();
}
}else if (k == e.HOME || k == e.END){
e.stopEvent();
pageNum = k == e.HOME ? 1 : d.pages;
this.field.setValue(pageNum);
}else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN){
e.stopEvent();
if(pageNum = this.readPage(d)){
var increment = e.shiftKey ? 10 : 1;
if(k == e.DOWN || k == e.PAGEDOWN){
increment *= -1;
}
pageNum += increment;
if(pageNum >= 1 & pageNum <= d.pages){
this.field.setValue(pageNum);
}
}
}
},

// private
readPage : function(d){
var v = this.field.getValue(), pageNum;
if (!v || isNaN(pageNum = parseInt(v, 10))) {
this.field.dom.value = d.activePage;
return false;
}
return pageNum;
},

// private
getPageData : function(){
var pi = this.pi;
var total = pi.total;
return {
total : total,
activePage : Math.ceil((pi.start+pi.limit)/pi.limit),
pages : total < pi.limit ? 1 : Math.ceil(total/pi.limit)
};
},

// private
resetToolBar : function(){
var fp = this.pi.start == 0;
var nl = (this.pi.start + this.pi.limit) >= this.pi.total;

this.first.setDisabled(fp);
this.prev.setDisabled(fp);
this.next.setDisabled(nl);
this.last.setDisabled(nl);

this.updateField();
},

setTreeNode : function(node){
this.treeNode = node;
this.pi = this.treeNode.attributes.pagingInfo;

this.resetToolBar();
}
});