UNPKG

10.1 kBJavaScriptView Raw
1/***
2 * A control to add a Column Picker (right+click on any column header to reveal the column picker)
3 *
4 * USAGE:
5 *
6 * Add the slick.columnpicker.(js|css) files and register it with the grid.
7 *
8 * Available options, by defining a columnPicker object:
9 *
10 * var options = {
11 * enableCellNavigation: true,
12 * columnPicker: {
13 * columnTitle: "Columns", // default to empty string
14 *
15 * // the last 2 checkboxes titles
16 * hideForceFitButton: false, // show/hide checkbox near the end "Force Fit Columns" (default:false)
17 * hideSyncResizeButton: false, // show/hide checkbox near the end "Synchronous Resize" (default:false)
18 * forceFitTitle: "Force fit columns", // default to "Force fit columns"
19 * headerColumnValueExtractor: "Extract the column label" // default to column.name
20 * syncResizeTitle: "Synchronous resize", // default to "Synchronous resize"
21 * }
22 * };
23 *
24 * @class Slick.Controls.ColumnPicker
25 * @constructor
26 */
27
28(function ($) {
29 'use strict';
30 function SlickColumnPicker(columns, grid, options) {
31 var _grid = grid;
32 var _options = options;
33 var _gridUid = (grid && grid.getUID) ? grid.getUID() : '';
34 var $columnTitleElm;
35 var $list;
36 var $menu;
37 var columnCheckboxes;
38 var onColumnsChanged = new Slick.Event();
39
40 var defaults = {
41 fadeSpeed: 250,
42
43 // the last 2 checkboxes titles
44 hideForceFitButton: false,
45 hideSyncResizeButton: false,
46 forceFitTitle: "Force fit columns",
47 syncResizeTitle: "Synchronous resize",
48 headerColumnValueExtractor:
49 function (columnDef) {
50 return columnDef.name;
51 }
52 };
53
54 function init(grid) {
55 grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);
56 grid.onColumnsReordered.subscribe(updateColumnOrder);
57 _options = $.extend({}, defaults, options);
58
59 $menu = $("<div class='slick-columnpicker " + _gridUid + "' style='display:none' />").appendTo(document.body);
60 $("<button type='button' class='close' data-dismiss='slick-columnpicker' aria-label='Close'><span class='close' aria-hidden='true'>&times;</span></button>").appendTo($menu);
61
62 // user could pass a title on top of the columns list
63 if (_options.columnPickerTitle || (_options.columnPicker && _options.columnPicker.columnTitle)) {
64 var columnTitle = _options.columnPickerTitle || _options.columnPicker.columnTitle;
65 $columnTitleElm = $("<div class='title'/>").append(columnTitle);
66 $columnTitleElm.appendTo($menu);
67 }
68
69 $menu.on("click", updateColumn);
70 $list = $("<span class='slick-columnpicker-list' />");
71
72 // Hide the menu on outside click.
73 $(document.body).on("mousedown", handleBodyMouseDown);
74
75 // destroy the picker if user leaves the page
76 $(window).on("beforeunload", destroy);
77 }
78
79 function destroy() {
80 _grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
81 _grid.onColumnsReordered.unsubscribe(updateColumnOrder);
82 if ($list) {
83 $list.remove();
84 }
85 if ($menu) {
86 $menu.off("click").remove();
87 }
88 $(document.body).off("mousedown", handleBodyMouseDown);
89 $(".slick-columnpicker." + _gridUid).hide(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);
90 $columnTitleElm = null;
91 $list = null;
92 $menu = null;
93 $(window).off("beforeunload");
94 }
95
96 function handleBodyMouseDown(e) {
97 if (($menu && $menu[0] != e.target && !$.contains($menu[0], e.target)) || e.target.className == "close") {
98 $menu.hide(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);
99 }
100 }
101
102 function handleHeaderContextMenu(e) {
103 e.preventDefault();
104 $list.empty();
105 updateColumnOrder();
106 columnCheckboxes = [];
107
108 var $li, $input, columnId;
109 var columnLabel, excludeCssClass;
110 for (var i = 0; i < columns.length; i++) {
111 columnId = columns[i].id;
112 excludeCssClass = columns[i].excludeFromColumnPicker ? "hidden" : "";
113 $li = $('<li class="' + excludeCssClass + '" />').appendTo($list);
114 $input = $("<input type='checkbox' id='" + _gridUid + "colpicker-" + columnId + "' />").data("column-id", columnId).appendTo($li);
115 columnCheckboxes.push($input);
116
117 if (_grid.getColumnIndex(columnId) != null) {
118 $input.attr("checked", "checked");
119 }
120
121 if (_options && _options.columnPicker && _options.columnPicker.headerColumnValueExtractor) {
122 columnLabel = _options.columnPicker.headerColumnValueExtractor(columns[i], _options);
123 } else {
124 columnLabel = defaults.headerColumnValueExtractor(columns[i], _options);
125 }
126
127 $("<label for='" + _gridUid + "colpicker-" + columnId + "' />")
128 .html(columnLabel)
129 .appendTo($li);
130 }
131
132 if (_options.columnPicker && (!_options.columnPicker.hideForceFitButton || !_options.columnPicker.hideSyncResizeButton)) {
133 $("<hr/>").appendTo($list);
134 }
135
136 if (!(_options.columnPicker && _options.columnPicker.hideForceFitButton)) {
137 var forceFitTitle = (_options.columnPicker && _options.columnPicker.forceFitTitle) || _options.forceFitTitle;
138 $li = $("<li />").appendTo($list);
139 $input = $("<input type='checkbox' id='" + _gridUid + "colpicker-forcefit' />").data("option", "autoresize").appendTo($li);
140 $("<label for='" + _gridUid + "colpicker-forcefit' />").text(forceFitTitle).appendTo($li);
141 if (_grid.getOptions().forceFitColumns) {
142 $input.attr("checked", "checked");
143 }
144 }
145
146 if (!(_options.columnPicker && _options.columnPicker.hideSyncResizeButton)) {
147 var syncResizeTitle = (_options.columnPicker && _options.columnPicker.syncResizeTitle) || _options.syncResizeTitle;
148 $li = $("<li />").appendTo($list);
149 $input = $("<input type='checkbox' id='" + _gridUid + "colpicker-syncresize' />").data("option", "syncresize").appendTo($li);
150 $("<label for='" + _gridUid + "colpicker-syncresize' />").text(syncResizeTitle).appendTo($li);
151 if (_grid.getOptions().syncColumnCellResize) {
152 $input.attr("checked", "checked");
153 }
154 }
155
156 $menu
157 .css("top", e.pageY - 10)
158 .css("left", e.pageX - 10)
159 .css("max-height", $(window).height() - e.pageY - 10)
160 .fadeIn(_options && _options.columnPicker && _options.columnPicker.fadeSpeed);
161
162 $list.appendTo($menu);
163 $li = null;
164 $input = null;
165 }
166
167 function updateColumnOrder() {
168 // Because columns can be reordered, we have to update the `columns`
169 // to reflect the new order, however we can't just take `grid.getColumns()`,
170 // as it does not include columns currently hidden by the picker.
171 // We create a new `columns` structure by leaving currently-hidden
172 // columns in their original ordinal position and interleaving the results
173 // of the current column sort.
174 var current = _grid.getColumns().slice(0);
175 var ordered = new Array(columns.length);
176 for (var i = 0; i < ordered.length; i++) {
177 if (_grid.getColumnIndex(columns[i].id) === undefined) {
178 // If the column doesn't return a value from getColumnIndex,
179 // it is hidden. Leave it in this position.
180 ordered[i] = columns[i];
181 } else {
182 // Otherwise, grab the next visible column.
183 ordered[i] = current.shift();
184 }
185 }
186 columns = ordered;
187 }
188
189 /** Update the Titles of each sections (command, customTitle, ...) */
190 function updateAllTitles(gridMenuOptions) {
191 if ($columnTitleElm && $columnTitleElm.text) {
192 $columnTitleElm.text(gridMenuOptions.columnTitle);
193 }
194 }
195
196 function updateColumn(e) {
197 if ($(e.target).data("option") == "autoresize") {
198 // when calling setOptions, it will resize with ALL Columns (even the hidden ones)
199 // we can avoid this problem by keeping a reference to the visibleColumns before setOptions and then setColumns after
200 var previousVisibleColumns = getVisibleColumns();
201 var isChecked = e.target.checked;
202 _grid.setOptions({ forceFitColumns: isChecked });
203 _grid.setColumns(previousVisibleColumns);
204 return;
205 }
206
207 if ($(e.target).data("option") == "syncresize") {
208 if (e.target.checked) {
209 _grid.setOptions({ syncColumnCellResize: true });
210 } else {
211 _grid.setOptions({ syncColumnCellResize: false });
212 }
213 return;
214 }
215
216 if ($(e.target).is(":checkbox")) {
217 var isChecked = e.target.checked;
218 var columnId = $(e.target).data("column-id") || "";
219 var visibleColumns = [];
220 $.each(columnCheckboxes, function (i) {
221 if ($(this).is(":checked")) {
222 visibleColumns.push(columns[i]);
223 }
224 });
225
226 if (!visibleColumns.length) {
227 $(e.target).attr("checked", "checked");
228 return;
229 }
230
231 _grid.setColumns(visibleColumns);
232 onColumnsChanged.notify({ columnId: columnId, showing: isChecked, allColumns: columns, columns: visibleColumns, grid: _grid });
233 }
234 }
235
236 function getAllColumns() {
237 return columns;
238 }
239
240 /** visible columns, we can simply get them directly from the grid */
241 function getVisibleColumns() {
242 return _grid.getColumns();
243 }
244
245 init(_grid);
246
247 return {
248 "init": init,
249 "getAllColumns": getAllColumns,
250 "getVisibleColumns": getVisibleColumns,
251 "destroy": destroy,
252 "updateAllTitles": updateAllTitles,
253 "onColumnsChanged": onColumnsChanged
254 };
255 }
256
257 // Slick.Controls.ColumnPicker
258 $.extend(true, window, { Slick: { Controls: { ColumnPicker: SlickColumnPicker } } });
259})(jQuery);