Upgrade to ExtJS 3.3.0 - Released 10/06/2010
[extjs.git] / src / widgets / tree / TreeSorter.js
1 /*!
2  * Ext JS Library 3.3.0
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.tree.TreeSorter
9  * Provides sorting of nodes in a {@link Ext.tree.TreePanel}.  The TreeSorter automatically monitors events on the
10  * associated TreePanel that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
11  * Example usage:<br />
12  * <pre><code>
13 new Ext.tree.TreeSorter(myTree, {
14     folderSort: true,
15     dir: "desc",
16     sortType: function(node) {
17         // sort by a custom, typed attribute:
18         return parseInt(node.id, 10);
19     }
20 });
21 </code></pre>
22  * @constructor
23  * @param {TreePanel} tree
24  * @param {Object} config
25  */
26 Ext.tree.TreeSorter = Ext.extend(Object, {
27     
28     constructor: function(tree, config){
29         /**
30      * @cfg {Boolean} folderSort True to sort leaf nodes under non-leaf nodes (defaults to false)
31      */
32     /**
33      * @cfg {String} property The named attribute on the node to sort by (defaults to "text").  Note that this
34      * property is only used if no {@link #sortType} function is specified, otherwise it is ignored.
35      */
36     /**
37      * @cfg {String} dir The direction to sort ("asc" or "desc," case-insensitive, defaults to "asc")
38      */
39     /**
40      * @cfg {String} leafAttr The attribute used to determine leaf nodes when {@link #folderSort} = true (defaults to "leaf")
41      */
42     /**
43      * @cfg {Boolean} caseSensitive true for case-sensitive sort (defaults to false)
44      */
45     /**
46      * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting.  The function
47      * will be called with a single parameter (the {@link Ext.tree.TreeNode} being evaluated) and is expected to return
48      * the node's sort value cast to the specific data type required for sorting.  This could be used, for example, when
49      * a node's text (or other attribute) should be sorted as a date or numeric value.  See the class description for
50      * example usage.  Note that if a sortType is specified, any {@link #property} config will be ignored.
51      */
52
53     Ext.apply(this, config);
54     tree.on({
55         scope: this,
56         beforechildrenrendered: this.doSort,
57         append: this.updateSort,
58         insert: this.updateSort,
59         textchange: this.updateSortParent
60     });
61
62     var desc = this.dir && this.dir.toLowerCase() == 'desc',
63         prop = this.property || 'text';
64         sortType = this.sortType;
65         folderSort = this.folderSort;
66         caseSensitive = this.caseSensitive === true;
67         leafAttr = this.leafAttr || 'leaf';
68
69     if(Ext.isString(sortType)){
70         sortType = Ext.data.SortTypes[sortType];
71     }
72     this.sortFn = function(n1, n2){
73         var attr1 = n1.attributes,
74             attr2 = n2.attributes;
75             
76         if(folderSort){
77             if(attr1[leafAttr] && !attr2[leafAttr]){
78                 return 1;
79             }
80             if(!attr1[leafAttr] && attr2[leafAttr]){
81                 return -1;
82             }
83         }
84         var prop1 = attr1[prop],
85             prop2 = attr2[prop],
86             v1 = sortType ? sortType(prop1) : (caseSensitive ? prop1 : prop1.toUpperCase());
87             v2 = sortType ? sortType(prop2) : (caseSensitive ? prop2 : prop2.toUpperCase());
88             
89         if(v1 < v2){
90             return desc ? 1 : -1;
91         }else if(v1 > v2){
92             return desc ? -1 : 1;
93         }
94         return 0;
95     };
96     },
97     
98     doSort : function(node){
99         node.sort(this.sortFn);
100     },
101
102     updateSort : function(tree, node){
103         if(node.childrenRendered){
104             this.doSort.defer(1, this, [node]);
105         }
106     },
107
108     updateSortParent : function(node){
109         var p = node.parentNode;
110         if(p && p.childrenRendered){
111             this.doSort.defer(1, this, [p]);
112         }
113     }    
114 });