django-vue3-admin-web/node_modules/vxe-table/es/table/module/menu/hook.js
2025-10-20 21:21:14 +08:00

315 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { nextTick } from 'vue';
import XEUtils from 'xe-utils';
import { VxeUI } from '../../../ui';
import { getDomNode, getAbsolutePos, getEventTargetNode } from '../../../ui/src/dom';
import { isEnableConf, hasChildrenList } from '../../../ui/src/utils';
const { menus, hooks, globalEvents, GLOBAL_EVENT_KEYS } = VxeUI;
const tableMenuMethodKeys = ['closeMenu'];
hooks.add('tableMenuModule', {
setupTable($xeTable) {
const { xID, props, reactData, internalData } = $xeTable;
const { refElem, refTableFilter, refTableMenu } = $xeTable.getRefMaps();
const { computeMouseOpts, computeIsContentMenu, computeMenuOpts } = $xeTable.getComputeMaps();
let menuMethods = {};
let menuPrivateMethods = {};
/**
* 显示快捷菜单
*/
const handleOpenMenuEvent = (evnt, type, params) => {
const { ctxMenuStore } = reactData;
const isContentMenu = computeIsContentMenu.value;
const menuOpts = computeMenuOpts.value;
const config = menuOpts[type];
const { transfer, visibleMethod } = menuOpts;
if (config) {
const { options, disabled } = config;
if (disabled) {
evnt.preventDefault();
}
else if (isContentMenu && options && options.length) {
params.options = options;
$xeTable.preventEvent(evnt, 'event.showMenu', params, () => {
if (!visibleMethod || visibleMethod(params)) {
evnt.preventDefault();
$xeTable.updateZindex();
const el = refElem.value;
const tableRect = el.getBoundingClientRect();
const { scrollTop, scrollLeft, visibleHeight, visibleWidth } = getDomNode();
let top = evnt.clientY - tableRect.y;
let left = evnt.clientX - tableRect.x;
if (transfer) {
top = evnt.clientY + scrollTop;
left = evnt.clientX + scrollLeft;
}
const handleVisible = () => {
internalData._currMenuParams = params;
Object.assign(ctxMenuStore, {
visible: true,
list: options,
selected: null,
selectChild: null,
showChild: false,
style: {
zIndex: internalData.tZindex,
top: `${top}px`,
left: `${left}px`
}
});
nextTick(() => {
const tableMenu = refTableMenu.value;
const ctxElem = tableMenu.getRefMaps().refElem.value;
const clientHeight = ctxElem.clientHeight;
const clientWidth = ctxElem.clientWidth;
const { boundingTop, boundingLeft } = getAbsolutePos(ctxElem);
const offsetTop = boundingTop + clientHeight - visibleHeight;
const offsetLeft = boundingLeft + clientWidth - visibleWidth;
if (offsetTop > -10) {
ctxMenuStore.style.top = `${Math.max(scrollTop + 2, top - clientHeight - 2)}px`;
}
if (offsetLeft > -10) {
ctxMenuStore.style.left = `${Math.max(scrollLeft + 2, left - clientWidth - 2)}px`;
}
});
};
const { keyboard, row, column } = params;
if (keyboard && row && column) {
$xeTable.scrollToRow(row, column).then(() => {
const cell = $xeTable.getCellElement(row, column);
if (cell) {
const { boundingTop, boundingLeft } = getAbsolutePos(cell);
top = boundingTop + scrollTop + Math.floor(cell.offsetHeight / 2);
left = boundingLeft + scrollLeft + Math.floor(cell.offsetWidth / 2);
}
handleVisible();
});
}
else {
handleVisible();
}
}
else {
menuMethods.closeMenu();
}
});
}
}
$xeTable.closeFilter();
};
menuMethods = {
/**
* 关闭快捷菜单
*/
closeMenu() {
Object.assign(reactData.ctxMenuStore, {
visible: false,
selected: null,
selectChild: null,
showChild: false
});
return nextTick();
}
};
menuPrivateMethods = {
/**
* 处理菜单的移动
*/
moveCtxMenu(evnt, ctxMenuStore, property, hasOper, operRest, menuList) {
let selectItem;
const selectIndex = XEUtils.findIndexOf(menuList, item => ctxMenuStore[property] === item);
if (hasOper) {
if (operRest && hasChildrenList(ctxMenuStore.selected)) {
ctxMenuStore.showChild = true;
}
else {
ctxMenuStore.showChild = false;
ctxMenuStore.selectChild = null;
}
}
else if (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP)) {
for (let len = selectIndex - 1; len >= 0; len--) {
if (menuList[len].visible !== false) {
selectItem = menuList[len];
break;
}
}
ctxMenuStore[property] = selectItem || menuList[menuList.length - 1];
}
else if (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN)) {
for (let index = selectIndex + 1; index < menuList.length; index++) {
if (menuList[index].visible !== false) {
selectItem = menuList[index];
break;
}
}
ctxMenuStore[property] = selectItem || menuList[0];
}
else if (ctxMenuStore[property] && (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ENTER) || globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.SPACEBAR))) {
$xeTable.ctxMenuLinkEvent(evnt, ctxMenuStore[property]);
}
},
handleOpenMenuEvent,
/**
* 快捷菜单事件处理
*/
handleGlobalContextmenuEvent(evnt) {
const $xeGrid = $xeTable.xeGrid;
const $xeGantt = $xeTable.xeGantt;
const { mouseConfig, menuConfig } = props;
const { editStore, ctxMenuStore } = reactData;
const { visibleColumn } = internalData;
const tableFilter = refTableFilter.value;
const tableMenu = refTableMenu.value;
const mouseOpts = computeMouseOpts.value;
const menuOpts = computeMenuOpts.value;
const el = refElem.value;
const { selected } = editStore;
const layoutList = ['header', 'body', 'footer'];
if (isEnableConf(menuConfig)) {
if (ctxMenuStore.visible && tableMenu && getEventTargetNode(evnt, tableMenu.getRefMaps().refElem.value).flag) {
evnt.preventDefault();
return;
}
if (internalData._keyCtx) {
const type = 'body';
const params = { type, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, keyboard: true, columns: visibleColumn.slice(0), $event: evnt };
// 如果开启单元格区域
if (mouseConfig && mouseOpts.area) {
const activeArea = $xeTable.getActiveCellArea();
if (activeArea && activeArea.row && activeArea.column) {
params.row = activeArea.row;
params.column = activeArea.column;
handleOpenMenuEvent(evnt, type, params);
return;
}
}
else if (mouseConfig && mouseOpts.selected) {
// 如果启用键盘导航且已选中单元格
if (selected.row && selected.column) {
params.row = selected.row;
params.column = selected.column;
handleOpenMenuEvent(evnt, type, params);
return;
}
}
}
// 分别匹配表尾、内容、表尾的快捷菜单
for (let index = 0; index < layoutList.length; index++) {
const layout = layoutList[index];
const columnTargetNode = getEventTargetNode(evnt, el, `vxe-${layout}--column`, (target) => {
// target=td|th直接向上找 table 去匹配即可
return target.parentNode.parentNode.parentNode.getAttribute('xid') === xID;
});
const params = { type: layout, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, columns: visibleColumn.slice(0), $event: evnt };
if (columnTargetNode.flag) {
const cell = columnTargetNode.targetElem;
const columnNodeRest = $xeTable.getColumnNode(cell);
const column = columnNodeRest ? columnNodeRest.item : null;
let typePrefix = `${layout}-`;
if (column) {
Object.assign(params, { column, columnIndex: $xeTable.getColumnIndex(column), cell });
}
if (layout === 'body') {
const rowNodeRest = $xeTable.getRowNode(cell.parentNode);
const row = rowNodeRest ? rowNodeRest.item : null;
typePrefix = '';
if (row) {
params.row = row;
params.rowIndex = $xeTable.getRowIndex(row);
}
}
const eventType = `${typePrefix}cell-menu`;
handleOpenMenuEvent(evnt, layout, params);
$xeTable.dispatchEvent(eventType, params, evnt);
return;
}
else if (getEventTargetNode(evnt, el, `vxe-table--${layout}-wrapper`, target => target.getAttribute('xid') === xID).flag) {
if (menuOpts.trigger === 'cell') {
evnt.preventDefault();
}
else {
handleOpenMenuEvent(evnt, layout, params);
}
return;
}
}
}
if (tableFilter && !getEventTargetNode(evnt, tableFilter.getRefMaps().refElem.value).flag) {
$xeTable.closeFilter();
}
menuMethods.closeMenu();
},
ctxMenuMouseoverEvent(evnt, item, child) {
const menuElem = evnt.currentTarget;
const { ctxMenuStore } = reactData;
evnt.preventDefault();
evnt.stopPropagation();
ctxMenuStore.selected = item;
ctxMenuStore.selectChild = child;
if (!child) {
ctxMenuStore.showChild = hasChildrenList(item);
if (ctxMenuStore.showChild) {
nextTick(() => {
const childWrapperElem = menuElem.nextElementSibling;
if (childWrapperElem) {
const { boundingTop, boundingLeft, visibleHeight, visibleWidth } = getAbsolutePos(menuElem);
const posTop = boundingTop + menuElem.offsetHeight;
const posLeft = boundingLeft + menuElem.offsetWidth;
let left = '';
let right = '';
// 是否超出右侧
if (posLeft + childWrapperElem.offsetWidth > visibleWidth - 10) {
left = 'auto';
right = `${menuElem.offsetWidth}px`;
}
// 是否超出底部
let top = '';
let bottom = '';
if (posTop + childWrapperElem.offsetHeight > visibleHeight - 10) {
top = 'auto';
bottom = '0';
}
childWrapperElem.style.left = left;
childWrapperElem.style.right = right;
childWrapperElem.style.top = top;
childWrapperElem.style.bottom = bottom;
}
});
}
}
},
ctxMenuMouseoutEvent(evnt, item) {
const { ctxMenuStore } = reactData;
if (!item.children) {
ctxMenuStore.selected = null;
}
ctxMenuStore.selectChild = null;
},
/**
* 快捷菜单点击事件
*/
ctxMenuLinkEvent(evnt, menu) {
const $xeGrid = $xeTable.xeGrid;
const $xeGantt = $xeTable.xeGantt;
// 如果一级菜单有配置 code 则允许点击,否则不能点击
if (!menu.disabled && (menu.code || !menu.children || !menu.children.length)) {
const gMenuOpts = menus.get(menu.code);
const params = Object.assign({}, internalData._currMenuParams, { menu, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, $event: evnt });
const tmMethod = gMenuOpts ? (gMenuOpts.tableMenuMethod || gMenuOpts.menuMethod) : null;
if (tmMethod) {
tmMethod(params, evnt);
}
$xeTable.dispatchEvent('menu-click', params, evnt);
menuMethods.closeMenu();
}
}
};
return Object.assign(Object.assign({}, menuMethods), menuPrivateMethods);
},
setupGrid($xeGrid) {
return $xeGrid.extendTableMethods(tableMenuMethodKeys);
},
setupGantt($xeGantt) {
return $xeGantt.extendTableMethods(tableMenuMethodKeys);
}
});