Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
9.2 KiB
259 lines
9.2 KiB
/*!
|
|
* Ext JS Library 3.2.0
|
|
* Copyright(c) 2006-2010 Ext JS, Inc.
|
|
* licensing@extjs.com
|
|
* http://www.extjs.com/license
|
|
*/
|
|
/**
|
|
* @class Ext.data.GroupingStore
|
|
* @extends Ext.data.Store
|
|
* A specialized store implementation that provides for grouping records by one of the available fields. This
|
|
* is usually used in conjunction with an {@link Ext.grid.GroupingView} to provide the data model for
|
|
* a grouped GridPanel.
|
|
*
|
|
* Internally, GroupingStore is simply a normal Store with multi sorting enabled from the start. The grouping field
|
|
* and direction are always injected as the first sorter pair. GroupingView picks up on the configured groupField and
|
|
* builds grid rows appropriately.
|
|
*
|
|
* @constructor
|
|
* Creates a new GroupingStore.
|
|
* @param {Object} config A config object containing the objects needed for the Store to access data,
|
|
* and read the data into Records.
|
|
* @xtype groupingstore
|
|
*/
|
|
Ext.data.GroupingStore = Ext.extend(Ext.data.Store, {
|
|
|
|
//inherit docs
|
|
constructor: function(config) {
|
|
config = config || {};
|
|
|
|
//We do some preprocessing here to massage the grouping + sorting options into a single
|
|
//multi sort array. If grouping and sorting options are both presented to the constructor,
|
|
//the sorters array consists of the grouping sorter object followed by the sorting sorter object
|
|
//see Ext.data.Store's sorting functions for details about how multi sorting works
|
|
this.hasMultiSort = true;
|
|
this.multiSortInfo = this.multiSortInfo || {sorters: []};
|
|
|
|
var sorters = this.multiSortInfo.sorters,
|
|
groupField = config.groupField || this.groupField,
|
|
sortInfo = config.sortInfo || this.sortInfo,
|
|
groupDir = config.groupDir || this.groupDir;
|
|
|
|
//add the grouping sorter object first
|
|
if(groupField){
|
|
sorters.push({
|
|
field : groupField,
|
|
direction: groupDir
|
|
});
|
|
}
|
|
|
|
//add the sorting sorter object if it is present
|
|
if (sortInfo) {
|
|
sorters.push(sortInfo);
|
|
}
|
|
|
|
Ext.data.GroupingStore.superclass.constructor.call(this, config);
|
|
|
|
this.addEvents(
|
|
/**
|
|
* @event groupchange
|
|
* Fired whenever a call to store.groupBy successfully changes the grouping on the store
|
|
* @param {Ext.data.GroupingStore} store The grouping store
|
|
* @param {String} groupField The field that the store is now grouped by
|
|
*/
|
|
'groupchange'
|
|
);
|
|
|
|
this.applyGroupField();
|
|
},
|
|
|
|
/**
|
|
* @cfg {String} groupField
|
|
* The field name by which to sort the store's data (defaults to '').
|
|
*/
|
|
/**
|
|
* @cfg {Boolean} remoteGroup
|
|
* True if the grouping should apply on the server side, false if it is local only (defaults to false). If the
|
|
* grouping is local, it can be applied immediately to the data. If it is remote, then it will simply act as a
|
|
* helper, automatically sending the grouping field name as the 'groupBy' param with each XHR call.
|
|
*/
|
|
remoteGroup : false,
|
|
/**
|
|
* @cfg {Boolean} groupOnSort
|
|
* True to sort the data on the grouping field when a grouping operation occurs, false to sort based on the
|
|
* existing sort info (defaults to false).
|
|
*/
|
|
groupOnSort:false,
|
|
|
|
groupDir : 'ASC',
|
|
|
|
/**
|
|
* Clears any existing grouping and refreshes the data using the default sort.
|
|
*/
|
|
clearGrouping : function(){
|
|
this.groupField = false;
|
|
|
|
if(this.remoteGroup){
|
|
if(this.baseParams){
|
|
delete this.baseParams.groupBy;
|
|
delete this.baseParams.groupDir;
|
|
}
|
|
var lo = this.lastOptions;
|
|
if(lo && lo.params){
|
|
delete lo.params.groupBy;
|
|
delete lo.params.groupDir;
|
|
}
|
|
|
|
this.reload();
|
|
}else{
|
|
this.sort();
|
|
this.fireEvent('datachanged', this);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Groups the data by the specified field.
|
|
* @param {String} field The field name by which to sort the store's data
|
|
* @param {Boolean} forceRegroup (optional) True to force the group to be refreshed even if the field passed
|
|
* in is the same as the current grouping field, false to skip grouping on the same field (defaults to false)
|
|
*/
|
|
groupBy : function(field, forceRegroup, direction) {
|
|
direction = direction ? (String(direction).toUpperCase() == 'DESC' ? 'DESC' : 'ASC') : this.groupDir;
|
|
|
|
if (this.groupField == field && this.groupDir == direction && !forceRegroup) {
|
|
return; // already grouped by this field
|
|
}
|
|
|
|
//check the contents of the first sorter. If the field matches the CURRENT groupField (before it is set to the new one),
|
|
//remove the sorter as it is actually the grouper. The new grouper is added back in by this.sort
|
|
sorters = this.multiSortInfo.sorters;
|
|
if (sorters.length > 0 && sorters[0].field == this.groupField) {
|
|
sorters.shift();
|
|
}
|
|
|
|
this.groupField = field;
|
|
this.groupDir = direction;
|
|
this.applyGroupField();
|
|
|
|
var fireGroupEvent = function() {
|
|
this.fireEvent('groupchange', this, this.getGroupState());
|
|
};
|
|
|
|
if (this.groupOnSort) {
|
|
this.sort(field, direction);
|
|
fireGroupEvent.call(this);
|
|
return;
|
|
}
|
|
|
|
if (this.remoteGroup) {
|
|
this.on('load', fireGroupEvent, this, {single: true});
|
|
this.reload();
|
|
} else {
|
|
this.sort(sorters);
|
|
fireGroupEvent.call(this);
|
|
}
|
|
},
|
|
|
|
//GroupingStore always uses multisorting so we intercept calls to sort here to make sure that our grouping sorter object
|
|
//is always injected first.
|
|
sort : function(fieldName, dir) {
|
|
if (this.remoteSort) {
|
|
return Ext.data.GroupingStore.superclass.sort.call(this, fieldName, dir);
|
|
}
|
|
|
|
var sorters = [];
|
|
|
|
//cater for any existing valid arguments to this.sort, massage them into an array of sorter objects
|
|
if (Ext.isArray(arguments[0])) {
|
|
sorters = arguments[0];
|
|
} else if (fieldName == undefined) {
|
|
//we preserve the existing sortInfo here because this.sort is called after
|
|
//clearGrouping and there may be existing sorting
|
|
sorters = [this.sortInfo];
|
|
} else {
|
|
//TODO: this is lifted straight from Ext.data.Store's singleSort function. It should instead be
|
|
//refactored into a common method if possible
|
|
var field = this.fields.get(fieldName);
|
|
if (!field) return false;
|
|
|
|
var name = field.name,
|
|
sortInfo = this.sortInfo || null,
|
|
sortToggle = this.sortToggle ? this.sortToggle[name] : null;
|
|
|
|
if (!dir) {
|
|
if (sortInfo && sortInfo.field == name) { // toggle sort dir
|
|
dir = (this.sortToggle[name] || 'ASC').toggle('ASC', 'DESC');
|
|
} else {
|
|
dir = field.sortDir;
|
|
}
|
|
}
|
|
|
|
this.sortToggle[name] = dir;
|
|
this.sortInfo = {field: name, direction: dir};
|
|
|
|
sorters = [this.sortInfo];
|
|
}
|
|
|
|
//add the grouping sorter object as the first multisort sorter
|
|
if (this.groupField) {
|
|
sorters.unshift({direction: this.groupDir, field: this.groupField});
|
|
}
|
|
|
|
return this.multiSort.call(this, sorters, dir);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* Saves the current grouping field and direction to this.baseParams and this.lastOptions.params
|
|
* if we're using remote grouping. Does not actually perform any grouping - just stores values
|
|
*/
|
|
applyGroupField: function(){
|
|
if (this.remoteGroup) {
|
|
if(!this.baseParams){
|
|
this.baseParams = {};
|
|
}
|
|
|
|
Ext.apply(this.baseParams, {
|
|
groupBy : this.groupField,
|
|
groupDir: this.groupDir
|
|
});
|
|
|
|
var lo = this.lastOptions;
|
|
if (lo && lo.params) {
|
|
lo.params.groupDir = this.groupDir;
|
|
|
|
//this is deleted because of a bug reported at http://www.extjs.com/forum/showthread.php?t=82907
|
|
delete lo.params.groupBy;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* TODO: This function is apparently never invoked anywhere in the framework. It has no documentation
|
|
* and should be considered for deletion
|
|
*/
|
|
applyGrouping : function(alwaysFireChange){
|
|
if(this.groupField !== false){
|
|
this.groupBy(this.groupField, true, this.groupDir);
|
|
return true;
|
|
}else{
|
|
if(alwaysFireChange === true){
|
|
this.fireEvent('datachanged', this);
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* Returns the grouping field that should be used. If groupOnSort is used this will be sortInfo's field,
|
|
* otherwise it will be this.groupField
|
|
* @return {String} The group field
|
|
*/
|
|
getGroupState : function(){
|
|
return this.groupOnSort && this.groupField !== false ?
|
|
(this.sortInfo ? this.sortInfo.field : undefined) : this.groupField;
|
|
}
|
|
});
|
|
Ext.reg('groupingstore', Ext.data.GroupingStore);
|