mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Fix linking of new records when attachment is the first thing added.
Summary: Fixes a bug when in a linked widget, the automatic reference wasn't being set for a new record if attachment is the first thing that gets added to the record. - Move handling of 'setCursorPos' pseudo-command to GristDoc to support cross-section switching (relevant when moving attachment into a cell of a non-active page widget) - Modernize code for AttachmentsWidget slightly (better typings, css conventions) - Change the fix in https://phab.getgrist.com/D3796 from using isolate to using different z-index values, to avoid a change in the look of the cursor on Attachment cells. Test Plan: Added a test case for what's possible to test with webdriver. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3811
This commit is contained in:
@@ -51,13 +51,6 @@ export class Cursor extends Disposable {
|
||||
moveToLastRecord(this: Cursor) { this.rowIndex(Infinity); },
|
||||
moveToFirstField(this: Cursor) { this.fieldIndex(0); },
|
||||
moveToLastField(this: Cursor) { this.fieldIndex(Infinity); },
|
||||
|
||||
// Command to be manually triggered on cell selection. Moves the cursor to the selected cell.
|
||||
// This is overridden by the formula editor to insert "$col" variables when clicking cells.
|
||||
setCursor(this: Cursor, rowModel: BaseRowModel, fieldModel: BaseRowModel) {
|
||||
this.rowIndex(rowModel ? rowModel._index() : 0);
|
||||
this.fieldIndex(fieldModel ? fieldModel._index()! : 0);
|
||||
},
|
||||
};
|
||||
|
||||
public viewData: LazyArrayModel<BaseRowModel>;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
overflow: auto;
|
||||
overscroll-behavior: none;
|
||||
|
||||
z-index: 2; /* scrollbar should be over the overlay background */
|
||||
z-index: 20; /* scrollbar should be over the overlay background */
|
||||
border-top: 1px solid var(--grist-theme-table-header-border, lightgrey);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 2; /* z-index must be here, doesnt work on children*/
|
||||
z-index: 20; /* z-index must be here, doesnt work on children*/
|
||||
}
|
||||
|
||||
.gridview_data_header {
|
||||
@@ -74,7 +74,7 @@
|
||||
border-bottom: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey));
|
||||
color: var(--grist-theme-table-header-fg, unset);
|
||||
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey));
|
||||
z-index: 2; /* goes over data cells */
|
||||
z-index: 20; /* goes over data cells */
|
||||
|
||||
padding-top: 2px;
|
||||
text-align: center;
|
||||
@@ -159,7 +159,7 @@
|
||||
height: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
|
||||
top: 1px; /* go under 1px border on scrollpane */
|
||||
border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
/* shadow should only show to the right of it (10px should be enough) */
|
||||
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
|
||||
clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
/* Right shadow - normally not displayed - activated when grid has frozen columns */
|
||||
@@ -193,7 +193,7 @@
|
||||
box-shadow: -8px 0 14px 4px var(--grist-theme-table-scroll-shadow, #444);
|
||||
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
|
||||
clip-path: polygon(0 0, 28px 0, 24px 100%, 0 100%);
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
*/
|
||||
left: calc(4em + var(--frozen-width, 0) * 1px);
|
||||
background-color: var(--grist-theme-table-frozen-columns-border, #999999);
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
user-select: none;
|
||||
pointer-events: none
|
||||
}
|
||||
@@ -222,14 +222,14 @@
|
||||
/* should only show below it (10px should be enough) */
|
||||
-webkit-clip-path: polygon(0 0, 0 10px, 100% 10px, 100% 0);
|
||||
clip-path: polygon(0 0, 0 10px, 100% 10px, 100% 0);
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.gridview_header_backdrop_left {
|
||||
width: calc(4rem + 1px); /* Matches rowid width (+border) */
|
||||
height:100%;
|
||||
top: 1px; /* go under 1px border on scrollpane */
|
||||
z-index: 1;
|
||||
z-index: 10;
|
||||
border-right: 1px solid var(--grist-theme-table-header-border, lightgray);
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
position: absolute;
|
||||
width: 0px; /* Matches rowid width (+border) */
|
||||
height: 100%;
|
||||
z-index: 3;
|
||||
z-index: 30;
|
||||
border-right: 1px solid var(--grist-theme-table-body-border, var(--grist-color-dark-grey)) !important;
|
||||
user-select: none;
|
||||
pointer-events: none
|
||||
@@ -248,7 +248,7 @@
|
||||
height: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
|
||||
top: 1px; /* go under 1px border on scrollpane */
|
||||
border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
|
||||
z-index: 1;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.gridview_data_pane > .scroll_shadow_top {
|
||||
@@ -269,7 +269,7 @@
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border: 2px solid var(--grist-theme-table-drag-drop-indicator, gray);
|
||||
z-index: 20;
|
||||
z-index: 200;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border: 1px solid var(--grist-theme-table-drag-drop-indicator, gray);
|
||||
z-index: 15;
|
||||
z-index: 150;
|
||||
top: 0px;
|
||||
background-color: var(--grist-theme-table-drag-drop-shadow, #F0F0F0);
|
||||
opacity: 0.5;
|
||||
@@ -289,7 +289,7 @@
|
||||
height: 0px;
|
||||
position: absolute;
|
||||
border: 2px solid var(--grist-theme-table-drag-drop-indicator, gray);
|
||||
z-index: 20;
|
||||
z-index: 200;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
height: 0px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--grist-theme-table-drag-drop-indicator, gray);
|
||||
z-index: 15;
|
||||
z-index: 150;
|
||||
left: 0px;
|
||||
background-color: var(--grist-theme-table-drag-drop-shadow, #F0F0F0);
|
||||
opacity: 0.5;
|
||||
@@ -311,7 +311,7 @@
|
||||
.record .field.frozen {
|
||||
position: sticky;
|
||||
left: calc(4em + 1px + (var(--frozen-position, 0) - var(--frozen-offset, 0)) * 1px); /* 4em for row number + total width of cells + 1px for border*/
|
||||
z-index: 1;
|
||||
z-index: 10;
|
||||
}
|
||||
/* for data field we need to reuse color from record (add-row and zebra stripes) */
|
||||
.gridview_row .record .field.frozen {
|
||||
|
||||
@@ -885,7 +885,7 @@ GridView.prototype._getColStyle = function(colIndex) {
|
||||
GridView.prototype.domToRowModel = function(elem, elemType) {
|
||||
switch (elemType) {
|
||||
case selector.COL:
|
||||
return 0;
|
||||
return undefined;
|
||||
case selector.ROW: // row > row num: row has record model
|
||||
return ko.utils.domData.get(elem.parentNode, 'itemModel');
|
||||
case selector.NONE:
|
||||
@@ -899,7 +899,7 @@ GridView.prototype.domToRowModel = function(elem, elemType) {
|
||||
GridView.prototype.domToColModel = function(elem, elemType) {
|
||||
switch (elemType) {
|
||||
case selector.ROW:
|
||||
return 0;
|
||||
return undefined;
|
||||
case selector.NONE:
|
||||
case selector.CELL: // cell: .field has col model
|
||||
case selector.COL: // col: .column_name I think
|
||||
|
||||
@@ -31,10 +31,11 @@ import {createSessionObs} from 'app/client/lib/sessionObs';
|
||||
import {setTestState} from 'app/client/lib/testState';
|
||||
import {selectFiles} from 'app/client/lib/uploads';
|
||||
import {reportError} from 'app/client/models/AppModel';
|
||||
import BaseRowModel from 'app/client/models/BaseRowModel';
|
||||
import DataTableModel from 'app/client/models/DataTableModel';
|
||||
import {DataTableModelWithDiff} from 'app/client/models/DataTableModelWithDiff';
|
||||
import {DocData} from 'app/client/models/DocData';
|
||||
import {DocInfoRec, DocModel, ViewRec, ViewSectionRec} from 'app/client/models/DocModel';
|
||||
import {DocInfoRec, DocModel, ViewFieldRec, ViewRec, ViewSectionRec} from 'app/client/models/DocModel';
|
||||
import {DocPageModel} from 'app/client/models/DocPageModel';
|
||||
import {UserError} from 'app/client/models/errors';
|
||||
import {urlState} from 'app/client/models/gristUrlState';
|
||||
@@ -361,6 +362,16 @@ export class GristDoc extends DisposableWithEvents {
|
||||
undo(this: GristDoc) { this._undoStack.sendUndoAction().catch(reportError); },
|
||||
redo(this: GristDoc) { this._undoStack.sendRedoAction().catch(reportError); },
|
||||
reloadPlugins() { this.docComm.reloadPlugins().then(() => G.window.location.reload(false)); },
|
||||
|
||||
// Command to be manually triggered on cell selection. Moves the cursor to the selected cell.
|
||||
// This is overridden by the formula editor to insert "$col" variables when clicking cells.
|
||||
setCursor(this: GristDoc, rowModel: BaseRowModel, fieldModel?: ViewFieldRec) {
|
||||
return this.setCursorPos({
|
||||
rowIndex: rowModel?._index() || 0,
|
||||
fieldIndex: fieldModel?._index() || 0,
|
||||
sectionId: fieldModel?.viewSection().getRowId(),
|
||||
});
|
||||
},
|
||||
}, this, true));
|
||||
|
||||
this.listenTo(app.comm, 'docUserAction', this.onDocUserAction);
|
||||
@@ -507,6 +518,21 @@ export class GristDoc extends DisposableWithEvents {
|
||||
return Object.assign(pos, viewInstance ? viewInstance.cursor.getCursorPos() : {});
|
||||
}
|
||||
|
||||
public async setCursorPos(cursorPos: CursorPos) {
|
||||
if (cursorPos.sectionId) {
|
||||
const desiredSection: ViewSectionRec = this.docModel.viewSections.getRowModel(cursorPos.sectionId);
|
||||
if (desiredSection.view.peek().getRowId() !== this.activeViewId.get()) {
|
||||
// This may be asynchronous. In other cases, the change is synchronous, and some code
|
||||
// relies on it (doesn't wait for this function to resolve).
|
||||
await this._switchToSectionId(cursorPos.sectionId);
|
||||
} else if (desiredSection !== this.viewModel.activeSection.peek()) {
|
||||
this.viewModel.activeSectionId(cursorPos.sectionId);
|
||||
}
|
||||
}
|
||||
const viewInstance = this.viewModel.activeSection.peek().viewInstance.peek();
|
||||
viewInstance?.setCursorPos(cursorPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the view/section and scroll to the record indicated by cursorPos. If cursorPos is
|
||||
* null, then moves to a position best suited for optActionGroup (not yet implemented).
|
||||
@@ -523,10 +549,7 @@ export class GristDoc extends DisposableWithEvents {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const viewInstance = await this._switchToSectionId(cursorPos.sectionId);
|
||||
if (viewInstance) {
|
||||
viewInstance.setCursorPos(cursorPos);
|
||||
}
|
||||
await this.setCursorPos(cursorPos);
|
||||
} catch(e) {
|
||||
reportError(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user