sorttable.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. (function() {
  2. var SELECTOR, addEventListener, clickEvents, numberRegExp, sortable, touchDevice, trimRegExp;
  3. SELECTOR = 'table[data-sortable]';
  4. numberRegExp = /^-?[£$¤]?[\d,.]+%?$/;
  5. trimRegExp = /^\s+|\s+$/g;
  6. clickEvents = ['click'];
  7. touchDevice = 'ontouchstart' in document.documentElement;
  8. if (touchDevice) {
  9. clickEvents.push('touchstart');
  10. }
  11. addEventListener = function(el, event, handler) {
  12. if (el.addEventListener != null) {
  13. return el.addEventListener(event, handler, false);
  14. } else {
  15. return el.attachEvent("on" + event, handler);
  16. }
  17. };
  18. sortable = {
  19. init: function(options) {
  20. var table, tables, _i, _len, _results;
  21. if (options == null) {
  22. options = {};
  23. }
  24. if (options.selector == null) {
  25. options.selector = SELECTOR;
  26. }
  27. tables = document.querySelectorAll(options.selector);
  28. _results = [];
  29. for (_i = 0, _len = tables.length; _i < _len; _i++) {
  30. table = tables[_i];
  31. _results.push(sortable.initTable(table));
  32. }
  33. return _results;
  34. },
  35. initTable: function(table) {
  36. var i, th, ths, _i, _len, _ref;
  37. if (((_ref = table.tHead) != null ? _ref.rows.length : void 0) !== 1) {
  38. return;
  39. }
  40. if (table.getAttribute('data-sortable-initialized') === 'true') {
  41. return;
  42. }
  43. table.setAttribute('data-sortable-initialized', 'true');
  44. ths = table.querySelectorAll('th');
  45. for (i = _i = 0, _len = ths.length; _i < _len; i = ++_i) {
  46. th = ths[i];
  47. if (th.getAttribute('data-sortable') !== 'false') {
  48. sortable.setupClickableTH(table, th, i);
  49. }
  50. }
  51. return table;
  52. },
  53. setupClickableTH: function(table, th, i) {
  54. var eventName, onClick, type, _i, _len, _results;
  55. type = sortable.getColumnType(table, i);
  56. onClick = function(e) {
  57. var compare, item, newSortedDirection, position, row, rowArray, sorted, sortedDirection, tBody, ths, value, _compare, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1;
  58. if (e.handled !== true) {
  59. e.handled = true;
  60. } else {
  61. return false;
  62. }
  63. sorted = this.getAttribute('data-sorted') === 'true';
  64. sortedDirection = this.getAttribute('data-sorted-direction');
  65. if (sorted) {
  66. newSortedDirection = sortedDirection === 'ascending' ? 'descending' : 'ascending';
  67. } else {
  68. newSortedDirection = type.defaultSortDirection;
  69. }
  70. ths = this.parentNode.querySelectorAll('th');
  71. for (_i = 0, _len = ths.length; _i < _len; _i++) {
  72. th = ths[_i];
  73. th.setAttribute('data-sorted', 'false');
  74. th.removeAttribute('data-sorted-direction');
  75. }
  76. this.setAttribute('data-sorted', 'true');
  77. this.setAttribute('data-sorted-direction', newSortedDirection);
  78. tBody = table.tBodies[0];
  79. rowArray = [];
  80. if (!sorted) {
  81. if (type.compare != null) {
  82. _compare = type.compare;
  83. } else {
  84. _compare = function(a, b) {
  85. return b - a;
  86. };
  87. }
  88. compare = function(a, b) {
  89. if (a[0] === b[0]) {
  90. return a[2] - b[2];
  91. }
  92. if (type.reverse) {
  93. return _compare(b[0], a[0]);
  94. } else {
  95. return _compare(a[0], b[0]);
  96. }
  97. };
  98. _ref = tBody.rows;
  99. for (position = _j = 0, _len1 = _ref.length; _j < _len1; position = ++_j) {
  100. row = _ref[position];
  101. value = sortable.getNodeValue(row.cells[i]);
  102. if (type.comparator != null) {
  103. value = type.comparator(value);
  104. }
  105. rowArray.push([value, row, position]);
  106. }
  107. rowArray.sort(compare);
  108. for (_k = 0, _len2 = rowArray.length; _k < _len2; _k++) {
  109. row = rowArray[_k];
  110. tBody.appendChild(row[1]);
  111. }
  112. } else {
  113. _ref1 = tBody.rows;
  114. for (_l = 0, _len3 = _ref1.length; _l < _len3; _l++) {
  115. item = _ref1[_l];
  116. rowArray.push(item);
  117. }
  118. rowArray.reverse();
  119. for (_m = 0, _len4 = rowArray.length; _m < _len4; _m++) {
  120. row = rowArray[_m];
  121. tBody.appendChild(row);
  122. }
  123. }
  124. if (typeof window['CustomEvent'] === 'function') {
  125. return typeof table.dispatchEvent === "function" ? table.dispatchEvent(new CustomEvent('Sortable.sorted', {
  126. bubbles: true
  127. })) : void 0;
  128. }
  129. };
  130. _results = [];
  131. for (_i = 0, _len = clickEvents.length; _i < _len; _i++) {
  132. eventName = clickEvents[_i];
  133. _results.push(addEventListener(th, eventName, onClick));
  134. }
  135. return _results;
  136. },
  137. getColumnType: function(table, i) {
  138. var row, specified, text, type, _i, _j, _len, _len1, _ref, _ref1, _ref2;
  139. specified = (_ref = table.querySelectorAll('th')[i]) != null ? _ref.getAttribute('data-sortable-type') : void 0;
  140. if (specified != null) {
  141. return sortable.typesObject[specified];
  142. }
  143. _ref1 = table.tBodies[0].rows;
  144. for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
  145. row = _ref1[_i];
  146. text = sortable.getNodeValue(row.cells[i]);
  147. _ref2 = sortable.types;
  148. for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
  149. type = _ref2[_j];
  150. if (type.match(text)) {
  151. return type;
  152. }
  153. }
  154. }
  155. return sortable.typesObject.alpha;
  156. },
  157. getNodeValue: function(node) {
  158. var dataValue;
  159. if (!node) {
  160. return '';
  161. }
  162. dataValue = node.getAttribute('data-value');
  163. if (dataValue !== null) {
  164. return dataValue;
  165. }
  166. if (typeof node.innerText !== 'undefined') {
  167. return node.innerText.replace(trimRegExp, '');
  168. }
  169. return node.textContent.replace(trimRegExp, '');
  170. },
  171. setupTypes: function(types) {
  172. var type, _i, _len, _results;
  173. sortable.types = types;
  174. sortable.typesObject = {};
  175. _results = [];
  176. for (_i = 0, _len = types.length; _i < _len; _i++) {
  177. type = types[_i];
  178. _results.push(sortable.typesObject[type.name] = type);
  179. }
  180. return _results;
  181. }
  182. };
  183. sortable.setupTypes([
  184. {
  185. name: 'numeric',
  186. defaultSortDirection: 'descending',
  187. match: function(a) {
  188. return a.match(numberRegExp);
  189. },
  190. comparator: function(a) {
  191. return parseFloat(a.replace(/[^0-9.-]/g, ''), 10) || 0;
  192. }
  193. }, {
  194. name: 'date',
  195. defaultSortDirection: 'ascending',
  196. reverse: true,
  197. match: function(a) {
  198. return !isNaN(Date.parse(a));
  199. },
  200. comparator: function(a) {
  201. return Date.parse(a) || 0;
  202. }
  203. }, {
  204. name: 'alpha',
  205. defaultSortDirection: 'ascending',
  206. match: function() {
  207. return true;
  208. },
  209. compare: function(a, b) {
  210. return a.localeCompare(b);
  211. }
  212. }
  213. ]);
  214. setTimeout(sortable.init, 0);
  215. if (typeof define === 'function' && define.amd) {
  216. define(function() {
  217. return sortable;
  218. });
  219. } else if (typeof exports !== 'undefined') {
  220. module.exports = sortable;
  221. } else {
  222. window.Sortable = sortable;
  223. }
  224. }).call(this);