UNPKG

mrnodebot

Version:
377 lines (336 loc) 14.5 kB
/** * TinySort is a small script that sorts HTML elements. It sorts by text- or attribute value, or by that of one of it's children. * @summary A nodeElement sorting script. * @version 2.2.0 * @license MIT/GPL * @author Ron Valstar <ron@ronvalstar.nl> * @copyright Ron Valstar <ron@ronvalstar.nl> * @namespace tinysort */ !(function (a, b) { function c() { return b; } typeof define === 'function' && define.amd ? define('tinysort', c) : a.tinysort = b; }(this, (function () { function a(a, f) { function j() { arguments.length === 0 ? s({}) : d(arguments, (a) => { s(c(a) ? { selector: a } : a); }), p = D.length; } function s(a) { const b = !!a.selector, c = b && a.selector[0] === ':', d = e(a || {}, r); D.push(e({ hasSelector: b, hasAttr: !(d.attr === i || d.attr === ''), hasData: d.data !== i, hasFilter: c, sortReturnNumber: d.order === 'asc' ? 1 : -1, }, d)); } function t() { d(a, (a, b) => { y ? y !== a.parentNode && (E = !1) : y = a.parentNode; const c = D[0], d = c.hasFilter; const e = c.selector; const f = !e || d && a.matchesSelector(e) || e && a.querySelector(e), g = f ? B : C, h = { elm: a, pos: b, posn: g.length }; A.push(h), g.push(h); }), x = B.slice(0); } function u() { B.sort(v); } function v(a, e) { let f = 0; for (q !== 0 && (q = 0); f === 0 && p > q;) { const i = D[q], j = i.ignoreDashes ? n : m; if (d(o, (a) => { const b = a.prepare; b && b(i); }), i.sortFunction) f = i.sortFunction(a, e); else if (i.order === 'rand') f = Math.random() < 0.5 ? 1 : -1; else { var k = h, r = b(a, i), s = b(e, i), t = r === '' || r === g, u = s === '' || s === g; if (r === s) f = 0; else if (i.emptyEnd && (t || u)) f = t && u ? 0 : t ? 1 : -1; else { if (!i.forceStrings) { const v = c(r) ? r && r.match(j) : h, w = c(s) ? s && s.match(j) : h; if (v && w) { const x = r.substr(0, r.length - v[0].length), y = s.substr(0, s.length - w[0].length); x === y && (k = !h, r = l(v[0]), s = l(w[0])); } } f = r === g || s === g ? 0 : s > r ? -1 : r > s ? 1 : 0; } } d(o, (a) => { const b = a.sort; b && (f = b(i, k, r, s, f)); }), f *= i.sortReturnNumber, f === 0 && q++; } return f === 0 && (f = a.pos > e.pos ? 1 : -1), f; } function w() { const a = B.length === A.length; E && a ? F ? B.forEach((a, b) => { a.elm.style.order = b; }) : (B.forEach((a) => { z.appendChild(a.elm); }), y.appendChild(z)) : (B.forEach((a) => { const b = a.elm, c = k.createElement('div'); a.ghost = c, b.parentNode.insertBefore(c, b); }), B.forEach((a, b) => { const c = x[b].ghost; c.parentNode.insertBefore(a.elm, c), c.parentNode.removeChild(c); })); } c(a) && (a = k.querySelectorAll(a)), a.length === 0 && console.warn('No elements to sort'); var x, y, z = k.createDocumentFragment(), A = [], B = [], C = [], D = [], E = !0, F = a.length && (f === g || f.useFlex !== !1) && getComputedStyle(a[0].parentNode, null).display.indexOf('flex') !== -1; return j.apply(i, Array.prototype.slice.call(arguments, 1)), t(), u(), w(), B.map(a => a.elm); } function b(a, b) { let d, e = a.elm; return b.selector && (b.hasFilter ? e.matchesSelector(b.selector) || (e = i) : e = e.querySelector(b.selector)), b.hasAttr ? d = e.getAttribute(b.attr) : b.useVal ? d = e.value || e.getAttribute('value') : b.hasData ? d = e.getAttribute(`data-${b.data}`) : e && (d = e.textContent), c(d) && (b.cases || (d = d.toLowerCase()), d = d.replace(/\s+/g, ' ')), d; } function c(a) { return typeof a === 'string'; } function d(a, b) { let c; const d = a.length; let e = d; for (; e--;) c = d - e - 1, b(a[c], c); } function e(a, b, c) { for (const d in b) (c || a[d] === g) && (a[d] = b[d]); return a; } function f(a, b, c) { o.push({ prepare: a, sort: b, sortBy: c }); } var g, h = !1, i = null, j = window, k = j.document, l = parseFloat, m = /(-?\d+\.?\d*)\s*$/g, n = /(\d+\.?\d*)\s*$/g, o = [], p = 0, q = 0, r = { selector: i, order: 'asc', attr: i, data: i, useVal: h, place: 'start', returns: h, cases: h, forceStrings: h, ignoreDashes: h, sortFunction: i, useFlex: h, emptyEnd: h, }; return j.Element && (function (a) { a.matchesSelector = a.matchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector || a.webkitMatchesSelector || function (a) { for (var b = this, c = (b.parentNode || b.document).querySelectorAll(a), d = -1; c[++d] && c[d] !== b;); return !!c[d]; }; }(Element.prototype)), e(f, { loop: d }), e(a, { plugin: f, defaults: r }); }()))); (function ($) { const $document = $(document); let signClass, sortEngine; $.bootstrapSortable = function (applyLast, sign, customSort) { // Check if moment.js is available const momentJsAvailable = (typeof moment !== 'undefined'); // Set class based on sign parameter signClass = !sign ? 'arrow' : sign; // Set sorting algorithm if (customSort === 'default') { customSort = defaultSortEngine; } sortEngine = customSort || sortEngine || defaultSortEngine; // Set attributes needed for sorting $('table.sortable').each(function () { const $this = $(this); applyLast = (applyLast === true); $this.find('span.sign').remove(); // Add placeholder cells for colspans $this.find('thead [colspan]').each(function () { const colspan = parseFloat($(this).attr('colspan')); for (let i = 1; i < colspan; i++) { $(this).after('<th class="colspan-compensate">'); } }); // Add placeholder cells for rowspans $this.find('thead [rowspan]').each(function () { const $cell = $(this); const rowspan = parseFloat($cell.attr('rowspan')); for (let i = 1; i < rowspan; i++) { const parentRow = $cell.parent('tr'); const nextRow = parentRow.next('tr'); const index = parentRow.children().index($cell); nextRow.children().eq(index).before('<th class="rowspan-compensate">'); } }); // Set indexes to header cells $this.find('thead tr').each(function (rowIndex) { $(this).find('th').each(function (columnIndex) { const $this = $(this); $this.addClass('nosort').removeClass('up down'); $this.attr('data-sortcolumn', columnIndex); $this.attr('data-sortkey', `${columnIndex}-${rowIndex}`); }); }); // Cleanup placeholder cells $this.find('thead .rowspan-compensate, .colspan-compensate').remove(); // Initialize sorting values $this.find('td').each(function () { const $this = $(this); if ($this.attr('data-dateformat') !== undefined && momentJsAvailable) { $this.attr('data-value', moment($this.text(), $this.attr('data-dateformat')).format('YYYY/MM/DD/HH/mm/ss')); } else { $this.attr('data-value') === undefined && $this.attr('data-value', $this.text()); } }); const context = lookupSortContext($this), bsSort = context.bsSort; $this.find('thead th[data-defaultsort!="disabled"]').each(function (index) { const $this = $(this); const $sortTable = $this.closest('table.sortable'); $this.data('sortTable', $sortTable); const sortKey = $this.attr('data-sortkey'); const thisLastSort = applyLast ? context.lastSort : -1; bsSort[sortKey] = applyLast ? bsSort[sortKey] : $this.attr('data-defaultsort'); if (bsSort[sortKey] !== undefined && (applyLast === (sortKey === thisLastSort))) { bsSort[sortKey] = bsSort[sortKey] === 'asc' ? 'desc' : 'asc'; doSort($this, $sortTable); } }); $this.trigger('sorted'); }); }; // Add click event to table header $document.on('click', 'table.sortable thead th[data-defaultsort!="disabled"]', function (e) { const $this = $(this), $table = $this.data('sortTable') || $this.closest('table.sortable'); $table.trigger('before-sort'); doSort($this, $table); $table.trigger('sorted'); }); // Look up sorting data appropriate for the specified table (jQuery element). // This allows multiple tables on one page without collisions. function lookupSortContext($table) { let context = $table.data('bootstrap-sortable-context'); if (context === undefined) { context = { bsSort: [], lastSort: undefined }; $table.find('thead th[data-defaultsort!="disabled"]').each(function (index) { const $this = $(this); const sortKey = $this.attr('data-sortkey'); context.bsSort[sortKey] = $this.attr('data-defaultsort'); if (context.bsSort[sortKey] !== undefined) { context.lastSort = sortKey; } }); $table.data('bootstrap-sortable-context', context); } return context; } function defaultSortEngine(rows, sortingParams) { tinysort(rows, sortingParams); } // Sorting mechanism separated function doSort($this, $table) { let sortColumn = parseFloat($this.attr('data-sortcolumn')); const context = lookupSortContext($table), bsSort = context.bsSort; const colspan = $this.attr('colspan'); if (colspan) { const mainSort = parseFloat($this.data('mainsort')) || 0; const rowIndex = parseFloat($this.data('sortkey').split('-').pop()); // If there is one more row in header, delve deeper if ($table.find('thead tr').length - 1 > rowIndex) { doSort($table.find(`[data-sortkey="${sortColumn + mainSort}-${rowIndex + 1}"]`), $table); return; } // Otherwise, just adjust the sortColumn sortColumn += mainSort; } const localSignClass = $this.attr('data-defaultsign') || signClass; // update arrow icon $table.find('th').each(function () { $(this).removeClass('up').removeClass('down').addClass('nosort'); }); if ($.browser.mozilla) { const moz_arrow = $table.find('div.mozilla'); if (moz_arrow !== undefined) { moz_arrow.find('.sign').remove(); moz_arrow.parent().html(moz_arrow.html()); } $this.wrapInner('<div class="mozilla"></div>'); $this.children().eq(0).append(`<span class="sign ${localSignClass}"></span>`); } else { $table.find('span.sign').remove(); $this.append(`<span class="sign ${localSignClass}"></span>`); } // sort direction const sortKey = $this.attr('data-sortkey'); const initialDirection = $this.attr('data-firstsort') !== 'desc' ? 'desc' : 'asc'; context.lastSort = sortKey; bsSort[sortKey] = (bsSort[sortKey] || initialDirection) === 'asc' ? 'desc' : 'asc'; if (bsSort[sortKey] === 'desc') { $this.find('span.sign').addClass('up'); $this.addClass('up').removeClass('down nosort'); } else { $this.addClass('down').removeClass('up nosort'); } // sort rows const rows = $table.children('tbody').children('tr'); sortEngine(rows, { selector: `td:nth-child(${sortColumn + 1})`, order: bsSort[sortKey], data: 'value' }); // add class to sorted column cells $table.find('td.sorted, th.sorted').removeClass('sorted'); rows.find(`td:eq(${sortColumn})`).addClass('sorted'); $this.addClass('sorted'); } // jQuery 1.9 removed this object if (!$.browser) { $.browser = { chrome: false, mozilla: false, opera: false, msie: false, safari: false, }; const ua = navigator.userAgent; $.each($.browser, (c) => { $.browser[c] = !!((new RegExp(c, 'i').test(ua))); if ($.browser.mozilla && c === 'mozilla') { $.browser.mozilla = !!((new RegExp('firefox', 'i').test(ua))); } if ($.browser.chrome && c === 'safari') { $.browser.safari = false; } }); } // Initialise on DOM ready $($.bootstrapSortable); }(jQuery));