gristlabs_grist-core/app/client/models/ColumnACIndexes.ts
George Gevoian 79f6f605f8 (core) Polish and enable Reference List widget
Summary:
Adds Reference List as a widget type.

Reference List is similar to Choice List: multiple references can be added
to each cell through a similar editor, and the individual references
will always reflect their current value from the referenced table.

Test Plan: Browser tests.

Reviewers: dsagal

Reviewed By: dsagal

Subscribers: paulfitz, jarek, alexmojaki, dsagal

Differential Revision: https://phab.getgrist.com/D2959
2021-08-12 11:51:21 -07:00

61 lines
2.3 KiB
TypeScript

/**
* Implements a cache of ACIndex objects for columns in Grist table.
*
* The getColACIndex() function returns the corresponding ACIndex, building it if needed and
* caching for subsequent calls. Any change to the column or a value in it invalidates the cache.
*
* It is available as tableData.columnACIndexes.
*
* It is currently used for auto-complete in the ReferenceEditor and ReferenceListEditor widgets.
*/
import {ACIndex, ACIndexImpl} from 'app/client/lib/ACIndex';
import {ColumnCache} from 'app/client/models/ColumnCache';
import {UserError} from 'app/client/models/errors';
import {TableData} from 'app/client/models/TableData';
import {localeCompare, nativeCompare} from 'app/common/gutil';
import {BaseFormatter} from 'app/common/ValueFormatter';
export interface ICellItem {
rowId: number|'new';
text: string; // Formatted cell text.
cleanText: string; // Trimmed lowercase text for searching.
}
export class ColumnACIndexes {
private _columnCache = new ColumnCache<ACIndex<ICellItem>>(this._tableData);
constructor(private _tableData: TableData) {}
/**
* Returns the column index for the given column, using a cached one if available.
* The formatter should be created using field.createVisibleColFormatter(). It's assumed that
* getColACIndex() is called for the same column with the the same formatter.
*/
public getColACIndex(colId: string, formatter: BaseFormatter): ACIndex<ICellItem> {
return this._columnCache.getValue(colId, () => this._buildColACIndex(colId, formatter));
}
private _buildColACIndex(colId: string, formatter: BaseFormatter): ACIndex<ICellItem> {
const rowIds = this._tableData.getRowIds();
const valColumn = this._tableData.getColValues(colId);
if (!valColumn) {
throw new UserError(`Invalid column ${this._tableData.tableId}.${colId}`);
}
const items: ICellItem[] = valColumn.map((val, i) => {
const rowId = rowIds[i];
const text = formatter.formatAny(val);
const cleanText = text.trim().toLowerCase();
return {rowId, text, cleanText};
});
items.sort(itemCompare);
return new ACIndexImpl(items);
}
}
function itemCompare(a: ICellItem, b: ICellItem) {
return localeCompare(a.cleanText, b.cleanText) ||
localeCompare(a.text, b.text) ||
nativeCompare(a.rowId, b.rowId);
}