sort.js revision 2b9aa50d4077b548fa76a5d5330265ab397caad3
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith/**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithAdds support for sorting the table data by API methods `table.sort(...)` or
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith`table.toggleSort(...)` or by clicking on column headers in the rendered UI.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithSorting by the API is enabled automatically when this module is `use()`d. To
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithenable UI triggered sorting, set the DataTable's `sortable` attribute to
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith`true`.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith<pre><code>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithvar table = new Y.DataTable({
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith columns: [ 'id', 'username', 'name', 'birthdate' ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith data: [ ... ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith sortable: true
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith});
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithtable.render('#table');
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith</code></pre>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithSetting `sortable` to `true` will enable UI sorting for all columns. To enable
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithUI sorting for certain columns only, set `sortable` to an array of column keys,
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithor just add `sortable: true` to the respective column configuration objects.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithThis uses the default setting of `sortable: auto` for the DataTable instance.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith<pre><code>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithvar table = new Y.DataTable({
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith columns: [
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith 'id',
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith { key: 'username', sortable: true },
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith { key: 'name', sortable: true },
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith { key: 'birthdate', sortable: true }
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith data: [ ... ]
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith // sortable: 'auto' is the default
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith});
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith// OR
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithvar table = new Y.DataTable({
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith columns: [ 'id', 'username', 'name', 'birthdate' ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith data: [ ... ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith sortable: [ 'username', 'name', 'birthdate' ]
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith});
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith</code></pre>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithTo disable UI sorting for all columns, set `sortable` to `false`. This still
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithpermits sorting via the API methods.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithAs new records are inserted into the table's `data` ModelList, they will be inserted at the correct index to preserve the sort order.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithThe current sort order is stored in the `sortBy` attribute. Assigning this value at instantiation will automatically sort your data.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithSorting is done by a simple value comparison using &lt; and &gt; on the field
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithvalue. If you need custom sorting, add a sort function in the column's
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith`sortFn` property. Columns whose content is generated by formatters, but don't
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithrelate to a single `key`, require a `sortFn` to be sortable.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith<pre><code>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithfunction nameSort(a, b) {
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith var aa = a.get('lastName'),
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith bb = a.get('lastName');
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith if (aa === bb) {
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith aa = a.get('firstName');
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith bb = b.get('firstName');
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith }
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith return (aa > bb) ? 1 : (aa < bb) ? -1 : 0;
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smithvar table = new Y.DataTable({
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith columns: [ 'id', 'username', { key: name, sortFn: nameSort }, 'birthdate' ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith data: [ ... ],
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith sortable: [ 'username', 'name', 'birthdate' ]
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith});
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith</code></pre>
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke SmithSee the user guide for more details.
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith@module datatable-sort
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith@class DataTable.Sortable
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith@for DataTable
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith**/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smithvar YLang = Y.Lang,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith isBoolean = YLang.isBoolean,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith isString = YLang.isString,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith isArray = YLang.isArray,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith isObject = YLang.isObject,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith toArray = Y.Array,
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith sub = YLang.sub,
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith dirMap = {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith asc : 1,
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith desc: -1,
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith "1" : 1,
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith "-1": -1
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith };
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smithfunction Sortable() {}
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithSortable.ATTRS = {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith // Which columns in the UI should suggest and respond to sorting interaction
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith // pass an empty array if no UI columns should show sortable, but you want the
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith // table.sort(...) API
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith /**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Controls which column headers can trigger sorting by user clicks.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Acceptable values are:
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * "auto" - (default) looks for `sortable: true` in the column configurations
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `true` - all columns are enabled
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `false - no UI sortable is enabled
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * {String[]} - array of key names to give sortable headers
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @attribute sortable
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @type {String|String[]|Boolean}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @default "auto"
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sortable: {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith value: 'auto',
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith validator: '_validateSortable'
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith /**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith The current sort configuration to maintain in the data.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Accepts column `key` strings or objects with a single property, the column
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith `key`, with a value of 1, -1, "asc", or "desc". E.g. `{ username: 'asc'
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith }`. String values are assumed to be ascending.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Example values would be:
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `"username"` - sort by the data's `username` field or the `key`
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith associated to a column with that `name`.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `{ username: "desc" }` - sort by `username` in descending order.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Alternately, use values "asc", 1 (same as "asc"), or -1 (same as "desc").
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `["lastName", "firstName"]` - ascending sort by `lastName`, but for
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith records with the same `lastName`, ascending subsort by `firstName`.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Array can have as many items as you want.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `[{ lastName: -1 }, "firstName"]` - descending sort by `lastName`,
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith ascending subsort by `firstName`. Mixed types are ok.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @attribute sortBy
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @type {String|String[]|Object|Object[]}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith **/
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith sortBy: {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith validator: '_validateSortBy',
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith getter: '_getSortBy'
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith /**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Strings containing language for sorting tooltips.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @attribute strings
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @type {Object}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @default (strings for current lang configured in the YUI instance config)
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith **/
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith strings: {}
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith};
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithY.mix(Sortable.prototype, {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith /**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Sort the data in the `data` ModelList and refresh the table with the new
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith order.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Acceptable values for `fields` are `key` strings or objects with a single
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith property, the column `key`, with a value of 1, -1, "asc", or "desc". E.g.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith `{ username: 'asc' }`. String values are assumed to be ascending.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Example values would be:
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `"username"` - sort by the data's `username` field or the `key`
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith associated to a column with that `name`.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `{ username: "desc" }` - sort by `username` in descending order.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Alternately, use values "asc", 1 (same as "asc"), or -1 (same as "desc").
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `["lastName", "firstName"]` - ascending sort by `lastName`, but for
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith records with the same `lastName`, ascending subsort by `firstName`.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Array can have as many items as you want.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith * `[{ lastName: -1 }, "firstName"]` - descending sort by `lastName`,
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith ascending subsort by `firstName`. Mixed types are ok.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @method sort
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @param {String|String[]|Object|Object[]} fields The field(s) to sort by
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {Object} [payload] Extra `sort` event payload you want to send along
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @return {DataTable}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @chainable
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sort: function (fields, payload) {
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith return this.fire('sort', Y.merge((payload || {}), {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy: fields || this.get('sortBy')
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith /**
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith Template for the node that will wrap the header content for sortable
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith columns.
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith @property SORTABLE_HEADER_TEMPLATE
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith @type {HTML}
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith @value '<div class="{className}" tabindex="0"><span class="{indicatorClass}"></span></div>'
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith **/
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith SORTABLE_HEADER_TEMPLATE: '<div class="{className}" tabindex="0"><span class="{indicatorClass}"></span></div>',
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith /**
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith Reverse the current sort direction of one or more fields currently being
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith sorted by.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Pass the `key` of the column or columns you want the sort order reversed
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith for.
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @method toggleSort
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @param {String|String[]} fields The field(s) to reverse sort order for
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {Object} [payload] Extra `sort` event payload you want to send along
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @return {DataTable}
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith @chainable
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith toggleSort: function (columns, payload) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith var current = this._sortBy,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy = [],
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith i, len, j, col, index;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // To avoid updating column configs or sortBy directly
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = current.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col = {};
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col[current[i]._id] = current[i].sortDir;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy.push(col);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (columns) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith columns = toArray(columns);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith for (i = 0, len = columns.length; i < len; ++i) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith col = columns[i];
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith index = -1;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith for (j = sortBy.length - 1; i >= 0; --i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (sortBy[j][col]) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy[j][col] *= -1;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith break;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith } else {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith for (i = 0, len = sortBy.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (col in sortBy[i]) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (sortBy[i].hasOwnProperty(col)) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy[i][col] *= -1;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith break;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
59c94cbcd6e39e484a57bf3665a8ab98beafc57eLuke Smith return this.fire('sort', Y.merge((payload || {}), {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith sortBy: sortBy
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith //--------------------------------------------------------------------------
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // Protected properties and methods
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith //--------------------------------------------------------------------------
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith /**
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith Sorts the `data` ModelList based on the new `sortBy` configuration.
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @method _afterSortByChange
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @param {EventFacade} e The `sortByChange` event
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @protected
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith **/
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith _afterSortByChange: function (e) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith // Can't use a setter because it's a chicken and egg problem. The
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith // columns need to be set up to translate, but columns are initialized
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith // from Core's initializer. So construction-time assignment would
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith // fail.
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith this._setSortBy();
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith // Don't sort unless sortBy has been set
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith if (this._sortBy.length) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith if (!this.data.comparator) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith this.data.comparator = this._sortComparator;
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith }
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith this.data.sort();
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith }
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith },
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Applies the sorting logic to the new ModelList if the `newVal` is a new
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith ModelList.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @method _afterSortDataChange
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {EventFacade} e the `dataChange` event
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith _afterSortDataChange: function (e) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // object values always trigger a change event, but we only want to
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // call _initSortFn if the value passed to the `data` attribute was a
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // new ModelList, not a set of new data as an array, or even the same
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // ModelList.
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (e.prevVal !== e.newVal || e.newVal.hasOwnProperty('_compare')) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._initSortFn();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith Checks if any of the fields in the modified record are fields that are
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith currently being sorted by, and if so, resorts the `data` ModelList.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @method _afterSortRecordChange
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith @param {EventFacade} e The Model's `change` event
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith _afterSortRecordChange: function (e) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith var i, len;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith for (i = 0, len = this._sortBy.length; i < len; ++i) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith if (e.changed[this._sortBy[i].key]) {
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith this.data.sort();
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith break;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Subscribes to state changes that warrant updating the UI, and adds the
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith click handler for triggering the sort operation from the UI.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _bindSortUI
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith _bindSortUI: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this.after(['sortableChange', 'sortByChange', 'columnsChange'],
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith Y.bind('_uiSetSortable', this));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (this._theadNode) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith this._sortHandle = this.delegate(['click','keypress'],
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith Y.rbind('_onUITriggerSort', this),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith '.' + this.getClassName('sortable', 'column'));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Sets the `sortBy` attribute from the `sort` event's `e.sortBy` value.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _defSortFn
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {EventFacade} e The `sort` event
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _defSortFn: function (e) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this.set.apply(this, ['sortBy', e.sortBy].concat(e.details));
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Removes the click subscription from the header for sorting.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method destructor
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith destructor: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (this._sortHandle) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this._sortHandle.detach();
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Getter for the `sortBy` attribute.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Supports the special subattribute "sortBy.state" to get a normalized JSON
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith version of the current sort state. Otherwise, returns the last assigned
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith value.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith For example:
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith <pre><code>var table = new Y.DataTable({
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith columns: [ ... ],
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith data: [ ... ],
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith sortBy: 'username'
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith });
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith table.get('sortBy'); // 'username'
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith table.get('sortBy.state'); // { key: 'username', dir: 1 }
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith table.sort(['lastName', { firstName: "desc" }]);
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith table.get('sortBy'); // ['lastName', { firstName: "desc" }]
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith table.get('sortBy.state'); // [{ key: "lastName", dir: 1 }, { key: "firstName", dir: -1 }]
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith </code></pre>
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith @method _getSortBy
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith @param {String|String[]|Object|Object[]} val The current sortBy value
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith @param {String} detail String passed to `get(HERE)`. to parse subattributes
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith _getSortBy: function (val, detail) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith var state, i, len, col;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // "sortBy." is 7 characters. Used to catch
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith detail = detail.slice(7);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // TODO: table.get('sortBy.asObject')? table.get('sortBy.json')?
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (detail === 'state') {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith state = [];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = this._sortBy.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col = this._sortBy[i];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith state.push({
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column: col._id,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith dir: col.sortDir
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith });
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // TODO: Always return an array?
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return { state: (state.length === 1) ? state[0] : state };
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith } else {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return val;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Sets up the initial sort state and instance properties. Publishes events
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith and subscribes to attribute change events to maintain internal state.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method initializer
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith initializer: function () {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith var boundParseSortable = Y.bind('_parseSortable', this);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._parseSortable();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this._setSortBy();
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._initSortFn();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith this._initSortStrings();
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.after({
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith renderHeader : Y.bind('_renderSortable', this),
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith dataChange : Y.bind('_afterSortDataChange', this),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortByChange : Y.bind('_afterSortByChange', this),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sortableChange: boundParseSortable,
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith columnsChange : boundParseSortable,
771b101c1b151cb6c431aceafc4c95cdd8d2a4e1Luke Smith "*:change" : Y.bind('_afterSortRecordChange', this)
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith });
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.publish('sort', {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith defaultFn: Y.bind('_defSortFn', this)
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith });
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Creates a `_compare` function for the `data` ModelList to allow custom
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith sorting by multiple fields.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _initSortFn
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _initSortFn: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith var self = this;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // TODO: This should be a ModelList extension.
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // FIXME: Modifying a component of the host seems a little smelly
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // FIXME: Declaring inline override to leverage closure vs
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // compiling a new function for each column/sortable change or
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // binding the _compare implementation to this, resulting in an
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // extra function hop during sorting. Lesser of three evils?
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.data._compare = function (a, b) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith var cmp = 0,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith i, len, col, dir, aa, bb;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = self._sortBy.length; !cmp && i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col = self._sortBy[i];
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith dir = col.sortDir;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (col.sortFn) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith cmp = col.sortFn(a, b) * dir;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith } else {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // FIXME? Requires columns without sortFns to have key
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith aa = a.get(col.key);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith bb = b.get(col.key);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith cmp = (aa > bb) ? dir : ((aa < bb) ? -dir : 0);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith return cmp;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith };
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith if (this._sortBy.length) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.data.comparator = this._sortComparator;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // TODO: is this necessary? Should it be elsewhere?
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.data.sort();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith } else {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // Leave the _compare method in place to avoid having to set it
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // up again. Mistake?
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith delete this.data.comparator;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith /**
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith Add the sort related strings to the `strings` map.
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith @method _initSortStrings
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith @protected
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith **/
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith _initSortStrings: function () {
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith // Not a valueFn because other class extensions will want to add to it
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith this.set('strings', Y.mix((this.get('strings') || {}),
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith Y.Intl.get('datatable-sort')));
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith },
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Fires the `sort` event in response to user clicks on sortable column
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith headers.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _onUITriggerSort
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {DOMEventFacade} e The `click` event
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _onUITriggerSort: function (e) {
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith var id = e.currentTarget.getAttribute('data-yui3-col-id'),
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy = e.shiftKey ? this.get('sortBy') : [{}],
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith column = id && this.getColumn(id),
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith i, len;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (e.type === 'keydown' && e.keyCode !== 32) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith return;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith // In case a headerTemplate injected a link
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith // TODO: Is this overreaching?
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith e.preventDefault();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith if (column) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (e.shiftKey) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith for (i = 0, len = sortBy.length; i < len; ++i) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (id === sortBy[i] || Math.abs(sortBy[i][id] === 1)) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (!isObject(sortBy[i])) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy[i] = {};
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy[i][id] = -(column.sortDir|0) || 1;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith break;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (i >= len) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy.push(column._id);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith } else {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy[0][id] = -(column.sortDir|0) || 1;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith this.fire('sort', {
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith originEvent: e,
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortBy: sortBy
8a6a44314c3b8b5125191793d3f3e0baa8d31b7cLuke Smith });
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Normalizes the possible input values for the `sortable` attribute, storing
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith the results in the `_sortable` property.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _parseSortable
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _parseSortable: function () {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith var sortable = this.get('sortable'),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith columns = [],
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith i, len, col;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (isArray(sortable)) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith for (i = 0, len = sortable.length; i < len; ++i) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith col = sortable[i];
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // isArray is called because arrays are objects, but will rely
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // on getColumn to nullify them for the subsequent if (col)
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (!isObject(col, true) || isArray(col)) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith col = this.getColumn(col);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (col) {
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith columns.push(col);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith } else if (sortable) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith columns = this._displayColumns.slice();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (sortable === 'auto') {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith for (i = columns.length - 1; i >= 0; --i) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (!columns[i].sortable) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith columns.splice(i, 1);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this._sortable = columns;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Initial application of the sortable UI.
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _renderSortable
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _renderSortable: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this._uiSetSortable();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._bindSortUI();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Parses the current `sortBy` attribute into a normalized structure for the
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith `data` ModelList's `_compare` method. Also updates the column
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith configurations' `sortDir` properties.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _setSortBy
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith _setSortBy: function () {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith var columns = this._displayColumns,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy = this.get('sortBy') || [],
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortedClass = ' ' + this.getClassName('sorted'),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith i, len, name, dir, field, column;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this._sortBy = [];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Purge current sort state from column configs
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = columns.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column = columns[i];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith delete column.sortDir;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (column.className) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // TODO: be more thorough
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column.className = column.className.replace(sortedClass, '');
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy = toArray(sortBy);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = sortBy.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith name = sortBy[i];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith dir = 1;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (isObject(name)) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith field = name;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Have to use a for-in loop to process sort({ foo: -1 })
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (name in field) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (field.hasOwnProperty(name)) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith dir = dirMap[field[name]];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith break;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (name) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Allow sorting of any model field and any column
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // FIXME: this isn't limited to model attributes, but there's no
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // convenient way to get a list of the attributes for a Model
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // subclass *including* the attributes of its superclasses.
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column = this.getColumn(name) || { _id: name, key: name };
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (column) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column.sortDir = dir;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (!column.className) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column.className = '';
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column.className += sortedClass;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this._sortBy.push(column);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Array of column configuration objects of those columns that need UI setup
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith for user interaction.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @property _sortable
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @type {Object[]}
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith //_sortable: null,
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Array of column configuration objects for those columns that are currently
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith being used to sort the data. Fake column objects are used for fields that
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith are not rendered as columns.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @property _sortBy
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @type {Object[]}
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith //_sortBy: null,
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Replacement `comparator` for the `data` ModelList that defers sorting logic
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith to the `_compare` method. The deferral is accomplished by returning `this`.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _sortComparator
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {Model} item The record being evaluated for sort position
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @return {Model} The record
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith _sortComparator: function (item) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // Defer sorting to ModelList's _compare
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return item;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Applies the appropriate classes to the `boundingBox` and column headers to
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith indicate sort state and sortability.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Also currently wraps the header content of sortable columns in a `<div>`
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith liner to give a CSS anchor for sort indicators.
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
55e462437cab83f4f545bfd864f3296cd2a0e806Luke Smith @method _uiSetSortable
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _uiSetSortable: function () {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith var columns = this._sortable || [],
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortableClass = this.getClassName('sortable', 'column'),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith ascClass = this.getClassName('sorted'),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith descClass = this.getClassName('sorted', 'desc'),
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith linerClass = this.getClassName('sort', 'liner'),
7a40ce4f121af8aa648db1d17f5b09be0b55df4bLuke Smith indicatorClass= this.getClassName('sort', 'indicator'),
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith sortableCols = {},
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith i, len, col, node, liner, title, desc;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.get('boundingBox').toggleClass(
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.getClassName('sortable'),
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith columns.length);
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith for (i = 0, len = columns.length; i < len; ++i) {
b2c3f7ee9595487fa2c245134423177b4421db5dLuke Smith sortableCols[columns[i].id] = columns[i];
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // TODO: this.head.render() + decorate cells?
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith this._theadNode.all('.' + sortableClass).each(function (node) {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith var col = sortableCols[node.get('id')],
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith liner = node.one('.' + linerClass),
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith indicator;
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (col) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (!col.sortDir) {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith node.removeClass(ascClass)
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith .removeClass(descClass);
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith } else {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith node.removeClass(sortableClass)
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith .removeClass(ascClass)
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith .removeClass(descClass);
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith if (liner) {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith liner.replace(liner.get('childNodes').toFrag());
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith }
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith indicator = node.one('.' + indicatorClass);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith if (indicator) {
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith indicator.remove().destroy(true);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith }
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith });
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = columns.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col = columns[i];
b2c3f7ee9595487fa2c245134423177b4421db5dLuke Smith node = this._theadNode.one('#' + col.id);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith desc = col.sortDir === -1;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (node) {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith liner = node.one('.' + linerClass);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith node.addClass(sortableClass);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (col.sortDir) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith node.addClass(ascClass);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith node.toggleClass(descClass, desc);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith node.setAttribute('aria-sort', desc ?
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith 'descending' : 'ascending');
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith if (!liner) {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith liner = Y.Node.create(Y.Lang.sub(
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith this.SORTABLE_HEADER_TEMPLATE, {
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith className: linerClass,
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith indicatorClass: indicatorClass
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith }));
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith liner.prepend(node.get('childNodes').toFrag());
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith node.append(liner);
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith }
2b9aa50d4077b548fa76a5d5330265ab397caad3Luke Smith
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith title = sub(this.getString(
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith (col.sortDir === 1) ? 'reverseSortBy' : 'sortBy'), {
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith column: col.abbr || col.label ||
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith col.key || ('column ' + i)
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith });
6fe31db087e6c93b1df3a96b888b55344e039a23Luke Smith
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith node.setAttribute('title', title);
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith // To combat VoiceOver from reading the sort title as the
7517febf3436a32039d125a66566b1c7be2f6b26Luke Smith // column header
b2c3f7ee9595487fa2c245134423177b4421db5dLuke Smith node.setAttribute('aria-labelledby', col.id);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Allows values `true`, `false`, "auto", or arrays of column names through.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _validateSortable
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {Any} val The input value to `set("sortable", VAL)`
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @return {Boolean}
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith _validateSortable: function (val) {
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith return val === 'auto' || isBoolean(val) || isArray(val);
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith },
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith /**
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith Allows strings, arrays of strings, objects, or arrays of objects.
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @method _validateSortBy
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @param {String|String[]|Object|Object[]} val The new `sortBy` value
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @return {Boolean}
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith @protected
f5443cec5378e1eba162c289f05b690b699c9c7bLuke Smith **/
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith _validateSortBy: function (val) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return val === null ||
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith isString(val) ||
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith isObject(val, true) ||
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith (isArray(val) && (isString(val[0]) || isObject(val, true)));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith}, true);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithY.DataTable.Sortable = Sortable;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithY.Base.mix(Y.DataTable, [Sortable]);