UNPKG

handsontable

Version:

Handsontable is a JavaScript Data Grid available for React, Angular and Vue.

116 lines 4.94 kB
import { normalizeCoordsIfNeeded, getMostTopStartPosition, getMostBottomEndPosition } from "../utils/utils.mjs"; import { GRID_SCOPE, GRID_GROUP, GRID_TAB_NAVIGATION_GROUP } from "../../shortcutContexts/index.mjs"; /** * @param {Handsontable} hot The Handsontable instance. */ export function focusGridScope(hot) { var _hot$rootGridElement; const clampCoordsIfNeeded = normalizeCoordsIfNeeded(hot); const rowWrapState = { wrapped: false, flipped: false }; let recentlyAddedFocusCoords; let isSavingCoordsEnabled = true; let isEmptyDataStateActive = false; hot.addHook('afterSelection', () => { if (isSavingCoordsEnabled) { var _hot$getSelectedRange; recentlyAddedFocusCoords = (_hot$getSelectedRange = hot.getSelectedRangeActive()) === null || _hot$getSelectedRange === void 0 ? void 0 : _hot$getSelectedRange.highlight; } }); hot.addHook('beforeRowWrap', (interruptedByAutoInsertMode, newCoords, isFlipped) => { rowWrapState.wrapped = true; rowWrapState.flipped = isFlipped; }); hot.addHook('beforeEmptyDataStateShow', () => { isEmptyDataStateActive = true; }); hot.addHook('beforeEmptyDataStateHide', () => { isEmptyDataStateActive = false; }); const context = hot.getShortcutManager().getContext(GRID_SCOPE); context.addShortcuts([{ keys: [['Tab'], ['Shift', 'Tab']], preventDefault: false, stopPropagation: false, relativeToGroup: GRID_GROUP, group: GRID_TAB_NAVIGATION_GROUP, position: 'before', callback() { const { tabNavigation } = hot.getSettings(); if (hot.getSelectedRangeActive() && !tabNavigation) { isSavingCoordsEnabled = false; } } }, { keys: [['Tab'], ['Shift', 'Tab']], preventDefault: false, stopPropagation: false, relativeToGroup: GRID_GROUP, group: GRID_TAB_NAVIGATION_GROUP, callback(event) { const { tabNavigation, autoWrapRow } = hot.getSettings(); isSavingCoordsEnabled = true; if (!tabNavigation || !hot.selection.isSelected() || autoWrapRow && rowWrapState.wrapped && rowWrapState.flipped || !autoWrapRow && rowWrapState.wrapped) { if (autoWrapRow && rowWrapState.wrapped && rowWrapState.flipped) { recentlyAddedFocusCoords = event.shiftKey ? getMostTopStartPosition(hot) : getMostBottomEndPosition(hot); } rowWrapState.wrapped = false; rowWrapState.flipped = false; } }, position: 'after' }]); const container = (_hot$rootGridElement = hot.rootGridElement) !== null && _hot$rootGridElement !== void 0 ? _hot$rootGridElement : hot.rootElement; hot.getFocusScopeManager().registerScope('grid', container, { contains: target => { if (container === target || container.contains(target)) { return true; } if (target.closest('.htMenu') !== null) { // TODO: Skip switching focus scope to 'grid' for context and dropdown menus since // focus management is not implemented for them. Their focus management // is handled manually. return false; } return hot.rootPortalElement.contains(target); }, runOnlyIf: () => { const { navigableHeaders } = hot.getSettings(); if ((isEmptyDataStateActive || !navigableHeaders) && hot.countRenderedRows() === 0 && hot.countRenderedCols() === 0 && hot.countRowHeaders() > 0 && hot.countColHeaders() > 0) { // When the corner is only rendered, and the EmptyDataState is active, deactivate the scope. return false; } return !navigableHeaders && hot.countRenderedRows() > 0 && hot.countRenderedCols() > 0 || navigableHeaders && (hot.countRowHeaders() > 0 || hot.countColHeaders() > 0); }, onActivate: focusSource => { if (focusSource === 'tab_from_above') { var _clampCoordsIfNeeded; const mostTopStartCoords = (_clampCoordsIfNeeded = clampCoordsIfNeeded(recentlyAddedFocusCoords)) !== null && _clampCoordsIfNeeded !== void 0 ? _clampCoordsIfNeeded : getMostTopStartPosition(hot); if (mostTopStartCoords) { const result = hot.runHooks('modifyFocusOnTabNavigation', 'from_above', mostTopStartCoords); if (result !== false) { hot.selectCell(mostTopStartCoords.row, mostTopStartCoords.col); } } } else if (focusSource === 'tab_from_below') { var _clampCoordsIfNeeded2; const mostBottomEndCoords = (_clampCoordsIfNeeded2 = clampCoordsIfNeeded(recentlyAddedFocusCoords)) !== null && _clampCoordsIfNeeded2 !== void 0 ? _clampCoordsIfNeeded2 : getMostBottomEndPosition(hot); if (mostBottomEndCoords) { const result = hot.runHooks('modifyFocusOnTabNavigation', 'from_below', mostBottomEndCoords); if (result !== false) { hot.selectCell(mostBottomEndCoords.row, mostBottomEndCoords.col); } } } } }); }