(function() { var SELECTOR, addEventListener, clickEvents, numberRegExp, sortable, touchDevice, trimRegExp; SELECTOR = 'table[data-sortable]'; numberRegExp = /^-?[£$¤]?[\d,.]+%?$/; trimRegExp = /^\s+|\s+$/g; clickEvents = ['click']; touchDevice = 'ontouchstart' in document.documentElement; if (touchDevice) { clickEvents.push('touchstart'); } addEventListener = function(el, event, handler) { if (el.addEventListener != null) { return el.addEventListener(event, handler, false); } else { return el.attachEvent("on" + event, handler); } }; sortable = { init: function(options) { var table, tables, _i, _len, _results; if (options == null) { options = {}; } if (options.selector == null) { options.selector = SELECTOR; } tables = document.querySelectorAll(options.selector); _results = []; for (_i = 0, _len = tables.length; _i < _len; _i++) { table = tables[_i]; _results.push(sortable.initTable(table)); } return _results; }, initTable: function(table) { var i, th, ths, _i, _len, _ref; if (((_ref = table.tHead) != null ? _ref.rows.length : void 0) !== 1) { return; } if (table.getAttribute('data-sortable-initialized') === 'true') { return; } table.setAttribute('data-sortable-initialized', 'true'); ths = table.querySelectorAll('th'); for (i = _i = 0, _len = ths.length; _i < _len; i = ++_i) { th = ths[i]; if (th.getAttribute('data-sortable') !== 'false') { sortable.setupClickableTH(table, th, i); } } return table; }, setupClickableTH: function(table, th, i) { var eventName, onClick, type, _i, _len, _results; type = sortable.getColumnType(table, i); onClick = function(e) { 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; if (e.handled !== true) { e.handled = true; } else { return false; } sorted = this.getAttribute('data-sorted') === 'true'; sortedDirection = this.getAttribute('data-sorted-direction'); if (sorted) { newSortedDirection = sortedDirection === 'ascending' ? 'descending' : 'ascending'; } else { newSortedDirection = type.defaultSortDirection; } ths = this.parentNode.querySelectorAll('th'); for (_i = 0, _len = ths.length; _i < _len; _i++) { th = ths[_i]; th.setAttribute('data-sorted', 'false'); th.removeAttribute('data-sorted-direction'); } this.setAttribute('data-sorted', 'true'); this.setAttribute('data-sorted-direction', newSortedDirection); tBody = table.tBodies[0]; rowArray = []; if (!sorted) { if (type.compare != null) { _compare = type.compare; } else { _compare = function(a, b) { return b - a; }; } compare = function(a, b) { if (a[0] === b[0]) { return a[2] - b[2]; } if (type.reverse) { return _compare(b[0], a[0]); } else { return _compare(a[0], b[0]); } }; _ref = tBody.rows; for (position = _j = 0, _len1 = _ref.length; _j < _len1; position = ++_j) { row = _ref[position]; value = sortable.getNodeValue(row.cells[i]); if (type.comparator != null) { value = type.comparator(value); } rowArray.push([value, row, position]); } rowArray.sort(compare); for (_k = 0, _len2 = rowArray.length; _k < _len2; _k++) { row = rowArray[_k]; tBody.appendChild(row[1]); } } else { _ref1 = tBody.rows; for (_l = 0, _len3 = _ref1.length; _l < _len3; _l++) { item = _ref1[_l]; rowArray.push(item); } rowArray.reverse(); for (_m = 0, _len4 = rowArray.length; _m < _len4; _m++) { row = rowArray[_m]; tBody.appendChild(row); } } if (typeof window['CustomEvent'] === 'function') { return typeof table.dispatchEvent === "function" ? table.dispatchEvent(new CustomEvent('Sortable.sorted', { bubbles: true })) : void 0; } }; _results = []; for (_i = 0, _len = clickEvents.length; _i < _len; _i++) { eventName = clickEvents[_i]; _results.push(addEventListener(th, eventName, onClick)); } return _results; }, getColumnType: function(table, i) { var row, specified, text, type, _i, _j, _len, _len1, _ref, _ref1, _ref2; specified = (_ref = table.querySelectorAll('th')[i]) != null ? _ref.getAttribute('data-sortable-type') : void 0; if (specified != null) { return sortable.typesObject[specified]; } _ref1 = table.tBodies[0].rows; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { row = _ref1[_i]; text = sortable.getNodeValue(row.cells[i]); _ref2 = sortable.types; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { type = _ref2[_j]; if (type.match(text)) { return type; } } } return sortable.typesObject.alpha; }, getNodeValue: function(node) { var dataValue; if (!node) { return ''; } dataValue = node.getAttribute('data-value'); if (dataValue !== null) { return dataValue; } if (typeof node.innerText !== 'undefined') { return node.innerText.replace(trimRegExp, ''); } return node.textContent.replace(trimRegExp, ''); }, setupTypes: function(types) { var type, _i, _len, _results; sortable.types = types; sortable.typesObject = {}; _results = []; for (_i = 0, _len = types.length; _i < _len; _i++) { type = types[_i]; _results.push(sortable.typesObject[type.name] = type); } return _results; } }; // ip type needs to go first to prevent 'numeric" from catching it // 3 dots = IPv4 // 2 colons = IPv6 // Crude but sufficient here sortable.setupTypes([ { name: 'ip', defaultSortDirection: 'ascending', match: function(a) { v4 = a.split(".").length; v6 = a.split(":").length; return ((v4 == 4) || (v6 > 2)); }, compare: function(a, b) { a = padip(a); b = padip(b); return ((a < b) ? -1 : ((a > b) ? 1 : 0)); } }, { name: 'numeric', defaultSortDirection: 'descending', match: function(a) { return a.match(numberRegExp); }, comparator: function(a) { return parseFloat(a.replace(/[^0-9.-]/g, ''), 10) || 0; } }, { name: 'date', defaultSortDirection: 'ascending', reverse: true, match: function(a) { return !isNaN(Date.parse(a)); }, comparator: function(a) { return Date.parse(a) || 0; } }, { name: 'alpha', defaultSortDirection: 'ascending', match: function() { return true; }, compare: function(a, b) { return a.localeCompare(b); } } ]); setTimeout(sortable.init, 0); if (typeof define === 'function' && define.amd) { define(function() { return sortable; }); } else if (typeof exports !== 'undefined') { module.exports = sortable; } else { window.Sortable = sortable; } }).call(this); // pad function is based on work by Dominique Fournier // https://www.datatables.net/plug-ins/sorting/ip-address function padip ( a ) { var i, item; var m = a.split("."), n = a.split(":"), x = "", xa = ""; if (m.length == 4) { // IPV4 for(i = 0; i < m.length; i++) { item = m[i]; if(item.length == 1) { x += "00" + item; } else if(item.length == 2) { x += "0" + item; } else { x += item; } } } else if (n.length > 0) { // IPV6 var count = 0; for(i = 0; i < n.length; i++) { item = n[i]; if (i > 0) { xa += ":"; } if(item.length === 0) { count += 0; } else if(item.length == 1) { xa += "000" + item; count += 4; } else if(item.length == 2) { xa += "00" + item; count += 4; } else if(item.length == 3) { xa += "0" + item; count += 4; } else { xa += item; count += 4; } } // Padding the :: n = xa.split(":"); var paddDone = 0; for (i = 0; i < n.length; i++) { item = n[i]; if (item.length === 0 && paddDone === 0) { for (var padding = 0 ; padding < (32-count) ; padding++) { x += "0"; paddDone = 1; } } else { x += item; } } } return x; }