424 lines
No EOL
14 KiB
JavaScript
424 lines
No EOL
14 KiB
JavaScript
/*
|
|
This file is part of Ext JS 3.4
|
|
|
|
Copyright (c) 2011-2013 Sencha Inc
|
|
|
|
Contact: http://www.sencha.com/contact
|
|
|
|
GNU General Public License Usage
|
|
This file may be used under the terms of the GNU General Public License version 3.0 as
|
|
published by the Free Software Foundation and appearing in the file LICENSE included in the
|
|
packaging of this file.
|
|
|
|
Please review the following information to ensure the GNU General Public License version 3.0
|
|
requirements will be met: http://www.gnu.org/copyleft/gpl.html.
|
|
|
|
If you are unsure which license is appropriate for your use, please contact the sales department
|
|
at http://www.sencha.com/contact.
|
|
|
|
Build date: 2013-04-03 15:07:25
|
|
*/
|
|
/**
|
|
* @class Ext.ux.tree.TreeGrid
|
|
* @extends Ext.tree.TreePanel
|
|
*
|
|
* @xtype treegrid
|
|
*/
|
|
Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
|
|
rootVisible : false,
|
|
useArrows : true,
|
|
lines : false,
|
|
borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
|
|
cls : 'x-treegrid',
|
|
|
|
columnResize : true,
|
|
enableSort : true,
|
|
reserveScrollOffset : true,
|
|
enableHdMenu : true,
|
|
|
|
columnsText : 'Columns',
|
|
|
|
initComponent : function() {
|
|
if(!this.root) {
|
|
this.root = new Ext.tree.AsyncTreeNode({text: 'Root'});
|
|
}
|
|
|
|
// initialize the loader
|
|
var l = this.loader;
|
|
if(!l){
|
|
l = new Ext.ux.tree.TreeGridLoader({
|
|
dataUrl: this.dataUrl,
|
|
requestMethod: this.requestMethod,
|
|
store: this.store
|
|
});
|
|
}else if(Ext.isObject(l) && !l.load){
|
|
l = new Ext.ux.tree.TreeGridLoader(l);
|
|
}
|
|
this.loader = l;
|
|
|
|
Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);
|
|
|
|
this.initColumns();
|
|
|
|
if(this.enableSort) {
|
|
this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort);
|
|
}
|
|
|
|
if(this.columnResize){
|
|
this.colResizer = new Ext.tree.ColumnResizer(this.columnResize);
|
|
this.colResizer.init(this);
|
|
}
|
|
|
|
var c = this.columns;
|
|
if(!this.internalTpl){
|
|
this.internalTpl = new Ext.XTemplate(
|
|
'<div class="x-grid3-header">',
|
|
'<div class="x-treegrid-header-inner">',
|
|
'<div class="x-grid3-header-offset">',
|
|
'<table style="table-layout: fixed;" cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
|
|
'<thead><tr class="x-grid3-hd-row">',
|
|
'<tpl for="columns">',
|
|
'<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}">',
|
|
'<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',
|
|
this.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
|
|
'{header}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
|
|
'</div>',
|
|
'</td></tpl>',
|
|
'</tr></thead>',
|
|
'</table>',
|
|
'</div></div>',
|
|
'</div>',
|
|
'<div class="x-treegrid-root-node">',
|
|
'<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
|
|
'</div>'
|
|
);
|
|
}
|
|
|
|
if(!this.colgroupTpl) {
|
|
this.colgroupTpl = new Ext.XTemplate(
|
|
'<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'
|
|
);
|
|
}
|
|
},
|
|
|
|
initColumns : function() {
|
|
var cs = this.columns,
|
|
len = cs.length,
|
|
columns = [],
|
|
i, c;
|
|
|
|
for(i = 0; i < len; i++){
|
|
c = cs[i];
|
|
if(!c.isColumn) {
|
|
c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn';
|
|
c = Ext.create(c);
|
|
}
|
|
c.init(this);
|
|
columns.push(c);
|
|
|
|
if(this.enableSort !== false && c.sortable !== false) {
|
|
c.sortable = true;
|
|
this.enableSort = true;
|
|
}
|
|
}
|
|
|
|
this.columns = columns;
|
|
},
|
|
|
|
onRender : function(){
|
|
Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
|
|
|
|
this.el.addClass('x-treegrid');
|
|
|
|
this.outerCt = this.body.createChild({
|
|
cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
|
|
});
|
|
|
|
this.internalTpl.overwrite(this.outerCt, {columns: this.columns});
|
|
|
|
this.mainHd = Ext.get(this.outerCt.dom.firstChild);
|
|
this.innerHd = Ext.get(this.mainHd.dom.firstChild);
|
|
this.innerBody = Ext.get(this.outerCt.dom.lastChild);
|
|
this.innerCt = Ext.get(this.innerBody.dom.firstChild);
|
|
|
|
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
|
|
|
|
if(this.hideHeaders){
|
|
this.el.child('.x-grid3-header').setDisplayed('none');
|
|
}
|
|
else if(this.enableHdMenu !== false){
|
|
this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
|
|
if(this.enableColumnHide !== false){
|
|
this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
|
|
this.colMenu.on({
|
|
scope: this,
|
|
beforeshow: this.beforeColMenuShow,
|
|
itemclick: this.handleHdMenuClick
|
|
});
|
|
this.hmenu.add({
|
|
itemId:'columns',
|
|
hideOnClick: false,
|
|
text: this.columnsText,
|
|
menu: this.colMenu,
|
|
iconCls: 'x-cols-icon'
|
|
});
|
|
}
|
|
this.hmenu.on('itemclick', this.handleHdMenuClick, this);
|
|
}
|
|
},
|
|
|
|
setRootNode : function(node){
|
|
node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;
|
|
node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
|
|
if(this.innerCt) {
|
|
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
|
|
}
|
|
return node;
|
|
},
|
|
|
|
clearInnerCt : function(){
|
|
if(Ext.isIE){
|
|
var dom = this.innerCt.dom;
|
|
while(dom.firstChild){
|
|
dom.removeChild(dom.firstChild);
|
|
}
|
|
}else{
|
|
Ext.ux.tree.TreeGrid.superclass.clearInnerCt.call(this);
|
|
}
|
|
},
|
|
|
|
initEvents : function() {
|
|
Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
|
|
|
|
this.mon(this.innerBody, 'scroll', this.syncScroll, this);
|
|
this.mon(this.innerHd, 'click', this.handleHdDown, this);
|
|
this.mon(this.mainHd, {
|
|
scope: this,
|
|
mouseover: this.handleHdOver,
|
|
mouseout: this.handleHdOut
|
|
});
|
|
},
|
|
|
|
onResize : function(w, h) {
|
|
Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
|
|
|
|
var bd = this.innerBody.dom;
|
|
var hd = this.innerHd.dom;
|
|
|
|
if(!bd){
|
|
return;
|
|
}
|
|
|
|
if(Ext.isNumber(h)){
|
|
bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px';
|
|
}
|
|
|
|
if(Ext.isNumber(w)){
|
|
var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
|
|
if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){
|
|
this.setScrollOffset(sw);
|
|
}else{
|
|
var me = this;
|
|
setTimeout(function(){
|
|
me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0);
|
|
}, 10);
|
|
}
|
|
}
|
|
},
|
|
|
|
updateColumnWidths : function() {
|
|
var cols = this.columns,
|
|
colCount = cols.length,
|
|
groups = this.outerCt.query('colgroup'),
|
|
groupCount = groups.length,
|
|
c, g, i, j;
|
|
|
|
for(i = 0; i<colCount; i++) {
|
|
c = cols[i];
|
|
for(j = 0; j<groupCount; j++) {
|
|
g = groups[j];
|
|
g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
|
|
}
|
|
}
|
|
|
|
for(i = 0, groups = this.innerHd.query('td'), len = groups.length; i<len; i++) {
|
|
c = Ext.fly(groups[i]);
|
|
if(cols[i] && cols[i].hidden) {
|
|
c.addClass('x-treegrid-hd-hidden');
|
|
}
|
|
else {
|
|
c.removeClass('x-treegrid-hd-hidden');
|
|
}
|
|
}
|
|
|
|
var tcw = this.getTotalColumnWidth();
|
|
Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
|
|
this.outerCt.select('table').setWidth(tcw);
|
|
this.syncHeaderScroll();
|
|
},
|
|
|
|
getVisibleColumns : function() {
|
|
var columns = [],
|
|
cs = this.columns,
|
|
len = cs.length,
|
|
i;
|
|
|
|
for(i = 0; i<len; i++) {
|
|
if(!cs[i].hidden) {
|
|
columns.push(cs[i]);
|
|
}
|
|
}
|
|
return columns;
|
|
},
|
|
|
|
getTotalColumnWidth : function() {
|
|
var total = 0;
|
|
for(var i = 0, cs = this.getVisibleColumns(), len = cs.length; i<len; i++) {
|
|
total += cs[i].width;
|
|
}
|
|
return total;
|
|
},
|
|
|
|
setScrollOffset : function(scrollOffset) {
|
|
this.scrollOffset = scrollOffset;
|
|
this.updateColumnWidths();
|
|
},
|
|
|
|
// private
|
|
handleHdDown : function(e, t){
|
|
var hd = e.getTarget('.x-treegrid-hd');
|
|
|
|
if(hd && Ext.fly(t).hasClass('x-grid3-hd-btn')){
|
|
var ms = this.hmenu.items,
|
|
cs = this.columns,
|
|
index = this.findHeaderIndex(hd),
|
|
c = cs[index],
|
|
sort = c.sortable;
|
|
|
|
e.stopEvent();
|
|
Ext.fly(hd).addClass('x-grid3-hd-menu-open');
|
|
this.hdCtxIndex = index;
|
|
|
|
this.fireEvent('headerbuttonclick', ms, c, hd, index);
|
|
|
|
this.hmenu.on('hide', function(){
|
|
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
|
|
}, this, {single:true});
|
|
|
|
this.hmenu.show(t, 'tl-bl?');
|
|
}
|
|
else if(hd) {
|
|
var index = this.findHeaderIndex(hd);
|
|
this.fireEvent('headerclick', this.columns[index], hd, index);
|
|
}
|
|
},
|
|
|
|
// private
|
|
handleHdOver : function(e, t){
|
|
var hd = e.getTarget('.x-treegrid-hd');
|
|
if(hd && !this.headersDisabled){
|
|
index = this.findHeaderIndex(hd);
|
|
this.activeHdRef = t;
|
|
this.activeHdIndex = index;
|
|
var el = Ext.get(hd);
|
|
this.activeHdRegion = el.getRegion();
|
|
el.addClass('x-grid3-hd-over');
|
|
this.activeHdBtn = el.child('.x-grid3-hd-btn');
|
|
if(this.activeHdBtn){
|
|
this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
|
|
}
|
|
}
|
|
},
|
|
|
|
// private
|
|
handleHdOut : function(e, t){
|
|
var hd = e.getTarget('.x-treegrid-hd');
|
|
if(hd && (!Ext.isIE || !e.within(hd, true))){
|
|
this.activeHdRef = null;
|
|
Ext.fly(hd).removeClass('x-grid3-hd-over');
|
|
hd.style.cursor = '';
|
|
}
|
|
},
|
|
|
|
findHeaderIndex : function(hd){
|
|
hd = hd.dom || hd;
|
|
var cs = hd.parentNode.childNodes;
|
|
for(var i = 0, c; c = cs[i]; i++){
|
|
if(c == hd){
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
// private
|
|
beforeColMenuShow : function(){
|
|
var cols = this.columns,
|
|
colCount = cols.length,
|
|
i, c;
|
|
this.colMenu.removeAll();
|
|
for(i = 1; i < colCount; i++){
|
|
c = cols[i];
|
|
if(c.hideable !== false){
|
|
this.colMenu.add(new Ext.menu.CheckItem({
|
|
itemId: 'col-' + i,
|
|
text: c.header,
|
|
checked: !c.hidden,
|
|
hideOnClick:false,
|
|
disabled: c.hideable === false
|
|
}));
|
|
}
|
|
}
|
|
},
|
|
|
|
// private
|
|
handleHdMenuClick : function(item){
|
|
var index = this.hdCtxIndex,
|
|
id = item.getItemId();
|
|
|
|
if(this.fireEvent('headermenuclick', this.columns[index], id, index) !== false) {
|
|
index = id.substr(4);
|
|
if(index > 0 && this.columns[index]) {
|
|
this.setColumnVisible(index, !item.checked);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
setColumnVisible : function(index, visible) {
|
|
this.columns[index].hidden = !visible;
|
|
this.updateColumnWidths();
|
|
},
|
|
|
|
/**
|
|
* Scrolls the grid to the top
|
|
*/
|
|
scrollToTop : function(){
|
|
this.innerBody.dom.scrollTop = 0;
|
|
this.innerBody.dom.scrollLeft = 0;
|
|
},
|
|
|
|
// private
|
|
syncScroll : function(){
|
|
this.syncHeaderScroll();
|
|
var mb = this.innerBody.dom;
|
|
this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
|
|
},
|
|
|
|
// private
|
|
syncHeaderScroll : function(){
|
|
var mb = this.innerBody.dom;
|
|
this.innerHd.dom.scrollLeft = mb.scrollLeft;
|
|
this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
|
|
},
|
|
|
|
registerNode : function(n) {
|
|
Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
|
|
if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
|
|
n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
|
|
}
|
|
}
|
|
});
|
|
|
|
Ext.reg('treegrid', Ext.ux.tree.TreeGrid); |