gristlabs_grist-core/app/client/components/BaseView2.ts
Alex Hall bf271c822b (core) Copy column type and options when pasting into an empty column
Summary:
Adds a `data-grist-col-ref` attribute to the copied HTML, then uses that when pasting to look up the source column and retrieve info about it. Copies the info into the target column if:

- The document is the same (the docId hash matches)
- The source column still exists and has the same type as when copied
- The source type isn't Text, because in that case it's nice if type guessing still happens
- The target column is empty, meaning it has type Any (we check earlier that it's not a formula column)

The info copied is the type, widgetOptions, and reference column settings (visible and display columns) but not conditional formatting.

The changes are mostly in a function `parsePasteForView` which is based on `BaseView._parsePasteForView` but ported to TypeScript in a new file `BaseView2.ts`.

Added a useraction `MaybeCopyDisplayFormula` exposing an existing Python function `maybe_copy_display_formula` because the target column needs a slightly different display formula.

Test Plan: Added a new nbrowser test file and fixture doc.

Reviewers: cyprien

Reviewed By: cyprien

Subscribers: jarek, dsagal

Differential Revision: https://phab.getgrist.com/D3344
2022-04-04 14:53:16 +02:00

90 lines
3.5 KiB
TypeScript

/**
* This file contains logic moved from BaseView.js and ported to TS.
*/
import {GristDoc} from 'app/client/components/GristDoc';
import {getDocIdHash, RichPasteObject} from 'app/client/lib/tableUtil';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {UserAction} from 'app/common/DocActions';
import {isFullReferencingType} from 'app/common/gristTypes';
import {SchemaTypes} from 'app/common/schema';
import {BulkColValues} from 'app/plugin/GristData';
import omit = require('lodash/omit');
/**
* Given a 2-d paste column-oriented paste data and target cols, transform the data to omit
* fields that shouldn't be pasted over and extract rich paste data if available.
* When pasting into empty columns, also update them with options from the source column.
* `data` is a column-oriented 2-d array of either
* plain strings or rich paste data returned by `tableUtil.parsePasteHtml`.
* `fields` are the target fields being pasted into.
*/
export async function parsePasteForView(
data: Array<string | RichPasteObject>[], fields: ViewFieldRec[], gristDoc: GristDoc
): Promise<BulkColValues> {
const result: BulkColValues = {};
const actions: UserAction[] = [];
const thisDocIdHash = getDocIdHash();
data.forEach((col, idx) => {
const field = fields[idx];
const colRec = field?.column();
if (!colRec || colRec.isRealFormula() || colRec.disableEditData()) {
return;
}
const parser = field.createValueParser() || (x => x);
let typeMatches = false;
if (col[0] && typeof col[0] === "object") {
const {colType, docIdHash, colRef} = col[0];
const targetType = colRec.type();
const docIdMatches = docIdHash === thisDocIdHash;
typeMatches = docIdMatches || !isFullReferencingType(colType || "");
if (targetType !== "Any") {
typeMatches = typeMatches && colType === targetType;
} else if (docIdMatches && colRef) {
// Try copying source column type and options into empty columns
const sourceColRec = gristDoc.docModel.columns.getRowModel(colRef);
const sourceType = sourceColRec.type();
// Check that the source column still exists, has a type other than Text, and the type hasn't changed.
// For Text columns, we don't copy over column info so that type guessing can still happen.
if (sourceColRec.getRowId() && sourceType !== "Text" && sourceType === colType) {
const colInfo: Partial<SchemaTypes["_grist_Tables_column"]> = {
type: sourceType,
visibleCol: sourceColRec.visibleCol(),
// Conditional formatting rules are not copied right now, that's a bit more complicated
// and copying the formula may or may not be desirable.
widgetOptions: JSON.stringify(omit(sourceColRec.widgetOptionsJson(), "rulesOptions")),
};
actions.push(
["UpdateRecord", "_grist_Tables_column", colRec.getRowId(), colInfo],
["MaybeCopyDisplayFormula", colRef, colRec.getRowId()],
);
}
}
}
result[colRec.colId()] = col.map(v => {
if (v) {
if (typeof v === "string") {
return parser(v);
}
if (typeMatches && v.hasOwnProperty('rawValue')) {
return v.rawValue;
}
if (v.hasOwnProperty('displayValue')) {
return parser(v.displayValue);
}
}
return v;
});
});
if (actions.length) {
await gristDoc.docData.sendActions(actions);
}
return result;
}