add conetext menu
This commit is contained in:
391
dist/sigpro-grid.esm.js
vendored
391
dist/sigpro-grid.esm.js
vendored
@@ -3516,6 +3516,9 @@ function _normaliseQwertyAzerty(keyboardEvent) {
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function _isPromise(fn) {
|
||||
return typeof fn.then === "function";
|
||||
}
|
||||
function _wrapInterval(action, timeout) {
|
||||
return new AgPromise((resolve) => {
|
||||
resolve(window.setInterval(action, timeout));
|
||||
@@ -56519,6 +56522,174 @@ var AgMenuList = class extends AgTabGuardComp {
|
||||
super.destroy();
|
||||
}
|
||||
};
|
||||
var CSS_MENU = "ag-menu";
|
||||
var CSS_CONTEXT_MENU_LOADING_ICON = "ag-context-menu-loading-icon";
|
||||
var AgContextMenuService = class extends AgBeanStub {
|
||||
constructor(params) {
|
||||
super();
|
||||
this.params = params;
|
||||
this.destroyLoadingSpinner = null;
|
||||
this.lastPromise = 0;
|
||||
}
|
||||
hideActiveMenu() {
|
||||
this.destroyBean(this.activeMenu);
|
||||
}
|
||||
showMenu(menuActionParams, mouseEvent, anchorToElement) {
|
||||
const { getMenuItems, shouldBlockMenuOpen: shouldBlockMenu } = this.params;
|
||||
const menuItems = getMenuItems(menuActionParams, mouseEvent);
|
||||
if (_isPromise(menuItems)) {
|
||||
const currentPromise = this.lastPromise + 1;
|
||||
this.lastPromise = currentPromise;
|
||||
if (!this.destroyLoadingSpinner) {
|
||||
this.createLoadingIcon(mouseEvent);
|
||||
}
|
||||
menuItems.then((menuItems2) => {
|
||||
if (this.lastPromise !== currentPromise) {
|
||||
return;
|
||||
}
|
||||
const { target } = mouseEvent;
|
||||
const isFromFakeEvent = !target;
|
||||
const shouldShowMenu = menuItems2?.length && (isFromFakeEvent || _isVisible(target)) && !shouldBlockMenu?.();
|
||||
if (shouldShowMenu) {
|
||||
this.createContextMenu({ menuItems: menuItems2, menuActionParams, mouseEvent, anchorToElement });
|
||||
}
|
||||
this.destroyLoadingSpinner?.();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (!menuItems?.length) {
|
||||
return false;
|
||||
}
|
||||
this.createContextMenu({ menuItems, menuActionParams, mouseEvent, anchorToElement });
|
||||
return true;
|
||||
}
|
||||
createLoadingIcon(mouseEvent) {
|
||||
const { beans } = this;
|
||||
const translate = this.getLocaleTextFunc();
|
||||
const loadingIcon = beans.iconSvc.createIconNoSpan("loadingMenuItems");
|
||||
const wrapperEl = _createAgElement({ tag: "div", cls: CSS_CONTEXT_MENU_LOADING_ICON });
|
||||
wrapperEl.appendChild(loadingIcon);
|
||||
const rootNode = _getRootNode(beans);
|
||||
const targetEl = _getPageBody(beans);
|
||||
if (!targetEl) {
|
||||
return;
|
||||
}
|
||||
targetEl.appendChild(wrapperEl);
|
||||
beans.ariaAnnounce?.announceValue(translate("ariaLabelLoadingContextMenu", "Loading Context Menu"), "contextmenu");
|
||||
beans.environment.applyThemeClasses(wrapperEl);
|
||||
_anchorElementToMouseMoveEvent(wrapperEl, mouseEvent, beans);
|
||||
const mouseMoveCallback = (e) => {
|
||||
_anchorElementToMouseMoveEvent(wrapperEl, e, beans);
|
||||
};
|
||||
rootNode.addEventListener("mousemove", mouseMoveCallback);
|
||||
this.destroyLoadingSpinner = () => {
|
||||
rootNode.removeEventListener("mousemove", mouseMoveCallback);
|
||||
wrapperEl.remove();
|
||||
this.destroyLoadingSpinner = null;
|
||||
};
|
||||
}
|
||||
createContextMenu(params) {
|
||||
const {
|
||||
mapMenuItems,
|
||||
menuItemCallbacks,
|
||||
beforeMenuOpen,
|
||||
onMenuClose,
|
||||
afterMenuDestroyed,
|
||||
onVisibleChanged,
|
||||
onMenuOpen
|
||||
} = this.params;
|
||||
const { menuItems, menuActionParams, mouseEvent, anchorToElement } = params;
|
||||
const popupSvc = this.beans.popupSvc;
|
||||
const getMenuItems = mapMenuItems ? (getGui) => mapMenuItems(menuItems, menuActionParams, getGui) : () => menuItems;
|
||||
const menu = new ContextMenu(getMenuItems, menuActionParams, menuItemCallbacks);
|
||||
this.createBean(menu);
|
||||
const eMenuGui = menu.getGui();
|
||||
beforeMenuOpen?.(menuActionParams);
|
||||
const positionParams = {
|
||||
additionalParams: menuItemCallbacks.getPostProcessPopupParams(menuActionParams),
|
||||
type: "contextMenu",
|
||||
mouseEvent,
|
||||
ePopup: eMenuGui,
|
||||
nudgeY: 1
|
||||
};
|
||||
const translate = this.getLocaleTextFunc();
|
||||
const addPopupRes = popupSvc?.addPopup({
|
||||
modal: true,
|
||||
eChild: eMenuGui,
|
||||
closeOnEsc: true,
|
||||
closedCallback: (e) => {
|
||||
menuItemCallbacks.preserveRangesWhile(this.beans, () => {
|
||||
onMenuClose?.();
|
||||
this.destroyBean(menu);
|
||||
afterMenuDestroyed?.();
|
||||
onVisibleChanged?.(false, e === undefined ? "api" : "ui");
|
||||
});
|
||||
},
|
||||
click: mouseEvent,
|
||||
positionCallback: () => {
|
||||
const isRtl = this.gos.get("enableRtl");
|
||||
popupSvc?.positionPopupUnderMouseEvent({
|
||||
...positionParams,
|
||||
nudgeX: isRtl ? (eMenuGui.offsetWidth + 1) * -1 : 1
|
||||
});
|
||||
},
|
||||
anchorToElement,
|
||||
ariaLabel: translate("ariaLabelContextMenu", "Context Menu")
|
||||
});
|
||||
if (addPopupRes) {
|
||||
onMenuOpen?.();
|
||||
menu.afterGuiAttached({ container: "contextMenu", hidePopup: addPopupRes.hideFunc });
|
||||
}
|
||||
if (this.activeMenu) {
|
||||
this.hideActiveMenu();
|
||||
}
|
||||
this.activeMenu = menu;
|
||||
menu.addEventListener("destroyed", () => {
|
||||
if (this.activeMenu === menu) {
|
||||
this.activeMenu = null;
|
||||
}
|
||||
});
|
||||
if (addPopupRes) {
|
||||
menu.addEventListener("closeMenu", (e) => addPopupRes.hideFunc({
|
||||
mouseEvent: e.mouseEvent ?? undefined,
|
||||
keyboardEvent: e.keyboardEvent ?? undefined,
|
||||
forceHide: true
|
||||
}));
|
||||
}
|
||||
const isApi = mouseEvent && mouseEvent instanceof MouseEvent && mouseEvent.type === "mousedown";
|
||||
onVisibleChanged?.(true, isApi ? "api" : "ui");
|
||||
}
|
||||
destroy() {
|
||||
this.destroyLoadingSpinner?.();
|
||||
super.destroy();
|
||||
}
|
||||
};
|
||||
var ContextMenu = class extends AgComponentStub {
|
||||
constructor(getMenuItems, menuActionParams, callbacks) {
|
||||
super({ tag: "div", cls: CSS_MENU, role: "presentation" });
|
||||
this.getMenuItems = getMenuItems;
|
||||
this.menuActionParams = menuActionParams;
|
||||
this.callbacks = callbacks;
|
||||
this.menuList = null;
|
||||
}
|
||||
postConstruct() {
|
||||
const menuList = this.createManagedBean(new AgMenuList(0, this.menuActionParams, this.callbacks));
|
||||
const menuItemsMapped = this.getMenuItems(() => this.getGui());
|
||||
menuList.addMenuItems(menuItemsMapped);
|
||||
this.appendChild(menuList);
|
||||
this.menuList = menuList;
|
||||
menuList.addEventListener("closeMenu", (e) => this.dispatchLocalEvent(e));
|
||||
}
|
||||
afterGuiAttached({ hidePopup }) {
|
||||
if (hidePopup) {
|
||||
this.addDestroyFunc(hidePopup);
|
||||
}
|
||||
const menuList = this.menuList;
|
||||
if (menuList) {
|
||||
this.callbacks.preserveRangesWhile(this.beans, () => _focusInto(menuList.getGui()));
|
||||
}
|
||||
}
|
||||
};
|
||||
var AgMenuItemRenderer = class extends AgComponentStub {
|
||||
constructor(callbacks) {
|
||||
super({ tag: "div" });
|
||||
@@ -63630,6 +63801,193 @@ var ColumnMenuFactory = class extends BeanStub {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
var CSS_CONTEXT_MENU_OPEN = "ag-context-menu-open";
|
||||
var ContextMenuService = class extends BeanStub {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.beanName = "contextMenuSvc";
|
||||
this.focusedCell = null;
|
||||
}
|
||||
postConstruct() {
|
||||
this.menu = this.createManagedBean(new AgContextMenuService({
|
||||
menuItemCallbacks: MENU_ITEM_CALLBACKS,
|
||||
getMenuItems: this.getMenuItems.bind(this),
|
||||
mapMenuItems: this.mapWithStockItems.bind(this),
|
||||
beforeMenuOpen: this.beforeMenuOpen.bind(this),
|
||||
onMenuOpen: this.onMenuOpen.bind(this),
|
||||
onMenuClose: this.onMenuClose.bind(this),
|
||||
afterMenuDestroyed: this.afterMenuDestroyed.bind(this),
|
||||
onVisibleChanged: this.dispatchVisibleChangedEvent.bind(this),
|
||||
shouldBlockMenuOpen: () => !!this.beans.overlays?.exclusive
|
||||
}));
|
||||
}
|
||||
hideActiveMenu() {
|
||||
this.menu.hideActiveMenu();
|
||||
}
|
||||
getMenuItems(menuActionParams, mouseEvent) {
|
||||
const { column, node, value } = menuActionParams;
|
||||
const defaultMenuOptions = [];
|
||||
const { clipboardSvc, chartSvc, csvCreator, excelCreator, colModel, rangeSvc, gos } = this.beans;
|
||||
if (_exists(node) && clipboardSvc) {
|
||||
if (column) {
|
||||
if (!gos.get("suppressCutToClipboard")) {
|
||||
defaultMenuOptions.push("cut");
|
||||
}
|
||||
defaultMenuOptions.push("copy", "copyWithHeaders", "copyWithGroupHeaders", "paste", "separator");
|
||||
}
|
||||
}
|
||||
if (gos.get("enableCharts") && chartSvc) {
|
||||
if (colModel.isPivotMode()) {
|
||||
defaultMenuOptions.push("pivotChart");
|
||||
}
|
||||
if (rangeSvc && !rangeSvc.isEmpty()) {
|
||||
defaultMenuOptions.push("chartRange");
|
||||
}
|
||||
}
|
||||
if (_exists(node)) {
|
||||
const enableRowPinning = gos.get("enableRowPinning");
|
||||
const isRowPinnable = gos.get("isRowPinnable");
|
||||
if (enableRowPinning) {
|
||||
const isGroupTotalRow = node.level > -1 && node.footer;
|
||||
const isGrandTotalRow = node.level === -1 && node.footer;
|
||||
const grandTotalRow = _getGrandTotalRow(gos);
|
||||
const isGrandTotalRowFixed = grandTotalRow === "pinnedBottom" || grandTotalRow === "pinnedTop";
|
||||
if (isGrandTotalRow && !isGrandTotalRowFixed || !isGrandTotalRow && !isGroupTotalRow) {
|
||||
const pinnable = isRowPinnable?.(node) ?? true;
|
||||
if (pinnable) {
|
||||
defaultMenuOptions.push("pinRowSubMenu");
|
||||
}
|
||||
}
|
||||
}
|
||||
const suppressExcel = gos.get("suppressExcelExport") || !excelCreator;
|
||||
const suppressCsv = gos.get("suppressCsvExport") || !csvCreator;
|
||||
const onIPad = _isIOSUserAgent();
|
||||
const anyExport = !onIPad && (!suppressExcel || !suppressCsv);
|
||||
if (anyExport) {
|
||||
defaultMenuOptions.push("export");
|
||||
}
|
||||
}
|
||||
const defaultItems = defaultMenuOptions.length ? defaultMenuOptions : undefined;
|
||||
const columnContextMenuItems = column?.getColDef().contextMenuItems;
|
||||
if (Array.isArray(columnContextMenuItems)) {
|
||||
return columnContextMenuItems;
|
||||
}
|
||||
if (typeof columnContextMenuItems === "function") {
|
||||
return columnContextMenuItems(_addGridCommonParams(gos, {
|
||||
column,
|
||||
node,
|
||||
value,
|
||||
defaultItems,
|
||||
event: mouseEvent
|
||||
}));
|
||||
}
|
||||
const userFunc = gos.getCallback("getContextMenuItems");
|
||||
return userFunc?.({ column, node, value, defaultItems, event: mouseEvent }) ?? defaultMenuOptions;
|
||||
}
|
||||
getContextMenuPosition(rowNode, column) {
|
||||
const rowCtrl = this.getRowCtrl(rowNode);
|
||||
const eGui = this.getCellGui(rowCtrl, column);
|
||||
if (!eGui) {
|
||||
return { x: 0, y: rowCtrl?.getRowYPosition() ?? 0 };
|
||||
}
|
||||
const rect = eGui.getBoundingClientRect();
|
||||
return {
|
||||
x: rect.x + rect.width / 2,
|
||||
y: rect.y + rect.height / 2
|
||||
};
|
||||
}
|
||||
showContextMenu(params) {
|
||||
const rowNode = params.rowNode ?? null;
|
||||
const column = params.column ?? null;
|
||||
let { anchorToElement, value, source } = params;
|
||||
if (rowNode && column && value == null) {
|
||||
value = this.beans.valueSvc.getValueForDisplay({ column, node: rowNode, from: "edit" }).value;
|
||||
}
|
||||
if (anchorToElement == null) {
|
||||
anchorToElement = this.getContextMenuAnchorElement(rowNode, column);
|
||||
}
|
||||
this.beans.menuUtils.onContextMenu({
|
||||
mouseEvent: params.mouseEvent ?? null,
|
||||
touchEvent: params.touchEvent ?? null,
|
||||
showMenuCallback: (eventOrTouch) => this.menu.showMenu({ node: rowNode, column, value }, eventOrTouch, anchorToElement),
|
||||
source
|
||||
});
|
||||
}
|
||||
handleContextMenuMouseEvent(mouseEvent, touchEvent, rowCtrl, cellCtrl) {
|
||||
const rowNode = cellCtrl?.rowNode ?? rowCtrl?.rowNode ?? null;
|
||||
const column = cellCtrl?.column ?? rowCtrl?.findFullWidthInfoForEvent(mouseEvent || touchEvent)?.column ?? null;
|
||||
const { valueSvc, ctrlsSvc } = this.beans;
|
||||
const value = column ? valueSvc.getValue(column, rowNode, "edit") : null;
|
||||
const gridBodyCon = ctrlsSvc.getGridBodyCtrl();
|
||||
const anchorToElement = cellCtrl ? cellCtrl.eGui : gridBodyCon.eGridBody;
|
||||
this.showContextMenu({
|
||||
mouseEvent,
|
||||
touchEvent,
|
||||
rowNode,
|
||||
column,
|
||||
value,
|
||||
anchorToElement,
|
||||
source: "ui"
|
||||
});
|
||||
}
|
||||
beforeMenuOpen(menuActionParams) {
|
||||
if (!menuActionParams.column) {
|
||||
this.beans.focusSvc.clearFocusedCell();
|
||||
}
|
||||
}
|
||||
onMenuOpen() {
|
||||
const { ctrlsSvc, focusSvc } = this.beans;
|
||||
ctrlsSvc.getGridBodyCtrl().eGridBody.classList.add(CSS_CONTEXT_MENU_OPEN);
|
||||
this.focusedCell = focusSvc.getFocusedCell();
|
||||
}
|
||||
onMenuClose() {
|
||||
this.beans.ctrlsSvc.getGridBodyCtrl().eGridBody.classList.remove(CSS_CONTEXT_MENU_OPEN);
|
||||
}
|
||||
afterMenuDestroyed() {
|
||||
const { beans, focusedCell } = this;
|
||||
_attemptToRestoreCellFocus(beans, focusedCell);
|
||||
}
|
||||
dispatchVisibleChangedEvent(visible, source) {
|
||||
this.eventSvc.dispatchEvent({
|
||||
type: "contextMenuVisibleChanged",
|
||||
visible,
|
||||
source
|
||||
});
|
||||
}
|
||||
getRowCtrl(rowNode) {
|
||||
const { rowIndex, rowPinned } = rowNode || {};
|
||||
if (rowIndex == null) {
|
||||
return;
|
||||
}
|
||||
return this.beans.rowRenderer.getRowByPosition({ rowIndex, rowPinned }) || undefined;
|
||||
}
|
||||
getCellGui(rowCtrl, column) {
|
||||
if (!rowCtrl || !column) {
|
||||
return;
|
||||
}
|
||||
const cellCtrl = rowCtrl.getCellCtrl(column);
|
||||
return cellCtrl?.eGui || undefined;
|
||||
}
|
||||
getContextMenuAnchorElement(rowNode, column) {
|
||||
const gridBodyEl = this.beans.ctrlsSvc.getGridBodyCtrl().eGridBody;
|
||||
const rowCtrl = this.getRowCtrl(rowNode);
|
||||
if (!rowCtrl) {
|
||||
return gridBodyEl;
|
||||
}
|
||||
const cellGui = this.getCellGui(rowCtrl, column);
|
||||
if (cellGui) {
|
||||
return cellGui;
|
||||
}
|
||||
if (rowCtrl.isFullWidth()) {
|
||||
return rowCtrl.getFullWidthElement();
|
||||
}
|
||||
return gridBodyEl;
|
||||
}
|
||||
mapWithStockItems(menuItems, menuActionParams, getGui) {
|
||||
const { column, node } = menuActionParams;
|
||||
return this.beans.menuItemMapper.mapWithStockItems(menuItems, column, node, getGui, "contextMenu");
|
||||
}
|
||||
};
|
||||
var TAB_FILTER = "filterMenuTab";
|
||||
var TAB_GENERAL = "generalMenuTab";
|
||||
var TAB_COLUMNS = "columnsMenuTab";
|
||||
@@ -64011,6 +64369,27 @@ var ColumnContextMenu = class extends Component {
|
||||
_focusInto(this.mainMenuList.getGui());
|
||||
}
|
||||
};
|
||||
function showContextMenu(beans, params) {
|
||||
const { contextMenuSvc } = beans;
|
||||
if (!contextMenuSvc) {
|
||||
return;
|
||||
}
|
||||
const { rowNode, column, value, x, y } = params || {};
|
||||
let { x: clientX, y: clientY } = contextMenuSvc.getContextMenuPosition(rowNode, column);
|
||||
if (x != null) {
|
||||
clientX = x;
|
||||
}
|
||||
if (y != null) {
|
||||
clientY = y;
|
||||
}
|
||||
contextMenuSvc.showContextMenu({
|
||||
mouseEvent: new MouseEvent("mousedown", { clientX, clientY }),
|
||||
rowNode,
|
||||
column,
|
||||
value,
|
||||
source: "api"
|
||||
});
|
||||
}
|
||||
function showColumnChooser(beans, params) {
|
||||
beans.colChooserFactory?.showColumnChooser({ chooserParams: params });
|
||||
}
|
||||
@@ -64155,6 +64534,15 @@ var ColumnMenuModule = {
|
||||
},
|
||||
dependsOn: [MenuCoreModule, SharedDragAndDropModule, ColumnMoveModule]
|
||||
};
|
||||
var ContextMenuModule = {
|
||||
moduleName: "ContextMenu",
|
||||
version: VERSION2,
|
||||
beans: [ContextMenuService],
|
||||
apiFunctions: {
|
||||
showContextMenu
|
||||
},
|
||||
dependsOn: [MenuCoreModule]
|
||||
};
|
||||
var SET_FILTER_SELECT_ALL = "__AG_SELECT_ALL__";
|
||||
var SET_FILTER_ADD_SELECTION_TO_FILTER = "__AG_ADD_SELECTION_TO_FILTER__";
|
||||
var FlatSetDisplayValueModel = class {
|
||||
@@ -77586,7 +77974,8 @@ ModuleRegistry.registerModules([
|
||||
NumberFilterModule,
|
||||
TextFilterModule,
|
||||
SetFilterModule,
|
||||
DateFilterModule
|
||||
DateFilterModule,
|
||||
ContextMenuModule
|
||||
]);
|
||||
var Grid = (props) => {
|
||||
const { data, options, api, on, class: className, style = "height: 100%; width: 100%", dark } = props;
|
||||
|
||||
68
dist/sigpro-grid.esm.min.js
vendored
68
dist/sigpro-grid.esm.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@ import {
|
||||
StatusBarModule,
|
||||
ExcelExportModule,
|
||||
ClipboardModule,
|
||||
ContextMenuModule
|
||||
} from "../ag-grid";
|
||||
|
||||
ModuleRegistry.registerModules([
|
||||
@@ -50,7 +51,8 @@ ModuleRegistry.registerModules([
|
||||
NumberFilterModule,
|
||||
TextFilterModule,
|
||||
SetFilterModule,
|
||||
DateFilterModule
|
||||
DateFilterModule,
|
||||
ContextMenuModule
|
||||
]);
|
||||
|
||||
const Grid = (props) => {
|
||||
|
||||
Reference in New Issue
Block a user