2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('datatable-sort', function(Y) {
11 * Plugs DataTable with sorting functionality.
14 * @submodule datatable-sort
18 * Adds column sorting to DataTable.
19 * @class DataTableSort
20 * @extends Plugin.Base
22 var YgetClassName = Y.ClassNameManager.getClassName,
24 DATATABLE = "datatable",
29 //TODO: Don't use hrefs - use tab/arrow/enter
30 TEMPLATE = '<a class="{link_class}" title="{link_title}" href="{link_href}">{value}</a>';
33 function DataTableSort() {
34 DataTableSort.superclass.constructor.apply(this, arguments);
37 /////////////////////////////////////////////////////////////////////////////
41 /////////////////////////////////////////////////////////////////////////////
42 Y.mix(DataTableSort, {
44 * The namespace for the plugin. This will be the property on the host which
45 * references the plugin instance.
62 * @value "dataTableSort"
64 NAME: "dataTableSort",
66 /////////////////////////////////////////////////////////////////////////////
70 /////////////////////////////////////////////////////////////////////////////
74 * @description Defines the trigger that causes a column to be sorted:
75 * {event, selector}, where "event" is an event type and "selector" is
76 * is a node query selector.
78 * @default {event:"click", selector:"th"}
79 * @writeOnce "initOnly"
82 value: {event:"click", selector:"th"},
87 * @attribute lastSortedBy
88 * @description Describes last known sort state: {key,dir}, where
89 * "key" is column key and "dir" is either "asc" or "desc".
93 setter: "_setLastSortedBy",
99 * @description Tokenized markup template for TH sort element.
101 * @default '<a class="{link_class}" title="{link_title}" href="{link_href}">{value}</a>'
109 /////////////////////////////////////////////////////////////////////////////
113 /////////////////////////////////////////////////////////////////////////////
114 Y.extend(DataTableSort, Y.Plugin.Base, {
116 /////////////////////////////////////////////////////////////////////////////
120 /////////////////////////////////////////////////////////////////////////////
124 * @method initializer
125 * @param config {Object} Config object.
128 initializer: function(config) {
129 var dt = this.get("host"),
130 trigger = this.get("trigger");
132 dt.get("recordset").plug(Y.Plugin.RecordsetSort, {dt: dt});
133 dt.get("recordset").sort.addTarget(dt);
135 // Wrap link around TH value
136 this.doBefore("_createTheadThNode", this._beforeCreateTheadThNode);
139 this.doBefore("_attachTheadThNode", this._beforeAttachTheadThNode);
140 this.doBefore("_attachTbodyTdNode", this._beforeAttachTbodyTdNode);
142 // Attach trigger handlers
143 dt.delegate(trigger.event, Y.bind(this._onEventSortColumn,this), trigger.selector);
146 dt.after("recordsetSort:sort", function() {
147 this._uiSetRecordset(this.get("recordset"));
149 this.on("lastSortedByChange", function(e) {
150 this._uiSetLastSortedBy(e.prevVal, e.newVal, dt);
154 //dt.after("recordset:mutation", function() {//reset lastSortedBy});
157 //add Column sortFn ATTR
159 // Update UI after the fact (render-then-plug case)
160 if(dt.get("rendered")) {
161 dt._uiSetColumnset(dt.get("columnset"));
162 this._uiSetLastSortedBy(null, this.get("lastSortedBy"), dt);
167 * @method _setLastSortedBy
168 * @description Normalizes lastSortedBy
169 * @param val {String | Object} {key, dir} or "key"
170 * @returns {key, dir, notdir}
173 _setLastSortedBy: function(val) {
174 if(Y.Lang.isString(val)) {
175 return {key:val, dir:"asc", notdir:"desc"};
177 else if (val && val.key) {
178 if(val.dir === "desc") {
179 return {key:val.key, dir:"desc", notdir:"asc"};
182 return {key:val.key, dir:"asc", notdir:"desc"};
193 * @method _uiSetLastSortedBy
194 * @param val {Object} New lastSortedBy object {key,dir}.
195 * @param dt {Y.DataTable.Base} Host.
198 _uiSetLastSortedBy: function(prevVal, newVal, dt) {
199 var prevKey = prevVal && prevVal.key,
200 prevDir = prevVal && prevVal.dir,
201 newKey = newVal && newVal.key,
202 newDir = newVal && newVal.dir,
203 cs = dt.get("columnset"),
204 prevColumn = cs.keyHash[prevKey],
205 newColumn = cs.keyHash[newKey],
206 tbodyNode = dt._tbodyNode,
207 prevRowList, newRowList;
211 prevColumn.thNode.removeClass(YgetClassName(DATATABLE, prevDir));
212 prevRowList = tbodyNode.all("."+YgetClassName(COLUMN, prevColumn.get("id")));
213 prevRowList.removeClass(YgetClassName(DATATABLE, prevDir));
218 newColumn.thNode.addClass(YgetClassName(DATATABLE, newDir));
219 newRowList = tbodyNode.all("."+YgetClassName(COLUMN, newColumn.get("id")));
220 newRowList.addClass(YgetClassName(DATATABLE, newDir));
225 * Before header cell element is created, inserts link markup around {value}.
227 * @method _beforeCreateTheadThNode
228 * @param o {Object} {value, column, tr}.
231 _beforeCreateTheadThNode: function(o) {
232 if(o.column.get("sortable")) {
233 o.value = Y.substitute(this.get("template"), {
234 link_class: o.link_class || "",
243 * Before header cell element is attached, sets applicable class names.
245 * @method _beforeAttachTheadThNode
246 * @param o {Object} {value, column, tr}.
249 _beforeAttachTheadThNode: function(o) {
250 var lastSortedBy = this.get("lastSortedBy"),
251 key = lastSortedBy && lastSortedBy.key,
252 dir = lastSortedBy && lastSortedBy.dir,
253 notdir = lastSortedBy && lastSortedBy.notdir;
255 // This Column is sortable
256 if(o.column.get("sortable")) {
257 o.th.addClass(YgetClassName(DATATABLE, "sortable"));
259 // This Column is currently sorted
260 if(key && (key === o.column.get("key"))) {
261 o.th.replaceClass(YgetClassName(DATATABLE, notdir), YgetClassName(DATATABLE, dir));
266 * Before header cell element is attached, sets applicable class names.
268 * @method _before_beforeAttachTbodyTdNode
269 * @param o {Object} {record, column, tr, headers, classnames, value}.
272 _beforeAttachTbodyTdNode: function(o) {
273 var lastSortedBy = this.get("lastSortedBy"),
274 key = lastSortedBy && lastSortedBy.key,
275 dir = lastSortedBy && lastSortedBy.dir,
276 notdir = lastSortedBy && lastSortedBy.notdir;
278 // This Column is sortable
279 if(o.column.get("sortable")) {
280 o.td.addClass(YgetClassName(DATATABLE, "sortable"));
282 // This Column is currently sorted
283 if(key && (key === o.column.get("key"))) {
284 o.td.replaceClass(YgetClassName(DATATABLE, notdir), YgetClassName(DATATABLE, dir));
288 * In response to the "trigger" event, sorts the underlying Recordset and
289 * updates the lastSortedBy attribute.
291 * @method _onEventSortColumn
292 * @param o {Object} {value, column, tr}.
295 _onEventSortColumn: function(e) {
297 //TODO: normalize e.currentTarget to TH
298 var dt = this.get("host"),
299 column = dt.get("columnset").idHash[e.currentTarget.get("id")],
300 key = column.get("key"),
301 field = column.get("field"),
302 lastSortedBy = this.get("lastSortedBy"),
303 dir = (lastSortedBy &&
304 lastSortedBy.key === key &&
305 lastSortedBy.dir === ASC) ? DESC : ASC,
306 sorter = column.get("sortFn");
307 if(column.get("sortable")) {
308 dt.get("recordset").sort.sort(field, dir === DESC, sorter);
309 this.set("lastSortedBy", {key: key, dir: dir});
314 Y.namespace("Plugin").DataTableSort = DataTableSort;
321 }, '3.3.0' ,{lang:['en'], requires:['datatable-base','plugin','recordset-sort']});