otsdaq_utilities  v2_05_02_indev
sort.js
1 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
2 
3 /* Tabulator v4.5.3 (c) Oliver Folkerd */
4 
5 var Sort = function Sort(table) {
6  this.table = table; //hold Tabulator object
7  this.sortList = []; //holder current sort
8  this.changed = false; //has the sort changed since last render
9 };
10 
11 //initialize column header for sorting
12 Sort.prototype.initializeColumn = function (column, content) {
13  var self = this,
14  sorter = false,
15  colEl,
16  arrowEl;
17 
18  switch (_typeof(column.definition.sorter)) {
19  case "string":
20  if (self.sorters[column.definition.sorter]) {
21  sorter = self.sorters[column.definition.sorter];
22  } else {
23  console.warn("Sort Error - No such sorter found: ", column.definition.sorter);
24  }
25  break;
26 
27  case "function":
28  sorter = column.definition.sorter;
29  break;
30  }
31 
32  column.modules.sort = {
33  sorter: sorter, dir: "none",
34  params: column.definition.sorterParams || {},
35  startingDir: column.definition.headerSortStartingDir || "asc",
36  tristate: typeof column.definition.headerSortTristate !== "undefined" ? column.definition.headerSortTristate : this.table.options.headerSortTristate
37  };
38 
39  if (typeof column.definition.headerSort === "undefined" ? this.table.options.headerSort !== false : column.definition.headerSort !== false) {
40 
41  colEl = column.getElement();
42 
43  colEl.classList.add("tabulator-sortable");
44 
45  arrowEl = document.createElement("div");
46  arrowEl.classList.add("tabulator-arrow");
47  //create sorter arrow
48  content.appendChild(arrowEl);
49 
50  //sort on click
51  colEl.addEventListener("click", function (e) {
52  var dir = "",
53  sorters = [],
54  match = false;
55 
56  if (column.modules.sort) {
57  if (column.modules.sort.tristate) {
58  if (column.modules.sort.dir == "none") {
59  dir = column.modules.sort.startingDir;
60  } else {
61  if (column.modules.sort.dir == column.modules.sort.startingDir) {
62  dir = column.modules.sort.dir == "asc" ? "desc" : "asc";
63  } else {
64  dir = "none";
65  }
66  }
67  } else {
68  switch (column.modules.sort.dir) {
69  case "asc":
70  dir = "desc";
71  break;
72 
73  case "desc":
74  dir = "asc";
75  break;
76 
77  default:
78  dir = column.modules.sort.startingDir;
79  }
80  }
81 
82  if (self.table.options.columnHeaderSortMulti && (e.shiftKey || e.ctrlKey)) {
83  sorters = self.getSort();
84 
85  match = sorters.findIndex(function (sorter) {
86  return sorter.field === column.getField();
87  });
88 
89  if (match > -1) {
90  sorters[match].dir = dir;
91 
92  if (match != sorters.length - 1) {
93  match = sorters.splice(match, 1)[0];
94  if (dir != "none") {
95  sorters.push(match);
96  }
97  }
98  } else {
99  if (dir != "none") {
100  sorters.push({ column: column, dir: dir });
101  }
102  }
103 
104  //add to existing sort
105  self.setSort(sorters);
106  } else {
107  if (dir == "none") {
108  self.clear();
109  } else {
110  //sort by column only
111  self.setSort(column, dir);
112  }
113  }
114 
115  self.table.rowManager.sorterRefresh(!self.sortList.length);
116  }
117  });
118  }
119 };
120 
121 //check if the sorters have changed since last use
122 Sort.prototype.hasChanged = function () {
123  var changed = this.changed;
124  this.changed = false;
125  return changed;
126 };
127 
128 //return current sorters
129 Sort.prototype.getSort = function () {
130  var self = this,
131  sorters = [];
132 
133  self.sortList.forEach(function (item) {
134  if (item.column) {
135  sorters.push({ column: item.column.getComponent(), field: item.column.getField(), dir: item.dir });
136  }
137  });
138 
139  return sorters;
140 };
141 
142 //change sort list and trigger sort
143 Sort.prototype.setSort = function (sortList, dir) {
144  var self = this,
145  newSortList = [];
146 
147  if (!Array.isArray(sortList)) {
148  sortList = [{ column: sortList, dir: dir }];
149  }
150 
151  sortList.forEach(function (item) {
152  var column;
153 
154  column = self.table.columnManager.findColumn(item.column);
155 
156  if (column) {
157  item.column = column;
158  newSortList.push(item);
159  self.changed = true;
160  } else {
161  console.warn("Sort Warning - Sort field does not exist and is being ignored: ", item.column);
162  }
163  });
164 
165  self.sortList = newSortList;
166 
167  if (this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.sort) {
168  this.table.modules.persistence.save("sort");
169  }
170 };
171 
172 //clear sorters
173 Sort.prototype.clear = function () {
174  this.setSort([]);
175 };
176 
177 //find appropriate sorter for column
178 Sort.prototype.findSorter = function (column) {
179  var row = this.table.rowManager.activeRows[0],
180  sorter = "string",
181  field,
182  value;
183 
184  if (row) {
185  row = row.getData();
186  field = column.getField();
187 
188  if (field) {
189 
190  value = column.getFieldValue(row);
191 
192  switch (typeof value === "undefined" ? "undefined" : _typeof(value)) {
193  case "undefined":
194  sorter = "string";
195  break;
196 
197  case "boolean":
198  sorter = "boolean";
199  break;
200 
201  default:
202  if (!isNaN(value) && value !== "") {
203  sorter = "number";
204  } else {
205  if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) {
206  sorter = "alphanum";
207  }
208  }
209  break;
210  }
211  }
212  }
213 
214  return this.sorters[sorter];
215 };
216 
217 //work through sort list sorting data
218 Sort.prototype.sort = function (data) {
219  var self = this,
220  lastSort,
221  sortList;
222 
223  sortList = this.table.options.sortOrderReverse ? self.sortList.slice().reverse() : self.sortList;
224 
225  if (self.table.options.dataSorting) {
226  self.table.options.dataSorting.call(self.table, self.getSort());
227  }
228 
229  self.clearColumnHeaders();
230 
231  if (!self.table.options.ajaxSorting) {
232 
233  sortList.forEach(function (item, i) {
234 
235  if (item.column && item.column.modules.sort) {
236 
237  //if no sorter has been defined, take a guess
238  if (!item.column.modules.sort.sorter) {
239  item.column.modules.sort.sorter = self.findSorter(item.column);
240  }
241 
242  self._sortItem(data, item.column, item.dir, sortList, i);
243  }
244 
245  self.setColumnHeader(item.column, item.dir);
246  });
247  } else {
248  sortList.forEach(function (item, i) {
249  self.setColumnHeader(item.column, item.dir);
250  });
251  }
252 
253  if (self.table.options.dataSorted) {
254  self.table.options.dataSorted.call(self.table, self.getSort(), self.table.rowManager.getComponents("active"));
255  }
256 };
257 
258 //clear sort arrows on columns
259 Sort.prototype.clearColumnHeaders = function () {
260  this.table.columnManager.getRealColumns().forEach(function (column) {
261  if (column.modules.sort) {
262  column.modules.sort.dir = "none";
263  column.getElement().setAttribute("aria-sort", "none");
264  }
265  });
266 };
267 
268 //set the column header sort direction
269 Sort.prototype.setColumnHeader = function (column, dir) {
270  column.modules.sort.dir = dir;
271  column.getElement().setAttribute("aria-sort", dir);
272 };
273 
274 //sort each item in sort list
275 Sort.prototype._sortItem = function (data, column, dir, sortList, i) {
276  var self = this;
277 
278  var params = typeof column.modules.sort.params === "function" ? column.modules.sort.params(column.getComponent(), dir) : column.modules.sort.params;
279 
280  data.sort(function (a, b) {
281 
282  var result = self._sortRow(a, b, column, dir, params);
283 
284  //if results match recurse through previous searchs to be sure
285  if (result === 0 && i) {
286  for (var j = i - 1; j >= 0; j--) {
287  result = self._sortRow(a, b, sortList[j].column, sortList[j].dir, params);
288 
289  if (result !== 0) {
290  break;
291  }
292  }
293  }
294 
295  return result;
296  });
297 };
298 
299 //process individual rows for a sort function on active data
300 Sort.prototype._sortRow = function (a, b, column, dir, params) {
301  var el1Comp, el2Comp, colComp;
302 
303  //switch elements depending on search direction
304  var el1 = dir == "asc" ? a : b;
305  var el2 = dir == "asc" ? b : a;
306 
307  a = column.getFieldValue(el1.getData());
308  b = column.getFieldValue(el2.getData());
309 
310  a = typeof a !== "undefined" ? a : "";
311  b = typeof b !== "undefined" ? b : "";
312 
313  el1Comp = el1.getComponent();
314  el2Comp = el2.getComponent();
315 
316  return column.modules.sort.sorter.call(this, a, b, el1Comp, el2Comp, column.getComponent(), dir, params);
317 };
318 
319 //default data sorters
320 Sort.prototype.sorters = {
321 
322  //sort numbers
323  number: function number(a, b, aRow, bRow, column, dir, params) {
324  var alignEmptyValues = params.alignEmptyValues;
325  var decimal = params.decimalSeparator || ".";
326  var thousand = params.thousandSeparator || ",";
327  var emptyAlign = 0;
328 
329  a = parseFloat(String(a).split(thousand).join("").split(decimal).join("."));
330  b = parseFloat(String(b).split(thousand).join("").split(decimal).join("."));
331 
332  //handle non numeric values
333  if (isNaN(a)) {
334  emptyAlign = isNaN(b) ? 0 : -1;
335  } else if (isNaN(b)) {
336  emptyAlign = 1;
337  } else {
338  //compare valid values
339  return a - b;
340  }
341 
342  //fix empty values in position
343  if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") {
344  emptyAlign *= -1;
345  }
346 
347  return emptyAlign;
348  },
349 
350  //sort strings
351  string: function string(a, b, aRow, bRow, column, dir, params) {
352  var alignEmptyValues = params.alignEmptyValues;
353  var emptyAlign = 0;
354  var locale;
355 
356  //handle empty values
357  if (!a) {
358  emptyAlign = !b ? 0 : -1;
359  } else if (!b) {
360  emptyAlign = 1;
361  } else {
362  //compare valid values
363  switch (_typeof(params.locale)) {
364  case "boolean":
365  if (params.locale) {
366  locale = this.table.modules.localize.getLocale();
367  }
368  break;
369  case "string":
370  locale = params.locale;
371  break;
372  }
373 
374  return String(a).toLowerCase().localeCompare(String(b).toLowerCase(), locale);
375  }
376 
377  //fix empty values in position
378  if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") {
379  emptyAlign *= -1;
380  }
381 
382  return emptyAlign;
383  },
384 
385  //sort date
386  date: function date(a, b, aRow, bRow, column, dir, params) {
387  if (!params.format) {
388  params.format = "DD/MM/YYYY";
389  }
390 
391  return this.sorters.datetime.call(this, a, b, aRow, bRow, column, dir, params);
392  },
393 
394  //sort hh:mm formatted times
395  time: function time(a, b, aRow, bRow, column, dir, params) {
396  if (!params.format) {
397  params.format = "hh:mm";
398  }
399 
400  return this.sorters.datetime.call(this, a, b, aRow, bRow, column, dir, params);
401  },
402 
403  //sort datetime
404  datetime: function datetime(a, b, aRow, bRow, column, dir, params) {
405  var format = params.format || "DD/MM/YYYY hh:mm:ss",
406  alignEmptyValues = params.alignEmptyValues,
407  emptyAlign = 0;
408 
409  if (typeof moment != "undefined") {
410  a = moment(a, format);
411  b = moment(b, format);
412 
413  if (!a.isValid()) {
414  emptyAlign = !b.isValid() ? 0 : -1;
415  } else if (!b.isValid()) {
416  emptyAlign = 1;
417  } else {
418  //compare valid values
419  return a - b;
420  }
421 
422  //fix empty values in position
423  if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") {
424  emptyAlign *= -1;
425  }
426 
427  return emptyAlign;
428  } else {
429  console.error("Sort Error - 'datetime' sorter is dependant on moment.js");
430  }
431  },
432 
433  //sort booleans
434  boolean: function boolean(a, b, aRow, bRow, column, dir, params) {
435  var el1 = a === true || a === "true" || a === "True" || a === 1 ? 1 : 0;
436  var el2 = b === true || b === "true" || b === "True" || b === 1 ? 1 : 0;
437 
438  return el1 - el2;
439  },
440 
441  //sort if element contains any data
442  array: function array(a, b, aRow, bRow, column, dir, params) {
443  var el1 = 0;
444  var el2 = 0;
445  var type = params.type || "length";
446  var alignEmptyValues = params.alignEmptyValues;
447  var emptyAlign = 0;
448 
449  function calc(value) {
450 
451  switch (type) {
452  case "length":
453  return value.length;
454  break;
455 
456  case "sum":
457  return value.reduce(function (c, d) {
458  return c + d;
459  });
460  break;
461 
462  case "max":
463  return Math.max.apply(null, value);
464  break;
465 
466  case "min":
467  return Math.min.apply(null, value);
468  break;
469 
470  case "avg":
471  return value.reduce(function (c, d) {
472  return c + d;
473  }) / value.length;
474  break;
475  }
476  }
477 
478  //handle non array values
479  if (!Array.isArray(a)) {
480  alignEmptyValues = !Array.isArray(b) ? 0 : -1;
481  } else if (!Array.isArray(b)) {
482  alignEmptyValues = 1;
483  } else {
484 
485  //compare valid values
486  el1 = a ? calc(a) : 0;
487  el2 = b ? calc(b) : 0;
488 
489  return el1 - el2;
490  }
491 
492  //fix empty values in position
493  if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") {
494  emptyAlign *= -1;
495  }
496 
497  return emptyAlign;
498  },
499 
500  //sort if element contains any data
501  exists: function exists(a, b, aRow, bRow, column, dir, params) {
502  var el1 = typeof a == "undefined" ? 0 : 1;
503  var el2 = typeof b == "undefined" ? 0 : 1;
504 
505  return el1 - el2;
506  },
507 
508  //sort alpha numeric strings
509  alphanum: function alphanum(as, bs, aRow, bRow, column, dir, params) {
510  var a,
511  b,
512  a1,
513  b1,
514  i = 0,
515  L,
516  rx = /(\d+)|(\D+)/g,
517  rd = /\d/;
518  var alignEmptyValues = params.alignEmptyValues;
519  var emptyAlign = 0;
520 
521  //handle empty values
522  if (!as && as !== 0) {
523  emptyAlign = !bs && bs !== 0 ? 0 : -1;
524  } else if (!bs && bs !== 0) {
525  emptyAlign = 1;
526  } else {
527 
528  if (isFinite(as) && isFinite(bs)) return as - bs;
529  a = String(as).toLowerCase();
530  b = String(bs).toLowerCase();
531  if (a === b) return 0;
532  if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
533  a = a.match(rx);
534  b = b.match(rx);
535  L = a.length > b.length ? b.length : a.length;
536  while (i < L) {
537  a1 = a[i];
538  b1 = b[i++];
539  if (a1 !== b1) {
540  if (isFinite(a1) && isFinite(b1)) {
541  if (a1.charAt(0) === "0") a1 = "." + a1;
542  if (b1.charAt(0) === "0") b1 = "." + b1;
543  return a1 - b1;
544  } else return a1 > b1 ? 1 : -1;
545  }
546  }
547 
548  return a.length > b.length;
549  }
550 
551  //fix empty values in position
552  if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") {
553  emptyAlign *= -1;
554  }
555 
556  return emptyAlign;
557  }
558 };
559 
560 Tabulator.prototype.registerModule("sort", Sort);