import {KoArray} from 'app/client/lib/koArray'; import {DocModel, IRowModel, recordSet, refRecord, TableRec, ViewFieldRec} from 'app/client/models/DocModel'; import {jsonObservable, ObjObservable} from 'app/client/models/modelUtil'; import * as gristTypes from 'app/common/gristTypes'; import {getReferencedTableId} from 'app/common/gristTypes'; import {BaseFormatter, createFormatter} from 'app/common/ValueFormatter'; import * as ko from 'knockout'; // Represents a column in a user-defined table. export interface ColumnRec extends IRowModel<"_grist_Tables_column"> { table: ko.Computed; widgetOptionsJson: ObjObservable; viewFields: ko.Computed>; summarySource: ko.Computed; // Is an empty column (undecided if formula or data); denoted by an empty formula. isEmpty: ko.Computed; // Is a real formula column (not an empty column; i.e. contains a non-empty formula). isRealFormula: ko.Computed; // Is a trigger formula column (not formula, but contains non-empty formula) hasTriggerFormula: ko.Computed; // Used for transforming a column. // Reference to the original column for a transform column, or to itself for a non-transforming column. origColRef: ko.Observable; origCol: ko.Computed; // Indicates whether a column is transforming. Manually set, but should be true in both the original // column being transformed and that column's transform column. isTransforming: ko.Observable; // Convenience observable to obtain and set the type with no suffix pureType: ko.Computed; // The column's display column _displayColModel: ko.Computed; // Display col ref to use for the column, defaulting to the plain column itself. displayColRef: ko.Computed; // The display column to use for the column, or the column itself when no displayCol is set. displayColModel: ko.Computed; visibleColModel: ko.Computed; disableModifyBase: ko.Computed; // True if column config can't be modified (name, type, etc.) disableModify: ko.Computed; // True if column can't be modified or is being transformed. disableEditData: ko.Computed; // True to disable editing of the data in this column. isHiddenCol: ko.Computed; // Returns the rowModel for the referenced table, or null, if is not a reference column. refTable: ko.Computed; // Helper which adds/removes/updates column's displayCol to match the formula. saveDisplayFormula(formula: string): Promise|undefined; // Helper for Reference/ReferenceList columns, which returns a formatter according // to the visibleCol associated with column. Subscribes to observables if used within a computed. createVisibleColFormatter(): BaseFormatter; } export function createColumnRec(this: ColumnRec, docModel: DocModel): void { this.table = refRecord(docModel.tables, this.parentId); this.widgetOptionsJson = jsonObservable(this.widgetOptions); this.viewFields = recordSet(this, docModel.viewFields, 'colRef'); this.summarySource = refRecord(docModel.columns, this.summarySourceCol); // Is this an empty column (undecided if formula or data); denoted by an empty formula. this.isEmpty = ko.pureComputed(() => this.isFormula() && this.formula() === ''); // Is this a real formula column (not an empty column; i.e. contains a non-empty formula). this.isRealFormula = ko.pureComputed(() => this.isFormula() && this.formula() !== ''); // If this column has a trigger formula defined this.hasTriggerFormula = ko.pureComputed(() => !this.isFormula() && this.formula() !== ''); // Used for transforming a column. // Reference to the original column for a transform column, or to itself for a non-transforming column. this.origColRef = ko.observable(this.getRowId()); this.origCol = refRecord(docModel.columns, this.origColRef); // Indicates whether a column is transforming. Manually set, but should be true in both the original // column being transformed and that column's transform column. this.isTransforming = ko.observable(false); // Convenience observable to obtain and set the type with no suffix this.pureType = ko.pureComputed(() => gristTypes.extractTypeFromColType(this.type())); // The column's display column this._displayColModel = refRecord(docModel.columns, this.displayCol); // Helper which adds/removes/updates this column's displayCol to match the formula. this.saveDisplayFormula = function(formula) { if (formula !== (this._displayColModel().formula() || '')) { return docModel.docData.sendAction(["SetDisplayFormula", this.table().tableId(), null, this.getRowId(), formula]); } }; // Display col ref to use for the column, defaulting to the plain column itself. this.displayColRef = ko.pureComputed(() => this.displayCol() || this.origColRef()); // The display column to use for the column, or the column itself when no displayCol is set. this.displayColModel = refRecord(docModel.columns, this.displayColRef); this.visibleColModel = refRecord(docModel.columns, this.visibleCol); this.disableModifyBase = ko.pureComputed(() => Boolean(this.summarySourceCol())); this.disableModify = ko.pureComputed(() => this.disableModifyBase() || this.isTransforming()); this.disableEditData = ko.pureComputed(() => Boolean(this.summarySourceCol())); this.isHiddenCol = ko.pureComputed(() => gristTypes.isHiddenCol(this.colId())); // Returns the rowModel for the referenced table, or null, if this is not a reference column. this.refTable = ko.pureComputed(() => { const refTableId = getReferencedTableId(this.type() || ""); return refTableId ? docModel.allTables.all().find(t => t.tableId() === refTableId) || null : null; }); // Helper for Reference/ReferenceList columns, which returns a formatter according to the visibleCol // associated with this column. If no visible column available, return formatting for the column itself. // Subscribes to observables if used within a computed. // TODO: It would be better to replace this with a pureComputed whose value is a formatter. this.createVisibleColFormatter = function() { const vcol = this.visibleColModel(); const documentSettings = docModel.docInfoRow.documentSettingsJson(); return (vcol.getRowId() !== 0) ? createFormatter(vcol.type(), vcol.widgetOptionsJson(), documentSettings) : createFormatter(this.type(), this.widgetOptionsJson(), documentSettings); }; }