view default/node_modules/tablesaw/src/tables.columntoggle.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
* Column Toggle: allows the user to toggle which columns are visible.
* Copyright (c) 2013 Filament Group, Inc.
* MIT License
*/

(function() {
	var data = {
		key: "tablesaw-coltoggle"
	};

	var ColumnToggle = function(element) {
		this.$table = $(element);

		if (!this.$table.length) {
			return;
		}

		this.tablesaw = this.$table.data("tablesaw");

		this.attributes = {
			btnTarget: "data-tablesaw-columntoggle-btn-target",
			set: "data-tablesaw-columntoggle-set"
		};

		this.classes = {
			columnToggleTable: "tablesaw-columntoggle",
			columnBtnContain: "tablesaw-columntoggle-btnwrap tablesaw-advance",
			columnBtn: "tablesaw-columntoggle-btn tablesaw-nav-btn down",
			popup: "tablesaw-columntoggle-popup",
			priorityPrefix: "tablesaw-priority-"
		};

		this.set = [];
		this.$headers = this.tablesaw._getPrimaryHeaderCells();

		this.$table.data(data.key, this);
	};

	// Column Toggle Sets (one column chooser can control multiple tables)
	ColumnToggle.prototype.initSet = function() {
		var set = this.$table.attr(this.attributes.set);
		if (set) {
			// Should not include the current table
			var table = this.$table[0];
			this.set = $("table[" + this.attributes.set + "='" + set + "']")
				.filter(function() {
					return this !== table;
				})
				.get();
		}
	};

	ColumnToggle.prototype.init = function() {
		if (!this.$table.length) {
			return;
		}

		var tableId,
			id,
			$menuButton,
			$popup,
			$menu,
			$btnContain,
			self = this;

		var cfg = this.tablesaw.getConfig({
			getColumnToggleLabelTemplate: function(text) {
				return "<label><input type='checkbox' checked>" + text + "</label>";
			}
		});

		this.$table.addClass(this.classes.columnToggleTable);

		tableId = this.$table.attr("id");
		id = tableId + "-popup";
		$btnContain = $("<div class='" + this.classes.columnBtnContain + "'></div>");
		// TODO next major version: remove .btn
		$menuButton = $(
			"<a href='#" +
				id +
				"' class='btn tablesaw-btn btn-micro " +
				this.classes.columnBtn +
				"' data-popup-link>" +
				"<span>" +
				Tablesaw.i18n.columnToggleButton +
				"</span></a>"
		);
		$popup = $("<div class='" + this.classes.popup + "' id='" + id + "'></div>");
		$menu = $("<div class='btn-group'></div>");

		this.$popup = $popup;

		var hasNonPersistentHeaders = false;
		this.$headers.each(function() {
			var $this = $(this),
				priority = $this.attr("data-tablesaw-priority"),
				$cells = self.tablesaw._$getCells(this);

			if (priority && priority !== "persist") {
				$cells.addClass(self.classes.priorityPrefix + priority);

				$(cfg.getColumnToggleLabelTemplate($this.text()))
					.appendTo($menu)
					.find('input[type="checkbox"]')
					.data("tablesaw-header", this);

				hasNonPersistentHeaders = true;
			}
		});

		if (!hasNonPersistentHeaders) {
			$menu.append("<label>" + Tablesaw.i18n.columnToggleError + "</label>");
		}

		$menu.appendTo($popup);

		function onToggleCheckboxChange(checkbox) {
			var checked = checkbox.checked;

			var header = self.getHeaderFromCheckbox(checkbox);
			var $cells = self.tablesaw._$getCells(header);

			$cells[!checked ? "addClass" : "removeClass"]("tablesaw-toggle-cellhidden");
			$cells[checked ? "addClass" : "removeClass"]("tablesaw-toggle-cellvisible");

			self.updateColspanCells(header, checked);

			self.$table.trigger("tablesawcolumns");
		}

		// bind change event listeners to inputs - TODO: move to a private method?
		$menu.find('input[type="checkbox"]').on("change", function(e) {
			onToggleCheckboxChange(e.target);

			if (self.set.length) {
				var index;
				$(self.$popup)
					.find("input[type='checkbox']")
					.each(function(j) {
						if (this === e.target) {
							index = j;
							return false;
						}
					});

				$(self.set).each(function() {
					var checkbox = $(this)
						.data(data.key)
						.$popup.find("input[type='checkbox']")
						.get(index);
					if (checkbox) {
						checkbox.checked = e.target.checked;
						onToggleCheckboxChange(checkbox);
					}
				});
			}
		});

		$menuButton.appendTo($btnContain);

		// Use a different target than the toolbar
		var $btnTarget = $(this.$table.attr(this.attributes.btnTarget));
		$btnContain.appendTo($btnTarget.length ? $btnTarget : this.tablesaw.$toolbar);

		function closePopup(event) {
			// Click came from inside the popup, ignore.
			if (event && $(event.target).closest("." + self.classes.popup).length) {
				return;
			}

			$(document).off("click." + tableId);
			$menuButton.removeClass("up").addClass("down");
			$btnContain.removeClass("visible");
		}

		var closeTimeout;
		function openPopup() {
			$btnContain.addClass("visible");
			$menuButton.removeClass("down").addClass("up");

			$(document).off("click." + tableId, closePopup);

			window.clearTimeout(closeTimeout);
			closeTimeout = window.setTimeout(function() {
				$(document).on("click." + tableId, closePopup);
			}, 15);
		}

		$menuButton.on("click.tablesaw", function(event) {
			event.preventDefault();

			if (!$btnContain.is(".visible")) {
				openPopup();
			} else {
				closePopup();
			}
		});

		$popup.appendTo($btnContain);

		this.$menu = $menu;

		// Fix for iOS not rendering shadows correctly when using `-webkit-overflow-scrolling`
		var $overflow = this.$table.closest(".tablesaw-overflow");
		if ($overflow.css("-webkit-overflow-scrolling")) {
			var timeout;
			$overflow.on("scroll", function() {
				var $div = $(this);
				window.clearTimeout(timeout);
				timeout = window.setTimeout(function() {
					$div.css("-webkit-overflow-scrolling", "auto");
					window.setTimeout(function() {
						$div.css("-webkit-overflow-scrolling", "touch");
					}, 0);
				}, 100);
			});
		}

		$(window).on(Tablesaw.events.resize + "." + tableId, function() {
			self.refreshToggle();
		});

		this.initSet();
		this.refreshToggle();
	};

	ColumnToggle.prototype.getHeaderFromCheckbox = function(checkbox) {
		return $(checkbox).data("tablesaw-header");
	};

	ColumnToggle.prototype.refreshToggle = function() {
		var self = this;
		var invisibleColumns = 0;
		this.$menu.find("input").each(function() {
			var header = self.getHeaderFromCheckbox(this);
			this.checked =
				self.tablesaw
					._$getCells(header)
					.eq(0)
					.css("display") === "table-cell";
		});

		this.updateColspanCells();
	};

	ColumnToggle.prototype.updateColspanCells = function(header, userAction) {
		this.tablesaw.updateColspanCells("tablesaw-toggle-cellhidden", header, userAction);
	};

	ColumnToggle.prototype.destroy = function() {
		this.$table.removeClass(this.classes.columnToggleTable);
		this.$table.find("th, td").each(function() {
			var $cell = $(this);
			$cell.removeClass("tablesaw-toggle-cellhidden").removeClass("tablesaw-toggle-cellvisible");

			this.className = this.className.replace(/\bui\-table\-priority\-\d\b/g, "");
		});
	};

	// on tablecreate, init
	$(document).on(Tablesaw.events.create, function(e, tablesaw) {
		if (tablesaw.mode === "columntoggle") {
			var table = new ColumnToggle(tablesaw.table);
			table.init();
		}
	});

	$(document).on(Tablesaw.events.destroy, function(e, tablesaw) {
		if (tablesaw.mode === "columntoggle") {
			$(tablesaw.table)
				.data(data.key)
				.destroy();
		}
	});

	$(document).on(Tablesaw.events.refresh, function(e, tablesaw) {
		if (tablesaw.mode === "columntoggle") {
			$(tablesaw.table)
				.data(data.key)
				.refreshPriority();
		}
	});

	Tablesaw.ColumnToggle = ColumnToggle;
})();