Files
railwaysystem/RuoYi-Vue/ruoyi-ui/node_modules1/handsontable/plugins/contextMenu/menu.mjs
T
2026-09-10 15:40:10 +08:00

869 lines
27 KiB
JavaScript

import "core-js/modules/es.array.push.js";
import Cursor from "./cursor.mjs";
import { SEPARATOR, NO_ITEMS, predefinedItems } from "./predefinedItems.mjs";
import { filterSeparators, hasSubMenu, isDisabled, isItemHidden, isSeparator, isSelectionDisabled, normalizeSelection } from "./utils.mjs";
import Core from "../../core.mjs";
import EventManager from "../../eventManager.mjs";
import { arrayEach, arrayFilter, arrayReduce } from "../../helpers/array.mjs";
import { isWindowsOS, isMobileBrowser, isIpadOS } from "../../helpers/browser.mjs";
import { addClass, empty, fastInnerHTML, isChildOf, isInput, removeClass, getParentWindow, hasClass } from "../../helpers/dom/element.mjs";
import { isRightClick } from "../../helpers/dom/event.mjs";
import { debounce, isFunction } from "../../helpers/function.mjs";
import { isUndefined, isDefined } from "../../helpers/mixed.mjs";
import { mixin, hasOwnProperty } from "../../helpers/object.mjs";
import localHooks from "../../mixins/localHooks.mjs";
const MIN_WIDTH = 215;
const SHORTCUTS_CONTEXT = 'menu';
const SHORTCUTS_GROUP = SHORTCUTS_CONTEXT;
/**
* @typedef MenuOptions
* @property {Menu} [parent=null] Instance of {@link Menu}.
* @property {string} [name=null] Name of the menu.
* @property {string} [className=''] Custom class name.
* @property {boolean} [keepInViewport=true] Determine if should be kept in viewport.
* @property {boolean} [standalone] Enabling closing menu when clicked element is not belongs to menu itself.
* @property {number} [minWidth=MIN_WIDTH] The minimum width.
* @property {HTMLElement} [container] The container.
*/
/**
* @private
* @class Menu
*/
class Menu {
/**
* @param {Core} hotInstance Handsontable instance.
* @param {MenuOptions} [options] Menu options.
*/
constructor(hotInstance, options) {
this.hot = hotInstance;
this.options = options || {
parent: null,
name: null,
className: '',
keepInViewport: true,
standalone: false,
minWidth: MIN_WIDTH,
container: this.hot.rootDocument.documentElement
};
this.eventManager = new EventManager(this);
this.container = this.createContainer(this.options.name);
this.hotMenu = null;
this.hotSubMenus = {};
this.parentMenu = this.options.parent || null;
this.menuItems = null;
this.origOutsideClickDeselects = null;
this.keyEvent = false;
this.offset = {
above: 0,
below: 0,
left: 0,
right: 0
};
this._afterScrollCallback = null;
this.registerEvents();
}
/**
* Register event listeners.
*
* @private
*/
registerEvents() {
let frame = this.hot.rootWindow;
while (frame) {
this.eventManager.addEventListener(frame.document, 'mousedown', event => this.onDocumentMouseDown(event));
this.eventManager.addEventListener(frame.document, 'contextmenu', event => this.onDocumentContextMenu(event));
frame = getParentWindow(frame);
}
}
/**
* Set array of objects which defines menu items.
*
* @param {Array} menuItems Menu items to display.
*/
setMenuItems(menuItems) {
this.menuItems = menuItems;
}
/**
* Returns currently selected menu item. Returns `null` if no item was selected.
*
* @returns {object|null}
*/
getSelectedItem() {
return this.hasSelectedItem() ? this.hotMenu.getSourceDataAtRow(this.hotMenu.getSelectedLast()[0]) : null;
}
/**
* Checks if the menu has selected (highlighted) any item from the menu list.
*
* @returns {boolean}
*/
hasSelectedItem() {
return Array.isArray(this.hotMenu.getSelectedLast());
}
/**
* Set offset menu position for specified area (`above`, `below`, `left` or `right`).
*
* @param {string} area Specified area name (`above`, `below`, `left` or `right`).
* @param {number} offset Offset value.
*/
setOffset(area) {
let offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
this.offset[area] = offset;
}
/**
* Check if menu is using as sub-menu.
*
* @returns {boolean}
*/
isSubMenu() {
return this.parentMenu !== null;
}
/**
* Open menu.
*
* @fires Hooks#beforeContextMenuShow
* @fires Hooks#afterContextMenuShow
*/
open() {
var _this = this;
this.runLocalHooks('beforeOpen');
this.container.removeAttribute('style');
this.container.style.display = 'block';
const delayedOpenSubMenu = debounce(row => this.openSubMenu(row), 300);
const minWidthOfMenu = this.options.minWidth || MIN_WIDTH;
let noItemsDefined = false;
let filteredItems = arrayFilter(this.menuItems, item => {
if (item.key === NO_ITEMS) {
noItemsDefined = true;
}
return isItemHidden(item, this.hot);
});
if (filteredItems.length < 1 && !noItemsDefined) {
filteredItems.push(predefinedItems()[NO_ITEMS]);
} else if (filteredItems.length === 0) {
return;
}
filteredItems = filterSeparators(filteredItems, SEPARATOR);
let shouldAutoCloseMenu = false;
const settings = {
data: filteredItems,
colHeaders: false,
autoColumnSize: true,
autoWrapRow: false,
modifyColWidth(width) {
if (isDefined(width) && width < minWidthOfMenu) {
return minWidthOfMenu;
}
return width;
},
autoRowSize: false,
readOnly: true,
editor: false,
copyPaste: false,
maxCols: 1,
columns: [{
data: 'name',
renderer: (hot, TD, row, col, prop, value) => this.menuItemRenderer(hot, TD, row, col, prop, value)
}],
renderAllRows: true,
fragmentSelection: false,
outsideClickDeselects: false,
disableVisualSelection: 'area',
layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr',
afterOnCellMouseOver: (event, coords) => {
if (this.isAllSubMenusClosed()) {
delayedOpenSubMenu(coords.row);
} else {
this.openSubMenu(coords.row);
}
},
rowHeights: row => filteredItems[row].name === SEPARATOR ? 1 : 23,
afterOnCellContextMenu: event => {
event.preventDefault();
// On the Windows platform, the "contextmenu" is triggered after the "mouseup" so that's
// why the closing menu is here. (#6507#issuecomment-582392301).
if (isWindowsOS() && shouldAutoCloseMenu && this.hasSelectedItem()) {
this.close(true);
}
},
beforeOnCellMouseUp: event => {
if (this.hasSelectedItem()) {
shouldAutoCloseMenu = !this.isCommandPassive(this.getSelectedItem());
this.executeCommand(event);
}
},
afterOnCellMouseUp: event => {
// If the code runs on the other platform than Windows, the "mouseup" is triggered
// after the "contextmenu". So then "mouseup" closes the menu. Otherwise, the closing
// menu responsibility is forwarded to "afterOnCellContextMenu" callback (#6507#issuecomment-582392301).
if ((!isWindowsOS() || !isRightClick(event)) && shouldAutoCloseMenu && this.hasSelectedItem()) {
// The timeout is necessary only for mobile devices. For desktop, the click event that is fired
// right after the mouseup event gets the event element target the same as the mouseup event.
// For mobile devices, the click event is triggered with native delay (~300ms), so when the mouseup
// event hides the tapped element, the click event grabs the element below. As a result, the filter
// by condition menu is closed and immediately open on tapping the "None" item.
if (isMobileBrowser() || isIpadOS()) {
setTimeout(() => this.close(true), 325);
} else {
this.close(true);
}
}
},
afterUnlisten: () => {
// Restore menu focus, fix for `this.instance.unlisten();` call in the tableView.js@260 file.
// This prevents losing table responsiveness for keyboard events when filter select menu is closed (#6497).
if (!this.hasSelectedItem() && this.isOpened()) {
this.hotMenu.listen();
}
}
};
this.origOutsideClickDeselects = this.hot.getSettings().outsideClickDeselects;
this.hot.getSettings().outsideClickDeselects = false;
this.hotMenu = new Core(this.container, settings);
this.hotMenu.addHook('afterInit', () => this.onAfterInit());
this.hotMenu.addHook('afterSelection', function () {
return _this.onAfterSelection(...arguments);
});
this.hotMenu.init();
this.hotMenu.listen();
const shortcutManager = this.hotMenu.getShortcutManager();
const menuContext = shortcutManager.addContext(SHORTCUTS_GROUP);
const config = {
group: SHORTCUTS_CONTEXT
};
const menuContextConfig = {
...config,
runOnlyIf: event => isInput(event.target) === false || this.container.contains(event.target) === false
};
// Default shortcuts for Handsontable should not be handled. Changing context will help with that.
shortcutManager.setActiveContextName('menu');
menuContext.addShortcuts([{
keys: [['Escape']],
callback: () => {
this.keyEvent = true;
this.close();
this.keyEvent = false;
}
}, {
keys: [['ArrowDown']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection) {
this.selectNextCell(selection[0], selection[1]);
} else {
this.selectFirstCell();
}
this.keyEvent = false;
}
}, {
keys: [['ArrowUp']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection) {
this.selectPrevCell(selection[0], selection[1]);
} else {
this.selectLastCell();
}
this.keyEvent = false;
}
}, {
keys: [['ArrowRight']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection) {
const menu = this.openSubMenu(selection[0]);
if (menu) {
menu.selectFirstCell();
}
}
this.keyEvent = false;
}
}, {
keys: [['ArrowLeft']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection && this.isSubMenu()) {
this.close();
if (this.parentMenu) {
this.parentMenu.hotMenu.listen();
}
}
this.keyEvent = false;
}
}, {
keys: [['Enter']],
callback: event => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (!this.hotMenu.getSourceDataAtRow(selection[0]).submenu) {
this.executeCommand(event);
this.close(true);
}
this.keyEvent = false;
}
}, {
keys: [['PageUp']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection) {
this.hotMenu.selection.transformStart(-this.hotMenu.countVisibleRows(), 0);
} else {
this.selectFirstCell();
}
this.keyEvent = false;
}
}, {
keys: [['PageDown']],
callback: () => {
const selection = this.hotMenu.getSelectedLast();
this.keyEvent = true;
if (selection) {
this.hotMenu.selection.transformStart(this.hotMenu.countVisibleRows(), 0);
} else {
this.selectLastCell();
}
this.keyEvent = false;
}
}], menuContextConfig);
this.blockMainTableCallbacks();
this.runLocalHooks('afterOpen');
}
/**
* Close menu.
*
* @param {boolean} [closeParent=false] If `true` try to close parent menu if exists.
*/
close() {
let closeParent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (!this.isOpened()) {
return;
}
if (closeParent && this.parentMenu) {
this.parentMenu.close();
} else {
this.closeAllSubMenus();
this.container.style.display = 'none';
this.releaseMainTableCallbacks();
this.hotMenu.destroy();
this.hotMenu = null;
this.hot.getSettings().outsideClickDeselects = this.origOutsideClickDeselects;
this.runLocalHooks('afterClose');
if (this.parentMenu) {
this.parentMenu.hotMenu.listen();
}
}
}
/**
* Open sub menu at the provided row index.
*
* @param {number} row Row index.
* @returns {Menu|boolean} Returns created menu or `false` if no one menu was created.
*/
openSubMenu(row) {
if (!this.hotMenu) {
return false;
}
const cell = this.hotMenu.getCell(row, 0);
this.closeAllSubMenus();
if (!cell || !hasSubMenu(cell)) {
return false;
}
const dataItem = this.hotMenu.getSourceDataAtRow(row);
const subMenu = new Menu(this.hot, {
parent: this,
name: dataItem.name,
className: this.options.className,
keepInViewport: true,
container: this.options.container
});
subMenu.setMenuItems(dataItem.submenu.items);
subMenu.open();
subMenu.setPosition(cell.getBoundingClientRect());
this.hotSubMenus[dataItem.key] = subMenu;
return subMenu;
}
/**
* Close sub menu at row index.
*
* @param {number} row Row index.
*/
closeSubMenu(row) {
const dataItem = this.hotMenu.getSourceDataAtRow(row);
const menus = this.hotSubMenus[dataItem.key];
if (menus) {
menus.destroy();
delete this.hotSubMenus[dataItem.key];
}
}
/**
* Close all opened sub menus.
*/
closeAllSubMenus() {
arrayEach(this.hotMenu.getData(), (value, row) => this.closeSubMenu(row));
}
/**
* Checks if all created and opened sub menus are closed.
*
* @returns {boolean}
*/
isAllSubMenusClosed() {
return Object.keys(this.hotSubMenus).length === 0;
}
/**
* Destroy instance.
*/
destroy() {
const menuContainerParentElement = this.container.parentNode;
this.clearLocalHooks();
this.close();
this.parentMenu = null;
this.eventManager.destroy();
if (menuContainerParentElement) {
menuContainerParentElement.removeChild(this.container);
}
}
/**
* Checks if menu was opened.
*
* @returns {boolean} Returns `true` if menu was opened.
*/
isOpened() {
return this.hotMenu !== null;
}
/**
* Execute menu command.
*
* The `executeCommand()` method works only for selected cells.
*
* When no cells are selected, `executeCommand()` doesn't do anything.
*
* @param {Event} [event] The mouse event object.
*/
executeCommand(event) {
if (!this.isOpened() || !this.hasSelectedItem()) {
return;
}
const selectedItem = this.getSelectedItem();
this.runLocalHooks('select', selectedItem, event);
if (this.isCommandPassive(selectedItem)) {
return;
}
const selRanges = this.hot.getSelectedRange();
const normalizedSelection = selRanges ? normalizeSelection(selRanges) : [];
this.runLocalHooks('executeCommand', selectedItem.key, normalizedSelection, event);
if (this.isSubMenu()) {
this.parentMenu.runLocalHooks('executeCommand', selectedItem.key, normalizedSelection, event);
}
}
/**
* Checks if the passed command is passive or not. The command is passive when it's marked as
* disabled, the descriptor object contains `isCommand` property set to `false`, command
* is a separator, or the item is recognized as submenu. For passive items the menu is not
* closed automatically after the user trigger the command through the UI.
*
* @param {object} commandDescriptor Selected menu item from the menu data source.
* @returns {boolean}
*/
isCommandPassive(commandDescriptor) {
const {
isCommand,
name: commandName,
disabled,
submenu
} = commandDescriptor;
const isItemDisabled = disabled === true || typeof disabled === 'function' && disabled.call(this.hot) === true;
return isCommand === false || commandName === SEPARATOR || isItemDisabled === true || submenu;
}
/**
* Set menu position based on dom event or based on literal object.
*
* @param {Event|object} coords Event or literal Object with coordinates.
*/
setPosition(coords) {
const cursor = new Cursor(coords, this.container.ownerDocument.defaultView);
if (this.options.keepInViewport) {
if (cursor.fitsBelow(this.container)) {
this.setPositionBelowCursor(cursor);
} else if (cursor.fitsAbove(this.container)) {
this.setPositionAboveCursor(cursor);
} else {
this.setPositionBelowCursor(cursor);
}
if (this.hot.isLtr()) {
this.setHorizontalPositionForLtr(cursor);
} else {
this.setHorizontalPositionForRtl(cursor);
}
} else {
this.setPositionBelowCursor(cursor);
this.setPositionOnRightOfCursor(cursor);
}
}
/**
* Set menu horizontal position for RTL mode.
*
* @param {Cursor} cursor `Cursor` object.
*/
setHorizontalPositionForRtl(cursor) {
if (cursor.fitsOnLeft(this.container)) {
this.setPositionOnLeftOfCursor(cursor);
} else {
this.setPositionOnRightOfCursor(cursor);
}
}
/**
* Set menu horizontal position for LTR mode.
*
* @param {Cursor} cursor `Cursor` object.
*/
setHorizontalPositionForLtr(cursor) {
if (cursor.fitsOnRight(this.container)) {
this.setPositionOnRightOfCursor(cursor);
} else {
this.setPositionOnLeftOfCursor(cursor);
}
}
/**
* Set menu position above cursor object.
*
* @param {Cursor} cursor `Cursor` object.
*/
setPositionAboveCursor(cursor) {
let top = this.offset.above + cursor.top - this.container.offsetHeight;
if (this.isSubMenu()) {
top = cursor.top + cursor.cellHeight - this.container.offsetHeight + 3;
}
this.container.style.top = `${top}px`;
}
/**
* Set menu position below cursor object.
*
* @param {Cursor} cursor `Cursor` object.
*/
setPositionBelowCursor(cursor) {
let top = this.offset.below + cursor.top + 1;
if (this.isSubMenu()) {
top = cursor.top - 1;
}
this.container.style.top = `${top}px`;
}
/**
* Set menu position on the right of cursor object.
*
* @param {Cursor} cursor `Cursor` object.
*/
setPositionOnRightOfCursor(cursor) {
let left = cursor.left;
if (this.isSubMenu()) {
const {
right: parentMenuRight
} = this.parentMenu.container.getBoundingClientRect();
// move the sub menu by the width of the parent's border (usually by 1-2 pixels)
left += cursor.cellWidth + parentMenuRight - (cursor.left + cursor.cellWidth);
} else {
left += this.offset.right;
}
this.container.style.left = `${left}px`;
}
/**
* Set menu position on the left of cursor object.
*
* @param {Cursor} cursor `Cursor` object.
*/
setPositionOnLeftOfCursor(cursor) {
let left = this.offset.left + cursor.left - this.container.offsetWidth;
if (this.isSubMenu()) {
const {
left: parentMenuLeft
} = this.parentMenu.container.getBoundingClientRect();
// move the sub menu by the width of the parent's border (usually by 1-2 pixels)
left -= cursor.left - parentMenuLeft;
}
this.container.style.left = `${left}px`;
}
/**
* Select first cell in opened menu.
*/
selectFirstCell() {
const cell = this.hotMenu.getCell(0, 0);
if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
this.selectNextCell(0, 0);
} else {
this.hotMenu.selectCell(0, 0);
}
}
/**
* Select last cell in opened menu.
*/
selectLastCell() {
const lastRow = this.hotMenu.countRows() - 1;
const cell = this.hotMenu.getCell(lastRow, 0);
if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
this.selectPrevCell(lastRow, 0);
} else {
// disable default "scroll-to-cell" option and instead of that...
this.hotMenu.selectCell(lastRow, 0, undefined, undefined, false);
// ...scroll to the cell with "snap to the bottom" option
this.hotMenu.scrollViewportTo(lastRow, 0, true, false);
}
}
/**
* Select next cell in opened menu.
*
* @param {number} row Row index.
* @param {number} col Column index.
*/
selectNextCell(row, col) {
const nextRow = row + 1;
const cell = nextRow < this.hotMenu.countRows() ? this.hotMenu.getCell(nextRow, col) : null;
if (!cell) {
return;
}
if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
this.selectNextCell(nextRow, col);
} else {
this.hotMenu.selectCell(nextRow, col);
}
}
/**
* Select previous cell in opened menu.
*
* @param {number} row Row index.
* @param {number} col Column index.
*/
selectPrevCell(row, col) {
const prevRow = row - 1;
const cell = prevRow >= 0 ? this.hotMenu.getCell(prevRow, col) : null;
if (!cell) {
return;
}
if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
this.selectPrevCell(prevRow, col);
} else {
this.hotMenu.selectCell(prevRow, col);
}
}
/**
* Menu item renderer.
*
* @private
* @param {Core} hot The Handsontable instance.
* @param {HTMLCellElement} TD The rendered cell element.
* @param {number} row The visual index.
* @param {number} col The visual index.
* @param {string} prop The column property if used.
* @param {string} value The cell value.
*/
menuItemRenderer(hot, TD, row, col, prop, value) {
const item = hot.getSourceDataAtRow(row);
const wrapper = this.hot.rootDocument.createElement('div');
const isSubMenu = itemToTest => hasOwnProperty(itemToTest, 'submenu');
const itemIsSeparator = itemToTest => new RegExp(SEPARATOR, 'i').test(itemToTest.name);
const itemIsDisabled = itemToTest => itemToTest.disabled === true || typeof itemToTest.disabled === 'function' && itemToTest.disabled.call(this.hot) === true;
const itemIsSelectionDisabled = itemToTest => itemToTest.disableSelection;
let itemValue = value;
if (typeof itemValue === 'function') {
itemValue = itemValue.call(this.hot);
}
empty(TD);
addClass(wrapper, 'htItemWrapper');
TD.appendChild(wrapper);
if (itemIsSeparator(item)) {
addClass(TD, 'htSeparator');
} else if (typeof item.renderer === 'function') {
addClass(TD, 'htCustomMenuRenderer');
TD.appendChild(item.renderer(hot, wrapper, row, col, prop, itemValue));
} else {
fastInnerHTML(wrapper, itemValue);
}
if (itemIsDisabled(item)) {
addClass(TD, 'htDisabled');
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.deselectCell());
} else if (itemIsSelectionDisabled(item)) {
addClass(TD, 'htSelectionDisabled');
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.deselectCell());
} else if (isSubMenu(item)) {
addClass(TD, 'htSubmenu');
if (itemIsSelectionDisabled(item)) {
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.deselectCell());
} else {
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.selectCell(row, col, void 0, void 0, false, false));
}
} else {
removeClass(TD, ['htSubmenu', 'htDisabled']);
if (itemIsSelectionDisabled(item)) {
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.deselectCell());
} else {
this.eventManager.addEventListener(TD, 'mouseenter', () => hot.selectCell(row, col, void 0, void 0, false, false));
}
}
}
/**
* Create container/wrapper for handsontable.
*
* @private
* @param {string} [name] Class name.
* @returns {HTMLElement}
*/
createContainer() {
let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
const doc = this.options.container.ownerDocument;
let className = name;
let container;
if (className) {
if (isFunction(className)) {
className = className.call(this.hot);
if (className === null || isUndefined(className)) {
className = '';
} else {
className = className.toString();
}
}
className = className.replace(/[^A-z0-9]/g, '_');
className = `${this.options.className}Sub_${className}`;
container = doc.querySelector(`.${this.options.className}.${className}`);
}
if (!container) {
container = doc.createElement('div');
addClass(container, `htMenu ${this.options.className}`);
if (className) {
addClass(container, className);
}
this.options.container.appendChild(container);
}
return container;
}
/**
* @private
*/
blockMainTableCallbacks() {
this._afterScrollCallback = function () {};
this.hot.addHook('afterScrollVertically', this._afterScrollCallback);
this.hot.addHook('afterScrollHorizontally', this._afterScrollCallback);
}
/**
* @private
*/
releaseMainTableCallbacks() {
if (this._afterScrollCallback) {
this.hot.removeHook('afterScrollVertically', this._afterScrollCallback);
this.hot.removeHook('afterScrollHorizontally', this._afterScrollCallback);
this._afterScrollCallback = null;
}
}
/**
* On after init listener.
*
* @private
*/
onAfterInit() {
const {
wtTable
} = this.hotMenu.view._wt;
const data = this.hotMenu.getSettings().data;
const hiderStyle = wtTable.hider.style;
const holderStyle = wtTable.holder.style;
const currentHiderWidth = parseInt(hiderStyle.width, 10);
const realHeight = arrayReduce(data, (accumulator, value) => accumulator + (value.name === SEPARATOR ? 1 : 26), 0);
// Additional 3px to menu's size because of additional border around its `table.htCore`.
holderStyle.width = `${currentHiderWidth + 3}px`;
holderStyle.height = `${realHeight + 3}px`;
hiderStyle.height = holderStyle.height;
}
/**
* On after selection listener.
*
* @param {number} r Selection start row index.
* @param {number} c Selection start column index.
* @param {number} r2 Selection end row index.
* @param {number} c2 Selection end column index.
* @param {object} preventScrolling Object with `value` property where its value change will be observed.
*/
onAfterSelection(r, c, r2, c2, preventScrolling) {
if (this.keyEvent === false) {
preventScrolling.value = true;
}
}
/**
* Document mouse down listener.
*
* @private
* @param {Event} event The mouse event object.
*/
onDocumentMouseDown(event) {
if (!this.isOpened()) {
return;
}
// Close menu when clicked element is not belongs to menu itself
if (this.options.standalone && this.hotMenu && !isChildOf(event.target, this.hotMenu.rootElement)) {
this.close(true);
// Automatically close menu when clicked element is not belongs to menu or submenu (not necessarily to itself)
} else if ((this.isAllSubMenusClosed() || this.isSubMenu()) && !isChildOf(event.target, '.htMenu')) {
this.close(true);
}
}
/**
* Document's contextmenu listener.
*
* @private
* @param {MouseEvent} event The mouse event object.
*/
onDocumentContextMenu(event) {
if (!this.isOpened()) {
return;
}
if (hasClass(event.target, 'htCore') && isChildOf(event.target, this.hotMenu.rootElement)) {
event.preventDefault();
}
}
}
mixin(Menu, localHooks);
export default Menu;