Mercurial > nebulaweb3
view 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 source
/* * 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 })();