1 var Sort =
function(table){
8 Sort.prototype.initializeColumn =
function(column, content){
15 switch(typeof column.definition.sorter){
17 if(
self.sorters[column.definition.sorter]){
18 sorter =
self.sorters[column.definition.sorter];
20 console.warn(
"Sort Error - No such sorter found: ", column.definition.sorter);
25 sorter = column.definition.sorter;
29 column.modules.sort = {
30 sorter:sorter, dir:
"none",
31 params:column.definition.sorterParams || {},
32 startingDir:column.definition.headerSortStartingDir ||
"asc",
33 tristate: typeof column.definition.headerSortTristate !==
"undefined" ? column.definition.headerSortTristate : this.table.options.headerSortTristate,
36 if(typeof column.definition.headerSort ===
"undefined" ? (
this.table.options.headerSort !==
false) : column.definition.headerSort !==
false){
38 colEl = column.getElement();
40 colEl.classList.add(
"tabulator-sortable");
43 arrowEl = document.createElement(
"div");
44 arrowEl.classList.add(
"tabulator-arrow");
46 content.appendChild(arrowEl);
49 colEl.addEventListener(
"click",
function(e){
54 if(column.modules.sort){
55 if(column.modules.sort.tristate){
56 if(column.modules.sort.dir ==
"none"){
57 dir = column.modules.sort.startingDir;
59 if(column.modules.sort.dir == column.modules.sort.startingDir){
60 dir = column.modules.sort.dir ==
"asc" ?
"desc" :
"asc";
66 switch(column.modules.sort.dir){
76 dir = column.modules.sort.startingDir;
81 if (
self.table.options.columnHeaderSortMulti && (e.shiftKey || e.ctrlKey)) {
82 sorters =
self.getSort();
84 match = sorters.findIndex(
function(sorter){
85 return sorter.field === column.getField();
89 sorters[match].dir = dir;
91 if(match != sorters.length -1){
92 match = sorters.splice(match, 1)[0];
99 sorters.push({column:column, dir:dir});
104 self.setSort(sorters);
110 self.setSort(column, dir);
115 self.table.rowManager.sorterRefresh(!
self.sortList.length);
122 Sort.prototype.hasChanged =
function(){
123 var changed = this.changed;
124 this.changed =
false;
129 Sort.prototype.getSort =
function(){
133 self.sortList.forEach(
function(item){
135 sorters.push({column:item.column.getComponent(), field:item.column.getField(), dir:item.dir});
143 Sort.prototype.setSort =
function(sortList, dir){
147 if(!Array.isArray(sortList)){
148 sortList = [{column: sortList, dir:dir}];
151 sortList.forEach(
function(item){
154 column =
self.table.columnManager.findColumn(item.column);
157 item.column = column;
158 newSortList.push(item);
161 console.warn(
"Sort Warning - Sort field does not exist and is being ignored: ", item.column);
166 self.sortList = newSortList;
168 if(this.table.options.persistence &&
this.table.modExists(
"persistence",
true) && this.table.modules.persistence.config.sort){
169 this.table.modules.persistence.save(
"sort");
174 Sort.prototype.clear =
function(){
179 Sort.prototype.findSorter =
function(column){
180 var row = this.table.rowManager.activeRows[0],
186 field = column.getField();
190 value = column.getFieldValue(row);
192 switch(typeof value){
202 if(!isNaN(value) && value !==
""){
205 if(value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)){
214 return this.sorters[sorter];
218 Sort.prototype.sort =
function(data){
219 var
self =
this, lastSort, sortList;
221 sortList = this.table.options.sortOrderReverse ?
self.sortList.slice().reverse() :
self.sortList;
223 if(
self.table.options.dataSorting){
224 self.table.options.dataSorting.call(
self.table,
self.getSort());
227 self.clearColumnHeaders();
229 if(!
self.table.options.ajaxSorting){
231 sortList.forEach(
function(item, i){
233 if(item.column && item.column.modules.sort){
236 if(!item.column.modules.sort.sorter){
237 item.column.modules.sort.sorter =
self.findSorter(item.column);
240 self._sortItem(data, item.column, item.dir, sortList, i);
243 self.setColumnHeader(item.column, item.dir);
246 sortList.forEach(
function(item, i){
247 self.setColumnHeader(item.column, item.dir);
251 if(
self.table.options.dataSorted){
252 self.table.options.dataSorted.call(
self.table,
self.getSort(),
self.table.rowManager.getComponents(
"active"));
258 Sort.prototype.clearColumnHeaders =
function(){
259 this.table.columnManager.getRealColumns().forEach(
function(column){
260 if(column.modules.sort){
261 column.modules.sort.dir =
"none";
262 column.getElement().setAttribute(
"aria-sort",
"none");
268 Sort.prototype.setColumnHeader =
function(column, dir){
269 column.modules.sort.dir = dir;
270 column.getElement().setAttribute(
"aria-sort", dir);
274 Sort.prototype._sortItem =
function(data, column, dir, sortList, i){
277 var params = typeof column.modules.sort.params ===
"function" ? column.modules.sort.params(column.getComponent(), dir) : column.modules.sort.params;
279 data.sort(
function(a, b){
281 var result =
self._sortRow(a, b, column, dir, params);
284 if(result === 0 && i){
285 for(var j = i-1; j>= 0; j--){
286 result =
self._sortRow(a, b, sortList[j].column, sortList[j].dir, params);
299 Sort.prototype._sortRow =
function(a, b, column, dir, params){
300 var el1Comp, el2Comp, colComp;
303 var el1 = dir ==
"asc" ? a : b;
304 var el2 = dir ==
"asc" ? b : a;
306 a = column.getFieldValue(el1.getData());
307 b = column.getFieldValue(el2.getData());
309 a = typeof a !==
"undefined" ? a :
"";
310 b = typeof b !==
"undefined" ? b :
"";
312 el1Comp = el1.getComponent();
313 el2Comp = el2.getComponent();
315 return column.modules.sort.sorter.call(
this, a, b, el1Comp, el2Comp, column.getComponent(), dir, params);
320 Sort.prototype.sorters = {
323 number:
function(a, b, aRow, bRow, column, dir, params){
324 var alignEmptyValues = params.alignEmptyValues;
325 var decimal = params.decimalSeparator ||
".";
326 var thousand = params.thousandSeparator ||
",";
329 a = parseFloat(String(a).split(thousand).join(
"").split(decimal).join(
"."));
330 b = parseFloat(String(b).split(thousand).join(
"").split(decimal).join(
"."));
334 emptyAlign = isNaN(b) ? 0 : -1;
343 if((alignEmptyValues ===
"top" && dir ===
"desc") || (alignEmptyValues ===
"bottom" && dir ===
"asc")){
351 string:
function(a, b, aRow, bRow, column, dir, params){
352 var alignEmptyValues = params.alignEmptyValues;
358 emptyAlign = !b ? 0 : -1;
363 switch(typeof params.locale){
366 locale = this.table.modules.localize.getLocale();
370 locale = params.locale;
374 return String(a).toLowerCase().localeCompare(String(b).toLowerCase(), locale);
378 if((alignEmptyValues ===
"top" && dir ===
"desc") || (alignEmptyValues ===
"bottom" && dir ===
"asc")){
386 date:
function(a, b, aRow, bRow, column, dir, params){
388 params.format =
"DD/MM/YYYY";
391 return this.sorters.datetime.call(
this, a, b, aRow, bRow, column, dir, params);
395 time:
function(a, b, aRow, bRow, column, dir, params){
397 params.format =
"hh:mm";
400 return this.sorters.datetime.call(
this, a, b, aRow, bRow, column, dir, params);
404 datetime:
function(a, b, aRow, bRow, column, dir, params){
405 var format = params.format ||
"DD/MM/YYYY hh:mm:ss",
406 alignEmptyValues = params.alignEmptyValues,
409 if(typeof moment !=
"undefined"){
410 a = moment(a, format);
411 b = moment(b, format);
414 emptyAlign = !b.isValid() ? 0 : -1;
415 }
else if(!b.isValid()){
423 if((alignEmptyValues ===
"top" && dir ===
"desc") || (alignEmptyValues ===
"bottom" && dir ===
"asc")){
430 console.error(
"Sort Error - 'datetime' sorter is dependant on moment.js");
435 boolean:
function(a, b, aRow, bRow, column, dir, params){
436 var el1 = a ===
true || a ===
"true" || a ===
"True" || a === 1 ? 1 : 0;
437 var el2 = b ===
true || b ===
"true" || b ===
"True" || b === 1 ? 1 : 0;
443 array:
function(a, b, aRow, bRow, column, dir, params){
446 var type = params.type ||
"length";
447 var alignEmptyValues = params.alignEmptyValues;
450 function calc(value){
458 return value.reduce(
function(c, d){
464 return Math.max.apply(null, value) ;
468 return Math.min.apply(null, value) ;
472 return value.reduce(
function(c, d){
480 if(!Array.isArray(a)){
481 alignEmptyValues = !Array.isArray(b) ? 0 : -1;
482 }
else if(!Array.isArray(b)){
483 alignEmptyValues = 1;
487 el1 = a ? calc(a) : 0;
488 el2 = b ? calc(b) : 0;
494 if((alignEmptyValues ===
"top" && dir ===
"desc") || (alignEmptyValues ===
"bottom" && dir ===
"asc")){
503 exists:
function(a, b, aRow, bRow, column, dir, params){
504 var el1 = typeof a ==
"undefined" ? 0 : 1;
505 var el2 = typeof b ==
"undefined" ? 0 : 1;
511 alphanum:
function(as, bs, aRow, bRow, column, dir, params){
512 var a, b, a1, b1, i= 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
513 var alignEmptyValues = params.alignEmptyValues;
518 emptyAlign = !bs && bs!== 0 ? 0 : -1;
519 }
else if(!bs && bs!== 0){
523 if(isFinite(as) && isFinite(bs))
return as - bs;
524 a = String(as).toLowerCase();
525 b = String(bs).toLowerCase();
526 if(a === b)
return 0;
527 if(!(rd.test(a) && rd.test(b)))
return a > b ? 1 : -1;
530 L = a.length > b.length ? b.length : a.length;
535 if(isFinite(a1) && isFinite(b1)){
536 if(a1.charAt(0) ===
"0") a1 =
"." + a1;
537 if(b1.charAt(0) ===
"0") b1 =
"." + b1;
540 else return a1 > b1 ? 1 : -1;
544 return a.length > b.length;
548 if((alignEmptyValues ===
"top" && dir ===
"desc") || (alignEmptyValues ===
"bottom" && dir ===
"asc")){
556 Tabulator.prototype.registerModule(
"sort", Sort);