Search code examples
javascriptextjsextjs4

ExtJS 4 Grid custom columns sorting (file manager style)


I was about to make a basic file manager using ExtJS 4. The problem I faced now is: how to make custom sorting for grid panel when clicking the columns.

Imagine we have store fields:

[
    { name: "is_dir", type: "boolean" },
    { name: "name",   type: "string"  },
    { name: "size",   type: "int"     }
]

And the data which comes from an array:

[
    { is_dir: true,  name: "..",        size: 0    },
    { is_dir: false, name: "file2.txt", size: 512  },
    { is_dir: true,  name: "folder2",   size: 0    },
    { is_dir: false, name: "file3.txt", size: 1024 },
    { is_dir: true,  name: "folder1",   size: 0    },
    { is_dir: true,  name: "file1.txt", size: 1024 },
    // ...
]

The idea is to make sorting like in any file manager (e.g. Total Commander, MC, FAR, etc) so, that:

  • the item with name ".." is always placed at the top
  • dirs go after ".." (if exists) in sorted order
  • files go after dirs (if exist) in sorted order

For example, the output with sorting by name and by size should be:

^ Name           | Size               Name             | ^ Size
-----------------------               -------------------------
..               | 0                  ..               | 0
folder1          | 0                  folder1          | 0
folder2          | 0                  folder2          | 0
file1.txt        | 1024               file2.txt        | 512
file2.txt        | 512                file1.txt        | 1024
file3.txt        | 1024               file3.txt        | 1024

I've tried to write custom sorterFn for store sorters property, however it didn't help. I believe there should be some easy solution for that.


Solution

  • I have forked @Alexey's answer with short sorting algorithm. Additionally, I fixed the problem with double sorting (because of this.callParent(arguments); which runs the basic sorting from the parent method). Here is the solution that works perfectly for me:

    sort: function(sorters) {
        sorters = sorters || { property: "name", direction: "ASC" };
        var mod = sorters.direction.toUpperCase() === "DESC" ? -1 : 1;
    
        this.sorters.clear();        // these lines are needed
        this.sorters.add(sorters);   // to update the column state
    
        this.doSort(function(a, b) {
            var a_type = a.get("is_dir"),
                b_type = b.get("is_dir"),
                a_name = a.get("name"),
                b_name = b.get("name");
    
            if (a_name === "..") return -1;
            if (a_type === b_type) {
                var a_prop = a.get(sorters.property),
                    b_prop = b.get(sorters.property);
    
                if (a_prop === b_name) {
                    return (a_name < b_name ? -1 : 1) * mod;
                } else {
                    return (a_prop < b_prop ? -1 : 1) * mod;
                }
            } else {
                return b_type - a_type;
            }
        });
    }
    

    DEMO: http://jsfiddle.net/cvdNW/186/