sort.js revision f5df3320c255ef9e7c007469613dc31b4f91a3d8
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith/**
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithAdds support for column sort.
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith@module datatable-sort
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
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith toArray = Y.Array,
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
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sortable: {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith value: 'auto',
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith validator: '_validateSortable'
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Last sort params
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith sortBy: {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith validator: '_validateSortBy',
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith getter: '_getSortBy'
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith strings: {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith valueFn: function () {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return Y.Intl.get('datatable-sort');
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith};
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke SmithY.mix(Sortable.prototype, {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sort: function (fields, payload) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.fire('sort', Y.merge((payload || {}), {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy: fields || this.get('sortBy')
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this.fire('sort', Y.merge((payload || {}), {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith sortBy: sortBy
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith //----------------------------------------------------------------------------
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // Protected properties and methods
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith //----------------------------------------------------------------------------
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _afterDataChange: 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
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith _afterSortByChange: function (e) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Can't use a setter because it's a chicken and egg problem. The columns
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // need to be set up to translate, but columns are initialized from
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Core's initializer. So construction-time assignment would fail.
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this._setSortBy();
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Don't sort unless sortBy has been set
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (this._sortBy.length) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (!this.data.comparator) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this.data.comparator = this._sortComparator;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this.data.sort();
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith _bindSortUI: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this.after(['sortableChange', 'sortByChange', 'columnsChange'],
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._uiSetSortable);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith if (this._theadNode) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._sortHandle = this._theadNode.delegate('click',
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith Y.rbind('_onUITriggerSort', this),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith '.' + this.getClassName('sortable', 'column'));
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _defSortFn: function (e) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this.set.apply(this, ['sortBy', e.sortBy].concat(e.details));
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith destructor: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (this._sortHandle) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this._sortHandle.detach();
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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
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
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.after({
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith renderHeader : Y.bind('_renderSortable', this),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith dataChange : Y.bind('_afterDataChange', this),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortByChange : Y.bind('_afterSortByChange', this),
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith sortableChange: boundParseSortable,
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith columnsChange : boundParseSortable
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith });
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.publish('sort', {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith defaultFn: Y.bind('_defSortFn', this)
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith });
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (this.get('sortable') && 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
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _onUITriggerSort: function (e) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith var id = e.currentTarget.get('id'),
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith config = {},
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith dir = 1,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith e.preventDefault();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // TODO: if (e.ctrlKey) { /* subsort */ }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (id) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith Y.Array.each(this._displayColumns, function (col) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith if (id === col._yuid) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith column = col._id;
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // Flip current sortDir or default to 1 (asc)
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith dir = -(col.sortDir|0) || 1;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith }
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith });
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (column) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith config[column] = dir;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this.fire('sort', {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith originEvent: e,
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith sortBy: [config]
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith });
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith }
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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) {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith columns.push(col._yuid);
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
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _renderSortable: function () {
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith this._uiSetSortable();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this._bindSortUI();
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith _sortComparator: function (item) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith // Defer sorting to ModelList's _compare
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith return item;
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith _validateSortable: function (val) {
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith return val === 'auto' || isBoolean(val) || isArray(val);
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith },
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke 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'),
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith linerClass = this.getClassName('sort', 'liner'),
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith i, len, col, node, content;
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.get('boundingBox').toggleClass(
4eafc0c9b36f7e8efc8808ab27dbed7ff8dc87abLuke Smith this.getClassName('sortable'),
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith columns.length);
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith // TODO: this.head.render() + decorate cells?
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith this._theadNode.all('.' + sortableClass)
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith .removeClass(sortableClass)
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith .removeClass(ascClass)
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith .removeClass(descClass)
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith .each(function (th) {
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith var liner = th.one('.' + linerClass);
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith if (liner) {
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith liner.replace(liner.get('childNodes').toFrag());
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith }
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith });
8fff801a4a38e13d6ff8181ff097fb01d058d617Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith for (i = 0, len = columns.length; i < len; ++i) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith col = columns[i];
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith node = this._theadNode.one('#' + col._yuid);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (node) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith node.addClass(sortableClass);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (col.sortDir) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith node.addClass(ascClass);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith if (col.sortDir === -1) {
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith node.addClass(descClass);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith Y.Node.create('<div class="' + linerClass + '"></div>')
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith .append(node.get('childNodes').toFrag())
f5df3320c255ef9e7c007469613dc31b4f91a3d8Luke Smith .appendTo(node);
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith }
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke Smith },
32624ce45f113c04dfa5469b3cc77df42c4c46f4Luke 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]);