happstack-yui-7373.5.2: bundle/datatable-sort/datatable-sort-coverage.js
/*
YUI 3.7.3 (build 5687)
Copyright 2012 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
http://yuilibrary.com/license/
*/
if (typeof _yuitest_coverage == "undefined"){
_yuitest_coverage = {};
_yuitest_coverline = function(src, line){
var coverage = _yuitest_coverage[src];
if (!coverage.lines[line]){
coverage.calledLines++;
}
coverage.lines[line]++;
};
_yuitest_coverfunc = function(src, name, line){
var coverage = _yuitest_coverage[src],
funcId = name + ":" + line;
if (!coverage.functions[funcId]){
coverage.calledFunctions++;
}
coverage.functions[funcId]++;
};
}
_yuitest_coverage["build/datatable-sort/datatable-sort.js"] = {
lines: {},
functions: {},
coveredLines: 0,
calledLines: 0,
coveredFunctions: 0,
calledFunctions: 0,
path: "build/datatable-sort/datatable-sort.js",
code: []
};
_yuitest_coverage["build/datatable-sort/datatable-sort.js"].code=["YUI.add('datatable-sort', function (Y, NAME) {","","/**","Adds support for sorting the table data by API methods `table.sort(...)` or","`table.toggleSort(...)` or by clicking on column headers in the rendered UI.","","@module datatable","@submodule datatable-sort","@since 3.5.0","**/","var YLang = Y.Lang,"," isBoolean = YLang.isBoolean,"," isString = YLang.isString,"," isArray = YLang.isArray,"," isObject = YLang.isObject,",""," toArray = Y.Array,"," sub = YLang.sub,",""," dirMap = {"," asc : 1,"," desc: -1,"," \"1\" : 1,"," \"-1\": -1"," };","","","/**","_API docs for this extension are included in the DataTable class._","","This DataTable class extension adds support for sorting the table data by API","methods `table.sort(...)` or `table.toggleSort(...)` or by clicking on column","headers in the rendered UI.","","Sorting by the API is enabled automatically when this module is `use()`d. To","enable UI triggered sorting, set the DataTable's `sortable` attribute to","`true`.","","<pre><code>","var table = new Y.DataTable({"," columns: [ 'id', 'username', 'name', 'birthdate' ],"," data: [ ... ],"," sortable: true","});","","table.render('#table');","</code></pre>","","Setting `sortable` to `true` will enable UI sorting for all columns. To enable","UI sorting for certain columns only, set `sortable` to an array of column keys,","or just add `sortable: true` to the respective column configuration objects.","This uses the default setting of `sortable: auto` for the DataTable instance.","","<pre><code>","var table = new Y.DataTable({"," columns: ["," 'id',"," { key: 'username', sortable: true },"," { key: 'name', sortable: true },"," { key: 'birthdate', sortable: true }"," ],"," data: [ ... ]"," // sortable: 'auto' is the default","});","","// OR","var table = new Y.DataTable({"," columns: [ 'id', 'username', 'name', 'birthdate' ],"," data: [ ... ],"," sortable: [ 'username', 'name', 'birthdate' ]","});","</code></pre>","","To disable UI sorting for all columns, set `sortable` to `false`. This still","permits sorting via the API methods.","","As new records are inserted into the table's `data` ModelList, they will be inserted at the correct index to preserve the sort order.","","The current sort order is stored in the `sortBy` attribute. Assigning this value at instantiation will automatically sort your data.","","Sorting is done by a simple value comparison using < and > on the field","value. If you need custom sorting, add a sort function in the column's","`sortFn` property. Columns whose content is generated by formatters, but don't","relate to a single `key`, require a `sortFn` to be sortable.","","<pre><code>","function nameSort(a, b, desc) {"," var aa = a.get('lastName') + a.get('firstName'),"," bb = a.get('lastName') + b.get('firstName'),"," order = (aa > bb) ? 1 : -(aa < bb);"," "," return desc ? -order : order;","}","","var table = new Y.DataTable({"," columns: [ 'id', 'username', { key: name, sortFn: nameSort }, 'birthdate' ],"," data: [ ... ],"," sortable: [ 'username', 'name', 'birthdate' ]","});","</code></pre>","","See the user guide for more details.","","@class DataTable.Sortable","@for DataTable","@since 3.5.0","**/","function Sortable() {}","","Sortable.ATTRS = {"," // Which columns in the UI should suggest and respond to sorting interaction"," // pass an empty array if no UI columns should show sortable, but you want the"," // table.sort(...) API"," /**"," Controls which column headers can trigger sorting by user clicks.",""," Acceptable values are:",""," * \"auto\" - (default) looks for `sortable: true` in the column configurations"," * `true` - all columns are enabled"," * `false - no UI sortable is enabled"," * {String[]} - array of key names to give sortable headers",""," @attribute sortable"," @type {String|String[]|Boolean}"," @default \"auto\""," @since 3.5.0"," **/"," sortable: {"," value: 'auto',"," validator: '_validateSortable'"," },",""," /**"," The current sort configuration to maintain in the data.",""," Accepts column `key` strings or objects with a single property, the column"," `key`, with a value of 1, -1, \"asc\", or \"desc\". E.g. `{ username: 'asc'"," }`. String values are assumed to be ascending.",""," Example values would be:",""," * `\"username\"` - sort by the data's `username` field or the `key`"," associated to a column with that `name`."," * `{ username: \"desc\" }` - sort by `username` in descending order."," Alternately, use values \"asc\", 1 (same as \"asc\"), or -1 (same as \"desc\")."," * `[\"lastName\", \"firstName\"]` - ascending sort by `lastName`, but for"," records with the same `lastName`, ascending subsort by `firstName`."," Array can have as many items as you want."," * `[{ lastName: -1 }, \"firstName\"]` - descending sort by `lastName`,"," ascending subsort by `firstName`. Mixed types are ok.",""," @attribute sortBy"," @type {String|String[]|Object|Object[]}"," @since 3.5.0"," **/"," sortBy: {"," validator: '_validateSortBy',"," getter: '_getSortBy'"," },",""," /**"," Strings containing language for sorting tooltips.",""," @attribute strings"," @type {Object}"," @default (strings for current lang configured in the YUI instance config)"," @since 3.5.0"," **/"," strings: {}","};","","Y.mix(Sortable.prototype, {",""," /**"," Sort the data in the `data` ModelList and refresh the table with the new"," order.",""," Acceptable values for `fields` are `key` strings or objects with a single"," property, the column `key`, with a value of 1, -1, \"asc\", or \"desc\". E.g."," `{ username: 'asc' }`. String values are assumed to be ascending.",""," Example values would be:",""," * `\"username\"` - sort by the data's `username` field or the `key`"," associated to a column with that `name`."," * `{ username: \"desc\" }` - sort by `username` in descending order."," Alternately, use values \"asc\", 1 (same as \"asc\"), or -1 (same as \"desc\")."," * `[\"lastName\", \"firstName\"]` - ascending sort by `lastName`, but for"," records with the same `lastName`, ascending subsort by `firstName`."," Array can have as many items as you want."," * `[{ lastName: -1 }, \"firstName\"]` - descending sort by `lastName`,"," ascending subsort by `firstName`. Mixed types are ok.",""," @method sort"," @param {String|String[]|Object|Object[]} fields The field(s) to sort by"," @param {Object} [payload] Extra `sort` event payload you want to send along"," @return {DataTable}"," @chainable"," @since 3.5.0"," **/"," sort: function (fields, payload) {"," /**"," Notifies of an impending sort, either from clicking on a column"," header, or from a call to the `sort` or `toggleSort` method.",""," The requested sort is available in the `sortBy` property of the event.",""," The default behavior of this event sets the table's `sortBy` attribute.",""," @event sort"," @param {String|String[]|Object|Object[]} sortBy The requested sort"," @preventable _defSortFn"," **/"," return this.fire('sort', Y.merge((payload || {}), {"," sortBy: fields || this.get('sortBy')"," }));"," },",""," /**"," Template for the node that will wrap the header content for sortable"," columns.",""," @property SORTABLE_HEADER_TEMPLATE"," @type {HTML}"," @value '<div class=\"{className}\" tabindex=\"0\"><span class=\"{indicatorClass}\"></span></div>'"," @since 3.5.0"," **/"," SORTABLE_HEADER_TEMPLATE: '<div class=\"{className}\" tabindex=\"0\"><span class=\"{indicatorClass}\"></span></div>',",""," /**"," Reverse the current sort direction of one or more fields currently being"," sorted by.",""," Pass the `key` of the column or columns you want the sort order reversed"," for.",""," @method toggleSort"," @param {String|String[]} fields The field(s) to reverse sort order for"," @param {Object} [payload] Extra `sort` event payload you want to send along"," @return {DataTable}"," @chainable"," @since 3.5.0"," **/"," toggleSort: function (columns, payload) {"," var current = this._sortBy,"," sortBy = [],"," i, len, j, col, index;",""," // To avoid updating column configs or sortBy directly"," for (i = 0, len = current.length; i < len; ++i) {"," col = {};"," col[current[i]._id] = current[i].sortDir;"," sortBy.push(col);"," }",""," if (columns) {"," columns = toArray(columns);",""," for (i = 0, len = columns.length; i < len; ++i) {"," col = columns[i];"," index = -1;",""," for (j = sortBy.length - 1; i >= 0; --i) {"," if (sortBy[j][col]) {"," sortBy[j][col] *= -1;"," break;"," }"," }"," }"," } else {"," for (i = 0, len = sortBy.length; i < len; ++i) {"," for (col in sortBy[i]) {"," if (sortBy[i].hasOwnProperty(col)) {"," sortBy[i][col] *= -1;"," break;"," }"," }"," }"," }",""," return this.fire('sort', Y.merge((payload || {}), {"," sortBy: sortBy"," }));"," },",""," //--------------------------------------------------------------------------"," // Protected properties and methods"," //--------------------------------------------------------------------------"," /**"," Sorts the `data` ModelList based on the new `sortBy` configuration.",""," @method _afterSortByChange"," @param {EventFacade} e The `sortByChange` event"," @protected"," @since 3.5.0"," **/"," _afterSortByChange: function (e) {"," // Can't use a setter because it's a chicken and egg problem. The"," // columns need to be set up to translate, but columns are initialized"," // from Core's initializer. So construction-time assignment would"," // fail."," this._setSortBy();",""," // Don't sort unless sortBy has been set"," if (this._sortBy.length) {"," if (!this.data.comparator) {"," this.data.comparator = this._sortComparator;"," }",""," this.data.sort();"," }"," },",""," /**"," Applies the sorting logic to the new ModelList if the `newVal` is a new"," ModelList.",""," @method _afterSortDataChange"," @param {EventFacade} e the `dataChange` event"," @protected"," @since 3.5.0"," **/"," _afterSortDataChange: function (e) {"," // object values always trigger a change event, but we only want to"," // call _initSortFn if the value passed to the `data` attribute was a"," // new ModelList, not a set of new data as an array, or even the same"," // ModelList."," if (e.prevVal !== e.newVal || e.newVal.hasOwnProperty('_compare')) {"," this._initSortFn();"," }"," },",""," /**"," Checks if any of the fields in the modified record are fields that are"," currently being sorted by, and if so, resorts the `data` ModelList.",""," @method _afterSortRecordChange"," @param {EventFacade} e The Model's `change` event"," @protected"," @since 3.5.0"," **/"," _afterSortRecordChange: function (e) {"," var i, len;",""," for (i = 0, len = this._sortBy.length; i < len; ++i) {"," if (e.changed[this._sortBy[i].key]) {"," this.data.sort();"," break;"," }"," }"," },",""," /**"," Subscribes to state changes that warrant updating the UI, and adds the"," click handler for triggering the sort operation from the UI.",""," @method _bindSortUI"," @protected"," @since 3.5.0"," **/"," _bindSortUI: function () {"," var handles = this._eventHandles;"," "," if (!handles.sortAttrs) {"," handles.sortAttrs = this.after("," ['sortableChange', 'sortByChange', 'columnsChange'],"," Y.bind('_uiSetSortable', this));"," }",""," if (!handles.sortUITrigger && this._theadNode) {"," handles.sortUITrigger = this.delegate(['click','keydown'],"," Y.rbind('_onUITriggerSort', this),"," '.' + this.getClassName('sortable', 'column'));"," }"," },",""," /**"," Sets the `sortBy` attribute from the `sort` event's `e.sortBy` value.",""," @method _defSortFn"," @param {EventFacade} e The `sort` event"," @protected"," @since 3.5.0"," **/"," _defSortFn: function (e) {"," this.set.apply(this, ['sortBy', e.sortBy].concat(e.details));"," },",""," /**"," Getter for the `sortBy` attribute."," "," Supports the special subattribute \"sortBy.state\" to get a normalized JSON"," version of the current sort state. Otherwise, returns the last assigned"," value.",""," For example:",""," <pre><code>var table = new Y.DataTable({"," columns: [ ... ],"," data: [ ... ],"," sortBy: 'username'"," });",""," table.get('sortBy'); // 'username'"," table.get('sortBy.state'); // { key: 'username', dir: 1 }",""," table.sort(['lastName', { firstName: \"desc\" }]);"," table.get('sortBy'); // ['lastName', { firstName: \"desc\" }]"," table.get('sortBy.state'); // [{ key: \"lastName\", dir: 1 }, { key: \"firstName\", dir: -1 }]"," </code></pre>",""," @method _getSortBy"," @param {String|String[]|Object|Object[]} val The current sortBy value"," @param {String} detail String passed to `get(HERE)`. to parse subattributes"," @protected"," @since 3.5.0"," **/"," _getSortBy: function (val, detail) {"," var state, i, len, col;",""," // \"sortBy.\" is 7 characters. Used to catch "," detail = detail.slice(7);",""," // TODO: table.get('sortBy.asObject')? table.get('sortBy.json')?"," if (detail === 'state') {"," state = [];",""," for (i = 0, len = this._sortBy.length; i < len; ++i) {"," col = this._sortBy[i];"," state.push({"," column: col._id,"," dir: col.sortDir"," });"," }",""," // TODO: Always return an array?"," return { state: (state.length === 1) ? state[0] : state };"," } else {"," return val;"," }"," },",""," /**"," Sets up the initial sort state and instance properties. Publishes events"," and subscribes to attribute change events to maintain internal state.",""," @method initializer"," @protected"," @since 3.5.0"," **/"," initializer: function () {"," var boundParseSortable = Y.bind('_parseSortable', this);",""," this._parseSortable();",""," this._setSortBy();",""," this._initSortFn();",""," this._initSortStrings();",""," this.after({"," 'table:renderHeader': Y.bind('_renderSortable', this),"," dataChange : Y.bind('_afterSortDataChange', this),"," sortByChange : Y.bind('_afterSortByChange', this),"," sortableChange : boundParseSortable,"," columnsChange : boundParseSortable"," });"," this.data.after(this.data.model.NAME + \":change\","," Y.bind('_afterSortRecordChange', this));",""," // TODO: this event needs magic, allowing async remote sorting"," this.publish('sort', {"," defaultFn: Y.bind('_defSortFn', this)"," });"," },",""," /**"," Creates a `_compare` function for the `data` ModelList to allow custom"," sorting by multiple fields.",""," @method _initSortFn"," @protected"," @since 3.5.0"," **/"," _initSortFn: function () {"," var self = this;",""," // TODO: This should be a ModelList extension."," // FIXME: Modifying a component of the host seems a little smelly"," // FIXME: Declaring inline override to leverage closure vs"," // compiling a new function for each column/sortable change or"," // binding the _compare implementation to this, resulting in an"," // extra function hop during sorting. Lesser of three evils?"," this.data._compare = function (a, b) {"," var cmp = 0,"," i, len, col, dir, aa, bb;",""," for (i = 0, len = self._sortBy.length; !cmp && i < len; ++i) {"," col = self._sortBy[i];"," dir = col.sortDir;",""," if (col.sortFn) {"," cmp = col.sortFn(a, b, (dir === -1));"," } else {"," // FIXME? Requires columns without sortFns to have key"," aa = a.get(col.key) || '';"," bb = b.get(col.key) || '';",""," cmp = (aa > bb) ? dir : ((aa < bb) ? -dir : 0);"," }"," }",""," return cmp;"," };",""," if (this._sortBy.length) {"," this.data.comparator = this._sortComparator;",""," // TODO: is this necessary? Should it be elsewhere?"," this.data.sort();"," } else {"," // Leave the _compare method in place to avoid having to set it"," // up again. Mistake?"," delete this.data.comparator;"," }"," },",""," /**"," Add the sort related strings to the `strings` map."," "," @method _initSortStrings"," @protected"," @since 3.5.0"," **/"," _initSortStrings: function () {"," // Not a valueFn because other class extensions will want to add to it"," this.set('strings', Y.mix((this.get('strings') || {}), "," Y.Intl.get('datatable-sort')));"," },",""," /**"," Fires the `sort` event in response to user clicks on sortable column"," headers.",""," @method _onUITriggerSort"," @param {DOMEventFacade} e The `click` event"," @protected"," @since 3.5.0"," **/"," _onUITriggerSort: function (e) {"," var id = e.currentTarget.getAttribute('data-yui3-col-id'),"," sortBy = e.shiftKey ? this.get('sortBy') : [{}],"," column = id && this.getColumn(id),"," i, len;",""," if (e.type === 'keydown' && e.keyCode !== 32) {"," return;"," }",""," // In case a headerTemplate injected a link"," // TODO: Is this overreaching?"," e.preventDefault();",""," if (column) {"," if (e.shiftKey) {"," for (i = 0, len = sortBy.length; i < len; ++i) {"," if (id === sortBy[i] || Math.abs(sortBy[i][id] === 1)) {"," if (!isObject(sortBy[i])) {"," sortBy[i] = {};"," }",""," sortBy[i][id] = -(column.sortDir|0) || 1;"," break;"," }"," }",""," if (i >= len) {"," sortBy.push(column._id);"," }"," } else {"," sortBy[0][id] = -(column.sortDir|0) || 1;"," }",""," this.fire('sort', {"," originEvent: e,"," sortBy: sortBy"," });"," }"," },",""," /**"," Normalizes the possible input values for the `sortable` attribute, storing"," the results in the `_sortable` property.",""," @method _parseSortable"," @protected"," @since 3.5.0"," **/"," _parseSortable: function () {"," var sortable = this.get('sortable'),"," columns = [],"," i, len, col;",""," if (isArray(sortable)) {"," for (i = 0, len = sortable.length; i < len; ++i) {"," col = sortable[i];",""," // isArray is called because arrays are objects, but will rely"," // on getColumn to nullify them for the subsequent if (col)"," if (!isObject(col, true) || isArray(col)) {"," col = this.getColumn(col);"," }",""," if (col) {"," columns.push(col);"," }"," }"," } else if (sortable) {"," columns = this._displayColumns.slice();",""," if (sortable === 'auto') {"," for (i = columns.length - 1; i >= 0; --i) {"," if (!columns[i].sortable) {"," columns.splice(i, 1);"," }"," }"," }"," }",""," this._sortable = columns;"," },",""," /**"," Initial application of the sortable UI.",""," @method _renderSortable"," @protected"," @since 3.5.0"," **/"," _renderSortable: function () {"," this._uiSetSortable();",""," this._bindSortUI();"," },",""," /**"," Parses the current `sortBy` attribute into a normalized structure for the"," `data` ModelList's `_compare` method. Also updates the column"," configurations' `sortDir` properties.",""," @method _setSortBy"," @protected"," @since 3.5.0"," **/"," _setSortBy: function () {"," var columns = this._displayColumns,"," sortBy = this.get('sortBy') || [],"," sortedClass = ' ' + this.getClassName('sorted'),"," i, len, name, dir, field, column;",""," this._sortBy = [];",""," // Purge current sort state from column configs"," for (i = 0, len = columns.length; i < len; ++i) {"," column = columns[i];",""," delete column.sortDir;",""," if (column.className) {"," // TODO: be more thorough"," column.className = column.className.replace(sortedClass, '');"," }"," }",""," sortBy = toArray(sortBy);",""," for (i = 0, len = sortBy.length; i < len; ++i) {"," name = sortBy[i];"," dir = 1;",""," if (isObject(name)) {"," field = name;"," // Have to use a for-in loop to process sort({ foo: -1 })"," for (name in field) {"," if (field.hasOwnProperty(name)) {"," dir = dirMap[field[name]];"," break;"," }"," }"," }",""," if (name) {"," // Allow sorting of any model field and any column"," // FIXME: this isn't limited to model attributes, but there's no"," // convenient way to get a list of the attributes for a Model"," // subclass *including* the attributes of its superclasses."," column = this.getColumn(name) || { _id: name, key: name };",""," if (column) {"," column.sortDir = dir;",""," if (!column.className) {"," column.className = '';"," }",""," column.className += sortedClass;",""," this._sortBy.push(column);"," }"," }"," }"," },",""," /**"," Array of column configuration objects of those columns that need UI setup"," for user interaction.",""," @property _sortable"," @type {Object[]}"," @protected"," @since 3.5.0"," **/"," //_sortable: null,",""," /**"," Array of column configuration objects for those columns that are currently"," being used to sort the data. Fake column objects are used for fields that"," are not rendered as columns.",""," @property _sortBy"," @type {Object[]}"," @protected"," @since 3.5.0"," **/"," //_sortBy: null,",""," /**"," Replacement `comparator` for the `data` ModelList that defers sorting logic"," to the `_compare` method. The deferral is accomplished by returning `this`.",""," @method _sortComparator"," @param {Model} item The record being evaluated for sort position"," @return {Model} The record"," @protected"," @since 3.5.0"," **/"," _sortComparator: function (item) {"," // Defer sorting to ModelList's _compare"," return item;"," },",""," /**"," Applies the appropriate classes to the `boundingBox` and column headers to"," indicate sort state and sortability.",""," Also currently wraps the header content of sortable columns in a `<div>`"," liner to give a CSS anchor for sort indicators.",""," @method _uiSetSortable"," @protected"," @since 3.5.0"," **/"," _uiSetSortable: function () {"," var columns = this._sortable || [],"," sortableClass = this.getClassName('sortable', 'column'),"," ascClass = this.getClassName('sorted'),"," descClass = this.getClassName('sorted', 'desc'),"," linerClass = this.getClassName('sort', 'liner'),"," indicatorClass= this.getClassName('sort', 'indicator'),"," sortableCols = {},"," i, len, col, node, liner, title, desc;",""," this.get('boundingBox').toggleClass("," this.getClassName('sortable'),"," columns.length);",""," for (i = 0, len = columns.length; i < len; ++i) {"," sortableCols[columns[i].id] = columns[i];"," }",""," // TODO: this.head.render() + decorate cells?"," this._theadNode.all('.' + sortableClass).each(function (node) {"," var col = sortableCols[node.get('id')],"," liner = node.one('.' + linerClass),"," indicator;",""," if (col) {"," if (!col.sortDir) {"," node.removeClass(ascClass)"," .removeClass(descClass);"," }"," } else {"," node.removeClass(sortableClass)"," .removeClass(ascClass)"," .removeClass(descClass);",""," if (liner) {"," liner.replace(liner.get('childNodes').toFrag());"," }",""," indicator = node.one('.' + indicatorClass);",""," if (indicator) {"," indicator.remove().destroy(true);"," }"," }"," });",""," for (i = 0, len = columns.length; i < len; ++i) {"," col = columns[i];"," node = this._theadNode.one('#' + col.id);"," desc = col.sortDir === -1;",""," if (node) {"," liner = node.one('.' + linerClass);",""," node.addClass(sortableClass);",""," if (col.sortDir) {"," node.addClass(ascClass);",""," node.toggleClass(descClass, desc);",""," node.setAttribute('aria-sort', desc ?"," 'descending' : 'ascending');"," }",""," if (!liner) {"," liner = Y.Node.create(Y.Lang.sub("," this.SORTABLE_HEADER_TEMPLATE, {"," className: linerClass,"," indicatorClass: indicatorClass"," }));",""," liner.prepend(node.get('childNodes').toFrag());",""," node.append(liner);"," }",""," title = sub(this.getString("," (col.sortDir === 1) ? 'reverseSortBy' : 'sortBy'), {"," column: col.abbr || col.label ||"," col.key || ('column ' + i)"," });",""," node.setAttribute('title', title);"," // To combat VoiceOver from reading the sort title as the"," // column header"," node.setAttribute('aria-labelledby', col.id);"," }"," }"," },",""," /**"," Allows values `true`, `false`, \"auto\", or arrays of column names through.",""," @method _validateSortable"," @param {Any} val The input value to `set(\"sortable\", VAL)`"," @return {Boolean}"," @protected"," @since 3.5.0"," **/"," _validateSortable: function (val) {"," return val === 'auto' || isBoolean(val) || isArray(val);"," },",""," /**"," Allows strings, arrays of strings, objects, or arrays of objects.",""," @method _validateSortBy"," @param {String|String[]|Object|Object[]} val The new `sortBy` value"," @return {Boolean}"," @protected"," @since 3.5.0"," **/"," _validateSortBy: function (val) {"," return val === null ||"," isString(val) ||"," isObject(val, true) ||"," (isArray(val) && (isString(val[0]) || isObject(val, true)));"," }","","}, true);","","Y.DataTable.Sortable = Sortable;","","Y.Base.mix(Y.DataTable, [Sortable]);","","","}, '3.7.3', {\"requires\": [\"datatable-base\"], \"lang\": [\"en\"], \"skinnable\": true});"];
_yuitest_coverage["build/datatable-sort/datatable-sort.js"].lines = {"1":0,"11":0,"108":0,"110":0,"173":0,"215":0,"246":0,"251":0,"252":0,"253":0,"254":0,"257":0,"258":0,"260":0,"261":0,"262":0,"264":0,"265":0,"266":0,"267":0,"272":0,"273":0,"274":0,"275":0,"276":0,"282":0,"303":0,"306":0,"307":0,"308":0,"311":0,"329":0,"330":0,"344":0,"346":0,"347":0,"348":0,"349":0,"363":0,"365":0,"366":0,"371":0,"372":0,"387":0,"420":0,"423":0,"426":0,"427":0,"429":0,"430":0,"431":0,"438":0,"440":0,"453":0,"455":0,"457":0,"459":0,"461":0,"463":0,"470":0,"474":0,"488":0,"496":0,"497":0,"500":0,"501":0,"502":0,"504":0,"505":0,"508":0,"509":0,"511":0,"515":0,"518":0,"519":0,"522":0,"526":0,"539":0,"553":0,"558":0,"559":0,"564":0,"566":0,"567":0,"568":0,"569":0,"570":0,"571":0,"574":0,"575":0,"579":0,"580":0,"583":0,"586":0,"602":0,"606":0,"607":0,"608":0,"612":0,"613":0,"616":0,"617":0,"620":0,"621":0,"623":0,"624":0,"625":0,"626":0,"632":0,"643":0,"645":0,"658":0,"663":0,"666":0,"667":0,"669":0,"671":0,"673":0,"677":0,"679":0,"680":0,"681":0,"683":0,"684":0,"686":0,"687":0,"688":0,"689":0,"694":0,"699":0,"701":0,"702":0,"704":0,"705":0,"708":0,"710":0,"751":0,"766":0,"775":0,"779":0,"780":0,"784":0,"785":0,"789":0,"790":0,"791":0,"795":0,"799":0,"800":0,"803":0,"805":0,"806":0,"811":0,"812":0,"813":0,"814":0,"816":0,"817":0,"819":0,"821":0,"822":0,"824":0,"826":0,"830":0,"831":0,"837":0,"839":0,"842":0,"848":0,"851":0,"866":0,"879":0,"887":0,"889":0};
_yuitest_coverage["build/datatable-sort/datatable-sort.js"].functions = {"Sortable:108":0,"sort:202":0,"toggleSort:245":0,"_afterSortByChange:298":0,"_afterSortDataChange:324":0,"_afterSortRecordChange:343":0,"_bindSortUI:362":0,"_defSortFn:386":0,"_getSortBy:419":0,"initializer:452":0,"_compare:496":0,"_initSortFn:487":0,"_initSortStrings:537":0,"_onUITriggerSort:552":0,"_parseSortable:601":0,"_renderSortable:642":0,"_setSortBy:657":0,"_sortComparator:749":0,"(anonymous 2):784":0,"_uiSetSortable:765":0,"_validateSortable:865":0,"_validateSortBy:878":0,"(anonymous 1):1":0};
_yuitest_coverage["build/datatable-sort/datatable-sort.js"].coveredLines = 174;
_yuitest_coverage["build/datatable-sort/datatable-sort.js"].coveredFunctions = 23;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 1);
YUI.add('datatable-sort', function (Y, NAME) {
/**
Adds support for sorting the table data by API methods `table.sort(...)` or
`table.toggleSort(...)` or by clicking on column headers in the rendered UI.
@module datatable
@submodule datatable-sort
@since 3.5.0
**/
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "(anonymous 1)", 1);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 11);
var YLang = Y.Lang,
isBoolean = YLang.isBoolean,
isString = YLang.isString,
isArray = YLang.isArray,
isObject = YLang.isObject,
toArray = Y.Array,
sub = YLang.sub,
dirMap = {
asc : 1,
desc: -1,
"1" : 1,
"-1": -1
};
/**
_API docs for this extension are included in the DataTable class._
This DataTable class extension adds support for sorting the table data by API
methods `table.sort(...)` or `table.toggleSort(...)` or by clicking on column
headers in the rendered UI.
Sorting by the API is enabled automatically when this module is `use()`d. To
enable UI triggered sorting, set the DataTable's `sortable` attribute to
`true`.
<pre><code>
var table = new Y.DataTable({
columns: [ 'id', 'username', 'name', 'birthdate' ],
data: [ ... ],
sortable: true
});
table.render('#table');
</code></pre>
Setting `sortable` to `true` will enable UI sorting for all columns. To enable
UI sorting for certain columns only, set `sortable` to an array of column keys,
or just add `sortable: true` to the respective column configuration objects.
This uses the default setting of `sortable: auto` for the DataTable instance.
<pre><code>
var table = new Y.DataTable({
columns: [
'id',
{ key: 'username', sortable: true },
{ key: 'name', sortable: true },
{ key: 'birthdate', sortable: true }
],
data: [ ... ]
// sortable: 'auto' is the default
});
// OR
var table = new Y.DataTable({
columns: [ 'id', 'username', 'name', 'birthdate' ],
data: [ ... ],
sortable: [ 'username', 'name', 'birthdate' ]
});
</code></pre>
To disable UI sorting for all columns, set `sortable` to `false`. This still
permits sorting via the API methods.
As new records are inserted into the table's `data` ModelList, they will be inserted at the correct index to preserve the sort order.
The current sort order is stored in the `sortBy` attribute. Assigning this value at instantiation will automatically sort your data.
Sorting is done by a simple value comparison using < and > on the field
value. If you need custom sorting, add a sort function in the column's
`sortFn` property. Columns whose content is generated by formatters, but don't
relate to a single `key`, require a `sortFn` to be sortable.
<pre><code>
function nameSort(a, b, desc) {
var aa = a.get('lastName') + a.get('firstName'),
bb = a.get('lastName') + b.get('firstName'),
order = (aa > bb) ? 1 : -(aa < bb);
return desc ? -order : order;
}
var table = new Y.DataTable({
columns: [ 'id', 'username', { key: name, sortFn: nameSort }, 'birthdate' ],
data: [ ... ],
sortable: [ 'username', 'name', 'birthdate' ]
});
</code></pre>
See the user guide for more details.
@class DataTable.Sortable
@for DataTable
@since 3.5.0
**/
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 108);
function Sortable() {}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 110);
Sortable.ATTRS = {
// Which columns in the UI should suggest and respond to sorting interaction
// pass an empty array if no UI columns should show sortable, but you want the
// table.sort(...) API
/**
Controls which column headers can trigger sorting by user clicks.
Acceptable values are:
* "auto" - (default) looks for `sortable: true` in the column configurations
* `true` - all columns are enabled
* `false - no UI sortable is enabled
* {String[]} - array of key names to give sortable headers
@attribute sortable
@type {String|String[]|Boolean}
@default "auto"
@since 3.5.0
**/
sortable: {
value: 'auto',
validator: '_validateSortable'
},
/**
The current sort configuration to maintain in the data.
Accepts column `key` strings or objects with a single property, the column
`key`, with a value of 1, -1, "asc", or "desc". E.g. `{ username: 'asc'
}`. String values are assumed to be ascending.
Example values would be:
* `"username"` - sort by the data's `username` field or the `key`
associated to a column with that `name`.
* `{ username: "desc" }` - sort by `username` in descending order.
Alternately, use values "asc", 1 (same as "asc"), or -1 (same as "desc").
* `["lastName", "firstName"]` - ascending sort by `lastName`, but for
records with the same `lastName`, ascending subsort by `firstName`.
Array can have as many items as you want.
* `[{ lastName: -1 }, "firstName"]` - descending sort by `lastName`,
ascending subsort by `firstName`. Mixed types are ok.
@attribute sortBy
@type {String|String[]|Object|Object[]}
@since 3.5.0
**/
sortBy: {
validator: '_validateSortBy',
getter: '_getSortBy'
},
/**
Strings containing language for sorting tooltips.
@attribute strings
@type {Object}
@default (strings for current lang configured in the YUI instance config)
@since 3.5.0
**/
strings: {}
};
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 173);
Y.mix(Sortable.prototype, {
/**
Sort the data in the `data` ModelList and refresh the table with the new
order.
Acceptable values for `fields` are `key` strings or objects with a single
property, the column `key`, with a value of 1, -1, "asc", or "desc". E.g.
`{ username: 'asc' }`. String values are assumed to be ascending.
Example values would be:
* `"username"` - sort by the data's `username` field or the `key`
associated to a column with that `name`.
* `{ username: "desc" }` - sort by `username` in descending order.
Alternately, use values "asc", 1 (same as "asc"), or -1 (same as "desc").
* `["lastName", "firstName"]` - ascending sort by `lastName`, but for
records with the same `lastName`, ascending subsort by `firstName`.
Array can have as many items as you want.
* `[{ lastName: -1 }, "firstName"]` - descending sort by `lastName`,
ascending subsort by `firstName`. Mixed types are ok.
@method sort
@param {String|String[]|Object|Object[]} fields The field(s) to sort by
@param {Object} [payload] Extra `sort` event payload you want to send along
@return {DataTable}
@chainable
@since 3.5.0
**/
sort: function (fields, payload) {
/**
Notifies of an impending sort, either from clicking on a column
header, or from a call to the `sort` or `toggleSort` method.
The requested sort is available in the `sortBy` property of the event.
The default behavior of this event sets the table's `sortBy` attribute.
@event sort
@param {String|String[]|Object|Object[]} sortBy The requested sort
@preventable _defSortFn
**/
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "sort", 202);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 215);
return this.fire('sort', Y.merge((payload || {}), {
sortBy: fields || this.get('sortBy')
}));
},
/**
Template for the node that will wrap the header content for sortable
columns.
@property SORTABLE_HEADER_TEMPLATE
@type {HTML}
@value '<div class="{className}" tabindex="0"><span class="{indicatorClass}"></span></div>'
@since 3.5.0
**/
SORTABLE_HEADER_TEMPLATE: '<div class="{className}" tabindex="0"><span class="{indicatorClass}"></span></div>',
/**
Reverse the current sort direction of one or more fields currently being
sorted by.
Pass the `key` of the column or columns you want the sort order reversed
for.
@method toggleSort
@param {String|String[]} fields The field(s) to reverse sort order for
@param {Object} [payload] Extra `sort` event payload you want to send along
@return {DataTable}
@chainable
@since 3.5.0
**/
toggleSort: function (columns, payload) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "toggleSort", 245);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 246);
var current = this._sortBy,
sortBy = [],
i, len, j, col, index;
// To avoid updating column configs or sortBy directly
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 251);
for (i = 0, len = current.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 252);
col = {};
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 253);
col[current[i]._id] = current[i].sortDir;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 254);
sortBy.push(col);
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 257);
if (columns) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 258);
columns = toArray(columns);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 260);
for (i = 0, len = columns.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 261);
col = columns[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 262);
index = -1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 264);
for (j = sortBy.length - 1; i >= 0; --i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 265);
if (sortBy[j][col]) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 266);
sortBy[j][col] *= -1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 267);
break;
}
}
}
} else {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 272);
for (i = 0, len = sortBy.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 273);
for (col in sortBy[i]) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 274);
if (sortBy[i].hasOwnProperty(col)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 275);
sortBy[i][col] *= -1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 276);
break;
}
}
}
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 282);
return this.fire('sort', Y.merge((payload || {}), {
sortBy: sortBy
}));
},
//--------------------------------------------------------------------------
// Protected properties and methods
//--------------------------------------------------------------------------
/**
Sorts the `data` ModelList based on the new `sortBy` configuration.
@method _afterSortByChange
@param {EventFacade} e The `sortByChange` event
@protected
@since 3.5.0
**/
_afterSortByChange: function (e) {
// Can't use a setter because it's a chicken and egg problem. The
// columns need to be set up to translate, but columns are initialized
// from Core's initializer. So construction-time assignment would
// fail.
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_afterSortByChange", 298);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 303);
this._setSortBy();
// Don't sort unless sortBy has been set
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 306);
if (this._sortBy.length) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 307);
if (!this.data.comparator) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 308);
this.data.comparator = this._sortComparator;
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 311);
this.data.sort();
}
},
/**
Applies the sorting logic to the new ModelList if the `newVal` is a new
ModelList.
@method _afterSortDataChange
@param {EventFacade} e the `dataChange` event
@protected
@since 3.5.0
**/
_afterSortDataChange: function (e) {
// object values always trigger a change event, but we only want to
// call _initSortFn if the value passed to the `data` attribute was a
// new ModelList, not a set of new data as an array, or even the same
// ModelList.
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_afterSortDataChange", 324);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 329);
if (e.prevVal !== e.newVal || e.newVal.hasOwnProperty('_compare')) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 330);
this._initSortFn();
}
},
/**
Checks if any of the fields in the modified record are fields that are
currently being sorted by, and if so, resorts the `data` ModelList.
@method _afterSortRecordChange
@param {EventFacade} e The Model's `change` event
@protected
@since 3.5.0
**/
_afterSortRecordChange: function (e) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_afterSortRecordChange", 343);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 344);
var i, len;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 346);
for (i = 0, len = this._sortBy.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 347);
if (e.changed[this._sortBy[i].key]) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 348);
this.data.sort();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 349);
break;
}
}
},
/**
Subscribes to state changes that warrant updating the UI, and adds the
click handler for triggering the sort operation from the UI.
@method _bindSortUI
@protected
@since 3.5.0
**/
_bindSortUI: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_bindSortUI", 362);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 363);
var handles = this._eventHandles;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 365);
if (!handles.sortAttrs) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 366);
handles.sortAttrs = this.after(
['sortableChange', 'sortByChange', 'columnsChange'],
Y.bind('_uiSetSortable', this));
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 371);
if (!handles.sortUITrigger && this._theadNode) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 372);
handles.sortUITrigger = this.delegate(['click','keydown'],
Y.rbind('_onUITriggerSort', this),
'.' + this.getClassName('sortable', 'column'));
}
},
/**
Sets the `sortBy` attribute from the `sort` event's `e.sortBy` value.
@method _defSortFn
@param {EventFacade} e The `sort` event
@protected
@since 3.5.0
**/
_defSortFn: function (e) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_defSortFn", 386);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 387);
this.set.apply(this, ['sortBy', e.sortBy].concat(e.details));
},
/**
Getter for the `sortBy` attribute.
Supports the special subattribute "sortBy.state" to get a normalized JSON
version of the current sort state. Otherwise, returns the last assigned
value.
For example:
<pre><code>var table = new Y.DataTable({
columns: [ ... ],
data: [ ... ],
sortBy: 'username'
});
table.get('sortBy'); // 'username'
table.get('sortBy.state'); // { key: 'username', dir: 1 }
table.sort(['lastName', { firstName: "desc" }]);
table.get('sortBy'); // ['lastName', { firstName: "desc" }]
table.get('sortBy.state'); // [{ key: "lastName", dir: 1 }, { key: "firstName", dir: -1 }]
</code></pre>
@method _getSortBy
@param {String|String[]|Object|Object[]} val The current sortBy value
@param {String} detail String passed to `get(HERE)`. to parse subattributes
@protected
@since 3.5.0
**/
_getSortBy: function (val, detail) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_getSortBy", 419);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 420);
var state, i, len, col;
// "sortBy." is 7 characters. Used to catch
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 423);
detail = detail.slice(7);
// TODO: table.get('sortBy.asObject')? table.get('sortBy.json')?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 426);
if (detail === 'state') {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 427);
state = [];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 429);
for (i = 0, len = this._sortBy.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 430);
col = this._sortBy[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 431);
state.push({
column: col._id,
dir: col.sortDir
});
}
// TODO: Always return an array?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 438);
return { state: (state.length === 1) ? state[0] : state };
} else {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 440);
return val;
}
},
/**
Sets up the initial sort state and instance properties. Publishes events
and subscribes to attribute change events to maintain internal state.
@method initializer
@protected
@since 3.5.0
**/
initializer: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "initializer", 452);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 453);
var boundParseSortable = Y.bind('_parseSortable', this);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 455);
this._parseSortable();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 457);
this._setSortBy();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 459);
this._initSortFn();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 461);
this._initSortStrings();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 463);
this.after({
'table:renderHeader': Y.bind('_renderSortable', this),
dataChange : Y.bind('_afterSortDataChange', this),
sortByChange : Y.bind('_afterSortByChange', this),
sortableChange : boundParseSortable,
columnsChange : boundParseSortable
});
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 470);
this.data.after(this.data.model.NAME + ":change",
Y.bind('_afterSortRecordChange', this));
// TODO: this event needs magic, allowing async remote sorting
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 474);
this.publish('sort', {
defaultFn: Y.bind('_defSortFn', this)
});
},
/**
Creates a `_compare` function for the `data` ModelList to allow custom
sorting by multiple fields.
@method _initSortFn
@protected
@since 3.5.0
**/
_initSortFn: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_initSortFn", 487);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 488);
var self = this;
// TODO: This should be a ModelList extension.
// FIXME: Modifying a component of the host seems a little smelly
// FIXME: Declaring inline override to leverage closure vs
// compiling a new function for each column/sortable change or
// binding the _compare implementation to this, resulting in an
// extra function hop during sorting. Lesser of three evils?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 496);
this.data._compare = function (a, b) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_compare", 496);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 497);
var cmp = 0,
i, len, col, dir, aa, bb;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 500);
for (i = 0, len = self._sortBy.length; !cmp && i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 501);
col = self._sortBy[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 502);
dir = col.sortDir;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 504);
if (col.sortFn) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 505);
cmp = col.sortFn(a, b, (dir === -1));
} else {
// FIXME? Requires columns without sortFns to have key
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 508);
aa = a.get(col.key) || '';
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 509);
bb = b.get(col.key) || '';
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 511);
cmp = (aa > bb) ? dir : ((aa < bb) ? -dir : 0);
}
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 515);
return cmp;
};
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 518);
if (this._sortBy.length) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 519);
this.data.comparator = this._sortComparator;
// TODO: is this necessary? Should it be elsewhere?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 522);
this.data.sort();
} else {
// Leave the _compare method in place to avoid having to set it
// up again. Mistake?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 526);
delete this.data.comparator;
}
},
/**
Add the sort related strings to the `strings` map.
@method _initSortStrings
@protected
@since 3.5.0
**/
_initSortStrings: function () {
// Not a valueFn because other class extensions will want to add to it
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_initSortStrings", 537);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 539);
this.set('strings', Y.mix((this.get('strings') || {}),
Y.Intl.get('datatable-sort')));
},
/**
Fires the `sort` event in response to user clicks on sortable column
headers.
@method _onUITriggerSort
@param {DOMEventFacade} e The `click` event
@protected
@since 3.5.0
**/
_onUITriggerSort: function (e) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_onUITriggerSort", 552);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 553);
var id = e.currentTarget.getAttribute('data-yui3-col-id'),
sortBy = e.shiftKey ? this.get('sortBy') : [{}],
column = id && this.getColumn(id),
i, len;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 558);
if (e.type === 'keydown' && e.keyCode !== 32) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 559);
return;
}
// In case a headerTemplate injected a link
// TODO: Is this overreaching?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 564);
e.preventDefault();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 566);
if (column) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 567);
if (e.shiftKey) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 568);
for (i = 0, len = sortBy.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 569);
if (id === sortBy[i] || Math.abs(sortBy[i][id] === 1)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 570);
if (!isObject(sortBy[i])) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 571);
sortBy[i] = {};
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 574);
sortBy[i][id] = -(column.sortDir|0) || 1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 575);
break;
}
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 579);
if (i >= len) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 580);
sortBy.push(column._id);
}
} else {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 583);
sortBy[0][id] = -(column.sortDir|0) || 1;
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 586);
this.fire('sort', {
originEvent: e,
sortBy: sortBy
});
}
},
/**
Normalizes the possible input values for the `sortable` attribute, storing
the results in the `_sortable` property.
@method _parseSortable
@protected
@since 3.5.0
**/
_parseSortable: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_parseSortable", 601);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 602);
var sortable = this.get('sortable'),
columns = [],
i, len, col;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 606);
if (isArray(sortable)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 607);
for (i = 0, len = sortable.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 608);
col = sortable[i];
// isArray is called because arrays are objects, but will rely
// on getColumn to nullify them for the subsequent if (col)
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 612);
if (!isObject(col, true) || isArray(col)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 613);
col = this.getColumn(col);
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 616);
if (col) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 617);
columns.push(col);
}
}
} else {_yuitest_coverline("build/datatable-sort/datatable-sort.js", 620);
if (sortable) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 621);
columns = this._displayColumns.slice();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 623);
if (sortable === 'auto') {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 624);
for (i = columns.length - 1; i >= 0; --i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 625);
if (!columns[i].sortable) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 626);
columns.splice(i, 1);
}
}
}
}}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 632);
this._sortable = columns;
},
/**
Initial application of the sortable UI.
@method _renderSortable
@protected
@since 3.5.0
**/
_renderSortable: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_renderSortable", 642);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 643);
this._uiSetSortable();
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 645);
this._bindSortUI();
},
/**
Parses the current `sortBy` attribute into a normalized structure for the
`data` ModelList's `_compare` method. Also updates the column
configurations' `sortDir` properties.
@method _setSortBy
@protected
@since 3.5.0
**/
_setSortBy: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_setSortBy", 657);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 658);
var columns = this._displayColumns,
sortBy = this.get('sortBy') || [],
sortedClass = ' ' + this.getClassName('sorted'),
i, len, name, dir, field, column;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 663);
this._sortBy = [];
// Purge current sort state from column configs
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 666);
for (i = 0, len = columns.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 667);
column = columns[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 669);
delete column.sortDir;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 671);
if (column.className) {
// TODO: be more thorough
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 673);
column.className = column.className.replace(sortedClass, '');
}
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 677);
sortBy = toArray(sortBy);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 679);
for (i = 0, len = sortBy.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 680);
name = sortBy[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 681);
dir = 1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 683);
if (isObject(name)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 684);
field = name;
// Have to use a for-in loop to process sort({ foo: -1 })
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 686);
for (name in field) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 687);
if (field.hasOwnProperty(name)) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 688);
dir = dirMap[field[name]];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 689);
break;
}
}
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 694);
if (name) {
// Allow sorting of any model field and any column
// FIXME: this isn't limited to model attributes, but there's no
// convenient way to get a list of the attributes for a Model
// subclass *including* the attributes of its superclasses.
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 699);
column = this.getColumn(name) || { _id: name, key: name };
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 701);
if (column) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 702);
column.sortDir = dir;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 704);
if (!column.className) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 705);
column.className = '';
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 708);
column.className += sortedClass;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 710);
this._sortBy.push(column);
}
}
}
},
/**
Array of column configuration objects of those columns that need UI setup
for user interaction.
@property _sortable
@type {Object[]}
@protected
@since 3.5.0
**/
//_sortable: null,
/**
Array of column configuration objects for those columns that are currently
being used to sort the data. Fake column objects are used for fields that
are not rendered as columns.
@property _sortBy
@type {Object[]}
@protected
@since 3.5.0
**/
//_sortBy: null,
/**
Replacement `comparator` for the `data` ModelList that defers sorting logic
to the `_compare` method. The deferral is accomplished by returning `this`.
@method _sortComparator
@param {Model} item The record being evaluated for sort position
@return {Model} The record
@protected
@since 3.5.0
**/
_sortComparator: function (item) {
// Defer sorting to ModelList's _compare
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_sortComparator", 749);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 751);
return item;
},
/**
Applies the appropriate classes to the `boundingBox` and column headers to
indicate sort state and sortability.
Also currently wraps the header content of sortable columns in a `<div>`
liner to give a CSS anchor for sort indicators.
@method _uiSetSortable
@protected
@since 3.5.0
**/
_uiSetSortable: function () {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_uiSetSortable", 765);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 766);
var columns = this._sortable || [],
sortableClass = this.getClassName('sortable', 'column'),
ascClass = this.getClassName('sorted'),
descClass = this.getClassName('sorted', 'desc'),
linerClass = this.getClassName('sort', 'liner'),
indicatorClass= this.getClassName('sort', 'indicator'),
sortableCols = {},
i, len, col, node, liner, title, desc;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 775);
this.get('boundingBox').toggleClass(
this.getClassName('sortable'),
columns.length);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 779);
for (i = 0, len = columns.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 780);
sortableCols[columns[i].id] = columns[i];
}
// TODO: this.head.render() + decorate cells?
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 784);
this._theadNode.all('.' + sortableClass).each(function (node) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "(anonymous 2)", 784);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 785);
var col = sortableCols[node.get('id')],
liner = node.one('.' + linerClass),
indicator;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 789);
if (col) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 790);
if (!col.sortDir) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 791);
node.removeClass(ascClass)
.removeClass(descClass);
}
} else {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 795);
node.removeClass(sortableClass)
.removeClass(ascClass)
.removeClass(descClass);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 799);
if (liner) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 800);
liner.replace(liner.get('childNodes').toFrag());
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 803);
indicator = node.one('.' + indicatorClass);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 805);
if (indicator) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 806);
indicator.remove().destroy(true);
}
}
});
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 811);
for (i = 0, len = columns.length; i < len; ++i) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 812);
col = columns[i];
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 813);
node = this._theadNode.one('#' + col.id);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 814);
desc = col.sortDir === -1;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 816);
if (node) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 817);
liner = node.one('.' + linerClass);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 819);
node.addClass(sortableClass);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 821);
if (col.sortDir) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 822);
node.addClass(ascClass);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 824);
node.toggleClass(descClass, desc);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 826);
node.setAttribute('aria-sort', desc ?
'descending' : 'ascending');
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 830);
if (!liner) {
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 831);
liner = Y.Node.create(Y.Lang.sub(
this.SORTABLE_HEADER_TEMPLATE, {
className: linerClass,
indicatorClass: indicatorClass
}));
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 837);
liner.prepend(node.get('childNodes').toFrag());
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 839);
node.append(liner);
}
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 842);
title = sub(this.getString(
(col.sortDir === 1) ? 'reverseSortBy' : 'sortBy'), {
column: col.abbr || col.label ||
col.key || ('column ' + i)
});
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 848);
node.setAttribute('title', title);
// To combat VoiceOver from reading the sort title as the
// column header
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 851);
node.setAttribute('aria-labelledby', col.id);
}
}
},
/**
Allows values `true`, `false`, "auto", or arrays of column names through.
@method _validateSortable
@param {Any} val The input value to `set("sortable", VAL)`
@return {Boolean}
@protected
@since 3.5.0
**/
_validateSortable: function (val) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_validateSortable", 865);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 866);
return val === 'auto' || isBoolean(val) || isArray(val);
},
/**
Allows strings, arrays of strings, objects, or arrays of objects.
@method _validateSortBy
@param {String|String[]|Object|Object[]} val The new `sortBy` value
@return {Boolean}
@protected
@since 3.5.0
**/
_validateSortBy: function (val) {
_yuitest_coverfunc("build/datatable-sort/datatable-sort.js", "_validateSortBy", 878);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 879);
return val === null ||
isString(val) ||
isObject(val, true) ||
(isArray(val) && (isString(val[0]) || isObject(val, true)));
}
}, true);
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 887);
Y.DataTable.Sortable = Sortable;
_yuitest_coverline("build/datatable-sort/datatable-sort.js", 889);
Y.Base.mix(Y.DataTable, [Sortable]);
}, '3.7.3', {"requires": ["datatable-base"], "lang": ["en"], "skinnable": true});