0
|
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 })();
|