1862 lines
45 KiB
JavaScript
1862 lines
45 KiB
JavaScript
if (Ext.version == '3.0') {
|
|
Ext.override(Ext.grid.GridView, {
|
|
ensureVisible : function(row, col, hscroll) {
|
|
|
|
var resolved = this.resolveCell(row, col, hscroll);
|
|
if (!resolved || !resolved.row) {
|
|
return;
|
|
}
|
|
|
|
var rowEl = resolved.row, cellEl = resolved.cell, c = this.scroller.dom, ctop = 0, p = rowEl, stop = this.el.dom;
|
|
|
|
var p = rowEl, stop = this.el.dom;
|
|
while (p && p != stop) {
|
|
ctop += p.offsetTop;
|
|
p = p.offsetParent;
|
|
}
|
|
ctop -= this.mainHd.dom.offsetHeight;
|
|
|
|
var cbot = ctop + rowEl.offsetHeight;
|
|
|
|
var ch = c.clientHeight;
|
|
var stop = parseInt(c.scrollTop, 10);
|
|
var sbot = stop + ch;
|
|
|
|
if (ctop < stop) {
|
|
c.scrollTop = ctop;
|
|
} else if (cbot > sbot) {
|
|
c.scrollTop = cbot - ch;
|
|
}
|
|
|
|
if (hscroll !== false) {
|
|
var cleft = parseInt(cellEl.offsetLeft, 10);
|
|
var cright = cleft + cellEl.offsetWidth;
|
|
|
|
var sleft = parseInt(c.scrollLeft, 10);
|
|
var sright = sleft + c.clientWidth;
|
|
if (cleft < sleft) {
|
|
c.scrollLeft = cleft;
|
|
} else if (cright > sright) {
|
|
c.scrollLeft = cright - c.clientWidth;
|
|
}
|
|
}
|
|
return this.getResolvedXY(resolved);
|
|
}
|
|
});
|
|
}
|
|
|
|
Ext.namespace('Ext.ux.maximgb.tg');
|
|
|
|
/**
|
|
* This class shouldn't be created directly use NestedSetStore or
|
|
* AdjacencyListStore instead.
|
|
*
|
|
* @abstract
|
|
*/
|
|
Ext.ux.maximgb.tg.AbstractTreeStore = Ext.extend(Ext.data.Store, {
|
|
/**
|
|
* @cfg {String} is_leaf_field_name Record leaf flag field name.
|
|
*/
|
|
leaf_field_name : 'Leaf',
|
|
|
|
/**
|
|
* Current page offset.
|
|
*
|
|
* @access private
|
|
*/
|
|
page_offset : 0,
|
|
|
|
/**
|
|
* Current active node.
|
|
*
|
|
* @access private
|
|
*/
|
|
active_node : null,
|
|
|
|
/**
|
|
* @constructor
|
|
*/
|
|
constructor : function(config) {
|
|
Ext.ux.maximgb.tg.AbstractTreeStore.superclass.constructor.call(this,
|
|
config);
|
|
|
|
if (!this.paramNames.active_node) {
|
|
this.paramNames.active_node = 'anode';
|
|
}
|
|
|
|
this.addEvents(
|
|
/**
|
|
* @event beforeexpandnode Fires before node expand. Return
|
|
* false to cancel operation. param {AbstractTreeStore}
|
|
* this param {Record} record
|
|
*/
|
|
'beforeexpandnode',
|
|
/**
|
|
* @event expandnode Fires after node expand. param
|
|
* {AbstractTreeStore} this param {Record} record
|
|
*/
|
|
'expandnode',
|
|
/**
|
|
* @event expandnodefailed Fires when expand node operation is
|
|
* failed. param {AbstractTreeStore} this param {id}
|
|
* Record id param {Record} Record, may be undefined
|
|
*/
|
|
'expandnodefailed',
|
|
/**
|
|
* @event beforecollapsenode Fires before node collapse. Return
|
|
* false to cancel operation. param {AbstractTreeStore}
|
|
* this param {Record} record
|
|
*/
|
|
'beforecollapsenode',
|
|
/**
|
|
* @event collapsenode Fires after node collapse. param
|
|
* {AbstractTreeStore} this param {Record} record
|
|
*/
|
|
'collapsenode',
|
|
/**
|
|
* @event beforeactivenodechange Fires before active node
|
|
* change. Return false to cancel operation. param
|
|
* {AbstractTreeStore} this param {Record} old active
|
|
* node record param {Record} new active node record
|
|
*/
|
|
'beforeactivenodechange',
|
|
/**
|
|
* @event activenodechange Fires after active node change. param
|
|
* {AbstractTreeStore} this param {Record} old active
|
|
* node record param {Record} new active node record
|
|
*/
|
|
'activenodechange');
|
|
},
|
|
|
|
// Store methods.
|
|
// -----------------------------------------------------------------------------------------------
|
|
/**
|
|
* Removes record and all its descendants.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* record Record to remove.
|
|
*/
|
|
remove : function(record) {
|
|
// ----- Modification start
|
|
if (record === this.active_node) {
|
|
this.setActiveNode(null);
|
|
}
|
|
this.removeNodeDescendants(record);
|
|
// ----- End of modification
|
|
Ext.ux.maximgb.tg.AbstractTreeStore.superclass.remove
|
|
.call(this, record);
|
|
},
|
|
|
|
/**
|
|
* Removes node descendants.
|
|
*
|
|
* @access private
|
|
*/
|
|
removeNodeDescendants : function(rc) {
|
|
var i, len, children = this.getNodeChildren(rc);
|
|
for (i = 0, len = children.length; i < len; i++) {
|
|
this.remove(children[i]);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Loads current active record data.
|
|
*/
|
|
load : function(options) {
|
|
if (options) {
|
|
if (options.params) {
|
|
if (options.params[this.paramNames.active_node] === undefined) {
|
|
options.params[this.paramNames.active_node] = this.active_node
|
|
? this.active_node.id
|
|
: null;
|
|
}
|
|
} else {
|
|
options.params = {};
|
|
options.params[this.paramNames.active_node] = this.active_node
|
|
? this.active_node.id
|
|
: null;
|
|
}
|
|
} else {
|
|
options = {
|
|
params : {}
|
|
};
|
|
options.params[this.paramNames.active_node] = this.active_node
|
|
? this.active_node.id
|
|
: null;
|
|
}
|
|
|
|
if (options.params[this.paramNames.active_node] !== null) {
|
|
options.add = true;
|
|
}
|
|
|
|
return Ext.ux.maximgb.tg.AbstractTreeStore.superclass.load.call(this,
|
|
options);
|
|
},
|
|
|
|
/**
|
|
* Called as a callback by the Reader during load operation.
|
|
*
|
|
* @access private
|
|
*/
|
|
loadRecords : function(o, options, success) {
|
|
|
|
if (!o || success === false) {
|
|
if (success !== false) {
|
|
this.fireEvent("load", this, [], options);
|
|
}
|
|
if (options.callback) {
|
|
options.callback
|
|
.call(options.scope || this, [], options, false);
|
|
}
|
|
return;
|
|
}
|
|
var r = o.records, t = o.totalRecords || r.length, page_offset = this
|
|
.getPageOffsetFromOptions(options), loaded_node_id = this
|
|
.getLoadedNodeIdFromOptions(options), loaded_node, i, len, record, idx, updated, self = this;
|
|
if (!options || options.add !== true/* || loaded_node_id === null */) {
|
|
if (this.pruneModifiedRecords) {
|
|
this.modified = [];
|
|
}
|
|
for (var i = 0, len = r.length; i < len; i++) {
|
|
r[i].join(this);
|
|
}
|
|
if (this.snapshot) {
|
|
this.data = this.snapshot;
|
|
delete this.snapshot;
|
|
}
|
|
this.data.clear();
|
|
this.data.addAll(r);
|
|
this.page_offset = page_offset;
|
|
this.totalLength = t;
|
|
this.applySort();
|
|
this.fireEvent("datachanged", this);
|
|
} else {
|
|
if (loaded_node_id) {
|
|
loaded_node = this.getById(loaded_node_id);
|
|
}
|
|
if (loaded_node) {
|
|
this.setNodeChildrenOffset(loaded_node, page_offset);
|
|
this.setNodeChildrenTotalCount(loaded_node, Math.max(t,
|
|
r.length));
|
|
this.removeNodeDescendants(loaded_node);
|
|
}
|
|
this.suspendEvents();
|
|
updated = {};
|
|
for (i = 0, len = r.length; i < len; i++) {
|
|
record = r[i];
|
|
idx = this.indexOfId(record.id);
|
|
if (idx == -1) {
|
|
updated[record.id] = false;
|
|
} else {
|
|
updated[record.id] = true;
|
|
this.setNodeExpanded(record, this.isExpandedNode(this
|
|
.getAt(idx)));
|
|
}
|
|
this.add(record);
|
|
}
|
|
this.applySort();
|
|
this.resumeEvents();
|
|
|
|
r.sort(function(r1, r2) {
|
|
var idx1 = self.data.indexOf(r1), idx2 = self.data.indexOf(r2), r;
|
|
|
|
if (idx1 > idx2) {
|
|
r = 1;
|
|
} else {
|
|
r = -1;
|
|
}
|
|
return r;
|
|
});
|
|
|
|
for (i = 0, len = r.length; i < len; i++) {
|
|
record = r[i];
|
|
if (updated[record.id] == true) {
|
|
this.fireEvent('update', this, record,
|
|
Ext.data.Record.COMMIT);
|
|
} else {
|
|
this.fireEvent("add", this, [record], this.data
|
|
.indexOf(record));
|
|
}
|
|
}
|
|
}
|
|
this.fireEvent("load", this, r, options);
|
|
if (options.callback) {
|
|
options.callback.call(options.scope || this, r, options, true);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Sort the Records.
|
|
*
|
|
* @access public
|
|
*/
|
|
sort : function(fieldName, dir) {
|
|
if (this.remoteSort) {
|
|
this.setActiveNode(null);
|
|
if (this.lastOptions) {
|
|
this.lastOptions.add = false;
|
|
if (this.lastOptions.params) {
|
|
this.lastOptions.params[this.paramNames.active_node] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ext.ux.maximgb.tg.AbstractTreeStore.superclass.sort.call(this,
|
|
fieldName, dir);
|
|
},
|
|
|
|
/**
|
|
* Applyes current sort method.
|
|
*
|
|
* @access private
|
|
*/
|
|
applySort : function() {
|
|
if (this.sortInfo && !this.remoteSort) {
|
|
var s = this.sortInfo, f = s.field;
|
|
this.sortData(f, s.direction);
|
|
}
|
|
// ----- Modification start
|
|
else {
|
|
this.applyTreeSort();
|
|
}
|
|
// ----- End of modification
|
|
},
|
|
|
|
/**
|
|
* Sorts data according to sort params and then applyes tree sorting.
|
|
*
|
|
* @access private
|
|
*/
|
|
sortData : function(f, direction) {
|
|
direction = direction || 'ASC';
|
|
var st = this.fields.get(f).sortType;
|
|
var fn = function(r1, r2) {
|
|
var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
|
|
return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
|
|
};
|
|
this.data.sort(direction, fn);
|
|
if (this.snapshot && this.snapshot != this.data) {
|
|
this.snapshot.sort(direction, fn);
|
|
}
|
|
// ----- Modification start
|
|
this.applyTreeSort();
|
|
// ----- End of modification
|
|
},
|
|
|
|
// Tree support methods.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Sorts store data with respect to nodes parent-child relation. Every child
|
|
* node will be positioned after its parent.
|
|
*
|
|
* @access public
|
|
*/
|
|
applyTreeSort : function() {
|
|
var i, len, temp, rec, records = [], roots = this.getRootNodes();
|
|
|
|
// Sorting data
|
|
for (i = 0, len = roots.length; i < len; i++) {
|
|
rec = roots[i];
|
|
records.push(rec);
|
|
this.collectNodeChildrenTreeSorted(records, rec);
|
|
}
|
|
|
|
if (records.length > 0) {
|
|
this.data.clear();
|
|
this.data.addAll(records);
|
|
}
|
|
|
|
// Sorting the snapshot if one present.
|
|
if (this.snapshot && this.snapshot !== this.data) {
|
|
temp = this.data;
|
|
this.data = this.snapshot;
|
|
this.snapshot = null;
|
|
this.applyTreeSort();
|
|
this.snapshot = this.data;
|
|
this.data = temp;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Recusively collects rec descendants and adds them to records[] array.
|
|
*
|
|
* @access private
|
|
* @param {Record[]}
|
|
* records
|
|
* @param {Record}
|
|
* rec
|
|
*/
|
|
collectNodeChildrenTreeSorted : function(records, rec) {
|
|
var i, len, child, children = this.getNodeChildren(rec);
|
|
|
|
for (i = 0, len = children.length; i < len; i++) {
|
|
child = children[i];
|
|
records.push(child);
|
|
this.collectNodeChildrenTreeSorted(records, child);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns current active node.
|
|
*
|
|
* @access public
|
|
* @return {Record}
|
|
*/
|
|
getActiveNode : function() {
|
|
return this.active_node;
|
|
},
|
|
|
|
/**
|
|
* Sets active node.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc Record to set active.
|
|
*/
|
|
setActiveNode : function(rc) {
|
|
if (this.active_node !== rc) {
|
|
if (rc) {
|
|
if (this.data.indexOf(rc) != -1) {
|
|
if (this.fireEvent('beforeactivenodechange', this,
|
|
this.active_node, rc) !== false) {
|
|
this.active_node = rc;
|
|
this.fireEvent('activenodechange', this,
|
|
this.active_node, rc);
|
|
}
|
|
} else {
|
|
throw "Given record is not from the store.";
|
|
}
|
|
} else {
|
|
if (this.fireEvent('beforeactivenodechange', this,
|
|
this.active_node, rc) !== false) {
|
|
this.active_node = rc;
|
|
this.fireEvent('activenodechange', this, this.active_node,
|
|
rc);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns true if node is expanded.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
*/
|
|
isExpandedNode : function(rc) {
|
|
return rc.ux_maximgb_tg_expanded === true;
|
|
},
|
|
|
|
/**
|
|
* Sets node expanded flag.
|
|
*
|
|
* @access private
|
|
*/
|
|
setNodeExpanded : function(rc, value) {
|
|
rc.ux_maximgb_tg_expanded = value;
|
|
},
|
|
|
|
/**
|
|
* Returns true if node's ancestors are all expanded - node is visible.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
*/
|
|
isVisibleNode : function(rc) {
|
|
var i, len, ancestors = this.getNodeAncestors(rc), result = true;
|
|
|
|
for (i = 0, len = ancestors.length; i < len; i++) {
|
|
result = result && this.isExpandedNode(ancestors[i]);
|
|
if (!result) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns true if node is a leaf.
|
|
*
|
|
* @access public
|
|
* @return {Boolean}
|
|
*/
|
|
isLeafNode : function(rc) {
|
|
return rc.get(this.leaf_field_name) == true;
|
|
},
|
|
|
|
/**
|
|
* Returns true if node was loaded.
|
|
*
|
|
* @access public
|
|
* @return {Boolean}
|
|
*/
|
|
isLoadedNode : function(rc) {
|
|
var result;
|
|
|
|
if (rc.ux_maximgb_tg_loaded !== undefined) {
|
|
result = rc.ux_maximgb_tg_loaded;
|
|
} else if (this.isLeafNode(rc) || this.hasChildNodes(rc)) {
|
|
result = true;
|
|
} else {
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Sets node loaded state.
|
|
*
|
|
* @access private
|
|
* @param {Record}
|
|
* rc
|
|
* @param {Boolean}
|
|
* value
|
|
*/
|
|
setNodeLoaded : function(rc, value) {
|
|
rc.ux_maximgb_tg_loaded = value;
|
|
},
|
|
|
|
/**
|
|
* Returns node's children offset.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
* @return {Integer}
|
|
*/
|
|
getNodeChildrenOffset : function(rc) {
|
|
return rc.ux_maximgb_tg_offset || 0;
|
|
},
|
|
|
|
/**
|
|
* Sets node's children offset.
|
|
*
|
|
* @access private
|
|
* @param {Record}
|
|
* rc
|
|
* @parma {Integer} value
|
|
*/
|
|
setNodeChildrenOffset : function(rc, value) {
|
|
rc.ux_maximgb_tg_offset = value;
|
|
},
|
|
|
|
/**
|
|
* Returns node's children total count
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
* @return {Integer}
|
|
*/
|
|
getNodeChildrenTotalCount : function(rc) {
|
|
return rc.ux_maximgb_tg_total || 0;
|
|
},
|
|
|
|
/**
|
|
* Sets node's children total count.
|
|
*
|
|
* @access private
|
|
* @param {Record}
|
|
* rc
|
|
* @param {Integer}
|
|
* value
|
|
*/
|
|
setNodeChildrenTotalCount : function(rc, value) {
|
|
rc.ux_maximgb_tg_total = value;
|
|
},
|
|
|
|
/**
|
|
* Collapses node.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
* @param {Record}
|
|
* rc Node to collapse.
|
|
*/
|
|
collapseNode : function(rc) {
|
|
if (this.isExpandedNode(rc)
|
|
&& this.fireEvent('beforecollapsenode', this, rc) !== false) {
|
|
this.setNodeExpanded(rc, false);
|
|
this.fireEvent('collapsenode', this, rc);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Expands node.
|
|
*
|
|
* @access public
|
|
* @param {Record}
|
|
* rc
|
|
*/
|
|
expandNode : function(rc) {
|
|
var params;
|
|
|
|
if (!this.isExpandedNode(rc)
|
|
&& this.fireEvent('beforeexpandnode', this, rc) !== false) {
|
|
// If node is already loaded then expanding now.
|
|
if (this.isLoadedNode(rc)) {
|
|
this.setNodeExpanded(rc, true);
|
|
this.fireEvent('expandnode', this, rc);
|
|
}
|
|
// If node isn't loaded yet then expanding after load.
|
|
else {
|
|
params = {};
|
|
params[this.paramNames.active_node] = rc.id;
|
|
this.load({
|
|
add : true,
|
|
params : params,
|
|
callback : this.expandNodeCallback,
|
|
scope : this
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
expandNodeCallback : function(r, options, success) {
|
|
var rc = this.getById(options.params[this.paramNames.active_node]);
|
|
|
|
if (success && rc) {
|
|
this.setNodeLoaded(rc, true);
|
|
this.setNodeExpanded(rc, true);
|
|
this.fireEvent('expandnode', this, rc);
|
|
} else {
|
|
this.fireEvent('expandnodefailed', this,
|
|
options.params[this.paramNames.active_node], rc);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Expands all nodes.
|
|
*
|
|
* @access public
|
|
*/
|
|
expandAll : function() {
|
|
var r, i, len, records = this.data.getRange();
|
|
this.suspendEvents();
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
r = records[i];
|
|
if (!this.isExpandedNode(r)) {
|
|
this.expandNode(r);
|
|
}
|
|
}
|
|
this.resumeEvents();
|
|
this.fireEvent('datachanged', this);
|
|
},
|
|
|
|
/**
|
|
* Collapses all nodes.
|
|
*
|
|
* @access public
|
|
*/
|
|
collapseAll : function() {
|
|
var r, i, len, records = this.data.getRange();
|
|
|
|
this.suspendEvents();
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
r = records[i];
|
|
if (this.isExpandedNode(r)) {
|
|
this.collapseNode(r);
|
|
}
|
|
}
|
|
this.resumeEvents();
|
|
this.fireEvent('datachanged', this);
|
|
},
|
|
|
|
/**
|
|
* Returns loaded node id from the load options.
|
|
*
|
|
* @access public
|
|
*/
|
|
getLoadedNodeIdFromOptions : function(options) {
|
|
var result = null;
|
|
if (options && options.params
|
|
&& options.params[this.paramNames.active_node]) {
|
|
result = options.params[this.paramNames.active_node];
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns start offset from the load options.
|
|
*/
|
|
getPageOffsetFromOptions : function(options) {
|
|
var result = 0;
|
|
if (options && options.params && options.params[this.paramNames.start]) {
|
|
result = parseInt(options.params[this.paramNames.start], 10);
|
|
if (isNaN(result)) {
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
|
|
// Public
|
|
hasNextSiblingNode : function(rc) {
|
|
return this.getNodeNextSibling(rc) !== null;
|
|
},
|
|
|
|
// Public
|
|
hasPrevSiblingNode : function(rc) {
|
|
return this.getNodePrevSibling(rc) !== null;
|
|
},
|
|
|
|
// Public
|
|
hasChildNodes : function(rc) {
|
|
return this.getNodeChildrenCount(rc) > 0;
|
|
},
|
|
|
|
// Public
|
|
getNodeAncestors : function(rc) {
|
|
var ancestors = [], parent;
|
|
|
|
parent = this.getNodeParent(rc);
|
|
while (parent) {
|
|
ancestors.push(parent);
|
|
parent = this.getNodeParent(parent);
|
|
}
|
|
|
|
return ancestors;
|
|
},
|
|
|
|
// Public
|
|
getNodeChildrenCount : function(rc) {
|
|
return this.getNodeChildren(rc).length;
|
|
},
|
|
|
|
// Public
|
|
getNodeNextSibling : function(rc) {
|
|
var siblings, parent, index, result = null;
|
|
|
|
parent = this.getNodeParent(rc);
|
|
if (parent) {
|
|
siblings = this.getNodeChildren(parent);
|
|
} else {
|
|
siblings = this.getRootNodes();
|
|
}
|
|
|
|
index = siblings.indexOf(rc);
|
|
|
|
if (index < siblings.length - 1) {
|
|
result = siblings[index + 1];
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
// Public
|
|
getNodePrevSibling : function(rc) {
|
|
var siblings, parent, index, result = null;
|
|
|
|
parent = this.getNodeParent(rc);
|
|
if (parent) {
|
|
siblings = this.getNodeChildren(parent);
|
|
} else {
|
|
siblings = this.getRootNodes();
|
|
}
|
|
|
|
index = siblings.indexOf(rc);
|
|
if (index > 0) {
|
|
result = siblings[index - 1];
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
// Abstract tree support methods.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
// Public - Abstract
|
|
getRootNodes : function() {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Public - Abstract
|
|
getNodeDepth : function(rc) {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Public - Abstract
|
|
getNodeParent : function(rc) {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Public - Abstract
|
|
getNodeChildren : function(rc) {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Public - Abstract
|
|
addToNode : function(parent, child) {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Public - Abstract
|
|
removeFromNode : function(parent, child) {
|
|
throw 'Abstract method call';
|
|
},
|
|
|
|
// Paging support methods.
|
|
// -----------------------------------------------------------------------------------------------
|
|
/**
|
|
* Returns top level node page offset.
|
|
*
|
|
* @access public
|
|
* @return {Integer}
|
|
*/
|
|
getPageOffset : function() {
|
|
return this.page_offset;
|
|
},
|
|
|
|
/**
|
|
* Returns active node page offset.
|
|
*
|
|
* @access public
|
|
* @return {Integer}
|
|
*/
|
|
getActiveNodePageOffset : function() {
|
|
var result;
|
|
|
|
if (this.active_node) {
|
|
result = this.getNodeChildrenOffset(this.active_node);
|
|
} else {
|
|
result = this.getPageOffset();
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns active node children count.
|
|
*
|
|
* @access public
|
|
* @return {Integer}
|
|
*/
|
|
getActiveNodeCount : function() {
|
|
var result;
|
|
|
|
if (this.active_node) {
|
|
result = this.getNodeChildrenCount(this.active_node);
|
|
} else {
|
|
result = this.getRootNodes().length;
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns active node total children count.
|
|
*
|
|
* @access public
|
|
* @return {Integer}
|
|
*/
|
|
getActiveNodeTotalCount : function() {
|
|
var result;
|
|
|
|
if (this.active_node) {
|
|
result = this.getNodeChildrenTotalCount(this.active_node);
|
|
} else {
|
|
result = this.getTotalCount();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Tree store for adjacency list tree representation.
|
|
*/
|
|
Ext.ux.maximgb.tg.AdjacencyListStore = Ext.extend(
|
|
Ext.ux.maximgb.tg.AbstractTreeStore, {
|
|
/**
|
|
* @cfg {String} parent_id_field_name Record parent id field name.
|
|
*/
|
|
parent_id_field_name : 'ParentId',
|
|
getRootNodes : function() {
|
|
var i, len, result = [], records = this.data.getRange();
|
|
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
if (records[i].get(this.parent_id_field_name) == null) {
|
|
result.push(records[i]);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
|
|
getNodeDepth : function(rc) {
|
|
return this.getNodeAncestors(rc).length;
|
|
},
|
|
|
|
getNodeParent : function(rc) {
|
|
return this.getById(rc.get(this.parent_id_field_name));
|
|
},
|
|
|
|
getNodeChildren : function(rc) {
|
|
|
|
var i, len, result = [], records = this.data.getRange();
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
if (records[i].get(this.parent_id_field_name) == rc.id) {
|
|
result.push(records[i]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
addToNode : function(parent, child) {
|
|
child.set(this.parent_id_field_name, parent.id);
|
|
this.addSorted(child);
|
|
},
|
|
|
|
removeFromNode : function(parent, child) {
|
|
this.remove(child);
|
|
}
|
|
});
|
|
|
|
Ext.reg('Ext.ux.maximgb.tg.AdjacencyListStore',
|
|
Ext.ux.maximgb.tg.AdjacencyListStore);
|
|
|
|
/**
|
|
* Tree store for nested set tree representation.
|
|
*/
|
|
Ext.ux.maximgb.tg.NestedSetStore = Ext.extend(
|
|
Ext.ux.maximgb.tg.AbstractTreeStore, {
|
|
/**
|
|
* @cfg {String} left_field_name Record NS-left bound field name.
|
|
*/
|
|
left_field_name : '_lft',
|
|
|
|
/**
|
|
* @cfg {String} right_field_name Record NS-right bound field name.
|
|
*/
|
|
right_field_name : '_rgt',
|
|
|
|
/**
|
|
* @cfg {String} level_field_name Record NS-level field name.
|
|
*/
|
|
level_field_name : 'Level',
|
|
|
|
/**
|
|
* @cfg {Number} root_node_level Root node level.
|
|
*/
|
|
root_node_level : 1,
|
|
|
|
getRootNodes : function() {
|
|
var i, len, result = [], records = this.data.getRange();
|
|
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
if (records[i].get(this.level_field_name) == this.root_node_level) {
|
|
result.push(records[i]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
getNodeDepth : function(rc) {
|
|
return rc.get(this.level_field_name) - this.root_node_level;
|
|
},
|
|
|
|
getNodeParent : function(rc) {
|
|
var result = null, rec, records = this.data.getRange(), i, len, lft, r_lft, rgt, r_rgt, level, r_level;
|
|
|
|
lft = rc.get(this.left_field_name);
|
|
rgt = rc.get(this.right_field_name);
|
|
level = rc.get(this.level_field_name);
|
|
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
rec = records[i];
|
|
r_lft = rec.get(this.left_field_name);
|
|
r_rgt = rec.get(this.right_field_name);
|
|
r_level = rec.get(this.level_field_name);
|
|
|
|
if (r_level == level - 1 && r_lft < lft && r_rgt > rgt) {
|
|
result = rec;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
getNodeChildren : function(rc) {
|
|
var lft, r_lft, rgt, r_rgt, level, r_level, records, rec, result = [];
|
|
|
|
records = this.data.getRange();
|
|
|
|
lft = rc.get(this.left_field_name);
|
|
rgt = rc.get(this.right_field_name);
|
|
level = rc.get(this.level_field_name);
|
|
|
|
for (i = 0, len = records.length; i < len; i++) {
|
|
rec = records[i];
|
|
r_lft = rec.get(this.left_field_name);
|
|
r_rgt = rec.get(this.right_field_name);
|
|
r_level = rec.get(this.level_field_name);
|
|
|
|
if (r_level == level + 1 && r_lft > lft && r_rgt < rgt) {
|
|
result.push(rec);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
});
|
|
|
|
Ext.ux.maximgb.tg.GridView = Ext.extend(Ext.grid.GridView, {
|
|
expanded_icon_class : 'ux-maximgb-tg-elbow-minus',
|
|
last_expanded_icon_class : 'ux-maximgb-tg-elbow-end-minus',
|
|
collapsed_icon_class : 'ux-maximgb-tg-elbow-plus',
|
|
last_collapsed_icon_class : 'ux-maximgb-tg-elbow-end-plus',
|
|
skip_width_update_class : 'ux-maximgb-tg-skip-width-update',
|
|
|
|
// private - overriden
|
|
initTemplates : function() {
|
|
var ts = this.templates || {};
|
|
|
|
if (!ts.row) {
|
|
ts.row = new Ext.Template(
|
|
'<div class="x-grid3-row ux-maximgb-tg-level-{level} {alt}" style="{tstyle} {display_style}">',
|
|
'<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
|
|
'<tbody>',
|
|
'<tr>{cells}</tr>',
|
|
(this.enableRowBody
|
|
? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}">'
|
|
+ '<td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on">'
|
|
+ '<div class="x-grid3-row-body">{body}</div>'
|
|
+ '</td>' + '</tr>'
|
|
: ''), '</tbody>', '</table>', '</div>');
|
|
}
|
|
|
|
if (!ts.mastercell) {
|
|
ts.mastercell = new Ext.Template(
|
|
'<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
|
|
'<div class="ux-maximgb-tg-mastercell-wrap">', // This is
|
|
// for
|
|
// editor to
|
|
// place
|
|
// itself
|
|
// right
|
|
'{treeui}',
|
|
'<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>',
|
|
'</div>', '</td>');
|
|
}
|
|
|
|
if (!ts.treeui) {
|
|
ts.treeui = new Ext.Template(
|
|
'<div class="ux-maximgb-tg-uiwrap" style="width: {wrap_width}px">',
|
|
'{elbow_line}',
|
|
'<div style="left: {left}px" class="{cls}"> </div>',
|
|
'</div>');
|
|
}
|
|
|
|
if (!ts.elbow_line) {
|
|
ts.elbow_line = new Ext.Template('<div style="left: {left}px" class="{cls}"> </div>');
|
|
}
|
|
|
|
this.templates = ts;
|
|
Ext.ux.maximgb.tg.GridView.superclass.initTemplates.call(this);
|
|
},
|
|
|
|
// Private - Overriden
|
|
doRender : function(cs, rs, ds, startRow, colCount, stripe) {
|
|
var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount - 1;
|
|
var tstyle = 'width:' + this.getTotalWidth() + ';';
|
|
// buffers
|
|
var buf = [], cb, c, p = {}, rp = {
|
|
tstyle : tstyle
|
|
}, r;
|
|
for (var j = 0, len = rs.length; j < len; j++) {
|
|
r = rs[j];
|
|
cb = [];
|
|
var rowIndex = (j + startRow);
|
|
|
|
var row_render_res = this.renderRow(r, rowIndex, colCount, ds,
|
|
this.cm.getTotalWidth());
|
|
|
|
if (row_render_res === false) {
|
|
for (var i = 0; i < colCount; i++) {
|
|
c = cs[i];
|
|
p.id = c.id;
|
|
p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last
|
|
? 'x-grid3-cell-last '
|
|
: '');
|
|
p.attr = p.cellAttr = "";
|
|
p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
|
|
p.style = c.style;
|
|
if (Ext.isEmpty(p.value)) {
|
|
p.value = " ";
|
|
}
|
|
if (this.markDirty && r.dirty
|
|
&& typeof r.modified[c.name] !== 'undefined') {
|
|
p.css += ' x-grid3-dirty-cell';
|
|
}
|
|
// ----- Modification start
|
|
if (c.id == this.grid.master_column_id) {
|
|
p.treeui = this.renderCellTreeUI(r, ds);
|
|
ct = ts.mastercell;
|
|
} else {
|
|
ct = ts.cell;
|
|
}
|
|
// ----- End of modification
|
|
cb[cb.length] = ct.apply(p);
|
|
}
|
|
} else {
|
|
cb.push(row_render_res);
|
|
}
|
|
|
|
var alt = [];
|
|
if (stripe && ((rowIndex + 1) % 2 == 0)) {
|
|
alt[0] = "x-grid3-row-alt";
|
|
}
|
|
if (r.dirty) {
|
|
alt[1] = " x-grid3-dirty-row";
|
|
}
|
|
rp.cols = colCount;
|
|
if (this.getRowClass) {
|
|
alt[2] = this.getRowClass(r, rowIndex, rp, ds);
|
|
}
|
|
rp.alt = alt.join(" ");
|
|
rp.cells = cb.join("");
|
|
// ----- Modification start
|
|
if (!ds.isVisibleNode(r)) {
|
|
rp.display_style = 'display: none;';
|
|
} else {
|
|
rp.display_style = '';
|
|
}
|
|
rp.level = ds.getNodeDepth(r);
|
|
// ----- End of modification
|
|
buf[buf.length] = rt.apply(rp);
|
|
}
|
|
return buf.join("");
|
|
},
|
|
|
|
renderCellTreeUI : function(record, store) {
|
|
var tpl = this.templates.treeui, line_tpl = this.templates.elbow_line, tpl_data = {}, rec, parent, depth = level = store
|
|
.getNodeDepth(record);
|
|
|
|
tpl_data.wrap_width = (depth + 1) * 16;
|
|
if (level > 0) {
|
|
tpl_data.elbow_line = '';
|
|
rec = record;
|
|
left = 0;
|
|
while (level--) {
|
|
parent = store.getNodeParent(rec);
|
|
if (parent) {
|
|
if (store.hasNextSiblingNode(parent)) {
|
|
tpl_data.elbow_line = line_tpl.apply({
|
|
left : level * 16,
|
|
cls : 'ux-maximgb-tg-elbow-line'
|
|
}) + tpl_data.elbow_line;
|
|
} else {
|
|
tpl_data.elbow_line = line_tpl.apply({
|
|
left : level * 16,
|
|
cls : 'ux-maximgb-tg-elbow-empty'
|
|
}) + tpl_data.elbow_line;
|
|
}
|
|
} else {
|
|
throw ["Tree inconsistency can't get level ", level + 1,
|
|
" node(id=", rec.id, ") parent."].join("");
|
|
}
|
|
rec = parent;
|
|
}
|
|
}
|
|
if (store.isLeafNode(record)) {
|
|
if (store.hasNextSiblingNode(record)) {
|
|
tpl_data.cls = 'ux-maximgb-tg-elbow';
|
|
} else {
|
|
tpl_data.cls = 'ux-maximgb-tg-elbow-end';
|
|
}
|
|
} else {
|
|
tpl_data.cls = 'ux-maximgb-tg-elbow-active ';
|
|
if (store.isExpandedNode(record)) {
|
|
if (store.hasNextSiblingNode(record)) {
|
|
tpl_data.cls += this.expanded_icon_class;
|
|
} else {
|
|
tpl_data.cls += this.last_expanded_icon_class;
|
|
}
|
|
} else {
|
|
if (store.hasNextSiblingNode(record)) {
|
|
tpl_data.cls += this.collapsed_icon_class;
|
|
} else {
|
|
tpl_data.cls += this.last_collapsed_icon_class;
|
|
}
|
|
}
|
|
}
|
|
tpl_data.left = 1 + depth * 16;
|
|
|
|
return tpl.apply(tpl_data);
|
|
},
|
|
|
|
// Template method
|
|
renderRow : function(record, index, col_count, ds, total_width) {
|
|
return false;
|
|
},
|
|
|
|
// private - overriden
|
|
afterRender : function() {
|
|
Ext.ux.maximgb.tg.GridView.superclass.afterRender.call(this);
|
|
this.updateAllColumnWidths();
|
|
},
|
|
|
|
// private - overriden to support missing column td's case, if row is
|
|
// rendered by renderRow()
|
|
// method.
|
|
updateAllColumnWidths : function() {
|
|
var tw = this.getTotalWidth(), clen = this.cm.getColumnCount(), ws = [], len, i;
|
|
for (i = 0; i < clen; i++) {
|
|
ws[i] = this.getColumnWidth(i);
|
|
}
|
|
this.innerHd.firstChild.style.width = this.getOffsetWidth();
|
|
this.innerHd.firstChild.firstChild.style.width = tw;
|
|
this.mainBody.dom.style.width = tw;
|
|
for (i = 0; i < clen; i++) {
|
|
var hd = this.getHeaderCell(i);
|
|
hd.style.width = ws[i];
|
|
}
|
|
|
|
var ns = this.getRows(), row, trow;
|
|
for (i = 0, len = ns.length; i < len; i++) {
|
|
row = ns[i];
|
|
row.style.width = tw;
|
|
if (row.firstChild) {
|
|
row.firstChild.style.width = tw;
|
|
trow = row.firstChild.rows[0];
|
|
for (var j = 0; j < clen && j < trow.childNodes.length; j++) {
|
|
if (!Ext.fly(trow.childNodes[j])
|
|
.hasClass(this.skip_width_update_class)) {
|
|
trow.childNodes[j].style.width = ws[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.onAllColumnWidthsUpdated(ws, tw);
|
|
},
|
|
|
|
// private - overriden to support missing column td's case, if row is
|
|
// rendered by renderRow()
|
|
// method.
|
|
updateColumnWidth : function(col, width) {
|
|
var w = this.getColumnWidth(col);
|
|
var tw = this.getTotalWidth();
|
|
this.innerHd.firstChild.style.width = this.getOffsetWidth();
|
|
this.innerHd.firstChild.firstChild.style.width = tw;
|
|
this.mainBody.dom.style.width = tw;
|
|
var hd = this.getHeaderCell(col);
|
|
hd.style.width = w;
|
|
|
|
var ns = this.getRows(), row;
|
|
for (var i = 0, len = ns.length; i < len; i++) {
|
|
row = ns[i];
|
|
row.style.width = tw;
|
|
if (row.firstChild) {
|
|
row.firstChild.style.width = tw;
|
|
if (col < row.firstChild.rows[0].childNodes.length) {
|
|
if (!Ext.fly(row.firstChild.rows[0].childNodes[col])
|
|
.hasClass(this.skip_width_update_class)) {
|
|
row.firstChild.rows[0].childNodes[col].style.width = w;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.onColumnWidthUpdated(col, w, tw);
|
|
},
|
|
|
|
// private - overriden to support missing column td's case, if row is
|
|
// rendered by renderRow()
|
|
// method.
|
|
updateColumnHidden : function(col, hidden) {
|
|
var tw = this.getTotalWidth();
|
|
this.innerHd.firstChild.style.width = this.getOffsetWidth();
|
|
this.innerHd.firstChild.firstChild.style.width = tw;
|
|
this.mainBody.dom.style.width = tw;
|
|
var display = hidden ? 'none' : '';
|
|
|
|
var hd = this.getHeaderCell(col);
|
|
hd.style.display = display;
|
|
|
|
var ns = this.getRows(), row, cell;
|
|
for (var i = 0, len = ns.length; i < len; i++) {
|
|
row = ns[i];
|
|
row.style.width = tw;
|
|
if (row.firstChild) {
|
|
row.firstChild.style.width = tw;
|
|
if (col < row.firstChild.rows[0].childNodes.length) {
|
|
if (!Ext.fly(row.firstChild.rows[0].childNodes[col])
|
|
.hasClass(this.skip_width_update_class)) {
|
|
row.firstChild.rows[0].childNodes[col].style.display = display;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.onColumnHiddenUpdated(col, hidden, tw);
|
|
delete this.lastViewWidth; // force recalc
|
|
this.layout();
|
|
},
|
|
|
|
// private - overriden to skip hidden rows processing.
|
|
processRows : function(startRow, skipStripe) {
|
|
var processed_cnt = 0;
|
|
|
|
if (this.ds.getCount() < 1) {
|
|
return;
|
|
}
|
|
skipStripe = !this.grid.stripeRows; // skipStripe ||
|
|
// !this.grid.stripeRows;
|
|
startRow = startRow || 0;
|
|
var rows = this.getRows();
|
|
var processed_cnt = 0;
|
|
|
|
Ext.each(rows, function(row, idx) {
|
|
row.rowIndex = idx;
|
|
row.className = row.className.replace(this.rowClsRe, ' ');
|
|
if (row.style.display != 'none') {
|
|
if (!skipStripe && ((processed_cnt + 1) % 2 === 0)) {
|
|
row.className += ' x-grid3-row-alt';
|
|
}
|
|
processed_cnt++;
|
|
}
|
|
}, this);
|
|
|
|
Ext.fly(rows[0]).addClass(this.firstRowCls);
|
|
Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);
|
|
},
|
|
|
|
ensureVisible : function(row, col, hscroll) {
|
|
var ancestors, record = this.ds.getAt(row);
|
|
|
|
if (!this.ds.isVisibleNode(record)) {
|
|
ancestors = this.ds.getNodeAncestors(record);
|
|
while (ancestors.length > 0) {
|
|
record = ancestors.shift();
|
|
if (!this.ds.isExpandedNode(record)) {
|
|
this.ds.expandNode(record);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ext.ux.maximgb.tg.GridView.superclass.ensureVisible.call(this,
|
|
row, col, hscroll);
|
|
},
|
|
|
|
// Private
|
|
expandRow : function(record, skip_process) {
|
|
var ds = this.ds, i, len, row, pmel, children, index, child_index;
|
|
|
|
if (typeof record == 'number') {
|
|
index = record;
|
|
record = ds.getAt(index);
|
|
} else {
|
|
index = ds.indexOf(record);
|
|
}
|
|
|
|
skip_process = skip_process || false;
|
|
|
|
row = this.getRow(index);
|
|
pmel = Ext.fly(row).child('.ux-maximgb-tg-elbow-active');
|
|
if (pmel) {
|
|
if (ds.hasNextSiblingNode(record)) {
|
|
pmel.removeClass(this.collapsed_icon_class);
|
|
pmel.removeClass(this.last_collapsed_icon_class);
|
|
pmel.addClass(this.expanded_icon_class);
|
|
} else {
|
|
pmel.removeClass(this.collapsed_icon_class);
|
|
pmel.removeClass(this.last_collapsed_icon_class);
|
|
pmel.addClass(this.last_expanded_icon_class);
|
|
}
|
|
}
|
|
if (ds.isVisibleNode(record)) {
|
|
children = ds.getNodeChildren(record);
|
|
for (i = 0, len = children.length; i < len; i++) {
|
|
child_index = ds.indexOf(children[i]);
|
|
row = this.getRow(child_index);
|
|
row.style.display = 'block';
|
|
if (ds.isExpandedNode(children[i])) {
|
|
this.expandRow(child_index, true);
|
|
}
|
|
}
|
|
}
|
|
if (!skip_process) {
|
|
this.processRows(0);
|
|
}
|
|
// this.updateAllColumnWidths();
|
|
},
|
|
|
|
collapseRow : function(record, skip_process) {
|
|
var ds = this.ds, i, len, children, row, index, child_index;
|
|
|
|
if (typeof record == 'number') {
|
|
index = record;
|
|
record = ds.getAt(index);
|
|
} else {
|
|
index = ds.indexOf(record);
|
|
}
|
|
|
|
skip_process = skip_process || false;
|
|
|
|
row = this.getRow(index);
|
|
pmel = Ext.fly(row).child('.ux-maximgb-tg-elbow-active');
|
|
if (pmel) {
|
|
if (ds.hasNextSiblingNode(record)) {
|
|
pmel.removeClass(this.expanded_icon_class);
|
|
pmel.removeClass(this.last_expanded_icon_class);
|
|
pmel.addClass(this.collapsed_icon_class);
|
|
} else {
|
|
pmel.removeClass(this.expanded_icon_class);
|
|
pmel.removeClass(this.last_expanded_icon_class);
|
|
pmel.addClass(this.last_collapsed_icon_class);
|
|
}
|
|
}
|
|
children = ds.getNodeChildren(record);
|
|
for (i = 0, len = children.length; i < len; i++) {
|
|
child_index = ds.indexOf(children[i]);
|
|
row = this.getRow(child_index);
|
|
if (row.style.display != 'none') {
|
|
row.style.display = 'none';
|
|
this.collapseRow(child_index, true);
|
|
}
|
|
}
|
|
if (!skip_process) {
|
|
this.processRows(0);
|
|
}
|
|
// this.updateAllColumnWidths();
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
initData : function(ds, cm) {
|
|
Ext.ux.maximgb.tg.GridView.superclass.initData.call(this, ds, cm);
|
|
if (this.ds) {
|
|
this.ds.un('expandnode', this.onStoreExpandNode, this);
|
|
this.ds.un('collapsenode', this.onStoreCollapseNode, this);
|
|
}
|
|
if (ds) {
|
|
ds.on('expandnode', this.onStoreExpandNode, this);
|
|
ds.on('collapsenode', this.onStoreCollapseNode, this);
|
|
}
|
|
},
|
|
|
|
onLoad : function(store, records, options) {
|
|
var ridx;
|
|
|
|
if (options
|
|
&& options.params
|
|
&& (options.params[store.paramNames.active_node] === null || store
|
|
.indexOfId(options.params[store.paramNames.active_node]) == -1)) {
|
|
Ext.ux.maximgb.tg.GridView.superclass.onLoad.call(this, store,
|
|
records, options);
|
|
}
|
|
},
|
|
|
|
onAdd : function(ds, records, index) {
|
|
Ext.ux.maximgb.tg.GridView.superclass.onAdd.call(this, ds, records,
|
|
index);
|
|
if (this.mainWrap) {
|
|
// this.updateAllColumnWidths();
|
|
this.processRows(0);
|
|
}
|
|
},
|
|
|
|
onRemove : function(ds, record, index, isUpdate) {
|
|
Ext.ux.maximgb.tg.GridView.superclass.onRemove.call(this, ds, record,
|
|
index, isUpdate);
|
|
if (isUpdate !== true) {
|
|
if (this.mainWrap) {
|
|
// this.updateAllColumnWidths();
|
|
this.processRows(0);
|
|
}
|
|
}
|
|
},
|
|
|
|
onUpdate : function(ds, record) {
|
|
Ext.ux.maximgb.tg.GridView.superclass.onUpdate.call(this, ds, record);
|
|
if (this.mainWrap) {
|
|
// this.updateAllColumnWidths();
|
|
this.processRows(0);
|
|
}
|
|
},
|
|
|
|
onStoreExpandNode : function(store, rc) {
|
|
this.expandRow(rc);
|
|
},
|
|
|
|
onStoreCollapseNode : function(store, rc) {
|
|
this.collapseRow(rc);
|
|
}
|
|
});
|
|
|
|
Ext.ux.maximgb.tg.GridPanel = Ext.extend(Ext.grid.GridPanel, {
|
|
/**
|
|
* @cfg {String|Integer} master_column_id Master column id. Master
|
|
* column cells are nested. Master column cell values are used
|
|
* to build breadcrumbs.
|
|
*/
|
|
master_column_id : 0,
|
|
|
|
/**
|
|
* @cfg {Stirng} TreeGrid panel custom class.
|
|
*/
|
|
tg_cls : 'ux-maximgb-tg-panel',
|
|
|
|
// Private
|
|
initComponent : function() {
|
|
this.initComponentPreOverride();
|
|
Ext.ux.maximgb.tg.GridPanel.superclass.initComponent.call(this);
|
|
this.getSelectionModel().on('selectionchange',
|
|
this.onTreeGridSelectionChange, this);
|
|
this.initComponentPostOverride();
|
|
},
|
|
|
|
initComponentPreOverride : Ext.emptyFn,
|
|
|
|
initComponentPostOverride : Ext.emptyFn,
|
|
|
|
// Private
|
|
onRender : function(ct, position) {
|
|
Ext.ux.maximgb.tg.GridPanel.superclass.onRender.call(this, ct,
|
|
position);
|
|
this.el.addClass(this.tg_cls);
|
|
},
|
|
|
|
/**
|
|
* Returns view instance.
|
|
*
|
|
* @access private
|
|
* @return {GridView}
|
|
*/
|
|
getView : function() {
|
|
if (!this.view) {
|
|
this.view = new Ext.ux.maximgb.tg.GridView(this.viewConfig);
|
|
}
|
|
return this.view;
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onClick : function(e) {
|
|
var target = e.getTarget(), view = this.getView(), row = view
|
|
.findRowIndex(target), store = this.getStore(), sm = this
|
|
.getSelectionModel(), record, record_id, do_default = true;
|
|
|
|
// Row click
|
|
if (row !== false) {
|
|
if (Ext.fly(target).hasClass('ux-maximgb-tg-elbow-active')) {
|
|
record = store.getAt(row);
|
|
if (store.isExpandedNode(record)) {
|
|
store.collapseNode(record);
|
|
} else {
|
|
store.expandNode(record);
|
|
}
|
|
do_default = false;
|
|
}
|
|
}
|
|
|
|
if (do_default) {
|
|
Ext.ux.maximgb.tg.GridPanel.superclass.onClick
|
|
.call(this, e);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onMouseDown : function(e) {
|
|
var target = e.getTarget();
|
|
|
|
if (!Ext.fly(target).hasClass('ux-maximgb-tg-elbow-active')) {
|
|
Ext.ux.maximgb.tg.GridPanel.superclass.onMouseDown.call(
|
|
this, e);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onTreeGridSelectionChange : function(sm, selection) {
|
|
var record, ancestors, store = this.getStore();
|
|
// Row selection model
|
|
if (sm.getSelected) {
|
|
record = sm.getSelected();
|
|
store.setActiveNode(record);
|
|
}
|
|
// Cell selection model
|
|
else if (sm.getSelectedCell && selection) {
|
|
record = selection.record;
|
|
store.setActiveNode(record);
|
|
}
|
|
|
|
// Ensuring that selected node is visible.
|
|
if (record) {
|
|
if (!store.isVisibleNode(record)) {
|
|
ancestors = store.getNodeAncestors(record);
|
|
while (ancestors.length > 0) {
|
|
store.expandNode(ancestors.pop());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
Ext.ux.maximgb.tg.EditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
|
|
/**
|
|
* @cfg {String|Integer} master_column_id Master column id. Master
|
|
* column cells are nested. Master column cell values are used
|
|
* to build breadcrumbs.
|
|
*/
|
|
master_column_id : 0,
|
|
|
|
// Private
|
|
initComponent : function() {
|
|
this.initComponentPreOverride();
|
|
|
|
Ext.ux.maximgb.tg.EditorGridPanel.superclass.initComponent
|
|
.call(this);
|
|
|
|
this.getSelectionModel().on('selectionchange',
|
|
this.onTreeGridSelectionChange, this);
|
|
|
|
this.initComponentPostOverride();
|
|
},
|
|
|
|
initComponentPreOverride : Ext.emptyFn,
|
|
|
|
initComponentPostOverride : Ext.emptyFn,
|
|
|
|
// Private
|
|
onRender : function(ct, position) {
|
|
Ext.ux.maximgb.tg.EditorGridPanel.superclass.onRender.call(
|
|
this, ct, position);
|
|
this.el.addClass('ux-maximgb-tg-panel');
|
|
},
|
|
|
|
/**
|
|
* Returns view instance.
|
|
*
|
|
* @access private
|
|
* @return {GridView}
|
|
*/
|
|
getView : function() {
|
|
if (!this.view) {
|
|
this.view = new Ext.ux.maximgb.tg.GridView(this.viewConfig);
|
|
}
|
|
return this.view;
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onClick : function(e) {
|
|
var target = e.getTarget(), view = this.getView(), row = view
|
|
.findRowIndex(target), store = this.getStore(), sm = this
|
|
.getSelectionModel(), record, record_id, do_default = true;
|
|
|
|
// Row click
|
|
if (row !== false) {
|
|
if (Ext.fly(target).hasClass('ux-maximgb-tg-elbow-active')) {
|
|
record = store.getAt(row);
|
|
if (store.isExpandedNode(record)) {
|
|
store.collapseNode(record);
|
|
} else {
|
|
store.expandNode(record);
|
|
}
|
|
do_default = false;
|
|
}
|
|
}
|
|
|
|
if (do_default) {
|
|
Ext.ux.maximgb.tg.EditorGridPanel.superclass.onClick.call(
|
|
this, e);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onMouseDown : function(e) {
|
|
var target = e.getTarget();
|
|
|
|
if (!Ext.fly(target).hasClass('ux-maximgb-tg-elbow-active')) {
|
|
Ext.ux.maximgb.tg.EditorGridPanel.superclass.onMouseDown
|
|
.call(this, e);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @access private
|
|
*/
|
|
onTreeGridSelectionChange : function(sm, selection) {
|
|
var record, ancestors, store = this.getStore();
|
|
// Row selection model
|
|
if (sm.getSelected) {
|
|
record = sm.getSelected();
|
|
store.setActiveNode(record);
|
|
}
|
|
// Cell selection model
|
|
else if (sm.getSelectedCell && selection) {
|
|
record = selection.record;
|
|
store.setActiveNode(record);
|
|
}
|
|
|
|
// Ensuring that selected node is visible.
|
|
if (record) {
|
|
if (!store.isVisibleNode(record)) {
|
|
ancestors = store.getNodeAncestors(record);
|
|
while (ancestors.length > 0) {
|
|
store.expandNode(ancestors.pop());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Paging toolbar for work this AbstractTreeStore.
|
|
*/
|
|
Ext.ux.maximgb.tg.PagingToolbar = Ext.extend(Ext.PagingToolbar, {
|
|
onRender : function(ct, position) {
|
|
Ext.ux.maximgb.tg.PagingToolbar.superclass.onRender.call(this,
|
|
ct, position);
|
|
this.updateUI();
|
|
},
|
|
|
|
getPageData : function() {
|
|
var total = 0, cursor = 0;
|
|
if (this.store) {
|
|
cursor = this.store.getActiveNodePageOffset();
|
|
total = this.store.getActiveNodeTotalCount();
|
|
}
|
|
return {
|
|
total : total,
|
|
activePage : Math.ceil((cursor + this.pageSize)
|
|
/ this.pageSize),
|
|
pages : total < this.pageSize ? 1 : Math.ceil(total
|
|
/ this.pageSize)
|
|
};
|
|
},
|
|
|
|
updateInfo : function() {
|
|
var count = 0, cursor = 0, total = 0, msg;
|
|
if (this.displayItem) {
|
|
if (this.store) {
|
|
cursor = this.store.getActiveNodePageOffset();
|
|
count = this.store.getActiveNodeCount();
|
|
total = this.store.getActiveNodeTotalCount();
|
|
}
|
|
msg = count == 0 ? this.emptyMsg : String.format(
|
|
this.displayMsg, cursor + 1, cursor + count, total);
|
|
this.displayItem.setText(msg);
|
|
}
|
|
},
|
|
|
|
updateUI : function() {
|
|
var d = this.getPageData(), ap = d.activePage, ps = d.pages;
|
|
|
|
this.afterTextItem.setText(String.format(this.afterPageText,
|
|
d.pages));
|
|
this.inputItem.setValue(ap);
|
|
|
|
this.first.setDisabled(ap == 1);
|
|
this.prev.setDisabled(ap == 1);
|
|
this.next.setDisabled(ap == ps);
|
|
this.last.setDisabled(ap == ps);
|
|
this.refresh.enable();
|
|
this.updateInfo();
|
|
},
|
|
|
|
bindStore : function(store, initial) {
|
|
if (!initial && this.store) {
|
|
this.store.un('activenodechange',
|
|
this.onStoreActiveNodeChange, this);
|
|
}
|
|
if (store) {
|
|
store.on('activenodechange', this.onStoreActiveNodeChange,
|
|
this);
|
|
}
|
|
Ext.ux.maximgb.tg.PagingToolbar.superclass.bindStore.call(this,
|
|
store, initial);
|
|
},
|
|
|
|
beforeLoad : function(store, options) {
|
|
var paramNames = this.getParams();
|
|
|
|
Ext.ux.maximgb.tg.PagingToolbar.superclass.beforeLoad.call(
|
|
this, store, options);
|
|
|
|
if (options && options.params) {
|
|
if (options.params[paramNames.start] === undefined) {
|
|
options.params[paramNames.start] = 0;
|
|
}
|
|
if (options.params[paramNames.limit] === undefined) {
|
|
options.params[paramNames.limit] = this.pageSize;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Move to the first page, has the same effect as clicking the
|
|
* 'first' button.
|
|
*/
|
|
moveFirst : function() {
|
|
this.doLoad(0);
|
|
},
|
|
|
|
/**
|
|
* Move to the previous page, has the same effect as clicking the
|
|
* 'previous' button.
|
|
*/
|
|
movePrevious : function() {
|
|
var store = this.store, cursor = store ? store
|
|
.getActiveNodePageOffset() : 0;
|
|
|
|
this.doLoad(Math.max(0, cursor - this.pageSize));
|
|
},
|
|
|
|
/**
|
|
* Move to the next page, has the same effect as clicking the 'next'
|
|
* button.
|
|
*/
|
|
moveNext : function() {
|
|
var store = this.store, cursor = store ? store
|
|
.getActiveNodePageOffset() : 0;
|
|
|
|
this.doLoad(cursor + this.pageSize);
|
|
},
|
|
|
|
/**
|
|
* Move to the last page, has the same effect as clicking the 'last'
|
|
* button.
|
|
*/
|
|
moveLast : function() {
|
|
var store = this.store, cursor = store ? store
|
|
.getActiveNodePageOffset() : 0, total = store ? store
|
|
.getActiveNodeTotalCount() : 0, extra = total
|
|
% this.pageSize;
|
|
|
|
this.doLoad(extra ? (total - extra) : total - this.pageSize);
|
|
},
|
|
|
|
onStoreActiveNodeChange : function(store, old_rec, new_rec) {
|
|
if (this.rendered) {
|
|
this.updateUI();
|
|
}
|
|
}
|
|
});
|
|
|
|
Ext.reg('Ext.ux.maximgb.tg.GridPanel', Ext.ux.maximgb.tg.GridPanel);
|
|
Ext.reg('Ext.ux.maximgb.tg.EditorGridPanel', Ext.ux.maximgb.tg.EditorGridPanel);
|
|
Ext.reg('Ext.ux.maximgb.tg.PagingToolbar', Ext.ux.maximgb.tg.PagingToolbar);
|