lib/Ext/util/Sortable.js
function(sorters, direction, where, doSort) {
        var me = this,
            sorter, sorterFn,
            newSorters;
        
        if (Ext.isArray(sorters)) {
            doSort = where;
            where = direction;
            newSorters = sorters;
        }
        else if (Ext.isObject(sorters)) {
            doSort = where;
            where = direction;
            newSorters = [sorters];
        }
        else if (Ext.isString(sorters)) {
            sorter = me.sorters.get(sorters);

            if (!sorter) {
                sorter = {
                    property : sorters,
                    direction: direction
                };
                newSorters = [sorter];
            }
            else if (direction === undefined) {
                sorter.toggle();
            }
            else {
                sorter.setDirection(direction);
            }
        }
        
        if (newSorters && newSorters.length) {
            newSorters = me.decodeSorters(newSorters);
            if (Ext.isString(where)) {
                if (where === 'prepend') {
                    sorters = me.sorters.clone().items;
                    
                    me.sorters.clear();
                    me.sorters.addAll(newSorters);
                    me.sorters.addAll(sorters);
                }
                else {
                    me.sorters.addAll(newSorters);
                }
            }
            else {
                me.sorters.clear();
                me.sorters.addAll(newSorters);
            }
            
            if (doSort !== false) {
                me.onBeforeSort(newSorters);
            }
        }
        
        if (doSort !== false) {
            sorters = me.sorters.items;
            if (sorters.length) {
                //construct an amalgamated sorter function which combines all of the Sorters passed
                sorterFn = function(r1, r2) {
                    var result = sorters[0].sort(r1, r2),
                        length = sorters.length,
                        i;

                        //if we have more than one sorter, OR any additional sorter functions together
                        for (i = 1; i < length; i++) {
                            result = result || sorters[i].sort.call(this, r1, r2);
                        }

                    return result;
                };

                me.doSort(sorterFn);                
            }
        }
        
        return sorters;
    }
function(sorters, direction, where, doSort) {
        var me = this,
            sorter, sorterFn,
            newSorters;
        
        if (Ext.isArray(sorters)) {
            doSort = where;
            where = direction;
            newSorters = sorters;
        }
        else if (Ext.isObject(sorters)) {
            doSort = where;
            where = direction;
            newSorters = [sorters];
        }
        else if (Ext.isString(sorters)) {
            sorter = me.sorters.get(sorters);

            if (!sorter) {
                sorter = {
                    property : sorters,
                    direction: direction
                };
                newSorters = [sorter];
            }
            else if (direction === undefined) {
                sorter.toggle();
            }
            else {
                sorter.setDirection(direction);
            }
        }
        
        if (newSorters && newSorters.length) {
            newSorters = me.decodeSorters(newSorters);
            if (Ext.isString(where)) {
                if (where === 'prepend') {
                    sorters = me.sorters.clone().items;
                    
                    me.sorters.clear();
                    me.sorters.addAll(newSorters);
                    me.sorters.addAll(sorters);
                }
                else {
                    me.sorters.addAll(newSorters);
                }
            }
            else {
                me.sorters.clear();
                me.sorters.addAll(newSorters);
            }
            
            if (doSort !== false) {
                me.onBeforeSort(newSorters);
            }
        }
        
        if (doSort !== false) {
            sorters = me.sorters.items;
            if (sorters.length) {
                //construct an amalgamated sorter function which combines all of the Sorters passed
                sorterFn = function(r1, r2) {
                    var result = sorters[0].sort(r1, r2),
                        length = sorters.length,
                        i;

                        //if we have more than one sorter, OR any additional sorter functions together
                        for (i = 1; i < length; i++) {
                            result = result || sorters[i].sort.call(this, r1, r2);
                        }

                    return result;
                };

                me.doSort(sorterFn);                
            }
        }
        
        return sorters;
    }
function ( sorters , direction , where , doSort ) { var me = this , sorter , sorterFn , newSorters ; if ( Ext . isArray ( sorters ) ) { doSort = where ; where = direction ; newSorters = sorters ; } else if ( Ext . isObject ( sorters ) ) { doSort = where ; where = direction ; newSorters = [ sorters ] ; } else if ( Ext . isString ( sorters ) ) { sorter = me . sorters . get ( sorters ) ; if ( ! sorter ) { sorter = { property : sorters , direction : direction } ; newSorters = [ sorter ] ; } else if ( direction === undefined ) { sorter . toggle ( ) ; } else { sorter . setDirection ( direction ) ; } } if ( newSorters && newSorters . length ) { newSorters = me . decodeSorters ( newSorters ) ; if ( Ext . isString ( where ) ) { if ( where === 'prepend' ) { sorters = me . sorters . clone ( ) . items ; me . sorters . clear ( ) ; me . sorters . addAll ( newSorters ) ; me . sorters . addAll ( sorters ) ; } else { me . sorters . addAll ( newSorters ) ; } } else { me . sorters . clear ( ) ; me . sorters . addAll ( newSorters ) ; } if ( doSort !== false ) { me . onBeforeSort ( newSorters ) ; } } if ( doSort !== false ) { sorters = me . sorters . items ; if ( sorters . length ) { //construct an amalgamated sorter function which combines all of the Sorters passed sorterFn = function ( r1 , r2 ) { var result = sorters [ 0 ] . sort ( r1 , r2 ) , length = sorters . length , i ; //if we have more than one sorter, OR any additional sorter functions together for ( i = 1 ; i < length ; i ++ ) { result = result || sorters [ i ] . sort . call ( this , r1 , r2 ) ; } return result ; } ; me . doSort ( sorterFn ) ; } } return sorters ; }
Sorts the data in the Store by one or more of its properties. Example usage:

//sort by a single field
myStore.sort('myField', 'DESC');

//sorting by multiple fields
myStore.sort([
{
property : 'age',
direction: 'ASC'
},
{
property : 'name',
direction: 'DESC'
}
]);

Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates
the actual sorting to its internal {@link Ext.util.MixedCollection}.

When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:

store.sort('myField');
store.sort('myField');

Is equivalent to this code, because Store handles the toggling automatically:

store.sort('myField', 'ASC');
store.sort('myField', 'DESC');

@param {String/Ext.util.Sorter[]} sorters Either a string name of one of the fields in this Store's configured
{@link Ext.data.Model Model}, or an array of sorter configurations.
@param {String} [direction="ASC"] The overall direction to sort the data by.
@param {String} [where]
@param {Boolean} [doSort]
@return {Ext.util.Sorter[]}
Sorts the data in the Store by one or more of its properties . Example usage :