UNPKG

7.98 kBJavaScriptView Raw
1(function ($) {
2 // register namespace
3 $.extend(true, window, {
4 "Slick": {
5 "Plugins": {
6 "HeaderButtons": HeaderButtons
7 }
8 }
9 });
10
11
12 /***
13 * A plugin to add custom buttons to column headers.
14 *
15 * USAGE:
16 *
17 * Add the plugin .js & .css files and register it with the grid.
18 *
19 * To specify a custom button in a column header, extend the column definition like so:
20 *
21 * var columns = [
22 * {
23 * id: 'myColumn',
24 * name: 'My column',
25 *
26 * // This is the relevant part
27 * header: {
28 * buttons: [
29 * {
30 * // button options
31 * },
32 * {
33 * // button options
34 * }
35 * ]
36 * }
37 * }
38 * ];
39 *
40 * Available button options:
41 * cssClass: CSS class to add to the button.
42 * image: Relative button image path.
43 * disabled: Whether the item is disabled.
44 * tooltip: Button tooltip.
45 * showOnHover: Only show the button on hover.
46 * handler: Button click handler.
47 * command: A command identifier to be passed to the onCommand event handlers.
48 *
49 * Available menu item options:
50 * action: Optionally define a callback function that gets executed when item is chosen (and/or use the onCommand event)
51 * command: A command identifier to be passed to the onCommand event handlers.
52 * cssClass: CSS class to add to the button.
53 * handler: Button click handler.
54 * image: Relative button image path.
55 * showOnHover: Only show the button on hover.
56 * tooltip: Button tooltip.
57 * itemVisibilityOverride: Callback method that user can override the default behavior of showing/hiding an item from the list
58 * itemUsabilityOverride: Callback method that user can override the default behavior of enabling/disabling an item from the list
59 *
60 * The plugin exposes the following events:
61 * onCommand: Fired on button click for buttons with 'command' specified.
62 * Event args:
63 * grid: Reference to the grid.
64 * column: Column definition.
65 * command: Button command identified.
66 * button: Button options. Note that you can change the button options in your
67 * event handler, and the column header will be automatically updated to
68 * reflect them. This is useful if you want to implement something like a
69 * toggle button.
70 *
71 *
72 * @param options {Object} Options:
73 * buttonCssClass: a CSS class to use for buttons (default 'slick-header-button')
74 * @class Slick.Plugins.HeaderButtons
75 * @constructor
76 */
77 function HeaderButtons(options) {
78 var _grid;
79 var _self = this;
80 var _handler = new Slick.EventHandler();
81 var _defaults = {
82 buttonCssClass: "slick-header-button"
83 };
84
85
86 function init(grid) {
87 options = $.extend(true, {}, _defaults, options);
88 _grid = grid;
89 _handler
90 .subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered)
91 .subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy);
92
93 // Force the grid to re-render the header now that the events are hooked up.
94 _grid.setColumns(_grid.getColumns());
95 }
96
97
98 function destroy() {
99 _handler.unsubscribeAll();
100 }
101
102
103 function handleHeaderCellRendered(e, args) {
104 var column = args.column;
105
106 if (column.header && column.header.buttons) {
107 // Append buttons in reverse order since they are floated to the right.
108 var i = column.header.buttons.length;
109 while (i--) {
110 var button = column.header.buttons[i];
111
112 // run each override functions to know if the item is visible and usable
113 var isItemVisible = runOverrideFunctionWhenExists(button.itemVisibilityOverride, args);
114 var isItemUsable = runOverrideFunctionWhenExists(button.itemUsabilityOverride, args);
115
116 // if the result is not visible then there's no need to go further
117 if (!isItemVisible) {
118 continue;
119 }
120
121 // when the override is defined, we need to use its result to update the disabled property
122 // so that "handleMenuItemCommandClick" has the correct flag and won't trigger a command clicked event
123 if (Object.prototype.hasOwnProperty.call(button, "itemUsabilityOverride")) {
124 button.disabled = isItemUsable ? false : true;
125 }
126
127 var btn = $("<div></div>")
128 .addClass(options.buttonCssClass)
129 .data("column", column)
130 .data("button", button);
131
132 if (button.disabled) {
133 btn.addClass("slick-header-button-disabled");
134 }
135
136 if (button.showOnHover) {
137 btn.addClass("slick-header-button-hidden");
138 }
139
140 if (button.image) {
141 btn.css("backgroundImage", "url(" + button.image + ")");
142 }
143
144 if (button.cssClass) {
145 btn.addClass(button.cssClass);
146 }
147
148 if (button.tooltip) {
149 btn.attr("title", button.tooltip);
150 }
151
152 if (button.command) {
153 btn.data("command", button.command);
154 }
155
156 if (button.handler) {
157 btn.on("click", button.handler);
158 }
159
160 btn
161 .on("click", handleButtonClick)
162 .appendTo(args.node);
163 }
164 }
165 }
166
167
168 function handleBeforeHeaderCellDestroy(e, args) {
169 var column = args.column;
170
171 if (column.header && column.header.buttons) {
172 // Removing buttons via jQuery will also clean up any event handlers and data.
173 // NOTE: If you attach event handlers directly or using a different framework,
174 // you must also clean them up here to avoid memory leaks.
175 $(args.node).find("." + options.buttonCssClass).remove();
176 }
177 }
178
179
180 function handleButtonClick(e) {
181 var command = $(this).data("command");
182 var columnDef = $(this).data("column");
183 var button = $(this).data("button");
184
185 var callbackArgs = {
186 "grid": _grid,
187 "column": columnDef,
188 "button": button
189 };
190
191 if (command != null) {
192 callbackArgs.command = command;
193 }
194
195 // execute action callback when defined
196 if (typeof button.action === "function") {
197 button.action.call(this, e, callbackArgs);
198 }
199
200 if (command != null && !button.disabled) {
201 _self.onCommand.notify(callbackArgs, e, _self);
202
203 // Update the header in case the user updated the button definition in the handler.
204 _grid.updateColumnHeader(columnDef.id);
205 }
206
207 // Stop propagation so that it doesn't register as a header click event.
208 e.preventDefault();
209 e.stopPropagation();
210 }
211
212 /**
213 * Method that user can pass to override the default behavior.
214 * In order word, user can choose or an item is (usable/visible/enable) by providing his own logic.
215 * @param overrideFn: override function callback
216 * @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid)
217 */
218 function runOverrideFunctionWhenExists(overrideFn, args) {
219 if (typeof overrideFn === 'function') {
220 return overrideFn.call(this, args);
221 }
222 return true;
223 }
224
225 $.extend(this, {
226 "init": init,
227 "destroy": destroy,
228 "pluginName": "HeaderButtons",
229
230 "onCommand": new Slick.Event()
231 });
232 }
233})(jQuery);