Mercurial > nebulaweb3
diff default/node_modules/tablesaw/src/tables.sortable.js @ 0:1d038bc9b3d2 default tip
Up:default
author | Liny <dev@neowd.com> |
---|---|
date | Sat, 31 May 2025 09:21:51 +0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/default/node_modules/tablesaw/src/tables.sortable.js Sat May 31 09:21:51 2025 +0800 @@ -0,0 +1,392 @@ +/* +* tablesaw: A set of plugins for responsive tables +* Sortable column headers +* Copyright (c) 2013 Filament Group, Inc. +* MIT License +*/ + +(function() { + function getSortValue(cell) { + var text = []; + $(cell.childNodes).each(function() { + var $el = $(this); + if ($el.is("input, select")) { + text.push($el.val()); + } else if ($el.is(".tablesaw-cell-label")) { + } else { + text.push(($el.text() || "").replace(/^\s+|\s+$/g, "")); + } + }); + + return text.join(""); + } + + var pluginName = "tablesaw-sortable", + initSelector = "table[data-" + pluginName + "]", + sortableSwitchSelector = "[data-" + pluginName + "-switch]", + attrs = { + sortCol: "data-tablesaw-sortable-col", + defaultCol: "data-tablesaw-sortable-default-col", + numericCol: "data-tablesaw-sortable-numeric", + subRow: "data-tablesaw-subrow", + ignoreRow: "data-tablesaw-ignorerow" + }, + classes = { + head: pluginName + "-head", + ascend: pluginName + "-ascending", + descend: pluginName + "-descending", + switcher: pluginName + "-switch", + tableToolbar: "tablesaw-bar-section", + sortButton: pluginName + "-btn" + }, + methods = { + _create: function(o) { + return $(this).each(function() { + var init = $(this).data(pluginName + "-init"); + if (init) { + return false; + } + $(this) + .data(pluginName + "-init", true) + .trigger("beforecreate." + pluginName) + [pluginName]("_init", o) + .trigger("create." + pluginName); + }); + }, + _init: function() { + var el = $(this); + var tblsaw = el.data("tablesaw"); + var heads; + var $switcher; + + function addClassToHeads(h) { + $.each(h, function(i, v) { + $(v).addClass(classes.head); + }); + } + + function makeHeadsActionable(h, fn) { + $.each(h, function(i, col) { + var b = $("<button class='" + classes.sortButton + "'/>"); + b.on("click", { col: col }, fn); + $(col) + .wrapInner(b) + .find("button") + .append("<span class='tablesaw-sortable-arrow'>"); + }); + } + + function clearOthers(headcells) { + $.each(headcells, function(i, v) { + var col = $(v); + col.removeAttr(attrs.defaultCol); + col.removeClass(classes.ascend); + col.removeClass(classes.descend); + }); + } + + function headsOnAction(e) { + if ($(e.target).is("a[href]")) { + return; + } + + e.stopPropagation(); + var headCell = $(e.target).closest("[" + attrs.sortCol + "]"), + v = e.data.col, + newSortValue = heads.index(headCell[0]); + + clearOthers( + headCell + .closest("thead") + .find("th") + .filter(function() { + return this !== headCell[0]; + }) + ); + if (headCell.is("." + classes.descend) || !headCell.is("." + classes.ascend)) { + el[pluginName]("sortBy", v, true); + newSortValue += "_asc"; + } else { + el[pluginName]("sortBy", v); + newSortValue += "_desc"; + } + if ($switcher) { + $switcher + .find("select") + .val(newSortValue) + .trigger("refresh"); + } + + e.preventDefault(); + } + + function handleDefault(heads) { + $.each(heads, function(idx, el) { + var $el = $(el); + if ($el.is("[" + attrs.defaultCol + "]")) { + if (!$el.is("." + classes.descend)) { + $el.addClass(classes.ascend); + } + } + }); + } + + function addSwitcher(heads) { + $switcher = $("<div>") + .addClass(classes.switcher) + .addClass(classes.tableToolbar); + + var html = ["<label>" + Tablesaw.i18n.sort + ":"]; + + // TODO next major version: remove .btn + html.push('<span class="btn tablesaw-btn"><select>'); + heads.each(function(j) { + var $t = $(this); + var isDefaultCol = $t.is("[" + attrs.defaultCol + "]"); + var isDescending = $t.is("." + classes.descend); + + var hasNumericAttribute = $t.is("[" + attrs.numericCol + "]"); + var numericCount = 0; + // Check only the first four rows to see if the column is numbers. + var numericCountMax = 5; + + $(this.cells.slice(0, numericCountMax)).each(function() { + if (!isNaN(parseInt(getSortValue(this), 10))) { + numericCount++; + } + }); + var isNumeric = numericCount === numericCountMax; + if (!hasNumericAttribute) { + $t.attr(attrs.numericCol, isNumeric ? "" : "false"); + } + + html.push( + "<option" + + (isDefaultCol && !isDescending ? " selected" : "") + + ' value="' + + j + + '_asc">' + + $t.text() + + " " + + (isNumeric ? "↑" : "(A-Z)") + + "</option>" + ); + html.push( + "<option" + + (isDefaultCol && isDescending ? " selected" : "") + + ' value="' + + j + + '_desc">' + + $t.text() + + " " + + (isNumeric ? "↓" : "(Z-A)") + + "</option>" + ); + }); + html.push("</select></span></label>"); + + $switcher.html(html.join("")); + + var $firstChild = tblsaw.$toolbar.children().eq(0); + if ($firstChild.length) { + $switcher.insertBefore($firstChild); + } else { + $switcher.appendTo(tblsaw.$toolbar); + } + $switcher.find(".tablesaw-btn").tablesawbtn(); + $switcher.find("select").on("change", function() { + var val = $(this) + .val() + .split("_"), + head = heads.eq(val[0]); + + clearOthers(head.siblings()); + el[pluginName]("sortBy", head.get(0), val[1] === "asc"); + }); + } + + el.addClass(pluginName); + + heads = el + .children() + .filter("thead") + .find("th[" + attrs.sortCol + "]"); + + addClassToHeads(heads); + makeHeadsActionable(heads, headsOnAction); + handleDefault(heads); + + if (el.is(sortableSwitchSelector)) { + addSwitcher(heads); + } + }, + sortRows: function(rows, colNum, ascending, col, tbody) { + function convertCells(cellArr, belongingToTbody) { + var cells = []; + $.each(cellArr, function(i, cell) { + var row = cell.parentNode; + var $row = $(row); + // next row is a subrow + var subrows = []; + var $next = $row.next(); + while ($next.is("[" + attrs.subRow + "]")) { + subrows.push($next[0]); + $next = $next.next(); + } + + var tbody = row.parentNode; + + // current row is a subrow + if ($row.is("[" + attrs.subRow + "]")) { + } else if (tbody === belongingToTbody) { + cells.push({ + element: cell, + cell: getSortValue(cell), + row: row, + subrows: subrows.length ? subrows : null, + ignored: $row.is("[" + attrs.ignoreRow + "]") + }); + } + }); + return cells; + } + + function getSortFxn(ascending, forceNumeric) { + var fn, + regex = /[^\-\+\d\.]/g; + if (ascending) { + fn = function(a, b) { + if (a.ignored || b.ignored) { + return 0; + } + if (forceNumeric) { + return ( + parseFloat(a.cell.replace(regex, "")) - parseFloat(b.cell.replace(regex, "")) + ); + } else { + return a.cell.toLowerCase() > b.cell.toLowerCase() ? 1 : -1; + } + }; + } else { + fn = function(a, b) { + if (a.ignored || b.ignored) { + return 0; + } + if (forceNumeric) { + return ( + parseFloat(b.cell.replace(regex, "")) - parseFloat(a.cell.replace(regex, "")) + ); + } else { + return a.cell.toLowerCase() < b.cell.toLowerCase() ? 1 : -1; + } + }; + } + return fn; + } + + function convertToRows(sorted) { + var newRows = [], + i, + l; + for (i = 0, l = sorted.length; i < l; i++) { + newRows.push(sorted[i].row); + if (sorted[i].subrows) { + newRows.push(sorted[i].subrows); + } + } + return newRows; + } + + var fn; + var sorted; + var cells = convertCells(col.cells, tbody); + + var customFn = $(col).data("tablesaw-sort"); + + fn = + (customFn && typeof customFn === "function" ? customFn(ascending) : false) || + getSortFxn( + ascending, + $(col).is("[" + attrs.numericCol + "]") && + !$(col).is("[" + attrs.numericCol + '="false"]') + ); + + sorted = cells.sort(fn); + + rows = convertToRows(sorted); + + return rows; + }, + makeColDefault: function(col, a) { + var c = $(col); + c.attr(attrs.defaultCol, "true"); + if (a) { + c.removeClass(classes.descend); + c.addClass(classes.ascend); + } else { + c.removeClass(classes.ascend); + c.addClass(classes.descend); + } + }, + sortBy: function(col, ascending) { + var el = $(this); + var colNum; + var tbl = el.data("tablesaw"); + tbl.$tbody.each(function() { + var tbody = this; + var $tbody = $(this); + var rows = tbl.getBodyRows(tbody); + var sortedRows; + var map = tbl.headerMapping[0]; + var j, k; + + // find the column number that we’re sorting + for (j = 0, k = map.length; j < k; j++) { + if (map[j] === col) { + colNum = j; + break; + } + } + + sortedRows = el[pluginName]("sortRows", rows, colNum, ascending, col, tbody); + + // replace Table rows + for (j = 0, k = sortedRows.length; j < k; j++) { + $tbody.append(sortedRows[j]); + } + }); + + el[pluginName]("makeColDefault", col, ascending); + + el.trigger("tablesaw-sorted"); + } + }; + + // Collection method. + $.fn[pluginName] = function(arrg) { + var args = Array.prototype.slice.call(arguments, 1), + returnVal; + + // if it's a method + if (arrg && typeof arrg === "string") { + returnVal = $.fn[pluginName].prototype[arrg].apply(this[0], args); + return typeof returnVal !== "undefined" ? returnVal : $(this); + } + // check init + if (!$(this).data(pluginName + "-active")) { + $(this).data(pluginName + "-active", true); + $.fn[pluginName].prototype._create.call(this, arrg); + } + return $(this); + }; + // add methods + $.extend($.fn[pluginName].prototype, methods); + + $(document).on(Tablesaw.events.create, function(e, Tablesaw) { + if (Tablesaw.$table.is(initSelector)) { + Tablesaw.$table[pluginName](); + } + }); + + // TODO OOP this and add to Tablesaw object +})();