UNPKG

27.3 kBJavaScriptView Raw
1(function ($) {
2 // register namespace
3 $.extend(true, window, {
4 "Slick": {
5 "Plugins": {
6 "CellMenu": CellMenu
7 }
8 }
9 });
10
11 /***
12 * A plugin to add Menu on a Cell click (click on the cell that has the cellMenu object defined)
13 * The "cellMenu" is defined in a Column Definition object
14 * Similar to the ContextMenu plugin (could be used in combo),
15 * except that it subscribes to the cell "onClick" event (regular mouse click or touch).
16 *
17 * A general use of this plugin is for an Action Dropdown Menu to do certain things on the row that was clicked
18 * You can use it to change the cell data property through a list of Options AND/OR through a list of Commands.
19 *
20 * USAGE:
21 *
22 * Add the slick.cellMenu.(js|css) files and register it with the grid.
23 *
24 * To specify a menu in a column header, extend the column definition like so:
25 * var cellMenuPlugin = new Slick.Plugins.CellMenu(columns, grid, options);
26 *
27 * Available cellMenu options, by defining a cellMenu object:
28 *
29 * var columns = [
30 * {
31 * id: "action", name: "Action", field: "action", formatter: fakeButtonFormatter,
32 * cellMenu: {
33 * optionTitle: "Change Effort Driven",
34 * optionItems: [
35 * { option: true, title: "True", iconCssClass: 'checkmark' },
36 * { option: false, title: "False" }
37 * ],
38 * commandTitle: "Commands",
39 * commandItems: [
40 * { command: "delete-row", title: "Delete Row", iconImage: "../images/delete.png", cssClass: 'bold', textCssClass: "red" },
41 * { divider: true },
42 * "divider" // you can pass "divider" as a string or an object
43 * { command: "help", title: "Help", iconCssClass: "icon-help" },
44 * { command: "help", title: "Disabled Command", disabled: true },
45 * ],
46 * }
47 * }
48 * ];
49 *
50 *
51 * Available cellMenu properties:
52 * commandTitle: Title of the Command section (optional)
53 * commandItems: Array of Command item objects (command/title pair)
54 * optionTitle: Title of the Option section (optional)
55 * optionItems: Array of Options item objects (option/title pair)
56 * hideCloseButton: Hide the Close button on top right (defaults to false)
57 * hideCommandSection: Hide the Commands section even when the commandItems array is filled (defaults to false)
58 * hideMenuOnScroll: Do we want to hide the Cell Menu when a scrolling event occurs (defaults to true)?
59 * hideOptionSection: Hide the Options section even when the optionItems array is filled (defaults to false)
60 * maxHeight: Maximum height that the drop menu will have, can be a number (250) or text ("none")
61 * width: Width that the drop menu will have, can be a number (250) or text (defaults to "auto")
62 * autoAdjustDrop: Auto-align dropup or dropdown menu to the left or right depending on grid viewport available space (defaults to true)
63 * autoAdjustDropOffset: Optionally add an offset to the auto-align of the drop menu (defaults to 0)
64 * autoAlignSide: Auto-align drop menu to the left or right depending on grid viewport available space (defaults to true)
65 * autoAlignSideOffset: Optionally add an offset to the left/right side auto-align (defaults to 0)
66 * menuUsabilityOverride: Callback method that user can override the default behavior of enabling/disabling the menu from being usable (must be combined with a custom formatter)
67 *
68 *
69 * Available menu Command/Option item properties:
70 * action: Optionally define a callback function that gets executed when item is chosen (and/or use the onCommand event)
71 * command: A command identifier to be passed to the onCommand event handlers (when using "commandItems").
72 * option: An option to be passed to the onOptionSelected event handlers (when using "optionItems").
73 * title: Menu item text label.
74 * divider: Boolean which tells if the current item is a divider, not an actual command. You could also pass "divider" instead of an object
75 * disabled: Whether the item/command is disabled.
76 * hidden: Whether the item/command is hidden.
77 * tooltip: Item tooltip.
78 * cssClass: A CSS class to be added to the menu item container.
79 * iconCssClass: A CSS class to be added to the menu item icon.
80 * textCssClass: A CSS class to be added to the menu item text.
81 * iconImage: A url to the icon image.
82 * itemVisibilityOverride: Callback method that user can override the default behavior of showing/hiding an item from the list
83 * itemUsabilityOverride: Callback method that user can override the default behavior of enabling/disabling an item from the list
84 *
85 *
86 * The plugin exposes the following events:
87 *
88 * onAfterMenuShow: Fired after the menu is shown. You can customize the menu or dismiss it by returning false.
89 * Event args:
90 * cell: Cell or column index
91 * row: Row index
92 * grid: Reference to the grid.
93 *
94 * onBeforeMenuShow: Fired before the menu is shown. You can customize the menu or dismiss it by returning false.
95 * Event args:
96 * cell: Cell or column index
97 * row: Row index
98 * grid: Reference to the grid.
99 *
100 * onBeforeMenuClose: Fired when the menu is closing.
101 * Event args:
102 * cell: Cell or column index
103 * row: Row index
104 * grid: Reference to the grid.
105 * menu: Menu DOM element
106 *
107 * onCommand: Fired on menu option clicked from the Command items list
108 * Event args:
109 * cell: Cell or column index
110 * row: Row index
111 * grid: Reference to the grid.
112 * command: Menu command identified.
113 * item: Menu item selected
114 * column: Cell Column definition
115 * dataContext: Cell Data Context (data object)
116 *
117 * onOptionSelected: Fired on menu option clicked from the Option items list
118 * Event args:
119 * cell: Cell or column index
120 * row: Row index
121 * grid: Reference to the grid.
122 * option: Menu option selected.
123 * item: Menu item selected
124 * column: Cell Column definition
125 * dataContext: Cell Data Context (data object)
126 *
127 *
128 * @param options {Object} Cell Menu Options
129 * @class Slick.Plugins.CellMenu
130 * @constructor
131 */
132 function CellMenu(optionProperties) {
133 var _cellMenuProperties;
134 var _currentCell = -1;
135 var _currentRow = -1;
136 var _grid;
137 var _gridOptions;
138 var _gridUid = "";
139 var _handler = new Slick.EventHandler();
140 var _self = this;
141 var $commandTitleElm;
142 var $optionTitleElm;
143 var $menu;
144
145 var _defaults = {
146 autoAdjustDrop: true, // dropup/dropdown
147 autoAlignSide: true, // left/right
148 autoAdjustDropOffset: 0,
149 autoAlignSideOffset: 0,
150 hideMenuOnScroll: true,
151 maxHeight: "none",
152 width: "auto",
153 };
154
155 function init(grid) {
156 _grid = grid;
157 _gridOptions = grid.getOptions();
158 _cellMenuProperties = $.extend({}, _defaults, optionProperties);
159 _gridUid = (grid && grid.getUID) ? grid.getUID() : "";
160 _handler.subscribe(_grid.onClick, handleCellClick);
161 if (_cellMenuProperties.hideMenuOnScroll) {
162 _handler.subscribe(_grid.onScroll, destroyMenu);
163 }
164 }
165
166 function setOptions(newOptions) {
167 _cellMenuProperties = $.extend({}, _cellMenuProperties, newOptions);
168 }
169
170 function destroy() {
171 _self.onAfterMenuShow.unsubscribe();
172 _self.onBeforeMenuShow.unsubscribe();
173 _self.onBeforeMenuClose.unsubscribe();
174 _self.onCommand.unsubscribe();
175 _self.onOptionSelected.unsubscribe();
176 _handler.unsubscribeAll();
177 if ($menu && $menu.remove) {
178 $menu.remove();
179 }
180 $commandTitleElm = null;
181 $optionTitleElm = null;
182 $menu = null;
183 }
184
185 function createMenu(e) {
186 var cell = _grid.getCellFromEvent(e);
187 _currentCell = cell && cell.cell;
188 _currentRow = cell && cell.row;
189 var columnDef = _grid.getColumns()[_currentCell];
190 var dataContext = _grid.getDataItem(_currentRow);
191
192 var commandItems = _cellMenuProperties.commandItems || [];
193 var optionItems = _cellMenuProperties.optionItems || [];
194
195 // make sure there's at least something to show before creating the Cell Menu
196 if (!columnDef || !columnDef.cellMenu || (!commandItems.length && optionItems.length)) {
197 return;
198 }
199
200 // delete any prior Cell Menu
201 destroyMenu();
202
203 // Let the user modify the menu or cancel altogether,
204 // or provide alternative menu implementation.
205 if (_self.onBeforeMenuShow.notify({
206 "cell": _currentCell,
207 "row": _currentRow,
208 "grid": _grid
209 }, e, _self) == false) {
210 return;
211 }
212
213 // create a new cell menu
214 var maxHeight = isNaN(_cellMenuProperties.maxHeight) ? _cellMenuProperties.maxHeight : _cellMenuProperties.maxHeight + "px";
215 var width = isNaN(_cellMenuProperties.width) ? _cellMenuProperties.width : _cellMenuProperties.width + "px";
216 var menuStyle = "width: " + width + "; max-height: " + maxHeight;
217 var menu = $('<div class="slick-cell-menu ' + _gridUid + '" style="' + menuStyle + '" />')
218 .css("top", e.pageY + 5)
219 .css("left", e.pageX)
220 .css("display", "none");
221
222 var closeButtonHtml = '<button type="button" class="close" data-dismiss="slick-cell-menu" aria-label="Close">'
223 + '<span class="close" aria-hidden="true">&times;</span></button>';
224
225 // -- Option List section
226 if (!_cellMenuProperties.hideOptionSection && optionItems.length > 0) {
227 var $optionMenu = $('<div class="slick-cell-menu-option-list" />');
228 if (!_cellMenuProperties.hideCloseButton) {
229 $(closeButtonHtml).on("click", handleCloseButtonClicked).appendTo(menu);
230 }
231 $optionMenu.appendTo(menu);
232 populateOptionItems(
233 _cellMenuProperties,
234 $optionMenu,
235 optionItems,
236 { cell: _currentCell, row: _currentRow, column: columnDef, dataContext: dataContext, grid: _grid }
237 );
238 }
239
240 // -- Command List section
241 if (!_cellMenuProperties.hideCommandSection && commandItems.length > 0) {
242 var $commandMenu = $('<div class="slick-cell-menu-command-list" />');
243 if (!_cellMenuProperties.hideCloseButton && (optionItems.length === 0 || _cellMenuProperties.hideOptionSection)) {
244 $(closeButtonHtml).on("click", handleCloseButtonClicked).appendTo(menu);
245 }
246 $commandMenu.appendTo(menu);
247 populateCommandItems(
248 _cellMenuProperties,
249 $commandMenu,
250 commandItems,
251 { cell: _currentCell, row: _currentRow, column: columnDef, dataContext: dataContext, grid: _grid }
252 );
253 }
254
255 menu.show();
256 menu.appendTo("body");
257
258 if (_self.onAfterMenuShow.notify({
259 "cell": _currentCell,
260 "row": _currentRow,
261 "grid": _grid
262 }, e, _self) == false) {
263 return;
264 }
265
266 return menu;
267 }
268
269 function calculateAvailableSpaceBottom(element) {
270 var windowHeight = $(window).innerHeight() || 0;
271 var pageScroll = $(window).scrollTop() || 0;
272 if (element && element.offset && element.length > 0) {
273 var elementOffsetTop = element.offset().top;
274 return windowHeight - (elementOffsetTop - pageScroll);
275 }
276 return 0;
277 }
278
279 function calculateAvailableSpaceTop(element) {
280 var pageScroll = $(window).scrollTop() || 0;
281 if (element && element.offset && element.length > 0) {
282 var elementOffsetTop = element.offset().top;
283 return elementOffsetTop - pageScroll;
284 }
285 return 0;
286 }
287
288 function handleCloseButtonClicked(e) {
289 if(!e.isDefaultPrevented()) {
290 destroyMenu(e);
291 }
292 }
293
294 function destroyMenu(e, args) {
295 $menu = $menu || $(".slick-cell-menu." + _gridUid);
296
297 if ($menu && $menu.remove) {
298 if ($menu.length > 0) {
299 if (_self.onBeforeMenuClose.notify({
300 "cell": args && args.cell,
301 "row": args && args.row,
302 "grid": _grid,
303 "menu": $menu
304 }, e, _self) == false) {
305 return;
306 }
307 }
308 $menu.remove();
309 $menu = null;
310 }
311 }
312
313 /**
314 * Reposition the menu drop (up/down) and the side (left/right)
315 * @param {*} event
316 */
317 function repositionMenu(e) {
318 var $parent = $(e.target).closest(".slick-cell");
319 var menuOffsetLeft = $parent ? $parent.offset().left : e.pageX;
320 var menuOffsetTop = $parent ? $parent.offset().top : e.pageY;
321 var parentCellWidth = $parent.outerWidth();
322 var menuHeight = $menu.outerHeight() || 0;
323 var menuWidth = $menu.outerWidth() || _cellMenuProperties.width || 0;
324 var rowHeight = _gridOptions.rowHeight;
325 var dropOffset = _cellMenuProperties.autoAdjustDropOffset;
326 var sideOffset = _cellMenuProperties.autoAlignSideOffset;
327
328 // if autoAdjustDrop is enable, we first need to see what position the drop will be located (defaults to bottom)
329 // without necessary toggling it's position just yet, we just want to know the future position for calculation
330 if (_cellMenuProperties.autoAdjustDrop) {
331 // since we reposition menu below slick cell, we need to take it in consideration and do our calculation from that element
332 var spaceBottom = calculateAvailableSpaceBottom($parent);
333 var spaceTop = calculateAvailableSpaceTop($parent);
334 var spaceBottomRemaining = spaceBottom + dropOffset - rowHeight;
335 var spaceTopRemaining = spaceTop - dropOffset + rowHeight;
336 var dropPosition = (spaceBottomRemaining < menuHeight && spaceTopRemaining > spaceBottomRemaining) ? 'top' : 'bottom';
337 if (dropPosition === 'top') {
338 $menu.removeClass("dropdown").addClass("dropup");
339 menuOffsetTop = menuOffsetTop - menuHeight - dropOffset;
340 } else {
341 $menu.removeClass("dropup").addClass("dropdown");
342 menuOffsetTop = menuOffsetTop + rowHeight + dropOffset;
343 }
344 }
345
346 // when auto-align is set, it will calculate whether it has enough space in the viewport to show the drop menu on the right (default)
347 // if there isn't enough space on the right, it will automatically align the drop menu to the left (defaults to the right)
348 // to simulate an align left, we actually need to know the width of the drop menu
349 if (_cellMenuProperties.autoAlignSide) {
350 var gridPos = _grid.getGridPosition();
351 var dropSide = ((menuOffsetLeft + menuWidth) >= gridPos.width) ? 'left' : 'right';
352 if (dropSide === 'left') {
353 $menu.removeClass("dropright").addClass("dropleft");
354 menuOffsetLeft = (menuOffsetLeft - (menuWidth - parentCellWidth) - sideOffset);
355 } else {
356 $menu.removeClass("dropleft").addClass("dropright");
357 menuOffsetLeft = menuOffsetLeft + sideOffset;
358 }
359 }
360
361 // ready to reposition the menu
362 $menu.css("top", menuOffsetTop);
363 $menu.css("left", menuOffsetLeft);
364 }
365
366 function handleCellClick(e, args) {
367 var cell = _grid.getCellFromEvent(e);
368 var dataContext = _grid.getDataItem(cell.row);
369 var columnDef = _grid.getColumns()[cell.cell];
370
371 // prevent event from bubbling but only on column that has a cell menu defined
372 if (columnDef && columnDef.cellMenu) {
373 e.preventDefault();
374 }
375
376 // merge the cellMenu of the column definition with the default properties
377 _cellMenuProperties = $.extend({}, _cellMenuProperties, columnDef.cellMenu);
378
379 // run the override function (when defined), if the result is false it won't go further
380 if (!args) {
381 args = {};
382 }
383 args.columnDef = columnDef;
384 args.dataContext = dataContext;
385 args.grid = _grid;
386 if (!runOverrideFunctionWhenExists(_cellMenuProperties.menuUsabilityOverride, args)) {
387 return;
388 }
389
390 // create the DOM element
391 $menu = createMenu(e, args);
392
393 // reposition the menu to where the user clicked
394 if ($menu) {
395 repositionMenu(e);
396 $menu
397 .data("cell", _currentCell)
398 .data("row", _currentRow)
399 .show();
400 }
401
402 // Hide the menu on outside click.
403 $("body").on("mousedown." + _gridUid, handleBodyMouseDown);
404 }
405
406 function handleBodyMouseDown(e) {
407 if ($menu && $menu[0] != e.target && !$.contains($menu[0], e.target)) {
408 if(!e.isDefaultPrevented()) {
409 closeMenu(e, { cell: _currentCell, row: _currentRow });
410 }
411 }
412 }
413
414 function closeMenu(e, args) {
415 if ($menu && $menu.length > 0) {
416 if (_self.onBeforeMenuClose.notify({
417 "cell": args && args.cell,
418 "row": args && args.row,
419 "grid": _grid,
420 "menu": $menu
421 }, e, _self) == false) {
422 return;
423 }
424 if ($menu && $menu.remove) {
425 $menu.remove();
426 $menu = null;
427 }
428 }
429 }
430
431 /** Construct the Option Items section. */
432 function populateOptionItems(cellMenu, optionMenuElm, optionItems, args) {
433 if (!args || !optionItems || !cellMenu) {
434 return;
435 }
436
437 // user could pass a title on top of the Options section
438 if (cellMenu && cellMenu.optionTitle) {
439 $optionTitleElm = $('<div class="title"/>').append(cellMenu.optionTitle);
440 $optionTitleElm.appendTo(optionMenuElm);
441 }
442
443 for (var i = 0, ln = optionItems.length; i < ln; i++) {
444 var item = optionItems[i];
445
446 // run each override functions to know if the item is visible and usable
447 var isItemVisible = runOverrideFunctionWhenExists(item.itemVisibilityOverride, args);
448 var isItemUsable = runOverrideFunctionWhenExists(item.itemUsabilityOverride, args);
449
450 // if the result is not visible then there's no need to go further
451 if (!isItemVisible) {
452 continue;
453 }
454
455 // when the override is defined, we need to use its result to update the disabled property
456 // so that "handleMenuItemOptionClick" has the correct flag and won't trigger an option clicked event
457 if (Object.prototype.hasOwnProperty.call(item, "itemUsabilityOverride")) {
458 item.disabled = isItemUsable ? false : true;
459 }
460
461 var $li = $('<div class="slick-cell-menu-item"></div>')
462 .data("option", item.option || "")
463 .data("item", item)
464 .on("click", handleMenuItemOptionClick)
465 .appendTo(optionMenuElm);
466
467 if (item.divider || item === "divider") {
468 $li.addClass("slick-cell-menu-item-divider");
469 continue;
470 }
471
472 // if the item is disabled then add the disabled css class
473 if (item.disabled || !isItemUsable) {
474 $li.addClass("slick-cell-menu-item-disabled");
475 }
476
477 // if the item is hidden then add the hidden css class
478 if (item.hidden) {
479 $li.addClass("slick-cell-menu-item-hidden");
480 }
481
482 if (item.cssClass) {
483 $li.addClass(item.cssClass);
484 }
485
486 if (item.tooltip) {
487 $li.attr("title", item.tooltip);
488 }
489
490 var $icon = $('<div class="slick-cell-menu-icon"></div>')
491 .appendTo($li);
492
493 if (item.iconCssClass) {
494 $icon.addClass(item.iconCssClass);
495 }
496
497 if (item.iconImage) {
498 $icon.css("background-image", "url(" + item.iconImage + ")");
499 }
500
501 var $text = $('<span class="slick-cell-menu-content"></span>')
502 .text(item.title)
503 .appendTo($li);
504
505 if (item.textCssClass) {
506 $text.addClass(item.textCssClass);
507 }
508 }
509 }
510
511 /** Construct the Command Items section. */
512 function populateCommandItems(cellMenu, commandMenuElm, commandItems, args) {
513 if (!args || !commandItems || !cellMenu) {
514 return;
515 }
516
517 // user could pass a title on top of the Commands section
518 if (cellMenu && cellMenu.commandTitle) {
519 $commandTitleElm = $('<div class="title"/>').append(cellMenu.commandTitle);
520 $commandTitleElm.appendTo(commandMenuElm);
521 }
522
523 for (var i = 0, ln = commandItems.length; i < ln; i++) {
524 var item = commandItems[i];
525
526 // run each override functions to know if the item is visible and usable
527 var isItemVisible = runOverrideFunctionWhenExists(item.itemVisibilityOverride, args);
528 var isItemUsable = runOverrideFunctionWhenExists(item.itemUsabilityOverride, args);
529
530 // if the result is not visible then there's no need to go further
531 if (!isItemVisible) {
532 continue;
533 }
534
535 // when the override is defined, we need to use its result to update the disabled property
536 // so that "handleMenuItemCommandClick" has the correct flag and won't trigger a command clicked event
537 if (Object.prototype.hasOwnProperty.call(item, "itemUsabilityOverride")) {
538 item.disabled = isItemUsable ? false : true;
539 }
540
541 var $li = $('<div class="slick-cell-menu-item"></div>')
542 .data("command", item.command || "")
543 .data("item", item)
544 .on("click", handleMenuItemCommandClick)
545 .appendTo(commandMenuElm);
546
547 if (item.divider || item === "divider") {
548 $li.addClass("slick-cell-menu-item-divider");
549 continue;
550 }
551
552 // if the item is disabled then add the disabled css class
553 if (item.disabled || !isItemUsable) {
554 $li.addClass("slick-cell-menu-item-disabled");
555 }
556
557 // if the item is hidden then add the hidden css class
558 if (item.hidden) {
559 $li.addClass("slick-cell-menu-item-hidden");
560 }
561
562 if (item.cssClass) {
563 $li.addClass(item.cssClass);
564 }
565
566 if (item.tooltip) {
567 $li.attr("title", item.tooltip);
568 }
569
570 var $icon = $('<div class="slick-cell-menu-icon"></div>')
571 .appendTo($li);
572
573 if (item.iconCssClass) {
574 $icon.addClass(item.iconCssClass);
575 }
576
577 if (item.iconImage) {
578 $icon.css("background-image", "url(" + item.iconImage + ")");
579 }
580
581 var $text = $('<span class="slick-cell-menu-content"></span>')
582 .text(item.title)
583 .appendTo($li);
584
585 if (item.textCssClass) {
586 $text.addClass(item.textCssClass);
587 }
588 }
589 }
590
591 function handleMenuItemCommandClick(e) {
592 var command = $(this).data("command");
593 var item = $(this).data("item");
594
595 if (!item || item.disabled || item.divider || item === "divider") {
596 return;
597 }
598
599 var row = $menu.data("row");
600 var cell = $menu.data("cell");
601
602 var columnDef = _grid.getColumns()[cell];
603 var dataContext = _grid.getDataItem(row);
604
605 if (command !== null && command !== "") {
606 // user could execute a callback through 2 ways
607 // via the onCommand event and/or an action callback
608 var callbackArgs = {
609 "cell": cell,
610 "row": row,
611 "grid": _grid,
612 "command": command,
613 "item": item,
614 "column": columnDef,
615 "dataContext": dataContext
616 };
617 _self.onCommand.notify(callbackArgs, e, _self);
618
619 // execute action callback when defined
620 if (typeof item.action === "function") {
621 item.action.call(this, e, callbackArgs);
622 }
623
624 if(!e.isDefaultPrevented()) {
625 closeMenu(e, { cell: cell, row: row });
626 }
627 }
628 }
629
630 function handleMenuItemOptionClick(e) {
631 var option = $(this).data("option");
632 var item = $(this).data("item");
633
634 if (!item || item.disabled || item.divider || item === "divider") {
635 return;
636 }
637 if (!_grid.getEditorLock().commitCurrentEdit()) {
638 return;
639 }
640
641 var row = $menu.data("row");
642 var cell = $menu.data("cell");
643
644 var columnDef = _grid.getColumns()[cell];
645 var dataContext = _grid.getDataItem(row);
646
647 if (option !== undefined) {
648 // user could execute a callback through 2 ways
649 // via the onOptionSelected event and/or an action callback
650 var callbackArgs = {
651 "cell": cell,
652 "row": row,
653 "grid": _grid,
654 "option": option,
655 "item": item,
656 "column": columnDef,
657 "dataContext": dataContext
658 };
659 _self.onOptionSelected.notify(callbackArgs, e, _self);
660
661 // execute action callback when defined
662 if (typeof item.action === "function") {
663 item.action.call(this, e, callbackArgs);
664 }
665
666 if(!e.isDefaultPrevented()) {
667 closeMenu(e, { cell: cell, row: row });
668 }
669 }
670 }
671
672 /**
673 * Method that user can pass to override the default behavior.
674 * In order word, user can choose or an item is (usable/visible/enable) by providing his own logic.
675 * @param overrideFn: override function callback
676 * @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid)
677 */
678 function runOverrideFunctionWhenExists(overrideFn, args) {
679 if (typeof overrideFn === 'function') {
680 return overrideFn.call(this, args);
681 }
682 return true;
683 }
684
685 $.extend(this, {
686 "init": init,
687 "closeMenu": destroyMenu,
688 "destroy": destroy,
689 "pluginName": "CellMenu",
690 "setOptions": setOptions,
691
692 "onAfterMenuShow": new Slick.Event(),
693 "onBeforeMenuShow": new Slick.Event(),
694 "onBeforeMenuClose": new Slick.Event(),
695 "onCommand": new Slick.Event(),
696 "onOptionSelected": new Slick.Event()
697 });
698 }
699})(jQuery);