Skip to content

Commit

Permalink
feat: allow to disable editing for individual cells (#7269)
Browse files Browse the repository at this point in the history
  • Loading branch information
sissbruecker authored Apr 11, 2024
1 parent 234935b commit 7a4c80c
Show file tree
Hide file tree
Showing 4 changed files with 393 additions and 51 deletions.
18 changes: 18 additions & 0 deletions packages/grid-pro/src/vaadin-grid-pro-edit-column-mixin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ export declare class GridProEditColumnMixinClass<TItem> {
*/
editorValuePath: string;

/**
* A function to check whether a specific cell of this column can be
* edited. This allows to disable editing of individual rows or cells,
* based on the item.
*
* Receives a `model` object containing the item for an individual row,
* and should return a boolean indicating whether the column's cell in
* that row is editable.
*
* The `model` object contains:
* - `model.index` The index of the item.
* - `model.item` The item.
* - `model.expanded` Sublevel toggle state.
* - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
* - `model.selected` Selected state.
*/
isCellEditable: (model: GridItemModel<TItem>) => boolean;

protected _getEditorComponent(cell: HTMLElement): HTMLElement | null;

protected _getEditorValue(editor: HTMLElement): unknown | null;
Expand Down
34 changes: 27 additions & 7 deletions packages/grid-pro/src/vaadin-grid-pro-edit-column-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* See https://vaadin.com/commercial-license-and-service-terms for the full
* license.
*/
import { addValueToAttribute } from '@vaadin/component-base/src/dom-utils.js';
import { get, set } from '@vaadin/component-base/src/path-utils.js';

/**
Expand Down Expand Up @@ -84,13 +83,36 @@ export const GridProEditColumnMixin = (superClass) =>
sync: true,
},

/**
* A function to check whether a specific cell of this column can be
* edited. This allows to disable editing of individual rows or cells,
* based on the item.
*
* Receives a `model` object containing the item for an individual row,
* and should return a boolean indicating whether the column's cell in
* that row is editable.
*
* The `model` object contains:
* - `model.index` The index of the item.
* - `model.item` The item.
* - `model.expanded` Sublevel toggle state.
* - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
* - `model.selected` Selected state.
*
* @type {(model: GridItemModel) => boolean}
*/
isCellEditable: {
type: Function,
observer: '_isCellEditableChanged',
},

/** @private */
_oldRenderer: Function,
};
}

static get observers() {
return ['_editModeRendererChanged(editModeRenderer, __initialized)', '_cellsChanged(_cells)'];
return ['_editModeRendererChanged(editModeRenderer, __initialized)'];
}

constructor() {
Expand Down Expand Up @@ -121,11 +143,9 @@ export const GridProEditColumnMixin = (superClass) =>
}

/** @private */
_cellsChanged() {
this._cells.forEach((cell) => {
const target = cell._focusButton || cell;
addValueToAttribute(target, 'part', 'editable-cell');
});
_isCellEditableChanged(newValue, oldValue) {
// Re-render grid to update editable-cell part names
this._grid.requestContentUpdate();
}

/** @private */
Expand Down
133 changes: 90 additions & 43 deletions packages/grid-pro/src/vaadin-grid-pro-inline-editing-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import { animationFrame } from '@vaadin/component-base/src/async.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { get, set } from '@vaadin/component-base/src/path-utils.js';
import { iterateRowCells, updatePart } from '@vaadin/grid/src/vaadin-grid-helpers.js';

/**
* @polymerMixin
Expand Down Expand Up @@ -218,6 +219,10 @@ export const InlineEditingMixin = (superClass) =>
return;
}

if (!this._isCellEditable(cell)) {
return;
}

callback(e);
}
});
Expand Down Expand Up @@ -325,8 +330,10 @@ export const InlineEditingMixin = (superClass) =>

/** @private */
_startEdit(cell, column) {
const isCellEditable = this._isCellEditable(cell);

// TODO: remove `_editingDisabled` after Flow counterpart is updated.
if (this.disabled || this._editingDisabled) {
if (this.disabled || this._editingDisabled || !isCellEditable) {
return;
}
// Cancel debouncer enqueued on focusout
Expand Down Expand Up @@ -421,59 +428,67 @@ export const InlineEditingMixin = (superClass) =>

this._cancelStopEdit();

const cols = this._getEditColumns();

const editableColumns = this._getEditColumns();
const { cell, column, model } = this.__edited;
const colIndex = cols.indexOf(column);
const { index } = model;

let nextCol = null;
let nextIdx = index;

// Enter key
if (e.keyCode === 13) {
nextCol = column;

// Move up / down
if (this.enterNextRow) {
nextIdx = e.shiftKey ? index - 1 : index + 1;
}
this._stopEdit();
e.preventDefault();
// Prevent vaadin-grid handler from being called
e.stopImmediatePropagation();

// Try to find the next editable cell
let nextIndex = model.index;
let nextColumn = column;
let nextCell = cell;
let directionX = 0;
let directionY = 0;

// Enter key: move up / down
if (e.keyCode === 13 && this.enterNextRow) {
directionY = e.shiftKey ? -1 : 1;
}

// Tab: move right / left
if (e.keyCode === 9) {
if (e.shiftKey) {
if (cols[colIndex - 1]) {
nextCol = cols[colIndex - 1];
} else if (index > 0) {
nextIdx = index - 1;
nextCol = cols[cols.length - 1];
directionX = e.shiftKey ? -1 : 1;
}

if (directionX || directionY) {
while (nextCell) {
if (directionX) {
// Move horizontally
nextColumn = editableColumns[editableColumns.indexOf(nextColumn) + directionX];
if (!nextColumn) {
// Wrap to the next or previous row
nextIndex += directionX;
nextColumn = editableColumns[directionX > 0 ? 0 : editableColumns.length - 1];
}
}
// Move vertically
if (directionY) {
nextIndex += directionY;
}
// Stop looking if the next cell is editable
const nextRow = this._getRowByIndex(nextIndex);
// eslint-disable-next-line @typescript-eslint/no-loop-func
nextCell = nextRow && Array.from(nextRow.children).find((cell) => cell._column === nextColumn);
if (nextCell && this._isCellEditable(nextCell)) {
break;
}
} else if (cols[colIndex + 1]) {
nextCol = cols[colIndex + 1];
} else {
nextIdx = index + 1;
nextCol = cols[0];
}
}

const nextRow = nextIdx === index ? cell.parentNode : this._getRowByIndex(nextIdx) || null;

this._stopEdit();

if (nextRow && nextCol) {
const nextCell = Array.from(nextRow.children).find((cell) => cell._column === nextCol);
e.preventDefault();

// Prevent vaadin-grid handler from being called
e.stopImmediatePropagation();
// Focus current cell as fallback
if (!nextCell) {
nextCell = cell;
nextIndex = model.index;
}

if (!this.singleCellEdit && nextCell !== cell) {
this._startEdit(nextCell, nextCol);
} else {
this._ensureScrolledToIndex(nextIdx);
nextCell.focus();
}
if (!this.singleCellEdit && nextCell !== cell) {
this._startEdit(nextCell, nextColumn);
} else {
this._ensureScrolledToIndex(nextIndex);
nextCell.focus();
}
}

Expand All @@ -492,6 +507,38 @@ export const InlineEditingMixin = (superClass) =>
super._updateItem(row, item);
}

/**
* Override method from `StylingMixin` to apply `editable-cell` part to the
* cells of edit columns.
*
* @override
*/
_generateCellPartNames(row, model) {
super._generateCellPartNames(row, model);

iterateRowCells(row, (cell) => {
const isEditable = this._isCellEditable(cell);
const target = cell._focusButton || cell;
updatePart(target, isEditable, 'editable-cell');
});
}

/** @private */
_isCellEditable(cell) {
const column = cell._column;
// Not editable if the column is not an edit column
if (!this._isEditColumn(column)) {
return false;
}
// Cell is editable by default if isCellEditable is not configured
if (!column.isCellEditable) {
return true;
}
// Otherwise, check isCellEditable function
const model = this.__getRowModel(cell.parentElement);
return column.isCellEditable(model);
}

/**
* Fired before exiting the cell edit mode, if the value has been changed.
* If the default is prevented, value change would not be applied.
Expand Down
Loading

0 comments on commit 7a4c80c

Please sign in to comment.