comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:1d038bc9b3d2
1 /*
2 * tablesaw: A set of plugins for responsive tables
3 * Column Toggle: allows the user to toggle which columns are visible.
4 * Copyright (c) 2013 Filament Group, Inc.
5 * MIT License
6 */
7
8 (function() {
9 var data = {
10 key: "tablesaw-coltoggle"
11 };
12
13 var ColumnToggle = function(element) {
14 this.$table = $(element);
15
16 if (!this.$table.length) {
17 return;
18 }
19
20 this.tablesaw = this.$table.data("tablesaw");
21
22 this.attributes = {
23 btnTarget: "data-tablesaw-columntoggle-btn-target",
24 set: "data-tablesaw-columntoggle-set"
25 };
26
27 this.classes = {
28 columnToggleTable: "tablesaw-columntoggle",
29 columnBtnContain: "tablesaw-columntoggle-btnwrap tablesaw-advance",
30 columnBtn: "tablesaw-columntoggle-btn tablesaw-nav-btn down",
31 popup: "tablesaw-columntoggle-popup",
32 priorityPrefix: "tablesaw-priority-"
33 };
34
35 this.set = [];
36 this.$headers = this.tablesaw._getPrimaryHeaderCells();
37
38 this.$table.data(data.key, this);
39 };
40
41 // Column Toggle Sets (one column chooser can control multiple tables)
42 ColumnToggle.prototype.initSet = function() {
43 var set = this.$table.attr(this.attributes.set);
44 if (set) {
45 // Should not include the current table
46 var table = this.$table[0];
47 this.set = $("table[" + this.attributes.set + "='" + set + "']")
48 .filter(function() {
49 return this !== table;
50 })
51 .get();
52 }
53 };
54
55 ColumnToggle.prototype.init = function() {
56 if (!this.$table.length) {
57 return;
58 }
59
60 var tableId,
61 id,
62 $menuButton,
63 $popup,
64 $menu,
65 $btnContain,
66 self = this;
67
68 var cfg = this.tablesaw.getConfig({
69 getColumnToggleLabelTemplate: function(text) {
70 return "<label><input type='checkbox' checked>" + text + "</label>";
71 }
72 });
73
74 this.$table.addClass(this.classes.columnToggleTable);
75
76 tableId = this.$table.attr("id");
77 id = tableId + "-popup";
78 $btnContain = $("<div class='" + this.classes.columnBtnContain + "'></div>");
79 // TODO next major version: remove .btn
80 $menuButton = $(
81 "<a href='#" +
82 id +
83 "' class='btn tablesaw-btn btn-micro " +
84 this.classes.columnBtn +
85 "' data-popup-link>" +
86 "<span>" +
87 Tablesaw.i18n.columnToggleButton +
88 "</span></a>"
89 );
90 $popup = $("<div class='" + this.classes.popup + "' id='" + id + "'></div>");
91 $menu = $("<div class='btn-group'></div>");
92
93 this.$popup = $popup;
94
95 var hasNonPersistentHeaders = false;
96 this.$headers.each(function() {
97 var $this = $(this),
98 priority = $this.attr("data-tablesaw-priority"),
99 $cells = self.tablesaw._$getCells(this);
100
101 if (priority && priority !== "persist") {
102 $cells.addClass(self.classes.priorityPrefix + priority);
103
104 $(cfg.getColumnToggleLabelTemplate($this.text()))
105 .appendTo($menu)
106 .find('input[type="checkbox"]')
107 .data("tablesaw-header", this);
108
109 hasNonPersistentHeaders = true;
110 }
111 });
112
113 if (!hasNonPersistentHeaders) {
114 $menu.append("<label>" + Tablesaw.i18n.columnToggleError + "</label>");
115 }
116
117 $menu.appendTo($popup);
118
119 function onToggleCheckboxChange(checkbox) {
120 var checked = checkbox.checked;
121
122 var header = self.getHeaderFromCheckbox(checkbox);
123 var $cells = self.tablesaw._$getCells(header);
124
125 $cells[!checked ? "addClass" : "removeClass"]("tablesaw-toggle-cellhidden");
126 $cells[checked ? "addClass" : "removeClass"]("tablesaw-toggle-cellvisible");
127
128 self.updateColspanCells(header, checked);
129
130 self.$table.trigger("tablesawcolumns");
131 }
132
133 // bind change event listeners to inputs - TODO: move to a private method?
134 $menu.find('input[type="checkbox"]').on("change", function(e) {
135 onToggleCheckboxChange(e.target);
136
137 if (self.set.length) {
138 var index;
139 $(self.$popup)
140 .find("input[type='checkbox']")
141 .each(function(j) {
142 if (this === e.target) {
143 index = j;
144 return false;
145 }
146 });
147
148 $(self.set).each(function() {
149 var checkbox = $(this)
150 .data(data.key)
151 .$popup.find("input[type='checkbox']")
152 .get(index);
153 if (checkbox) {
154 checkbox.checked = e.target.checked;
155 onToggleCheckboxChange(checkbox);
156 }
157 });
158 }
159 });
160
161 $menuButton.appendTo($btnContain);
162
163 // Use a different target than the toolbar
164 var $btnTarget = $(this.$table.attr(this.attributes.btnTarget));
165 $btnContain.appendTo($btnTarget.length ? $btnTarget : this.tablesaw.$toolbar);
166
167 function closePopup(event) {
168 // Click came from inside the popup, ignore.
169 if (event && $(event.target).closest("." + self.classes.popup).length) {
170 return;
171 }
172
173 $(document).off("click." + tableId);
174 $menuButton.removeClass("up").addClass("down");
175 $btnContain.removeClass("visible");
176 }
177
178 var closeTimeout;
179 function openPopup() {
180 $btnContain.addClass("visible");
181 $menuButton.removeClass("down").addClass("up");
182
183 $(document).off("click." + tableId, closePopup);
184
185 window.clearTimeout(closeTimeout);
186 closeTimeout = window.setTimeout(function() {
187 $(document).on("click." + tableId, closePopup);
188 }, 15);
189 }
190
191 $menuButton.on("click.tablesaw", function(event) {
192 event.preventDefault();
193
194 if (!$btnContain.is(".visible")) {
195 openPopup();
196 } else {
197 closePopup();
198 }
199 });
200
201 $popup.appendTo($btnContain);
202
203 this.$menu = $menu;
204
205 // Fix for iOS not rendering shadows correctly when using `-webkit-overflow-scrolling`
206 var $overflow = this.$table.closest(".tablesaw-overflow");
207 if ($overflow.css("-webkit-overflow-scrolling")) {
208 var timeout;
209 $overflow.on("scroll", function() {
210 var $div = $(this);
211 window.clearTimeout(timeout);
212 timeout = window.setTimeout(function() {
213 $div.css("-webkit-overflow-scrolling", "auto");
214 window.setTimeout(function() {
215 $div.css("-webkit-overflow-scrolling", "touch");
216 }, 0);
217 }, 100);
218 });
219 }
220
221 $(window).on(Tablesaw.events.resize + "." + tableId, function() {
222 self.refreshToggle();
223 });
224
225 this.initSet();
226 this.refreshToggle();
227 };
228
229 ColumnToggle.prototype.getHeaderFromCheckbox = function(checkbox) {
230 return $(checkbox).data("tablesaw-header");
231 };
232
233 ColumnToggle.prototype.refreshToggle = function() {
234 var self = this;
235 var invisibleColumns = 0;
236 this.$menu.find("input").each(function() {
237 var header = self.getHeaderFromCheckbox(this);
238 this.checked =
239 self.tablesaw
240 ._$getCells(header)
241 .eq(0)
242 .css("display") === "table-cell";
243 });
244
245 this.updateColspanCells();
246 };
247
248 ColumnToggle.prototype.updateColspanCells = function(header, userAction) {
249 this.tablesaw.updateColspanCells("tablesaw-toggle-cellhidden", header, userAction);
250 };
251
252 ColumnToggle.prototype.destroy = function() {
253 this.$table.removeClass(this.classes.columnToggleTable);
254 this.$table.find("th, td").each(function() {
255 var $cell = $(this);
256 $cell.removeClass("tablesaw-toggle-cellhidden").removeClass("tablesaw-toggle-cellvisible");
257
258 this.className = this.className.replace(/\bui\-table\-priority\-\d\b/g, "");
259 });
260 };
261
262 // on tablecreate, init
263 $(document).on(Tablesaw.events.create, function(e, tablesaw) {
264 if (tablesaw.mode === "columntoggle") {
265 var table = new ColumnToggle(tablesaw.table);
266 table.init();
267 }
268 });
269
270 $(document).on(Tablesaw.events.destroy, function(e, tablesaw) {
271 if (tablesaw.mode === "columntoggle") {
272 $(tablesaw.table)
273 .data(data.key)
274 .destroy();
275 }
276 });
277
278 $(document).on(Tablesaw.events.refresh, function(e, tablesaw) {
279 if (tablesaw.mode === "columntoggle") {
280 $(tablesaw.table)
281 .data(data.key)
282 .refreshPriority();
283 }
284 });
285
286 Tablesaw.ColumnToggle = ColumnToggle;
287 })();