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);
|