diff default/node_modules/tablesaw/src/tables.swipetoggle.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.swipetoggle.js	Sat May 31 09:21:51 2025 +0800
@@ -0,0 +1,369 @@
+/*
+* tablesaw: A set of plugins for responsive tables
+* Swipe Toggle: swipe gesture (or buttons) to navigate which columns are shown.
+* Copyright (c) 2013 Filament Group, Inc.
+* MIT License
+*/
+
+(function() {
+	var classes = {
+		hideBtn: "disabled",
+		persistWidths: "tablesaw-fix-persist",
+		hiddenCol: "tablesaw-swipe-cellhidden",
+		persistCol: "tablesaw-swipe-cellpersist",
+		allColumnsVisible: "tablesaw-all-cols-visible"
+	};
+	var attrs = {
+		disableTouchEvents: "data-tablesaw-no-touch",
+		ignorerow: "data-tablesaw-ignorerow",
+		subrow: "data-tablesaw-subrow"
+	};
+
+	function createSwipeTable(tbl, $table) {
+		var tblsaw = $table.data("tablesaw");
+
+		var $btns = $("<div class='tablesaw-advance'></div>");
+		// TODO next major version: remove .btn
+		var $prevBtn = $(
+			"<a href='#' class='btn tablesaw-nav-btn tablesaw-btn btn-micro left'>" +
+				Tablesaw.i18n.swipePreviousColumn +
+				"</a>"
+		).appendTo($btns);
+		// TODO next major version: remove .btn
+		var $nextBtn = $(
+			"<a href='#' class='btn tablesaw-nav-btn tablesaw-btn btn-micro right'>" +
+				Tablesaw.i18n.swipeNextColumn +
+				"</a>"
+		).appendTo($btns);
+
+		var $headerCells = tbl._getPrimaryHeaderCells();
+		var $headerCellsNoPersist = $headerCells.not('[data-tablesaw-priority="persist"]');
+		var headerWidths = [];
+		var $head = $(document.head || "head");
+		var tableId = $table.attr("id");
+
+		if (!$headerCells.length) {
+			throw new Error("tablesaw swipe: no header cells found.");
+		}
+
+		$table.addClass("tablesaw-swipe");
+
+		function initMinHeaderWidths() {
+			$table.css({
+				width: "1px"
+			});
+
+			// remove any hidden columns
+			$table.find("." + classes.hiddenCol).removeClass(classes.hiddenCol);
+
+			headerWidths = [];
+			// Calculate initial widths
+			$headerCells.each(function() {
+				headerWidths.push(this.offsetWidth);
+			});
+
+			// reset props
+			$table.css({
+				width: ""
+			});
+		}
+
+		initMinHeaderWidths();
+
+		$btns.appendTo(tblsaw.$toolbar);
+
+		if (!tableId) {
+			tableId = "tableswipe-" + Math.round(Math.random() * 10000);
+			$table.attr("id", tableId);
+		}
+
+		function showColumn(headerCell) {
+			tblsaw._$getCells(headerCell).removeClass(classes.hiddenCol);
+		}
+
+		function hideColumn(headerCell) {
+			tblsaw._$getCells(headerCell).addClass(classes.hiddenCol);
+		}
+
+		function persistColumn(headerCell) {
+			tblsaw._$getCells(headerCell).addClass(classes.persistCol);
+		}
+
+		function isPersistent(headerCell) {
+			return $(headerCell).is('[data-tablesaw-priority="persist"]');
+		}
+
+		function unmaintainWidths() {
+			$table.removeClass(classes.persistWidths);
+			$("#" + tableId + "-persist").remove();
+		}
+
+		function maintainWidths() {
+			var prefix = "#" + tableId + ".tablesaw-swipe ",
+				styles = [],
+				tableWidth = $table.width(),
+				hash = [],
+				newHash;
+
+			// save persistent column widths (as long as they take up less than 75% of table width)
+			$headerCells.each(function(index) {
+				var width;
+				if (isPersistent(this)) {
+					width = this.offsetWidth;
+
+					if (width < tableWidth * 0.75) {
+						hash.push(index + "-" + width);
+						styles.push(
+							prefix +
+								" ." +
+								classes.persistCol +
+								":nth-child(" +
+								(index + 1) +
+								") { width: " +
+								width +
+								"px; }"
+						);
+					}
+				}
+			});
+			newHash = hash.join("_");
+
+			if (styles.length) {
+				$table.addClass(classes.persistWidths);
+				var $style = $("#" + tableId + "-persist");
+				// If style element not yet added OR if the widths have changed
+				if (!$style.length || $style.data("tablesaw-hash") !== newHash) {
+					// Remove existing
+					$style.remove();
+
+					$("<style>" + styles.join("\n") + "</style>")
+						.attr("id", tableId + "-persist")
+						.data("tablesaw-hash", newHash)
+						.appendTo($head);
+				}
+			}
+		}
+
+		function getNext() {
+			var next = [],
+				checkFound;
+
+			$headerCellsNoPersist.each(function(i) {
+				var $t = $(this),
+					isHidden = $t.css("display") === "none" || $t.is("." + classes.hiddenCol);
+
+				if (!isHidden && !checkFound) {
+					checkFound = true;
+					next[0] = i;
+				} else if (isHidden && checkFound) {
+					next[1] = i;
+
+					return false;
+				}
+			});
+
+			return next;
+		}
+
+		function getPrev() {
+			var next = getNext();
+			return [next[1] - 1, next[0] - 1];
+		}
+
+		function nextpair(fwd) {
+			return fwd ? getNext() : getPrev();
+		}
+
+		function canAdvance(pair) {
+			return pair[1] > -1 && pair[1] < $headerCellsNoPersist.length;
+		}
+
+		function matchesMedia() {
+			var matchMedia = $table.attr("data-tablesaw-swipe-media");
+			return !matchMedia || ("matchMedia" in window && window.matchMedia(matchMedia).matches);
+		}
+
+		function fakeBreakpoints() {
+			if (!matchesMedia()) {
+				return;
+			}
+
+			var containerWidth = $table.parent().width(),
+				persist = [],
+				sum = 0,
+				sums = [],
+				visibleNonPersistantCount = $headerCells.length;
+
+			$headerCells.each(function(index) {
+				var $t = $(this),
+					isPersist = $t.is('[data-tablesaw-priority="persist"]');
+
+				persist.push(isPersist);
+				sum += headerWidths[index];
+				sums.push(sum);
+
+				// is persistent or is hidden
+				if (isPersist || sum > containerWidth) {
+					visibleNonPersistantCount--;
+				}
+			});
+
+			// We need at least one column to swipe.
+			var needsNonPersistentColumn = visibleNonPersistantCount === 0;
+
+			$headerCells.each(function(index) {
+				if (sums[index] > containerWidth) {
+					hideColumn(this);
+				}
+			});
+
+			$headerCells.each(function(index) {
+				if (persist[index]) {
+					// for visual box-shadow
+					persistColumn(this);
+					return;
+				}
+
+				if (sums[index] <= containerWidth || needsNonPersistentColumn) {
+					needsNonPersistentColumn = false;
+					showColumn(this);
+					tblsaw.updateColspanCells(classes.hiddenCol, this, true);
+				}
+			});
+
+			unmaintainWidths();
+
+			$table.trigger("tablesawcolumns");
+		}
+
+		function advance(fwd) {
+			var pair = nextpair(fwd);
+			if (canAdvance(pair)) {
+				if (isNaN(pair[0])) {
+					if (fwd) {
+						pair[0] = 0;
+					} else {
+						pair[0] = $headerCellsNoPersist.length - 1;
+					}
+				}
+
+				// TODO just blindly hiding the previous column and showing the next column can result in
+				// column content overflow
+				maintainWidths();
+				hideColumn($headerCellsNoPersist.get(pair[0]));
+				tblsaw.updateColspanCells(classes.hiddenCol, $headerCellsNoPersist.get(pair[0]), false);
+
+				showColumn($headerCellsNoPersist.get(pair[1]));
+				tblsaw.updateColspanCells(classes.hiddenCol, $headerCellsNoPersist.get(pair[1]), true);
+
+				$table.trigger("tablesawcolumns");
+			}
+		}
+
+		$prevBtn.add($nextBtn).on("click", function(e) {
+			advance(!!$(e.target).closest($nextBtn).length);
+			e.preventDefault();
+		});
+
+		function getCoord(event, key) {
+			return (event.touches || event.originalEvent.touches)[0][key];
+		}
+
+		if (!$table.is("[" + attrs.disableTouchEvents + "]")) {
+			$table.on("touchstart.swipetoggle", function(e) {
+				var originX = getCoord(e, "pageX");
+				var originY = getCoord(e, "pageY");
+				var x;
+				var y;
+				var scrollTop = window.pageYOffset;
+
+				$(window).off(Tablesaw.events.resize, fakeBreakpoints);
+
+				$(this)
+					.on("touchmove.swipetoggle", function(e) {
+						x = getCoord(e, "pageX");
+						y = getCoord(e, "pageY");
+					})
+					.on("touchend.swipetoggle", function() {
+						var cfg = tbl.getConfig({
+							swipeHorizontalThreshold: 30,
+							swipeVerticalThreshold: 30
+						});
+
+						// This config code is a little awkward because shoestring doesn’t support deep $.extend
+						// Trying to work around when devs only override one of (not both) horizontalThreshold or
+						// verticalThreshold in their TablesawConfig.
+						// @TODO major version bump: remove cfg.swipe, move to just use the swipePrefix keys
+						var verticalThreshold = cfg.swipe
+							? cfg.swipe.verticalThreshold
+							: cfg.swipeVerticalThreshold;
+						var horizontalThreshold = cfg.swipe
+							? cfg.swipe.horizontalThreshold
+							: cfg.swipeHorizontalThreshold;
+
+						var isPageScrolled = Math.abs(window.pageYOffset - scrollTop) >= verticalThreshold;
+						var isVerticalSwipe = Math.abs(y - originY) >= verticalThreshold;
+
+						if (!isVerticalSwipe && !isPageScrolled) {
+							if (x - originX < -1 * horizontalThreshold) {
+								advance(true);
+							}
+							if (x - originX > horizontalThreshold) {
+								advance(false);
+							}
+						}
+
+						window.setTimeout(function() {
+							$(window).on(Tablesaw.events.resize, fakeBreakpoints);
+						}, 300);
+
+						$(this).off("touchmove.swipetoggle touchend.swipetoggle");
+					});
+			});
+		}
+
+		$table
+			.on("tablesawcolumns.swipetoggle", function() {
+				var canGoPrev = canAdvance(getPrev());
+				var canGoNext = canAdvance(getNext());
+				$prevBtn[canGoPrev ? "removeClass" : "addClass"](classes.hideBtn);
+				$nextBtn[canGoNext ? "removeClass" : "addClass"](classes.hideBtn);
+
+				tblsaw.$toolbar[!canGoPrev && !canGoNext ? "addClass" : "removeClass"](
+					classes.allColumnsVisible
+				);
+			})
+			.on("tablesawnext.swipetoggle", function() {
+				advance(true);
+			})
+			.on("tablesawprev.swipetoggle", function() {
+				advance(false);
+			})
+			.on(Tablesaw.events.destroy + ".swipetoggle", function() {
+				var $t = $(this);
+
+				$t.removeClass("tablesaw-swipe");
+				tblsaw.$toolbar.find(".tablesaw-advance").remove();
+				$(window).off(Tablesaw.events.resize, fakeBreakpoints);
+
+				$t.off(".swipetoggle");
+			})
+			.on(Tablesaw.events.refresh, function() {
+				unmaintainWidths();
+				initMinHeaderWidths();
+				fakeBreakpoints();
+			});
+
+		fakeBreakpoints();
+		$(window).on(Tablesaw.events.resize, fakeBreakpoints);
+	}
+
+	// on tablecreate, init
+	$(document).on(Tablesaw.events.create, function(e, tablesaw) {
+		if (tablesaw.mode === "swipe") {
+			createSwipeTable(tablesaw, tablesaw.$table);
+		}
+	});
+
+	// TODO OOP this and add to Tablesaw object
+})();