1111import { animationFrame } from '@vaadin/component-base/src/async.js' ;
1212import { Debouncer } from '@vaadin/component-base/src/debounce.js' ;
1313import { get , set } from '@vaadin/component-base/src/path-utils.js' ;
14+ import { iterateRowCells , updatePart } from '@vaadin/grid/src/vaadin-grid-helpers.js' ;
1415
1516/**
1617 * @polymerMixin
@@ -218,6 +219,10 @@ export const InlineEditingMixin = (superClass) =>
218219 return ;
219220 }
220221
222+ if ( ! this . _isCellEditable ( cell ) ) {
223+ return ;
224+ }
225+
221226 callback ( e ) ;
222227 }
223228 } ) ;
@@ -325,8 +330,10 @@ export const InlineEditingMixin = (superClass) =>
325330
326331 /** @private */
327332 _startEdit ( cell , column ) {
333+ const isCellEditable = this . _isCellEditable ( cell ) ;
334+
328335 // TODO: remove `_editingDisabled` after Flow counterpart is updated.
329- if ( this . disabled || this . _editingDisabled ) {
336+ if ( this . disabled || this . _editingDisabled || ! isCellEditable ) {
330337 return ;
331338 }
332339 // Cancel debouncer enqueued on focusout
@@ -421,59 +428,67 @@ export const InlineEditingMixin = (superClass) =>
421428
422429 this . _cancelStopEdit ( ) ;
423430
424- const cols = this . _getEditColumns ( ) ;
425-
431+ const editableColumns = this . _getEditColumns ( ) ;
426432 const { cell, column, model } = this . __edited ;
427- const colIndex = cols . indexOf ( column ) ;
428- const { index } = model ;
429433
430- let nextCol = null ;
431- let nextIdx = index ;
432-
433- // Enter key
434- if ( e . keyCode === 13 ) {
435- nextCol = column ;
436-
437- // Move up / down
438- if ( this . enterNextRow ) {
439- nextIdx = e . shiftKey ? index - 1 : index + 1 ;
440- }
434+ this . _stopEdit ( ) ;
435+ e . preventDefault ( ) ;
436+ // Prevent vaadin-grid handler from being called
437+ e . stopImmediatePropagation ( ) ;
438+
439+ // Try to find the next editable cell
440+ let nextIndex = model . index ;
441+ let nextColumn = column ;
442+ let nextCell = cell ;
443+ let directionX = 0 ;
444+ let directionY = 0 ;
445+
446+ // Enter key: move up / down
447+ if ( e . keyCode === 13 && this . enterNextRow ) {
448+ directionY = e . shiftKey ? - 1 : 1 ;
441449 }
442450
443451 // Tab: move right / left
444452 if ( e . keyCode === 9 ) {
445- if ( e . shiftKey ) {
446- if ( cols [ colIndex - 1 ] ) {
447- nextCol = cols [ colIndex - 1 ] ;
448- } else if ( index > 0 ) {
449- nextIdx = index - 1 ;
450- nextCol = cols [ cols . length - 1 ] ;
453+ directionX = e . shiftKey ? - 1 : 1 ;
454+ }
455+
456+ if ( directionX || directionY ) {
457+ while ( nextCell ) {
458+ if ( directionX ) {
459+ // Move horizontally
460+ nextColumn = editableColumns [ editableColumns . indexOf ( nextColumn ) + directionX ] ;
461+ if ( ! nextColumn ) {
462+ // Wrap to the next or previous row
463+ nextIndex += directionX ;
464+ nextColumn = editableColumns [ directionX > 0 ? 0 : editableColumns . length - 1 ] ;
465+ }
466+ }
467+ // Move vertically
468+ if ( directionY ) {
469+ nextIndex += directionY ;
470+ }
471+ // Stop looking if the next cell is editable
472+ const nextRow = this . _getRowByIndex ( nextIndex ) ;
473+ // eslint-disable-next-line @typescript-eslint/no-loop-func
474+ nextCell = nextRow && Array . from ( nextRow . children ) . find ( ( cell ) => cell . _column === nextColumn ) ;
475+ if ( nextCell && this . _isCellEditable ( nextCell ) ) {
476+ break ;
451477 }
452- } else if ( cols [ colIndex + 1 ] ) {
453- nextCol = cols [ colIndex + 1 ] ;
454- } else {
455- nextIdx = index + 1 ;
456- nextCol = cols [ 0 ] ;
457478 }
458479 }
459480
460- const nextRow = nextIdx === index ? cell . parentNode : this . _getRowByIndex ( nextIdx ) || null ;
461-
462- this . _stopEdit ( ) ;
463-
464- if ( nextRow && nextCol ) {
465- const nextCell = Array . from ( nextRow . children ) . find ( ( cell ) => cell . _column === nextCol ) ;
466- e . preventDefault ( ) ;
467-
468- // Prevent vaadin-grid handler from being called
469- e . stopImmediatePropagation ( ) ;
481+ // Focus current cell as fallback
482+ if ( ! nextCell ) {
483+ nextCell = cell ;
484+ nextIndex = model . index ;
485+ }
470486
471- if ( ! this . singleCellEdit && nextCell !== cell ) {
472- this . _startEdit ( nextCell , nextCol ) ;
473- } else {
474- this . _ensureScrolledToIndex ( nextIdx ) ;
475- nextCell . focus ( ) ;
476- }
487+ if ( ! this . singleCellEdit && nextCell !== cell ) {
488+ this . _startEdit ( nextCell , nextColumn ) ;
489+ } else {
490+ this . _ensureScrolledToIndex ( nextIndex ) ;
491+ nextCell . focus ( ) ;
477492 }
478493 }
479494
@@ -492,6 +507,38 @@ export const InlineEditingMixin = (superClass) =>
492507 super . _updateItem ( row , item ) ;
493508 }
494509
510+ /**
511+ * Override method from `StylingMixin` to apply `editable-cell` part to the
512+ * cells of edit columns.
513+ *
514+ * @override
515+ */
516+ _generateCellPartNames ( row , model ) {
517+ super . _generateCellPartNames ( row , model ) ;
518+
519+ iterateRowCells ( row , ( cell ) => {
520+ const isEditable = this . _isCellEditable ( cell ) ;
521+ const target = cell . _focusButton || cell ;
522+ updatePart ( target , isEditable , 'editable-cell' ) ;
523+ } ) ;
524+ }
525+
526+ /** @private */
527+ _isCellEditable ( cell ) {
528+ const column = cell . _column ;
529+ // Not editable if the column is not an edit column
530+ if ( ! this . _isEditColumn ( column ) ) {
531+ return false ;
532+ }
533+ // Cell is editable by default if isCellEditable is not configured
534+ if ( ! column . isCellEditable ) {
535+ return true ;
536+ }
537+ // Otherwise, check isCellEditable function
538+ const model = this . __getRowModel ( cell . parentElement ) ;
539+ return column . isCellEditable ( model ) ;
540+ }
541+
495542 /**
496543 * Fired before exiting the cell edit mode, if the value has been changed.
497544 * If the default is prevented, value change would not be applied.
0 commit comments