slickgrid
Version:
A lightning fast JavaScript grid/spreadsheet
198 lines (196 loc) • 14.3 kB
JavaScript
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.headermenu.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, SlickEventHandler = Slick.EventHandler, Utils = Slick.Utils, SlickHeaderMenu = class {
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "HeaderMenu");
__publicField(this, "onAfterMenuShow", new SlickEvent("onAfterMenuShow"));
__publicField(this, "onBeforeMenuShow", new SlickEvent("onBeforeMenuShow"));
__publicField(this, "onCommand", new SlickEvent("onCommand"));
// --
// protected props
__publicField(this, "_grid");
__publicField(this, "_gridUid", "");
__publicField(this, "_handler", new SlickEventHandler());
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "_defaults", {
buttonCssClass: void 0,
buttonImage: void 0,
minWidth: 100,
autoAlign: !0,
autoAlignOffset: 0,
subMenuOpenByEvent: "mouseover"
});
__publicField(this, "_options");
__publicField(this, "_activeHeaderColumnElm");
__publicField(this, "_menuElm");
__publicField(this, "_subMenuParentId", "");
this._options = Utils.extend(!0, {}, options, this._defaults);
}
init(grid) {
this._grid = grid, this._gridUid = (grid == null ? void 0 : grid.getUID()) || "", Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._handler.subscribe(this._grid.onHeaderCellRendered, this.handleHeaderCellRendered.bind(this)).subscribe(this._grid.onBeforeHeaderCellDestroy, this.handleBeforeHeaderCellDestroy.bind(this)), this._grid.setColumns(this._grid.getColumns()), this._bindingEventService.bind(document.body, "click", this.handleBodyMouseDown.bind(this));
}
setOptions(newOptions) {
this._options = Utils.extend(!0, {}, this._options, newOptions);
}
getGridUidSelector() {
let gridUid = this._grid.getUID() || "";
return gridUid ? `.${gridUid}` : "";
}
destroy() {
var _a;
this._handler.unsubscribeAll(), this._bindingEventService.unbindAll(), this._menuElm = this._menuElm || document.body.querySelector(`.slick-header-menu${this.getGridUidSelector()}`), (_a = this._menuElm) == null || _a.remove(), this._activeHeaderColumnElm = void 0;
}
destroyAllMenus() {
this.destroySubMenus(), this._bindingEventService.unbindAll("parent-menu"), document.querySelectorAll(`.slick-header-menu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
/** Close and destroy all previously opened sub-menus */
destroySubMenus() {
this._bindingEventService.unbindAll("sub-menu"), document.querySelectorAll(`.slick-header-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
handleBodyMouseDown(e) {
var _a;
let isMenuClicked = !1;
(_a = this._menuElm) != null && _a.contains(e.target) && (isMenuClicked = !0), isMenuClicked || document.querySelectorAll(`.slick-header-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => {
subElm.contains(e.target) && (isMenuClicked = !0);
}), (this._menuElm !== e.target && !isMenuClicked && !e.defaultPrevented || e.target.className === "close") && this.hideMenu();
}
hideMenu() {
var _a;
this._menuElm && (this._menuElm.remove(), this._menuElm = void 0), (_a = this._activeHeaderColumnElm) == null || _a.classList.remove("slick-header-column-active"), this.destroySubMenus();
}
handleHeaderCellRendered(_e, args) {
var _a;
let column = args.column, menu = (_a = column == null ? void 0 : column.header) == null ? void 0 : _a.menu;
if (menu != null && menu.items && console.warn('[SlickGrid] Header Menu "items" property was deprecated in favor of "commandItems" to align with all other Menu plugins.'), menu) {
if (!this.runOverrideFunctionWhenExists(this._options.menuUsabilityOverride, args))
return;
let elm = document.createElement("div");
if (elm.className = "slick-header-menubutton", elm.ariaLabel = "Header Menu", elm.role = "button", !this._options.buttonCssClass && !this._options.buttonImage && (this._options.buttonCssClass = "caret"), this._options.buttonCssClass) {
let icon = document.createElement("span");
icon.classList.add(...Utils.classNameToList(this._options.buttonCssClass)), elm.appendChild(icon);
}
this._options.buttonImage && (elm.style.backgroundImage = `url(${this._options.buttonImage})`), this._options.tooltip && (elm.title = this._options.tooltip), this._bindingEventService.bind(elm, "click", (e) => {
this.destroyAllMenus(), this.createParentMenu(e, menu, args.column);
}), args.node.appendChild(elm);
}
}
handleBeforeHeaderCellDestroy(_e, args) {
var _a;
(_a = args.column.header) != null && _a.menu && args.node.querySelectorAll(".slick-header-menubutton").forEach((elm) => elm.remove());
}
addSubMenuTitleWhenExists(item, commandMenuElm) {
if (item !== "divider" && (item != null && item.subMenuTitle)) {
let subMenuTitleElm = document.createElement("div");
subMenuTitleElm.className = "slick-menu-title", subMenuTitleElm.textContent = item.subMenuTitle;
let subMenuTitleClass = item.subMenuTitleCssClass;
subMenuTitleClass && subMenuTitleElm.classList.add(...Utils.classNameToList(subMenuTitleClass)), commandMenuElm.appendChild(subMenuTitleElm);
}
}
createParentMenu(event, menu, columnDef) {
let callbackArgs = {
grid: this._grid,
column: columnDef,
menu
};
if (this.onBeforeMenuShow.notify(callbackArgs, event, this).getReturnValue() === !1)
return;
this._menuElm = this.createMenu(menu.commandItems || menu.items, columnDef);
let containerNode = this._grid.getContainerNode();
containerNode && containerNode.appendChild(this._menuElm), this.repositionMenu(event, this._menuElm), this.onAfterMenuShow.notify(callbackArgs, event, this).getReturnValue() !== !1 && (event.preventDefault(), event.stopPropagation());
}
createMenu(commandItems, columnDef, level = 0, item) {
let isSubMenu = level > 0, subMenuCommand = item == null ? void 0 : item.command, subMenuId = level === 1 && subMenuCommand ? subMenuCommand.replaceAll(" ", "") : "";
subMenuId && (this._subMenuParentId = subMenuId), isSubMenu && (subMenuId = this._subMenuParentId);
let menuClasses = `slick-header-menu slick-menu-level-${level} ${this._gridUid}`, bodyMenuElm = document.body.querySelector(`.slick-header-menu.slick-menu-level-${level}${this.getGridUidSelector()}`);
if (bodyMenuElm) {
if (bodyMenuElm.dataset.subMenuParent === subMenuId)
return bodyMenuElm;
this.destroySubMenus();
}
let menuElm = document.createElement("div");
menuElm.className = menuClasses, level > 0 && (menuElm.classList.add("slick-submenu"), subMenuId && (menuElm.dataset.subMenuParent = subMenuId)), menuElm.classList.add(this._gridUid), menuElm.role = "menu", menuElm.ariaLabel = level > 1 ? "SubMenu" : "Header Menu", menuElm.style.minWidth = `${this._options.minWidth}px`, menuElm.setAttribute("aria-expanded", "true");
let callbackArgs = {
grid: this._grid,
column: columnDef,
menu: { items: commandItems }
};
item && level > 0 && this.addSubMenuTitleWhenExists(item, menuElm);
for (let i = 0; i < commandItems.length; i++) {
let addClickListener = !0, item2 = commandItems[i], isItemVisible = this.runOverrideFunctionWhenExists(item2.itemVisibilityOverride, callbackArgs), isItemUsable = this.runOverrideFunctionWhenExists(item2.itemUsabilityOverride, callbackArgs);
if (!isItemVisible)
continue;
Object.prototype.hasOwnProperty.call(item2, "itemUsabilityOverride") && (item2.disabled = !isItemUsable);
let menuItemElm = document.createElement("div");
menuItemElm.className = "slick-header-menuitem", menuItemElm.role = "menuitem", (item2.divider || item2 === "divider") && (menuItemElm.classList.add("slick-header-menuitem-divider"), addClickListener = !1), item2.disabled && menuItemElm.classList.add("slick-header-menuitem-disabled"), item2.hidden && menuItemElm.classList.add("slick-header-menuitem-hidden"), item2.cssClass && menuItemElm.classList.add(...Utils.classNameToList(item2.cssClass)), item2.tooltip && (menuItemElm.title = item2.tooltip || "");
let iconElm = document.createElement("div");
iconElm.className = "slick-header-menuicon", menuItemElm.appendChild(iconElm), item2.iconCssClass && iconElm.classList.add(...Utils.classNameToList(item2.iconCssClass)), item2.iconImage && (iconElm.style.backgroundImage = "url(" + item2.iconImage + ")");
let textElm = document.createElement("span");
if (textElm.className = "slick-header-menucontent", textElm.textContent = item2.title || "", menuItemElm.appendChild(textElm), item2.textCssClass && textElm.classList.add(...Utils.classNameToList(item2.textCssClass)), menuElm.appendChild(menuItemElm), addClickListener) {
let eventGroup = isSubMenu ? "sub-menu" : "parent-menu";
this._bindingEventService.bind(menuItemElm, "click", this.handleMenuItemClick.bind(this, item2, columnDef, level), void 0, eventGroup);
}
if (this._options.subMenuOpenByEvent === "mouseover" && this._bindingEventService.bind(menuItemElm, "mouseover", (e) => {
item2.commandItems || item2.items ? this.repositionSubMenu(item2, columnDef, level, e) : isSubMenu || this.destroySubMenus();
}), item2.commandItems || item2.items) {
let chevronElm = document.createElement("div");
chevronElm.className = "sub-item-chevron", this._options.subItemChevronClass ? chevronElm.classList.add(...Utils.classNameToList(this._options.subItemChevronClass)) : chevronElm.textContent = "\u2B9E", menuItemElm.classList.add("slick-submenu-item"), menuItemElm.appendChild(chevronElm);
}
}
return menuElm;
}
handleMenuItemClick(item, columnDef, level = 0, e) {
if (item !== "divider" && !item.disabled && !item.divider) {
let command = item.command || "";
if (Utils.isDefined(command) && !item.commandItems && !item.items) {
let callbackArgs = {
grid: this._grid,
column: columnDef,
command,
item
};
this.onCommand.notify(callbackArgs, e, this), typeof item.action == "function" && item.action.call(this, e, callbackArgs), e.defaultPrevented || this.hideMenu();
} else item.commandItems || item.items ? this.repositionSubMenu(item, columnDef, level, e) : this.destroySubMenus();
}
}
repositionSubMenu(item, columnDef, level, e) {
e.target.classList.contains("slick-header-menubutton") && this.destroySubMenus();
let subMenuElm = this.createMenu(item.commandItems || item.items || [], columnDef, level + 1, item);
document.body.appendChild(subMenuElm), this.repositionMenu(e, subMenuElm);
}
repositionMenu(e, menuElm) {
var _a, _b, _c, _d, _e, _f, _g, _h;
let buttonElm = e.target, isSubMenu = menuElm.classList.contains("slick-submenu"), parentElm = isSubMenu ? e.target.closest(".slick-header-menuitem") : buttonElm, btnOffset = Utils.offset(buttonElm), gridPos = this._grid.getGridPosition(), menuWidth = menuElm.offsetWidth, menuOffset = Utils.offset(this._menuElm), parentOffset = Utils.offset(parentElm), menuOffsetTop = isSubMenu ? (_a = parentOffset == null ? void 0 : parentOffset.top) != null ? _a : 0 : (_e = (_b = buttonElm.clientHeight) != null ? _b : btnOffset == null ? void 0 : btnOffset.top) != null ? _e : 0 + ((_d = (_c = this._options) == null ? void 0 : _c.menuOffsetTop) != null ? _d : 0), menuOffsetLeft = isSubMenu ? (_f = parentOffset == null ? void 0 : parentOffset.left) != null ? _f : 0 : (_g = btnOffset == null ? void 0 : btnOffset.left) != null ? _g : 0;
if (isSubMenu && parentElm) {
let subMenuPosCalc = menuOffsetLeft + Number(menuWidth);
isSubMenu && (subMenuPosCalc += parentElm.clientWidth);
let browserWidth = document.documentElement.clientWidth;
(subMenuPosCalc >= gridPos.width || subMenuPosCalc >= browserWidth ? "left" : "right") === "left" ? (menuElm.classList.remove("dropright"), menuElm.classList.add("dropleft"), menuOffsetLeft -= menuWidth) : (menuElm.classList.remove("dropleft"), menuElm.classList.add("dropright"), isSubMenu && (menuOffsetLeft += parentElm.offsetWidth));
} else
menuOffsetLeft + menuElm.offsetWidth >= gridPos.width && (menuOffsetLeft = menuOffsetLeft + buttonElm.clientWidth - menuElm.clientWidth + (this._options.autoAlignOffset || 0)), menuOffsetLeft -= (_h = menuOffset == null ? void 0 : menuOffset.left) != null ? _h : 0;
menuElm.style.top = `${menuOffsetTop}px`, menuElm.style.left = `${menuOffsetLeft}px`, this._activeHeaderColumnElm = menuElm.closest(".slick-header-column"), this._activeHeaderColumnElm && this._activeHeaderColumnElm.classList.add("slick-header-column-active");
}
/**
* 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)
*/
runOverrideFunctionWhenExists(overrideFn, args) {
return typeof overrideFn == "function" ? overrideFn.call(this, args) : !0;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
Plugins: {
HeaderMenu: SlickHeaderMenu
}
}
});
})();
//# sourceMappingURL=slick.headermenu.js.map