UNPKG

@bokeh/slickgrid

Version:

A lightning fast JavaScript grid/spreadsheet

229 lines (192 loc) 7.71 kB
var $ = require("../slick.jquery"); var Slick = require("../slick.core"); /*** * A plugin to add custom buttons to column headers. * * USAGE: * * Add the plugin .js & .css files and register it with the grid. * * To specify a custom button in a column header, extend the column definition like so: * * var columns = [ * { * id: 'myColumn', * name: 'My column', * * // This is the relevant part * header: { * buttons: [ * { * // button options * }, * { * // button options * } * ] * } * } * ]; * * Available button options: * cssClass: CSS class to add to the button. * image: Relative button image path. * disabled: Whether the item is disabled. * tooltip: Button tooltip. * showOnHover: Only show the button on hover. * handler: Button click handler. * command: A command identifier to be passed to the onCommand event handlers. * * Available menu item options: * action: Optionally define a callback function that gets executed when item is chosen (and/or use the onCommand event) * command: A command identifier to be passed to the onCommand event handlers. * cssClass: CSS class to add to the button. * handler: Button click handler. * image: Relative button image path. * showOnHover: Only show the button on hover. * tooltip: Button tooltip. * itemVisibilityOverride: Callback method that user can override the default behavior of showing/hiding an item from the list * itemUsabilityOverride: Callback method that user can override the default behavior of enabling/disabling an item from the list * * The plugin exposes the following events: * onCommand: Fired on button click for buttons with 'command' specified. * Event args: * grid: Reference to the grid. * column: Column definition. * command: Button command identified. * button: Button options. Note that you can change the button options in your * event handler, and the column header will be automatically updated to * reflect them. This is useful if you want to implement something like a * toggle button. * * * @param options {Object} Options: * buttonCssClass: a CSS class to use for buttons (default 'slick-header-button') * @class Slick.Plugins.HeaderButtons * @constructor */ function HeaderButtons(options) { var _grid; var _self = this; var _handler = new Slick.EventHandler(); var _defaults = { buttonCssClass: "slick-header-button" }; function init(grid) { options = $.extend(true, {}, _defaults, options); _grid = grid; _handler .subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered) .subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy); // Force the grid to re-render the header now that the events are hooked up. _grid.setColumns(_grid.getColumns()); } function destroy() { _handler.unsubscribeAll(); } function handleHeaderCellRendered(e, args) { var column = args.column; if (column.header && column.header.buttons) { // Append buttons in reverse order since they are floated to the right. var i = column.header.buttons.length; while (i--) { var button = column.header.buttons[i]; // run each override functions to know if the item is visible and usable var isItemVisible = runOverrideFunctionWhenExists(button.itemVisibilityOverride, args); var isItemUsable = runOverrideFunctionWhenExists(button.itemUsabilityOverride, args); // if the result is not visible then there's no need to go further if (!isItemVisible) { continue; } // when the override is defined, we need to use its result to update the disabled property // so that "handleMenuItemCommandClick" has the correct flag and won't trigger a command clicked event if (Object.prototype.hasOwnProperty.call(button, "itemUsabilityOverride")) { button.disabled = isItemUsable ? false : true; } var btn = $("<div></div>") .addClass(options.buttonCssClass) .data("column", column) .data("button", button); if (button.disabled) { btn.addClass("slick-header-button-disabled"); } if (button.showOnHover) { btn.addClass("slick-header-button-hidden"); } if (button.image) { btn.css("backgroundImage", "url(" + button.image + ")"); } if (button.cssClass) { btn.addClass(button.cssClass); } if (button.tooltip) { btn.attr("title", button.tooltip); } if (button.command) { btn.data("command", button.command); } if (button.handler) { btn.on("click", button.handler); } btn .on("click", handleButtonClick) .appendTo(args.node); } } } function handleBeforeHeaderCellDestroy(e, args) { var column = args.column; if (column.header && column.header.buttons) { // Removing buttons via jQuery will also clean up any event handlers and data. // NOTE: If you attach event handlers directly or using a different framework, // you must also clean them up here to avoid memory leaks. $(args.node).find("." + options.buttonCssClass).remove(); } } function handleButtonClick(e) { var command = $(this).data("command"); var columnDef = $(this).data("column"); var button = $(this).data("button"); var callbackArgs = { "grid": _grid, "column": columnDef, "button": button }; if (command != null) { callbackArgs.command = command; } // execute action callback when defined if (typeof button.action === "function") { button.action.call(this, e, callbackArgs); } if (command != null && !button.disabled) { _self.onCommand.notify(callbackArgs, e, _self); // Update the header in case the user updated the button definition in the handler. _grid.updateColumnHeader(columnDef.id); } // Stop propagation so that it doesn't register as a header click event. e.preventDefault(); e.stopPropagation(); } /** * Method that user can pass to override the default behavior. * In order word, user can choose or an item is (usable/visible/enable) by providing his own logic. * @param overrideFn: override function callback * @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid) */ function runOverrideFunctionWhenExists(overrideFn, args) { if (typeof overrideFn === 'function') { return overrideFn.call(this, args); } return true; } $.extend(this, { "init": init, "destroy": destroy, "pluginName": "HeaderButtons", "onCommand": new Slick.Event() }); } module.exports = { "HeaderButtons": HeaderButtons };