UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,102 lines (1,096 loc) • 63.3 kB
/** * DevExtreme (ui/grid_core/ui.grid_core.keyboard_navigation.js) * Version: 18.2.18 * Build date: Tue Oct 18 2022 * * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var _renderer = require("../../core/renderer"); var _renderer2 = _interopRequireDefault(_renderer); var _dom_adapter = require("../../core/dom_adapter"); var _dom_adapter2 = _interopRequireDefault(_dom_adapter); var _events_engine = require("../../events/core/events_engine"); var _events_engine2 = _interopRequireDefault(_events_engine); var _uiGrid_core = require("./ui.grid_core.modules"); var _uiGrid_core2 = _interopRequireDefault(_uiGrid_core); var _type = require("../../core/utils/type"); var _array = require("../../core/utils/array"); var _selectors = require("../widget/selectors"); var _iterator = require("../../core/utils/iterator"); var _ui = require("../widget/ui.keyboard_processor"); var _ui2 = _interopRequireDefault(_ui); var _utils = require("../../events/utils"); var _utils2 = _interopRequireDefault(_utils); var _pointer = require("../../events/pointer"); var _pointer2 = _interopRequireDefault(_pointer); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } var ROWS_VIEW_CLASS = "rowsview", EDIT_FORM_CLASS = "edit-form", GROUP_FOOTER_CLASS = "group-footer", ROW_CLASS = "dx-row", DATA_ROW_CLASS = "dx-data-row", GROUP_ROW_CLASS = "dx-group-row", EDIT_FORM_ITEM_CLASS = "edit-form-item", MASTER_DETAIL_ROW_CLASS = "dx-master-detail-row", FREESPACE_ROW_CLASS = "dx-freespace-row", VIRTUAL_ROW_CLASS = "dx-virtual-row", MASTER_DETAIL_CELL_CLASS = "dx-master-detail-cell", DROPDOWN_EDITOR_OVERLAY_CLASS = "dx-dropdowneditor-overlay", COMMAND_EXPAND_CLASS = "dx-command-expand", CELL_FOCUS_DISABLED_CLASS = "dx-cell-focus-disabled", EDITOR_CELL_CLASS = "dx-editor-cell", INTERACTIVE_ELEMENTS_SELECTOR = "input:not([type='hidden']), textarea, a, [tabindex]", VIEWS = ["rowsView"], EDIT_MODE_ROW = "row", EDIT_MODE_FORM = "form", EDIT_MODE_BATCH = "batch", EDIT_MODE_CELL = "cell", FOCUS_TYPE_ROW = "row", FOCUS_TYPE_CELL = "cell"; function isGroupRow($row) { return $row && $row.hasClass(GROUP_ROW_CLASS) } function isDetailRow($row) { return $row && $row.hasClass(MASTER_DETAIL_ROW_CLASS) } function isDataRow($row) { return $row && !isGroupRow($row) && !isDetailRow($row) } function isNotFocusedRow($row) { return !$row || $row.hasClass(FREESPACE_ROW_CLASS) || $row.hasClass(VIRTUAL_ROW_CLASS) } function isCellElement($element) { return $element.length && "TD" === $element[0].tagName } var KeyboardNavigationController = _uiGrid_core2.default.ViewController.inherit({ _isRowEditMode: function() { var editMode = this._editingController.getEditMode(); return editMode === EDIT_MODE_ROW || editMode === EDIT_MODE_FORM }, _isCellEditMode: function() { var editMode = this._editingController.getEditMode(); return editMode === EDIT_MODE_CELL || editMode === EDIT_MODE_BATCH }, _focusView: function(view, viewIndex) { this._focusedViews.viewIndex = viewIndex; this._focusedView = view }, _getInteractiveElement: function($cell, isLast) { var $focusedElement = $cell.find(INTERACTIVE_ELEMENTS_SELECTOR).filter(":visible"); return isLast ? $focusedElement.last() : $focusedElement.first() }, _focusInteractiveElement: function($cell, isLast) { if (!$cell) { return } var $focusedElement = this._getInteractiveElement($cell, isLast); _events_engine2.default.trigger($focusedElement, "focus") }, _updateFocus: function() { var that = this; setTimeout(function() { var $cell = that._getFocusedCell(), $cellEditingCell = that._isCellEditMode() && $cell; if ($cell && !(that._isMasterDetailCell($cell) && !that._isRowEditMode())) { if (that._hasSkipRow($cell.parent())) { $cell = that._getNextCell(that._focusedCellPosition && that._focusedCellPosition.rowIndex > 0 ? "upArrow" : "downArrow") } if ($cell && $cell.length > 0) { if ($cell.is("td") || $cell.hasClass(that.addWidgetPrefix(EDIT_FORM_ITEM_CLASS))) { if (that.getController("editorFactory").focus() || $cellEditingCell) { that._focus($cell) } else { if (that._isHiddenFocus) { that._focus($cell, true) } } if (that._editingController.isEditing()) { that._focusInteractiveElement.bind(that)($cell) } } else { _events_engine2.default.trigger($cell, "focus") } } } }) }, _applyTabIndexToElement: function($element) { var tabIndex = this.option("tabIndex"); $element.attr("tabIndex", (0, _type.isDefined)(tabIndex) ? tabIndex : 0) }, _isEventInCurrentGrid: function(event) { var $grid = (0, _renderer2.default)(event.target).closest("." + this.getWidgetContainerClass()).parent(); return $grid.is(this.component.$element()) }, _clickHandler: function(e) { var event = e.event, $target = (0, _renderer2.default)(event.currentTarget), isEditingCell = $target.hasClass(EDITOR_CELL_CLASS), data = event.data; if (this._isEventInCurrentGrid(event) && this._isCellValid($target)) { $target = this._isInsideEditForm($target) ? (0, _renderer2.default)(event.target) : $target; this._focusView(data.view, data.viewIndex); if ($target.parent().hasClass(FREESPACE_ROW_CLASS)) { this._updateFocusedCellPosition($target); this._focusedView.element().attr("tabindex", 0); this._focusedView.focus() } else { if (!isEditingCell && !this._isMasterDetailCell($target)) { this._clickTargetCellHandler(event, $target) } else { this._updateFocusedCellPosition($target) } } } else { if ($target.is("td")) { this._resetFocusedCell() } } }, _allowRowUpdating: function() { var rowIndex = this.getVisibleRowIndex(), row = this._dataController.items()[rowIndex]; return this._editingController.allowUpdating({ row: row }) }, _clickTargetCellHandler: function(event, $cell) { var args, columnIndex = this.getView("rowsView").getCellIndex($cell), column = this._columnsController.getVisibleColumns()[columnIndex], isCellEditMode = this._isCellEditMode(); this.setCellFocusType(); args = this._fireFocusChangingEvents(event, $cell, true); $cell = args.$newCellElement; if (!args.cancel) { if (args.resetFocusedRow) { this.getController("focus")._resetFocusedRow(); return } if (args.rowIndexChanged) { $cell = this._getFocusedCell() } if (!args.isHighlighted && !isCellEditMode) { this.setRowFocusType() } this._updateFocusedCellPosition($cell); if (this._allowRowUpdating() && isCellEditMode && column && column.allowEditing) { this._isHiddenFocus = false } else { var $target = event && (0, _renderer2.default)(event.target), isInteractiveTarget = $target && $target.not($cell).is(INTERACTIVE_ELEMENTS_SELECTOR), isDisabled = !args.isHighlighted || isInteractiveTarget; this._focus($cell, isDisabled, isInteractiveTarget) } } else { this.setRowFocusType(); this.setFocusedRowIndex(args.prevRowIndex); $cell = this._getFocusedCell(); if (this._editingController.isEditing() && isCellEditMode) { this._editingController.closeEditCell() } } }, _initFocusedViews: function() { var that = this, clickAction = that.createAction(that._clickHandler); that._focusedViews = []; (0, _iterator.each)(VIEWS, function(key, viewName) { var view = that.getView(viewName); if (view && view.isVisible()) { that._focusedViews.push(view) } }); (0, _iterator.each)(that._focusedViews, function(index, view) { if (view) { view.renderCompleted.add(function(e) { var $element = view.element(), isFullUpdate = !e || "refresh" === e.changeType, isFocusedViewCorrect = that._focusedView && that._focusedView.name === view.name, needUpdateFocus = false, isAppend = e && ("append" === e.changeType || "prepend" === e.changeType); _events_engine2.default.off($element, _utils2.default.addNamespace(_pointer2.default.down, "dxDataGridKeyboardNavigation"), clickAction); _events_engine2.default.on($element, _utils2.default.addNamespace(_pointer2.default.down, "dxDataGridKeyboardNavigation"), "." + ROW_CLASS + " > td, ." + ROW_CLASS, { viewIndex: index, view: view }, clickAction); that._initKeyDownProcessor(that, $element, that._keyDownHandler); if (isFocusedViewCorrect) { needUpdateFocus = that._isNeedFocus ? !isAppend : that._isHiddenFocus && isFullUpdate; needUpdateFocus && that._updateFocus() } }) } }) }, _initKeyDownProcessor: function(context, element, handler) { if (this._keyDownProcessor) { this._keyDownProcessor.dispose(); this._keyDownProcessor = null } this._keyDownProcessor = new _ui2.default({ element: element, context: context, handler: handler }) }, _getCell: function(cellPosition) { if (this._focusedView && cellPosition) { return this._focusedView.getCell({ rowIndex: cellPosition.rowIndex - this._dataController.getRowIndexOffset(), columnIndex: cellPosition.columnIndex }) } }, _getFocusedCell: function() { return this._getCell(this._focusedCellPosition) }, _getRowIndex: function($row) { var that = this, focusedView = that._focusedView, rowIndex = -1; if (focusedView) { rowIndex = focusedView.getRowIndex($row) } if (rowIndex >= 0) { rowIndex += that._dataController.getRowIndexOffset() } return rowIndex }, _updateFocusedCellPosition: function($cell, direction) { var position = this._getCellPosition($cell, direction); if (position) { if (!$cell.length || position.rowIndex >= 0 && position.columnIndex >= 0) { this.setFocusedCellPosition(position.rowIndex, position.columnIndex) } } }, _getCellPosition: function($cell, direction) { var rowIndex, columnIndex, that = this, $rowElement = $cell.closest("tr"); if ($rowElement.length > 0 && that._focusedView) { rowIndex = $rowElement.length > 0 && that._getRowIndex($rowElement); columnIndex = that._focusedView.getCellIndex($cell, rowIndex); if (direction) { columnIndex = "previous" === direction ? columnIndex - 1 : columnIndex + 1; columnIndex = that._applyColumnIndexBoundaries(columnIndex) } return { rowIndex: rowIndex, columnIndex: columnIndex } } }, setFocusedCellPosition: function(rowIndex, columnIndex) { this.setFocusedRowIndex(rowIndex); this.setFocusedColumnIndex(columnIndex) }, setFocusedRowIndex: function(rowIndex) { if (!this._focusedCellPosition) { this._focusedCellPosition = {} } this._focusedCellPosition.rowIndex = rowIndex }, setFocusedColumnIndex: function(columnIndex) { if (!this._focusedCellPosition) { this._focusedCellPosition = {} } this._focusedCellPosition.columnIndex = columnIndex }, getVisibleRowIndex: function() { if (this._focusedCellPosition) { if (!this._focusedCellPosition.rowIndex) { return this._focusedCellPosition.rowIndex } return this._focusedCellPosition.rowIndex - this._dataController.getRowIndexOffset() } return null }, getVisibleColumnIndex: function() { if (this._focusedCellPosition) { return (0, _type.isDefined)(this._focusedCellPosition.columnIndex) ? this._focusedCellPosition.columnIndex : -1 } return -1 }, getFocusedColumnIndex: function() { return this._focusedCellPosition ? this._focusedCellPosition.columnIndex : null }, _applyColumnIndexBoundaries: function(columnIndex) { var visibleColumnsCount = this._getVisibleColumnCount(); if (columnIndex < 0) { columnIndex = 0 } else { if (columnIndex >= visibleColumnsCount) { columnIndex = visibleColumnsCount - 1 } } return columnIndex }, _isCellValid: function($cell) { if ((0, _type.isDefined)($cell)) { var rowsView = this.getView("rowsView"), $row = $cell.parent(), visibleColumns = this._columnsController.getVisibleColumns(), columnIndex = rowsView.getCellIndex($cell), column = visibleColumns[columnIndex], visibleColumnCount = this._getVisibleColumnCount(), editingController = this._editingController, isMasterDetailRow = isDetailRow($row), isShowWhenGrouped = column && column.showWhenGrouped, isDataCell = column && !$cell.hasClass(COMMAND_EXPAND_CLASS) && isDataRow($row), isValidGroupSpaceColumn = function() { return !isMasterDetailRow && column && (!(0, _type.isDefined)(column.groupIndex) || isShowWhenGrouped && isDataCell) || parseInt($cell.attr("colspan")) > 1 }; if (this._isMasterDetailCell($cell)) { return true } if (visibleColumnCount > columnIndex && isValidGroupSpaceColumn()) { var rowItems = this._dataController.items(), visibleRowIndex = rowsView.getRowIndex($row), row = rowItems[visibleRowIndex], isCellEditing = editingController && this._isCellEditMode() && editingController.isEditing(), isRowEditingInCurrentRow = editingController && editingController.isEditRow(visibleRowIndex), isEditing = isRowEditingInCurrentRow || isCellEditing; if (column.command) { return !isEditing && "expand" === column.command } if (isCellEditing && row && "data" !== row.rowType) { return false } return !isEditing || column.allowEditing } } }, _isCellByPositionValid: function(cellPosition) { var $cell = this._getCell(cellPosition); return this._isCellValid($cell) }, _focus: function($cell, disableFocus, isInteractiveElement) { var $row = $cell && $cell.is("td") ? $cell.parent() : $cell; if ($row && isNotFocusedRow($row)) { return } var $focusElement, $prevFocusedCell = this._getFocusedCell(), focusedView = this._focusedView, $focusViewElement = focusedView && focusedView.element(); this._isHiddenFocus = disableFocus; if (isGroupRow($row) || this.isRowFocusType()) { $focusElement = $row; if (focusedView) { this.setFocusedRowIndex(this._getRowIndex($row)) } } else { if (isCellElement($cell)) { $focusElement = $cell; this._updateFocusedCellPosition($cell) } } $prevFocusedCell && $prevFocusedCell.is("td") && $prevFocusedCell.not($focusElement).removeAttr("tabIndex"); if ($focusElement) { if (!isInteractiveElement) { this._applyTabIndexToElement($focusElement); _events_engine2.default.trigger($focusElement, "focus") } if (disableFocus) { $focusViewElement && $focusViewElement.find("." + CELL_FOCUS_DISABLED_CLASS + "[tabIndex]").not($focusElement).removeClass(CELL_FOCUS_DISABLED_CLASS).removeAttr("tabIndex"); $focusElement.addClass(CELL_FOCUS_DISABLED_CLASS) } else { $focusViewElement && $focusViewElement.find("." + CELL_FOCUS_DISABLED_CLASS + ":not(." + MASTER_DETAIL_CELL_CLASS + ")").removeClass(CELL_FOCUS_DISABLED_CLASS); this.getController("editorFactory").focus($focusElement) } } }, _hasSkipRow: function($row) { var row = $row && $row.get(0); return row && ("none" === row.style.display || $row.hasClass(this.addWidgetPrefix(GROUP_FOOTER_CLASS)) || isDetailRow($row) && !$row.hasClass(this.addWidgetPrefix(EDIT_FORM_CLASS))) }, _enterKeyHandler: function(eventArgs, isEditing) { var $cell = this._getFocusedCell(), rowIndex = this.getVisibleRowIndex(), $row = this._focusedView && this._focusedView.getRow(rowIndex); if (this.option("grouping.allowCollapsing") && isGroupRow($row) || this.option("masterDetail.enabled") && $cell && $cell.hasClass(COMMAND_EXPAND_CLASS)) { var key = this._dataController.getKeyByRowIndex(rowIndex), item = this._dataController.items()[rowIndex]; if (void 0 !== key && item && item.data && !item.data.isContinuation) { this._dataController.changeRowExpand(key) } } else { if (isEditing) { $cell = this._getCellElementFromTarget(eventArgs.originalEvent.target); this._updateFocusedCellPosition($cell); if (this._isRowEditMode()) { this._focusEditFormCell($cell); setTimeout(this._editingController.saveEditData.bind(this._editingController)) } else { var $target = (0, _renderer2.default)(eventArgs.originalEvent.target); _events_engine2.default.trigger($target, "blur"); this._editingController.closeEditCell(); eventArgs.originalEvent.preventDefault() } } else { var column = this._columnsController.getVisibleColumns()[this._focusedCellPosition.columnIndex], row = this._dataController.items()[rowIndex]; if (this._editingController.allowUpdating({ row: row }) && column && column.allowEditing) { if (this._isRowEditMode()) { this._editingController.editRow(rowIndex) } else { this._focusedCellPosition && this._editingController.editCell(rowIndex, this._focusedCellPosition.columnIndex) } } } } }, _leftRightKeysHandler: function(eventArgs, isEditing) { var directionCode, rowIndex = this.getVisibleRowIndex(), $event = eventArgs.originalEvent, $row = this._focusedView && this._focusedView.getRow(rowIndex); if (!isEditing && isDataRow($row)) { this.setCellFocusType(); directionCode = this._getDirectionCodeByKey(eventArgs.keyName); this._arrowKeysHandlerFocusCell($event, this._getNextCell(directionCode)); if ($event) { $event.preventDefault() } } }, _getDirectionCodeByKey: function(key) { var directionCode; if (this.option("rtlEnabled")) { directionCode = "leftArrow" === key ? "nextInRow" : "previousInRow" } else { directionCode = "leftArrow" === key ? "previousInRow" : "nextInRow" } return directionCode }, _upDownKeysHandler: function(eventArgs, isEditing) { var $cell, rowHeight, rowIndex = this.getVisibleRowIndex(), $row = this._focusedView && this._focusedView.getRow(rowIndex), $event = eventArgs.originalEvent, isUpArrow = "upArrow" === eventArgs.keyName, dataSource = this._dataController.dataSource(); if (!isEditing && $row && !isDetailRow($row)) { $cell = this._getNextCell(eventArgs.keyName); if ($cell && this._isCellValid($cell)) { this._arrowKeysHandlerFocusCell($event, $cell, true) } else { if (this._isVirtualScrolling() && isUpArrow && dataSource && !dataSource.isLoading()) { rowHeight = $row.outerHeight(); rowIndex = this._focusedCellPosition.rowIndex - 1; this._scrollBy(-rowHeight, rowIndex, $event) } } if ($event) { $event.preventDefault() } } }, _arrowKeysHandlerFocusCell: function($event, $cell, upDown) { var args = this._fireFocusChangingEvents($event, $cell, upDown, true); $cell = args.$newCellElement; if (!args.cancel && this._isCellValid($cell)) { this._focus($cell, !args.isHighlighted) } }, _fireFocusChangingEvents: function($event, $cell, fireRowEvent, isHighlighted) { var args = {}, cellPosition = this._getCellPosition($cell) || {}; if (this.isCellFocusType()) { args = this._fireFocusedCellChanging($event, $cell, isHighlighted); if (!args.cancel) { cellPosition.columnIndex = args.newColumnIndex; cellPosition.rowIndex = args.newRowIndex; isHighlighted = args.isHighlighted } } if (!args.cancel && fireRowEvent) { args = this._fireFocusedRowChanging($event, $cell.parent()); if (!args.cancel) { cellPosition.rowIndex = args.newRowIndex; args.isHighlighted = isHighlighted } } args.$newCellElement = this._getCell(cellPosition); if (!args.$newCellElement || !args.$newCellElement.length) { args.$newCellElement = $cell } return args }, _isVirtualScrolling: function() { var scrollingMode = this.option("scrolling.mode"); return "virtual" === scrollingMode || "infinite" === scrollingMode }, _scrollBy: function(top, rowIndex, $event) { var that = this, scrollable = this.getView("rowsView").getScrollable(); if (that._focusedCellPosition) { var scrollHandler = function scrollHandler() { scrollable.off("scroll", scrollHandler); setTimeout(that.restoreFocusableElement.bind(that, rowIndex, $event)) }; scrollable.on("scroll", scrollHandler) } scrollable.scrollBy({ left: 0, top: top }) }, restoreFocusableElement: function(rowIndex, $event) { var args, $rowElement, that = this, isUpArrow = (0, _type.isDefined)(rowIndex), rowsView = that.getView("rowsView"), $rowsViewElement = rowsView.element(), columnIndex = that._focusedCellPosition.columnIndex, rowIndexOffset = that._dataController.getRowIndexOffset(); rowIndex = isUpArrow ? rowIndex : rowsView.getTopVisibleItemIndex() + rowIndexOffset; if (!isUpArrow) { that.getController("editorFactory").loseFocus(); that._applyTabIndexToElement($rowsViewElement); _events_engine2.default.trigger($rowsViewElement, "focus") } else { $rowElement = rowsView.getRow(rowIndex - rowIndexOffset); args = that._fireFocusedRowChanging($event, $rowElement); if (!args.cancel && args.rowIndexChanged) { rowIndex = args.newRowIndex } } if (!isUpArrow || !args.cancel) { that.setFocusedCellPosition(rowIndex, columnIndex) } isUpArrow && that._updateFocus() }, _pageUpDownKeyHandler: function(eventArgs) { var pageIndex = this._dataController.pageIndex(), pageCount = this._dataController.pageCount(), pagingEnabled = this.option("paging.enabled"), isPageUp = "pageUp" === eventArgs.keyName, pageStep = isPageUp ? -1 : 1, scrollable = this.getView("rowsView").getScrollable(); if (pagingEnabled && !this._isVirtualScrolling()) { if ((isPageUp ? pageIndex > 0 : pageIndex < pageCount - 1) && !this._isVirtualScrolling()) { this._dataController.pageIndex(pageIndex + pageStep); eventArgs.originalEvent.preventDefault() } } else { if (scrollable && scrollable._container().height() < scrollable.$content().height()) { this._scrollBy(scrollable._container().height() * pageStep); eventArgs.originalEvent.preventDefault() } } }, _spaceKeyHandler: function(eventArgs, isEditing) { var isFocusedRowElement, rowIndex = this.getVisibleRowIndex(), $target = (0, _renderer2.default)(eventArgs.originalEvent && eventArgs.originalEvent.target); if (this.option("selection") && "none" !== this.option("selection").mode && !isEditing) { isFocusedRowElement = "row" === this._getElementType($target) && this.isRowFocusType() && isDataRow($target); if (isFocusedRowElement) { this._selectionController.startSelectionWithCheckboxes() } if (isFocusedRowElement || $target.parent().hasClass(DATA_ROW_CLASS) || $target.hasClass(this.addWidgetPrefix(ROWS_VIEW_CLASS))) { this._selectionController.changeItemSelection(rowIndex, { shift: eventArgs.shift, control: eventArgs.ctrl }); eventArgs.originalEvent.preventDefault() } } }, _ctrlAKeyHandler: function(eventArgs, isEditing) { if (!isEditing && eventArgs.ctrl && !eventArgs.alt && "multiple" === this.option("selection.mode") && this.option("selection.allowSelectAll")) { this._selectionController.selectAll(); eventArgs.originalEvent.preventDefault() } }, _isInsideEditForm: function(element) { return (0, _renderer2.default)(element).closest("." + this.addWidgetPrefix(EDIT_FORM_CLASS)).length > 0 }, _isMasterDetailCell: function(element) { var $masterDetailCell = (0, _renderer2.default)(element).closest("." + MASTER_DETAIL_CELL_CLASS), $masterDetailGrid = $masterDetailCell.closest("." + this.getWidgetContainerClass()).parent(); return $masterDetailCell.length && $masterDetailGrid.is(this.component.$element()) }, _processNextCellInMasterDetail: function($nextCell) { if (!this._isInsideEditForm($nextCell) && $nextCell) { this._applyTabIndexToElement($nextCell) } }, _handleTabKeyOnMasterDetailCell: function(target, direction) { if (this._isMasterDetailCell(target)) { this._updateFocusedCellPosition((0, _renderer2.default)(target), direction); var $nextCell = this._getNextCell(direction, "row"); this._processNextCellInMasterDetail($nextCell); return true } return false }, _tabKeyHandler: function(eventArgs, isEditing) { var editingOptions = this.option("editing"), direction = eventArgs.shift ? "previous" : "next", isOriginalHandlerRequired = !eventArgs.shift && this._isLastValidCell(this._focusedCellPosition) || eventArgs.shift && this._isFirstValidCell(this._focusedCellPosition), eventTarget = eventArgs.originalEvent.target; if (this._handleTabKeyOnMasterDetailCell(eventTarget, direction)) { return } if (editingOptions && eventTarget && !isOriginalHandlerRequired) { if ((0, _renderer2.default)(eventTarget).hasClass(this.addWidgetPrefix(ROWS_VIEW_CLASS))) { this._resetFocusedCell() } if (isEditing) { if (!this._editingCellTabHandler(eventArgs, direction)) { return } } else { if (this._targetCellTabHandler(eventArgs, direction)) { isOriginalHandlerRequired = true } } } if (isOriginalHandlerRequired) { this.getController("editorFactory").loseFocus(); if (this._editingController.isEditing() && !this._isRowEditMode()) { this._resetFocusedCell(); this._editingController.closeEditCell() } } else { eventArgs.originalEvent.preventDefault() } }, _editingCellTabHandler: function(eventArgs, direction) { var column, row, $cell, isEditingAllowed, editingOptions = this.option("editing"), eventTarget = eventArgs.originalEvent.target; this._updateFocusedCellPosition(this._getCellElementFromTarget(eventTarget)); $cell = this._getNextCell(direction); if (!$cell || this._handleTabKeyOnMasterDetailCell($cell, direction)) { return false } column = this._columnsController.getVisibleColumns()[this.getView("rowsView").getCellIndex($cell)]; row = this._dataController.items()[this._getRowIndex($cell && $cell.parent())]; if (column.allowEditing) { var _isDataRow = !row || "data" === row.rowType; isEditingAllowed = editingOptions.allowUpdating ? _isDataRow : row && row.inserted } if (!isEditingAllowed) { this._editingController.closeEditCell() } if (this._focusCell($cell)) { if (!this._isRowEditMode() && isEditingAllowed) { this._editingController.editCell(this.getVisibleRowIndex(), this._focusedCellPosition.columnIndex) } else { this._focusInteractiveElement($cell, eventArgs.shift) } } return true }, _targetCellTabHandler: function(eventArgs, direction) { var elementType, $event = eventArgs.originalEvent, eventTarget = $event.target, $cell = this._getCellElementFromTarget(eventTarget), $lastInteractiveElement = this._getInteractiveElement($cell, !eventArgs.shift), isOriginalHandlerRequired = false; if ($lastInteractiveElement.length && eventTarget !== $lastInteractiveElement.get(0)) { isOriginalHandlerRequired = true } else { if (void 0 === this._focusedCellPosition.rowIndex && (0, _renderer2.default)(eventTarget).hasClass(ROW_CLASS)) { this._updateFocusedCellPosition((0, _renderer2.default)(eventTarget).children().first()) } elementType = this._getElementType(eventTarget); if (this.isRowFocusType()) { this.setCellFocusType(); if ("row" === elementType && isDataRow((0, _renderer2.default)(eventTarget))) { eventTarget = this.getFirstValidCellInRow((0, _renderer2.default)(eventTarget)); elementType = this._getElementType(eventTarget) } } $cell = this._getNextCellByTabKey($event, direction, elementType); if (!$cell) { return false } $cell = this._checkNewLineTransition($event, $cell); if (!$cell) { return false } this._focusCell($cell); this._focusInteractiveElement($cell, eventArgs.shift) } return isOriginalHandlerRequired }, _getNextCellByTabKey: function($event, direction, elementType) { var $cell = this._getNextCell(direction, elementType), args = this._fireFocusedCellChanging($event, $cell, true); if (args.cancel) { return } if (args.$newCellElement) { $cell = args.$newCellElement } return $cell }, _checkNewLineTransition: function($event, $cell) { var rowIndex = this.getVisibleRowIndex(), $row = $cell.parent(); if (rowIndex !== this._getRowIndex($row)) { var cellPosition = this._getCellPosition($cell), args = this._fireFocusedRowChanging($event, $row); if (args.cancel) { return } if (args.rowIndexChanged) { this.setFocusedColumnIndex(cellPosition.columnIndex); $cell = this._getFocusedCell() } } return $cell }, getFirstValidCellInRow: function($row, columnIndex) { var $cell, $result, that = this, $cells = $row.find("> td"); columnIndex = columnIndex || 0; for (var i = columnIndex; i < $cells.length; ++i) { $cell = $cells.eq(i); if (that._isCellValid($cell)) { $result = $cell; break } } return $result }, _focusCell: function($cell) { if (this._isCellValid($cell)) { this._focus($cell); return true } }, _getElementType: function(target) { return (0, _renderer2.default)(target).is("tr") ? "row" : "cell" }, _focusEditFormCell: function($cell) { if ($cell.hasClass(MASTER_DETAIL_CELL_CLASS)) { this.getController("editorFactory").focus($cell, true) } }, _escapeKeyHandler: function(eventArgs, isEditing) { var $cell = this._getCellElementFromTarget(eventArgs.originalEvent.target); if (isEditing) { this._updateFocusedCellPosition($cell); if (!this._isRowEditMode()) { if ("cell" === this._editingController.getEditMode()) { this._editingController.cancelEditData() } else { this._editingController.closeEditCell() } } else { this._focusEditFormCell($cell); this._editingController.cancelEditData() } eventArgs.originalEvent.preventDefault() } }, _ctrlFKeyHandler: function(eventArgs) { if (eventArgs.ctrl && this.option("searchPanel") && this.option("searchPanel").visible) { this._headerPanel.focus(); eventArgs.originalEvent.preventDefault() } }, _keyDownHandler: function(e) { var isEditing = this._editingController.isEditing(), needStopPropagation = true, originalEvent = e.originalEvent, args = { handled: false, event: originalEvent }; this.executeAction("onKeyDown", args); if (originalEvent.isDefaultPrevented()) { return } this._isNeedFocus = true; this._isNeedScroll = true; this._updateFocusedCellPosition(this._getCellElementFromTarget(args.event.target)); if (!args.handled) { switch (e.keyName) { case "leftArrow": case "rightArrow": this._leftRightKeysHandler(e, isEditing); break; case "upArrow": case "downArrow": this._upDownKeysHandler(e, isEditing); break; case "pageUp": case "pageDown": this._pageUpDownKeyHandler(e); break; case "space": this._spaceKeyHandler(e, isEditing); break; case "A": this._ctrlAKeyHandler(e, isEditing); break; case "tab": this._tabKeyHandler(e, isEditing); break; case "enter": this._enterKeyHandler(e, isEditing); break; case "escape": this._escapeKeyHandler(e, isEditing); break; case "F": this._ctrlFKeyHandler(e); break; default: this._isNeedFocus = false; this._isNeedScroll = false; needStopPropagation = false } if (needStopPropagation) { originalEvent.stopPropagation() } } }, _isLastRow: function(rowIndex) { if (this._isVirtualScrolling()) { return rowIndex >= this._dataController.totalItemsCount() - 1 } return rowIndex === this.getController("data").items().length - 1 }, _getNextCell: function(keyCode, elementType, cellPosition) { var rowIndex, newFocusedCellPosition, $cell, $row, focusedCellPosition = cellPosition || this._focusedCellPosition, isRowFocusType = this.isRowFocusType(), includeCommandCells = isRowFocusType || (0, _array.inArray)(keyCode, ["next", "previous"]) > -1, isLastCellOnDirection = "previous" === keyCode ? this._isFirstValidCell(focusedCellPosition) : this._isLastValidCell(focusedCellPosition); if (this._focusedView && focusedCellPosition) { newFocusedCellPosition = this._getNewPositionByCode(focusedCellPosition, elementType, keyCode); $cell = this._getCell(newFocusedCellPosition); if ($cell && !this._isCellValid($cell) && this._isCellInRow(newFocusedCellPosition, includeCommandCells) && !isLastCellOnDirection) { if (isRowFocusType) { $cell = this.getFirstValidCellInRow($cell.parent(), newFocusedCellPosition.columnIndex) } else { $cell = this._getNextCell(keyCode, "cell", newFocusedCellPosition) } } $row = $cell && $cell.parent(); if (this._hasSkipRow($row)) { rowIndex = this._getRowIndex($row); if (!this._isLastRow(rowIndex)) { $cell = this._getNextCell(keyCode, "row", { columnIndex: focusedCellPosition.columnIndex, rowIndex: rowIndex }) } else { return null } } return $cell } return null }, _getNewPositionByCode: function(cellPosition, elementType, code) { var visibleColumnsCount, columnIndex = cellPosition.columnIndex, rowIndex = cellPosition.rowIndex; if (void 0 === cellPosition.rowIndex && "next" === code) { return { columnIndex: 0, rowIndex: 0 } } switch (code) { case "nextInRow": case "next": visibleColumnsCount = this._getVisibleColumnCount(); if (columnIndex < visibleColumnsCount - 1 && !this._isLastValidCell({ columnIndex: columnIndex, rowIndex: rowIndex }) && "row" !== elementType) { columnIndex++ } else { if (!this._isLastRow(rowIndex) && "next" === code) { columnIndex = 0; rowIndex++ } } break; case "previousInRow": case "previous": if (columnIndex > 0 && !this._isFirstValidCell({ columnIndex: columnIndex, rowIndex: rowIndex }) && "row" !== elementType) { columnIndex-- } else { if (rowIndex > 0 && "previous" === code) { rowIndex--; visibleColumnsCount = this._getVisibleColumnCount(); columnIndex = visibleColumnsCount - 1 } } break; case "upArrow": rowIndex = rowIndex > 0 ? rowIndex - 1 : rowIndex; break; case "downArrow": rowIndex = !this._isLastRow(rowIndex) ? rowIndex + 1 : rowIndex } return { columnIndex: columnIndex, rowIndex: rowIndex } }, _isFirstValidCell: function(cellPosition) { var isFirstValidCell = false; if (0 === cellPosition.rowIndex && cellPosition.columnIndex >= 0) { isFirstValidCell = isFirstValidCell || !this._haveValidCellBeforePosition(cellPosition) } return isFirstValidCell }, _haveValidCellBeforePosition: function(cellPosition) { var columnIndex = cellPosition.columnIndex, hasValidCells = false; while (columnIndex > 0 && !hasValidCells) { var checkingPosition = { columnIndex: --columnIndex, rowIndex: cellPosition.rowIndex }; hasValidCells = this._isCellByPositionValid(checkingPosition) } return hasValidCells }, _isLastValidCell: function(cellPosition) { var nextColumnIndex = cellPosition.columnIndex >= 0 ? cellPosition.columnIndex + 1 : 0, checkingPosition = { columnIndex: nextColumnIndex, rowIndex: cellPosition.rowIndex }, visibleColumnsCount = this._getVisibleColumnCount(), isCheckingCellValid = this._isCellByPositionValid(checkingPosition); if (!this._isLastRow(cellPosition.rowIndex)) { return false } if (cellPosition.columnIndex === visibleColumnsCount - 1) { return true } if (isCheckingCellValid) { return false } return this._isLastValidCell(checkingPosition) }, _getVisibleColumnCount: function() { return this.getController("columns").getVisibleColumns().length }, _isCellInRow: function(cellPosition, includeCommandCells) { var columnIndex = cellPosition.columnIndex, visibleColumnsCount = this._getVisibleColumnCount(); return includeCommandCells ? columnIndex >= 0 && columnIndex <= visibleColumnsCount - 1 : columnIndex > 0 && columnIndex < visibleColumnsCount - 1 }, _resetFocusedCell: function() { var that = this, $cell = that._getFocusedCell(); $cell && $cell.removeAttr("tabIndex"); that._focusedView && that._focusedView.renderFocusState && that._focusedView.renderFocusState(); that._isNeedFocus = false; that._isNeedScroll = false; that._focusedCellPosition = {} }, _getCellElementFromTarget: function(target) { return (0, _renderer2.default)(target).closest("." + ROW_CLASS + "> td") }, init: function() { var that = this; if (that.option("useKeyboard")) { that._dataController = that.getController("data"); that._selectionController = that.getController("selection"); that._editingController = that.getController("editing"); that._headerPanel = that.getView("headerPanel"); that._columnsController = that.getController("columns"); that.getController("editorFactory").focused.add(function($element) { that.setupFocusedView(); if (that._isNeedScroll) { if ($element.is(":visible") && that._focusedView && that._focusedView.getScrollable) { that._scrollToElement($element); that._isNeedScroll = false } } }); that._focusedCellPosition = {}; that._canceledCellPosition = null; that._initFocusedViews(); that._documentClickHandler = that.createAction(function(e) { var $target = (0, _renderer2.default)(e.event.target), isCurrentRowsViewClick = that._isEventInCurrentGrid(e.event) && $target.closest("." + that.addWidgetPrefix(ROWS_VIEW_CLASS)).length, isEditorOverlay = $target.closest("." + DROPDOWN_EDITOR_OVERLAY_CLASS).length; if (!isCurrentRowsViewClick && !isEditorOverlay) { that._resetFocusedCell() } }); that.createAction("onKeyDown"); _events_engine2.default.on(_dom_adapter2.default.getDocument(), _utils2.default.addNamespace(_pointer2.default.down, "dxDataGridKeyboardNavigation"), that._documentClickHandler) } }, _scrollToElement: function($element, offset) { var scrollable = this._focusedView.getScrollable(); scrollable && scrollable.update(); scrollable && scrollable.scrollToElement($element, offset); }, focus: function(element) { var activeElementSelector, focusedRowEnabled = this.option("focusedRowEnabled"), isHighlighted = isCellElement((0, _renderer2.default)(element)); if (!element) { activeElementSelector = focusedRowEnabled ? ".dx-row[tabindex]" : ".dx-row[tabIndex], .dx-row > td[tabindex]"; element = this.component.$element().find(activeElementSelector).first() } element && this._focusElement((0, _renderer2.default)(element), isHighlighted) }, _focusElement: function($element, isHighlighted) { var focusView = this._getFocusedViewByElement($element), isRowFocusType = this.isRowFocusType(), args = {}; if (!focusView || isCellElement($element) && !this._isCellValid($element)) { return } this._focusView(focusView.view, focusView.viewIndex); this._isNeedFocus = true; this._isNeedScroll = true; if (isCellElement($element) || isGroupRow($element)) { this.setCellFocusType(); args = this._fireFocusChangingEvents(null, $element, false, isHighlighted); $element = args.$newCellElement; if (isRowFocusType && !args.isHighlighted) { this.setRowFocusType() } } this._focus($element, !args.isHighlighted); this._focusInteractiveElement($element) }, getFocusedView: function() { return this._focusedView }, _getFocusedViewByElement: function($element) { var condition = function(view) { return $element.closest(view._$element).length }; return this._getFocusedViewByCondition(condition) }, _getFocusedViewByCondition: function(conditionFunction) { var focusView; (0, _iterator.each)(this._focusedViews, function(index, view) { if (conditionFunction(view)) { focusView = { viewIndex: index, view: view }; return false } }); return focusView }, isRowFocusType: function() { return this.focusType === FOCUS_TYPE_ROW }, isCellFocusType: function() { return this