195 lines
6.2 KiB
JavaScript
195 lines
6.2 KiB
JavaScript
/**
|
|
* Represents a single sorter that can be used as part of the sorters configuration in Ext.mixin.Sortable.
|
|
*
|
|
* A common place for Sorters to be used are {@link Ext.data.Store Stores}. For example:
|
|
*
|
|
* @example miniphone
|
|
* var store = Ext.create('Ext.data.Store', {
|
|
* fields: ['firstName', 'lastName'],
|
|
* sorters: 'lastName',
|
|
*
|
|
* data: [
|
|
* { firstName: 'Tommy', lastName: 'Maintz' },
|
|
* { firstName: 'Rob', lastName: 'Dougan' },
|
|
* { firstName: 'Ed', lastName: 'Spencer'},
|
|
* { firstName: 'Jamie', lastName: 'Avins' },
|
|
* { firstName: 'Nick', lastName: 'Poulden'}
|
|
* ]
|
|
* });
|
|
*
|
|
* Ext.create('Ext.List', {
|
|
* fullscreen: true,
|
|
* itemTpl: '<div class="contact">{firstName} <strong>{lastName}</strong></div>',
|
|
* store: store
|
|
* });
|
|
*
|
|
* In the next example, we specify a custom sorter function:
|
|
*
|
|
* @example miniphone
|
|
* var store = Ext.create('Ext.data.Store', {
|
|
* fields: ['person'],
|
|
* sorters: [
|
|
* {
|
|
* // Sort by first letter of last name, in descending order
|
|
* sorterFn: function(record1, record2) {
|
|
* var name1 = record1.data.person.name.split('-')[1].substr(0, 1),
|
|
* name2 = record2.data.person.name.split('-')[1].substr(0, 1);
|
|
*
|
|
* return name1 > name2 ? 1 : (name1 === name2 ? 0 : -1);
|
|
* },
|
|
* direction: 'DESC'
|
|
* }
|
|
* ],
|
|
* data: [
|
|
* { person: { name: 'Tommy-Maintz' } },
|
|
* { person: { name: 'Rob-Dougan' } },
|
|
* { person: { name: 'Ed-Spencer' } },
|
|
* { person: { name: 'Nick-Poulden' } },
|
|
* { person: { name: 'Jamie-Avins' } }
|
|
* ]
|
|
* });
|
|
*
|
|
* Ext.create('Ext.List', {
|
|
* fullscreen: true,
|
|
* itemTpl: '{person.name}',
|
|
* store: store
|
|
* });
|
|
*/
|
|
Ext.define('Ext.util.Sorter', {
|
|
isSorter: true,
|
|
|
|
config: {
|
|
/**
|
|
* @cfg {String} property The property to sort by. Required unless `sorterFn` is provided
|
|
*/
|
|
property: null,
|
|
|
|
/**
|
|
* @cfg {Function} sorterFn A specific sorter function to execute. Can be passed instead of {@link #property}.
|
|
* This function should compare the two passed arguments, returning -1, 0 or 1 depending on if item 1 should be
|
|
* sorted before, at the same level, or after item 2.
|
|
*
|
|
* sorterFn: function(person1, person2) {
|
|
* return (person1.age > person2.age) ? 1 : (person1.age === person2.age ? 0 : -1);
|
|
* }
|
|
*/
|
|
sorterFn: null,
|
|
|
|
/**
|
|
* @cfg {String} root Optional root property. This is mostly useful when sorting a Store, in which case we set the
|
|
* root to 'data' to make the filter pull the {@link #property} out of the data object of each item
|
|
*/
|
|
root: null,
|
|
|
|
/**
|
|
* @cfg {Function} transform A function that will be run on each value before
|
|
* it is compared in the sorter. The function will receive a single argument,
|
|
* the value.
|
|
*/
|
|
transform: null,
|
|
|
|
/**
|
|
* @cfg {String} direction The direction to sort by. Valid values are "ASC", and "DESC".
|
|
*/
|
|
direction: "ASC",
|
|
|
|
/**
|
|
* @cfg {Mixed} id An optional id this sorter can be keyed by in Collections. If
|
|
* no id is specified it will use the property name used in this Sorter. If no
|
|
* property is specified, e.g. when adding a custom sorter function we will generate
|
|
* a random id.
|
|
*/
|
|
id: undefined
|
|
},
|
|
|
|
constructor: function(config) {
|
|
this.initConfig(config);
|
|
},
|
|
|
|
// <debug>
|
|
applySorterFn: function(sorterFn) {
|
|
if (!sorterFn && !this.getProperty()) {
|
|
Ext.Logger.error("A Sorter requires either a property or a sorterFn.");
|
|
}
|
|
return sorterFn;
|
|
},
|
|
|
|
applyProperty: function(property) {
|
|
if (!property && !this.getSorterFn()) {
|
|
Ext.Logger.error("A Sorter requires either a property or a sorterFn.");
|
|
}
|
|
return property;
|
|
},
|
|
// </debug>
|
|
|
|
applyId: function(id) {
|
|
if (!id) {
|
|
id = this.getProperty();
|
|
if (!id) {
|
|
id = Ext.id(null, 'ext-sorter-');
|
|
}
|
|
}
|
|
|
|
return id;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* Creates and returns a function which sorts an array by the given property and direction
|
|
* @return {Function} A function which sorts by the property/direction combination provided
|
|
*/
|
|
createSortFunction: function(sorterFn) {
|
|
var me = this,
|
|
modifier = me.getDirection().toUpperCase() == "DESC" ? -1 : 1;
|
|
|
|
//create a comparison function. Takes 2 objects, returns 1 if object 1 is greater,
|
|
//-1 if object 2 is greater or 0 if they are equal
|
|
return function(o1, o2) {
|
|
return modifier * sorterFn.call(me, o1, o2);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* Basic default sorter function that just compares the defined property of each object
|
|
*/
|
|
defaultSortFn: function(item1, item2) {
|
|
var me = this,
|
|
transform = me._transform,
|
|
root = me._root,
|
|
value1, value2,
|
|
property = me._property;
|
|
|
|
if (root !== null) {
|
|
item1 = item1[root];
|
|
item2 = item2[root];
|
|
}
|
|
|
|
value1 = item1[property];
|
|
value2 = item2[property];
|
|
|
|
if (transform) {
|
|
value1 = transform(value1);
|
|
value2 = transform(value2);
|
|
}
|
|
|
|
return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0);
|
|
},
|
|
|
|
updateDirection: function() {
|
|
this.updateSortFn();
|
|
},
|
|
|
|
updateSortFn: function() {
|
|
this.sort = this.createSortFunction(this.getSorterFn() || this.defaultSortFn);
|
|
},
|
|
|
|
/**
|
|
* Toggles the direction of this Sorter. Note that when you call this function,
|
|
* the Collection this Sorter is part of does not get refreshed automatically.
|
|
*/
|
|
toggle: function() {
|
|
this.setDirection(Ext.String.toggle(this.getDirection(), "ASC", "DESC"));
|
|
}
|
|
});
|