(core) Add shortcut for opening Record Card

Summary: Also adds tests for previously untested Record Card behavior.

Test Plan: Browser tests.

Reviewers: jarek

Reviewed By: jarek

Differential Revision: https://phab.getgrist.com/D4136
This commit is contained in:
George Gevoian
2023-12-08 00:59:42 -05:00
parent d0318af39b
commit 7e05284cf2
12 changed files with 376 additions and 21 deletions

View File

@@ -228,7 +228,7 @@ BaseView.commonCommands = {
this.scrollToCursor(true).catch(reportError);
this.activateEditorAtCursor({init});
},
editField: function() { closeRegisteredMenu(); this.scrollToCursor(true); this.activateEditorAtCursor(); },
editField: function(event) { closeRegisteredMenu(); this.scrollToCursor(true); this.activateEditorAtCursor({event}); },
insertRecordBefore: function() { this.insertRow(this.cursor.rowIndex()); },
insertRecordAfter: function() { this.insertRow(this.cursor.rowIndex() + 1); },
@@ -243,6 +243,12 @@ BaseView.commonCommands = {
filterByThisCellValue: function() { this.filterByThisCellValue(); },
duplicateRows: function() { this._duplicateRows().catch(reportError); },
openDiscussion: function() { this.openDiscussionAtCursor(); },
viewAsCard: function() {
/* Overridden by subclasses.
*
* This is still needed so that <space> doesn't trigger the `input` command
* if a subclass doesn't support opening the current record as a card. */
},
};
BaseView.prototype.selectedRows = function() {

View File

@@ -308,7 +308,7 @@ GridView.gridCommands = {
fieldEditSave: function() { this.cursor.rowIndex(this.cursor.rowIndex() + 1); },
// Re-define editField after fieldEditSave to make it take precedence for the Enter key.
editField: function() { closeRegisteredMenu(); this.scrollToCursor(true); this.activateEditorAtCursor(); },
editField: function(event) { closeRegisteredMenu(); this.scrollToCursor(true); this.activateEditorAtCursor({event}); },
insertFieldBefore: function(maybeKeyboardEvent) {
if (!maybeKeyboardEvent) {

View File

@@ -71,7 +71,6 @@ export type CommandName =
| 'input'
| 'editLabel'
| 'editLayout'
| 'toggleCheckbox'
| 'historyPrevious'
| 'historyNext'
| 'makeFormula'
@@ -273,7 +272,7 @@ export const groups: CommendGroupDef[] = [{
},
{
name: 'viewAsCard',
keys: [],
keys: ['Space'],
desc: 'Show the record card widget of the selected record',
},
]
@@ -483,10 +482,6 @@ export const groups: CommendGroupDef[] = [{
name: 'editLayout',
keys: [],
desc: 'Edit record layout'
}, {
name: 'toggleCheckbox',
keys: ['Enter', 'Space'],
desc: 'Toggles the value of checkbox cells'
}, {
name: 'historyPrevious',
keys: ['Up'],

View File

@@ -10,9 +10,10 @@ dispose.makeDisposable(CheckBoxEditor);
_.extend(CheckBoxEditor.prototype, TextEditor.prototype);
// For documentation, see NewBaseEditor.ts
CheckBoxEditor.skipEditor = function(typedVal, cellVal) {
if (typedVal === ' ') {
// This is a special case when user hits <space>. We return the toggled value to save, and by
CheckBoxEditor.skipEditor = function(typedVal, cellVal, {event}) {
// eslint-disable-next-line no-undef
if (typedVal === '<enter>' || (event && event instanceof KeyboardEvent)) {
// This is a special case when user hits <enter>. We return the toggled value to save, and by
// this indicate that the editor should not open.
return !cellVal;
}

View File

@@ -699,6 +699,7 @@ export class FieldBuilder extends Disposable {
public buildEditorDom(editRow: DataRowModel, mainRowModel: DataRowModel, options: {
init?: string,
state?: any
event?: KeyboardEvent | MouseEvent
}) {
// If the user attempts to edit a value during transform, finalize (i.e. cancel or execute)
// the transform.
@@ -733,7 +734,13 @@ export class FieldBuilder extends Disposable {
return clearOwn();
}
if (!this._readonly.get() && saveWithoutEditor(editorCtor, editRow, this.field, options.init)) {
if (
!this._readonly.get() &&
saveWithoutEditor(editorCtor, editRow, this.field, {
typedVal: options.init,
event: options.event,
})
) {
return clearOwn();
}

View File

@@ -24,16 +24,20 @@ const t = makeT('FieldEditor');
/**
* Check if the typed-in value should change the cell without opening the cell editor, and if so,
* saves and returns true. E.g. on typing space, CheckBoxEditor toggles the cell without opening.
* saves and returns true. E.g. on typing enter, CheckBoxEditor toggles the cell without opening.
*/
export function saveWithoutEditor(
editorCtor: IEditorConstructor, editRow: DataRowModel, field: ViewFieldRec, typedVal: string|undefined
editorCtor: IEditorConstructor,
editRow: DataRowModel,
field: ViewFieldRec,
options: {typedVal?: string, event?: KeyboardEvent|MouseEvent}
): boolean {
const {typedVal, event} = options;
// Never skip the editor if editing a formula. Also, check that skipEditor static function
// exists (we don't bother adding it on old-style JS editors that don't need it).
if (!field.column.peek().isRealFormula.peek() && editorCtor.skipEditor) {
const origVal = editRow.cells[field.colId()].peek();
const skipEditorValue = editorCtor.skipEditor(typedVal, origVal);
const skipEditorValue = editorCtor.skipEditor(typedVal, origVal, {event});
if (skipEditorValue !== undefined) {
setAndSave(editRow, field, skipEditorValue).catch(reportError);
return true;

View File

@@ -54,9 +54,13 @@ export abstract class NewBaseEditor extends Disposable {
/**
* Check if the typed-in value should change the cell without opening the editor, and if so,
* returns the value to save. E.g. on typing " ", CheckBoxEditor toggles value without opening.
* returns the value to save. E.g. on typing <enter>, CheckBoxEditor toggles value without opening.
*/
public static skipEditor(typedVal: string|undefined, origVal: CellValue): CellValue|undefined {
public static skipEditor(
typedVal: string|undefined,
origVal: CellValue,
options?: {event?: KeyboardEvent|MouseEvent}
): CellValue|undefined {
return undefined;
}

View File

@@ -86,6 +86,7 @@ export class ReferenceList extends Reference {
ev.stopPropagation();
ev.preventDefault();
}),
testId('ref-list-link-icon'),
),
cssLabel(isBlankReference ? '[Blank]' : formattedValue,
testId('ref-list-cell-token-label'),

View File

@@ -18,11 +18,11 @@ abstract class ToggleBase extends NewAbstractWidget {
return;
}
if (!this.field.column().isRealFormula()) {
// Move the cursor here, and pretend that spacebar was pressed. This triggers an editing
// Move the cursor here, and pretend that enter was pressed. This triggers an editing
// flow which is handled by CheckBoxEditor.skipEditor(). This way the edit applies to
// editRow, which handles setting default values based on widget linking.
commands.allCommands.setCursor.run(row, this.field);
commands.allCommands.input.run(' ');
commands.allCommands.input.run('<enter>');
}
}),
dom.on('dblclick', (event) => {