mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Speed up and upgrade build.
Summary:
- Upgrades to build-related packages:
- Upgrade typescript, related libraries and typings.
- Upgrade webpack, eslint; add tsc-watch, node-dev, eslint_d.
- Build organization changes:
- Build webpack from original typescript, transpiling only; with errors still
reported by a background tsc watching process.
- Typescript-related changes:
- Reduce imports of AWS dependencies (very noticeable speedup)
- Avoid auto-loading global @types
- Client code is now built with isolatedModules flag (for safe transpilation)
- Use allowJs to avoid copying JS files manually.
- Linting changes
- Enhance Arcanist ESLintLinter to run before/after commands, and set up to use eslint_d
- Update eslint config, and include .eslintignore to avoid linting generated files.
- Include a bunch of eslint-prompted and eslint-generated fixes
- Add no-unused-expression rule to eslint, and fix a few warnings about it
- Other items:
- Refactor cssInput to avoid circular dependency
- Remove a bit of unused code, libraries, dependencies
Test Plan: No behavior changes, all existing tests pass. There are 30 tests fewer reported because `test_gpath.py` was removed (it's been unused for years)
Reviewers: paulfitz
Reviewed By: paulfitz
Subscribers: paulfitz
Differential Revision: https://phab.getgrist.com/D3498
This commit is contained in:
@@ -81,7 +81,7 @@ export class Cursor extends Disposable {
|
||||
this.viewData = baseView.viewData;
|
||||
|
||||
this._sectionId = this.autoDispose(ko.computed(() => baseView.viewSection.id()));
|
||||
this._rowId = ko.observable(optCursorPos.rowId || 0);
|
||||
this._rowId = ko.observable<RowId|null>(optCursorPos.rowId || 0);
|
||||
this.rowIndex = this.autoDispose(ko.computed({
|
||||
read: () => {
|
||||
if (!this._isLive()) { return this.rowIndex.peek(); }
|
||||
|
||||
@@ -93,7 +93,7 @@ export class TypeTransform extends ColumnTransform {
|
||||
const colInfo = await TypeConversion.prepTransformColInfo(docModel, this.origColumn, this.origDisplayCol, toType);
|
||||
// NOTE: We could add rules with AddColumn action, but there are some optimizations that converts array values.
|
||||
const rules = colInfo.rules;
|
||||
delete colInfo.rules;
|
||||
delete (colInfo as any).rules;
|
||||
const newColInfos = await this._tableData.sendTableActions([
|
||||
['AddColumn', 'gristHelper_Converted', {...colInfo, isFormula: false, formula: ''}],
|
||||
['AddColumn', 'gristHelper_Transform', colInfo],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { GristDoc } from 'app/client/components/GristDoc';
|
||||
import { ViewFieldRec, ViewSectionRec } from 'app/client/models/DocModel';
|
||||
import { cssField, cssInput, cssLabel} from 'app/client/ui/MakeCopyMenu';
|
||||
import { cssInput } from 'app/client/ui/cssInput';
|
||||
import { cssField, cssLabel } from 'app/client/ui/MakeCopyMenu';
|
||||
import { IPageWidget, toPageWidget } from 'app/client/ui/PageWidgetPicker';
|
||||
import { confirmModal } from 'app/client/ui2018/modals';
|
||||
import { BulkColValues, getColValues, RowRecord, UserAction } from 'app/common/DocActions';
|
||||
|
||||
7
app/client/declarations.d.ts
vendored
7
app/client/declarations.d.ts
vendored
@@ -12,7 +12,6 @@ declare module "app/client/lib/browserGlobals";
|
||||
declare module "app/client/lib/dom";
|
||||
declare module "app/client/lib/koDom";
|
||||
declare module "app/client/lib/koForm";
|
||||
declare module "app/client/lib/koSession";
|
||||
declare module "app/client/widgets/UserType";
|
||||
declare module "app/client/widgets/UserTypeImpl";
|
||||
|
||||
@@ -319,3 +318,9 @@ declare module "app/client/lib/koUtil" {
|
||||
// with polyfills for old browsers.
|
||||
declare module "bowser/bundled";
|
||||
declare module "randomcolor";
|
||||
|
||||
interface Location {
|
||||
// We use reload(true) in places, which has an effect in Firefox, but may be more of a
|
||||
// historical accident than an intentional choice.
|
||||
reload(forceGet?: boolean): void;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
exports.loadBillingPage = () => import('app/client/ui/BillingPage' /* webpackChunkName: "BillingModule" */);
|
||||
exports.loadGristDoc = () => import('app/client/components/GristDoc' /* webpackChunkName: "GristDoc" */);
|
||||
exports.loadMomentTimezone = () => import('moment-timezone');
|
||||
// When importing this way, the module is under the "default" member, not sure why (maybe
|
||||
// esbuild-loader's doing).
|
||||
exports.loadMomentTimezone = () => import('moment-timezone').then(m => m.default);
|
||||
exports.loadPlotly = () => import('plotly.js-basic-dist' /* webpackChunkName: "plotly" */);
|
||||
exports.loadSearch = () => import('app/client/ui2018/search' /* webpackChunkName: "search" */);
|
||||
exports.loadUserManager = () => import('app/client/ui/UserManager' /* webpackChunkName: "usermanager" */);
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* koSession offers observables whose values are tied to the browser session or history:
|
||||
*
|
||||
* sessionValue(key) - an observable preserved across history entries and reloads.
|
||||
*
|
||||
* Note: we could also support "browserValue", shared across all tabs and across browser restarts
|
||||
* (same as sessionValue but using window.localStorage), but it seems more appropriate to store
|
||||
* such values on the server.
|
||||
*/
|
||||
|
||||
/* global window, $ */
|
||||
|
||||
var _ = require('underscore');
|
||||
var ko = require('knockout');
|
||||
|
||||
/**
|
||||
* Maps a string key to an observable. The space of keys is shared for all kinds of observables,
|
||||
* and they differ only in where they store their state. Each observable gets several extra
|
||||
* properties:
|
||||
* @property {String} ksKey The key used for storage. It should be unique across koSession values.
|
||||
* @property {Object} ksDefault The default value if the storage doesn't have one.
|
||||
* @property {Function} ksFetch The method to fetch the value from storage.
|
||||
* @property {Function} ksSave The method to save the value to storage.
|
||||
*/
|
||||
var _sessionValues = {};
|
||||
|
||||
function createObservable(key, defaultValue, methods) {
|
||||
var obs = _sessionValues[key];
|
||||
if (!obs) {
|
||||
_sessionValues[key] = obs = ko.observable();
|
||||
obs.ksKey = key;
|
||||
obs.ksDefaultValue = defaultValue;
|
||||
obs.ksFetch = methods.fetch;
|
||||
obs.ksSave = methods.save;
|
||||
obs.dispose = methods.dispose;
|
||||
|
||||
// We initialize the observable before setting rateLimit, to ensure that the initialization
|
||||
// doesn't end up triggering subscribers that are about to be added (which seems to be a bit
|
||||
// of a problem with rateLimit extender, and possibly deferred). This workaround relies on the
|
||||
// fact that the extender modifies its target without creating a new one.
|
||||
obs(obs.ksFetch());
|
||||
obs.extend({deferred: true});
|
||||
|
||||
obs.subscribe(function(newValue) {
|
||||
if (newValue !== this.ksFetch()) {
|
||||
console.log("koSession: %s changed %s -> %s", this.ksKey, this.ksFetch(), newValue);
|
||||
this.ksSave(newValue);
|
||||
}
|
||||
}, obs);
|
||||
}
|
||||
return obs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable whose value sticks across reloads and navigation, but is different for
|
||||
* different browser tabs. E.g. it may be used to reflect whether a side pane is open.
|
||||
* The `key` isn't visible to the user, so pick any unique string name.
|
||||
*/
|
||||
function sessionValue(key, optDefault) {
|
||||
return createObservable(key, optDefault, sessionValueMethods);
|
||||
}
|
||||
exports.sessionValue = sessionValue;
|
||||
|
||||
var sessionValueMethods = {
|
||||
'fetch': function() {
|
||||
var value = window.sessionStorage.getItem(this.ksKey);
|
||||
if (!value) {
|
||||
return this.ksDefaultValue;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {
|
||||
return this.ksDefaultValue;
|
||||
}
|
||||
},
|
||||
'save': function(value) {
|
||||
window.sessionStorage.setItem(this.ksKey, JSON.stringify(value));
|
||||
},
|
||||
'dispose': function(value) {
|
||||
window.sessionStorage.removeItem(this.ksKey);
|
||||
}
|
||||
};
|
||||
|
||||
function onApplyState() {
|
||||
_.each(_sessionValues, function(obs, key) {
|
||||
obs(obs.ksFetch());
|
||||
});
|
||||
}
|
||||
|
||||
$(window).on('applyState', onApplyState);
|
||||
@@ -21,13 +21,12 @@ export class DataRowModel extends BaseRowModel {
|
||||
public _validationFailures: ko.PureComputed<Array<IRowModel<'_grist_Validations'>>>;
|
||||
public _isAddRow: ko.Observable<boolean>;
|
||||
|
||||
private _allValidationsList: ko.Computed<KoArray<ValidationRec>>;
|
||||
private _isRealChange: ko.Observable<boolean>;
|
||||
|
||||
public constructor(dataTableModel: DataTableModel, colNames: string[]) {
|
||||
super(dataTableModel, colNames);
|
||||
|
||||
this._allValidationsList = dataTableModel.tableMetaRow.validations;
|
||||
const allValidationsList: ko.Computed<KoArray<ValidationRec>> = dataTableModel.tableMetaRow.validations;
|
||||
|
||||
this._isAddRow = ko.observable(false);
|
||||
|
||||
@@ -36,10 +35,10 @@ export class DataRowModel extends BaseRowModel {
|
||||
// changes, those should only be enabled when _isRealChange is true.
|
||||
this._isRealChange = ko.observable(true);
|
||||
|
||||
this._validationFailures = this.autoDispose(ko.pureComputed(function() {
|
||||
return this._allValidationsList().all().filter(
|
||||
this._validationFailures = this.autoDispose(ko.pureComputed(() => {
|
||||
return allValidationsList().all().filter(
|
||||
validation => !this.cells[this.getValidationNameFromId(validation.id())]());
|
||||
}, this));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,16 +41,8 @@ import {decodeObject} from 'app/plugin/objtypes';
|
||||
|
||||
// Re-export all the entity types available. The recommended usage is like this:
|
||||
// import {ColumnRec, ViewFieldRec} from 'app/client/models/DocModel';
|
||||
export {ColumnRec} from 'app/client/models/entities/ColumnRec';
|
||||
export {DocInfoRec} from 'app/client/models/entities/DocInfoRec';
|
||||
export {FilterRec} from 'app/client/models/entities/FilterRec';
|
||||
export {PageRec} from 'app/client/models/entities/PageRec';
|
||||
export {TabBarRec} from 'app/client/models/entities/TabBarRec';
|
||||
export {TableRec} from 'app/client/models/entities/TableRec';
|
||||
export {ValidationRec} from 'app/client/models/entities/ValidationRec';
|
||||
export {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
export {ViewRec} from 'app/client/models/entities/ViewRec';
|
||||
export {ViewSectionRec} from 'app/client/models/entities/ViewSectionRec';
|
||||
export type {ColumnRec, DocInfoRec, FilterRec, PageRec, TabBarRec, TableRec, ValidationRec,
|
||||
ViewFieldRec, ViewRec, ViewSectionRec};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@ import {buildColFilter, ColumnFilterFunc} from 'app/common/ColumnFilterFunc';
|
||||
import {buildRowFilter, RowFilterFunc, RowValueFunc } from 'app/common/RowFilterFunc';
|
||||
import {Computed, Disposable, MutableObsArray, obsArray, Observable, UseCB} from 'grainjs';
|
||||
|
||||
export {ColumnFilterFunc} from 'app/common/ColumnFilterFunc';
|
||||
export type {ColumnFilterFunc};
|
||||
|
||||
interface OpenColumnFilter {
|
||||
colRef: number;
|
||||
|
||||
@@ -306,7 +306,7 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
// in which case the UI prevents various things like hiding columns or changing the widget type.
|
||||
this.isRaw = this.autoDispose(ko.pureComputed(() => this.table().rawViewSectionRef() === this.getRowId()));
|
||||
|
||||
this.borderWidthPx = ko.pureComputed(function() { return this.borderWidth() + 'px'; }, this);
|
||||
this.borderWidthPx = ko.pureComputed(() => this.borderWidth() + 'px');
|
||||
|
||||
this.layoutSpecObj = modelUtil.jsonObservable(this.layoutSpec);
|
||||
|
||||
@@ -487,7 +487,7 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
this.linkSrcCol = refRecord(docModel.columns, this.activeLinkSrcColRef);
|
||||
this.linkTargetCol = refRecord(docModel.columns, this.activeLinkTargetColRef);
|
||||
|
||||
this.activeRowId = ko.observable(null);
|
||||
this.activeRowId = ko.observable<RowId|null>(null);
|
||||
|
||||
this._linkingState = Holder.create(this);
|
||||
this.linkingState = this.autoDispose(ko.pureComputed(() => {
|
||||
@@ -506,7 +506,7 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
}));
|
||||
|
||||
// If the view instance for this section is instantiated, it will be accessible here.
|
||||
this.viewInstance = ko.observable(null);
|
||||
this.viewInstance = ko.observable<BaseView|null>(null);
|
||||
|
||||
// Describes the most recent cursor position in the section.
|
||||
this.lastCursorPos = {
|
||||
@@ -542,8 +542,8 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
);
|
||||
|
||||
this.hasCustomOptions = ko.observable(false);
|
||||
this.desiredAccessLevel = ko.observable(null);
|
||||
this.columnsToMap = ko.observable(null);
|
||||
this.desiredAccessLevel = ko.observable<AccessLevel|null>(null);
|
||||
this.columnsToMap = ko.observable<ColumnsToMap|null>(null);
|
||||
// Calculate mapped columns for Custom Widget.
|
||||
this.mappedColumns = ko.pureComputed(() => {
|
||||
// First check if widget has requested a custom column mapping and
|
||||
|
||||
@@ -236,7 +236,7 @@ export class BillingPage extends Disposable {
|
||||
moneyPlan?.amount ? [
|
||||
makeSummaryFeature([`Your team site has `, `${sub.userCount}`,
|
||||
` member${sub.userCount !== 1 ? 's' : ''}`]),
|
||||
tier ? this._makeAppSumoFeature(discountName!) : null,
|
||||
tier ? this._makeAppSumoFeature(discountName) : null,
|
||||
// Currently the subtotal is misleading and scary when tiers are in effect.
|
||||
// In this case, for now, just report what will be invoiced.
|
||||
!tier ? makeSummaryFeature([`Your ${moneyPlan.interval}ly subtotal is `,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import {AppModel, reportError} from 'app/client/models/AppModel';
|
||||
import {getLoginOrSignupUrl, urlState} from 'app/client/models/gristUrlState';
|
||||
import {getWorkspaceInfo, ownerName, workspaceName} from 'app/client/models/WorkspaceInfo';
|
||||
import {cssInput} from 'app/client/ui/cssInput';
|
||||
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
|
||||
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
|
||||
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
|
||||
@@ -275,16 +276,6 @@ class SaveCopyModal extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
export const cssInput = styled('input', `
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
font-size: ${vars.mediumFontSize};
|
||||
border-radius: 3px;
|
||||
padding: 5px;
|
||||
border: 1px solid ${colors.darkGrey};
|
||||
outline: none;
|
||||
`);
|
||||
|
||||
export const cssField = styled('div', `
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
|
||||
12
app/client/ui/cssInput.ts
Normal file
12
app/client/ui/cssInput.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {colors, vars} from 'app/client/ui2018/cssVars';
|
||||
import {styled} from 'grainjs';
|
||||
|
||||
export const cssInput = styled('input', `
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
font-size: ${vars.mediumFontSize};
|
||||
border-radius: 3px;
|
||||
padding: 5px;
|
||||
border: 1px solid ${colors.darkGrey};
|
||||
outline: none;
|
||||
`);
|
||||
@@ -75,7 +75,7 @@ export function prepareForTransition(elem: HTMLElement, prepare: () => void) {
|
||||
// Recompute styles while transitions are off. See https://stackoverflow.com/a/16575811/328565
|
||||
// for explanation and https://stackoverflow.com/a/31862081/328565 for the recommendation used
|
||||
// here to trigger a style computation without a reflow.
|
||||
window.getComputedStyle(elem).opacity; // tslint:disable-line:no-unused-expression
|
||||
window.getComputedStyle(elem).opacity; // eslint-disable-line no-unused-expressions
|
||||
|
||||
// Restore transitions.
|
||||
elem.style.transitionProperty = prior;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FocusLayer} from 'app/client/lib/FocusLayer';
|
||||
import {reportError} from 'app/client/models/errors';
|
||||
import {cssInput} from 'app/client/ui/MakeCopyMenu';
|
||||
import {cssInput} from 'app/client/ui/cssInput';
|
||||
import {prepareForTransition, TransitionWatcher} from 'app/client/ui/transitions';
|
||||
import {bigBasicButton, bigPrimaryButton, cssButton} from 'app/client/ui2018/buttons';
|
||||
import {colors, mediaSmall, testId, vars} from 'app/client/ui2018/cssVars';
|
||||
|
||||
@@ -29,7 +29,7 @@ export class ChoiceTextBox extends NTextBox {
|
||||
private _choiceValues: Computed<string[]>;
|
||||
private _choiceValuesSet: Computed<Set<string>>;
|
||||
private _choiceOptions: KoSaveableObservable<ChoiceOptions | null | undefined>;
|
||||
private _choiceOptionsByName: Computed<ChoiceOptionsByName>
|
||||
private _choiceOptionsByName: Computed<ChoiceOptionsByName>;
|
||||
|
||||
constructor(field: ViewFieldRec) {
|
||||
super(field);
|
||||
|
||||
@@ -17,6 +17,9 @@ export interface IMargins {
|
||||
right: number;
|
||||
}
|
||||
|
||||
export type IRect = ISize & IMargins;
|
||||
|
||||
|
||||
// edgeMargin is how many pixels to leave before the edge of the browser window by default.
|
||||
// This is added to margins that may be passed into the constructor.
|
||||
const edgeMargin = 12;
|
||||
@@ -37,8 +40,8 @@ export class EditorPlacement extends Disposable {
|
||||
public readonly onReposition = this.autoDispose(new Emitter());
|
||||
|
||||
private _editorRoot: HTMLElement;
|
||||
private _maxRect: ClientRect|DOMRect;
|
||||
private _cellRect: ClientRect|DOMRect;
|
||||
private _maxRect: IRect;
|
||||
private _cellRect: IRect;
|
||||
private _margins: IMargins;
|
||||
|
||||
// - editorDom is the DOM to attach. It gets destroyed when EditorPlacement is disposed.
|
||||
@@ -141,7 +144,7 @@ export class EditorPlacement extends Disposable {
|
||||
|
||||
// Get the bounding rect of elem excluding borders. This allows the editor to match cellElem more
|
||||
// closely which is more visible in case of DetailView.
|
||||
function rectWithoutBorders(elem: Element): ClientRect {
|
||||
function rectWithoutBorders(elem: Element): IRect {
|
||||
const rect = elem.getBoundingClientRect();
|
||||
const style = getComputedStyle(elem, null);
|
||||
const bTop = parseFloat(style.getPropertyValue('border-top-width'));
|
||||
|
||||
@@ -55,6 +55,7 @@ function getTypeDefinition(type: string | false) {
|
||||
}
|
||||
|
||||
type ComputedStyle = {style?: Style; error?: true} | null | undefined;
|
||||
|
||||
/**
|
||||
* Builds a font option computed property.
|
||||
*/
|
||||
@@ -62,12 +63,13 @@ function buildFontOptions(
|
||||
builder: FieldBuilder,
|
||||
computedRule: ko.Computed<ComputedStyle>,
|
||||
optionName: keyof Style) {
|
||||
return koUtil.withKoUtils(ko.computed(function() {
|
||||
|
||||
return koUtil.withKoUtils(ko.computed(() => {
|
||||
if (builder.isDisposed()) { return false; }
|
||||
const style = computedRule()?.style;
|
||||
const styleFlag = style?.[optionName] || this.field[optionName]();
|
||||
const styleFlag = style?.[optionName] || builder.field[optionName]();
|
||||
return styleFlag;
|
||||
}, builder)).onlyNotifyUnequal();
|
||||
})).onlyNotifyUnequal();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,9 +133,9 @@ export class FieldBuilder extends Disposable {
|
||||
});
|
||||
|
||||
// Observable which evaluates to a *function* that decides if a value is valid.
|
||||
this._isRightType = ko.pureComputed(function() {
|
||||
this._isRightType = ko.pureComputed<(value: CellValue, options?: any) => boolean>(() => {
|
||||
return gristTypes.isRightType(this._readOnlyPureType()) || _.constant(false);
|
||||
}, this);
|
||||
});
|
||||
|
||||
// Returns a boolean indicating whether the column is type Reference or ReferenceList.
|
||||
this._isRef = this.autoDispose(ko.computed(() => {
|
||||
@@ -154,7 +156,7 @@ export class FieldBuilder extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
this.widget = ko.pureComputed({
|
||||
this.widget = ko.pureComputed<object>({
|
||||
owner: this,
|
||||
read() { return this.options().widget; },
|
||||
write(widget) {
|
||||
@@ -196,10 +198,10 @@ export class FieldBuilder extends Disposable {
|
||||
this._rowMap = new Map();
|
||||
|
||||
// Returns the constructor for the widget, and only notifies subscribers on changes.
|
||||
this._widgetCons = this.autoDispose(koUtil.withKoUtils(ko.computed(function() {
|
||||
this._widgetCons = this.autoDispose(koUtil.withKoUtils(ko.computed(() => {
|
||||
return UserTypeImpl.getWidgetConstructor(this.options().widget,
|
||||
this._readOnlyPureType());
|
||||
}, this)).onlyNotifyUnequal());
|
||||
})).onlyNotifyUnequal());
|
||||
|
||||
// Computed builder for the widget.
|
||||
this.widgetImpl = this.autoDispose(koUtil.computedBuilder(() => {
|
||||
@@ -467,28 +469,28 @@ export class FieldBuilder extends Disposable {
|
||||
return { style : new CombinedStyle(styles, flags) };
|
||||
}, this).extend({ deferred: true })).previousOnUndefined();
|
||||
|
||||
const widgetObs = koUtil.withKoUtils(ko.computed(function() {
|
||||
const widgetObs = koUtil.withKoUtils(ko.computed(() => {
|
||||
// TODO: Accessing row values like this doesn't always work (row and field might not be updated
|
||||
// simultaneously).
|
||||
if (this.isDisposed()) { return null; } // Work around JS errors during field removal.
|
||||
const value = row.cells[this.field.colId()];
|
||||
const cell = value && value();
|
||||
if (value && this._isRightType()(cell, this.options) || row._isAddRow.peek()) {
|
||||
if ((value) && this._isRightType()(cell, this.options) || row._isAddRow.peek()) {
|
||||
return this.widgetImpl();
|
||||
} else if (gristTypes.isVersions(cell)) {
|
||||
return this.diffImpl;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, this).extend({ deferred: true })).onlyNotifyUnequal();
|
||||
}).extend({ deferred: true })).onlyNotifyUnequal();
|
||||
|
||||
const textColor = koUtil.withKoUtils(ko.computed(function() {
|
||||
const textColor = koUtil.withKoUtils(ko.computed(() => {
|
||||
if (this.isDisposed()) { return null; }
|
||||
const fromRules = computedRule()?.style?.textColor;
|
||||
return fromRules || this.field.textColor() || '';
|
||||
}, this)).onlyNotifyUnequal();
|
||||
})).onlyNotifyUnequal();
|
||||
|
||||
const fillColor = koUtil.withKoUtils(ko.computed(function() {
|
||||
const fillColor = koUtil.withKoUtils(ko.computed(() => {
|
||||
if (this.isDisposed()) { return null; }
|
||||
const fromRules = computedRule()?.style?.fillColor;
|
||||
let fill = fromRules || this.field.fillColor();
|
||||
@@ -496,7 +498,7 @@ export class FieldBuilder extends Disposable {
|
||||
// If there is no color we are using fully transparent white color (for tests mainly).
|
||||
fill = fill ? fill.toUpperCase() : fill;
|
||||
return (fill === '#FFFFFF' ? '' : fill) || '#FFFFFF00';
|
||||
}, this)).onlyNotifyUnequal();
|
||||
})).onlyNotifyUnequal();
|
||||
|
||||
const fontBold = buildFontOptions(this, computedRule, 'fontBold');
|
||||
const fontItalic = buildFontOptions(this, computedRule, 'fontItalic');
|
||||
|
||||
@@ -135,6 +135,7 @@ export class NTextEditor extends NewBaseEditor {
|
||||
// but we got same enough spaces, we will force browser to check the available space once more time.
|
||||
if (enoughSpace(rect, size) && hasScroll(textInput)) {
|
||||
textInput.style.overflow = "hidden";
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
textInput.clientHeight; // just access metrics is enough to repaint
|
||||
textInput.style.overflow = "auto";
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
dom,
|
||||
DomContents,
|
||||
fromKo,
|
||||
IDisposableOwnerT,
|
||||
Observable,
|
||||
} from 'grainjs';
|
||||
|
||||
@@ -30,8 +31,13 @@ export abstract class NewAbstractWidget extends Disposable {
|
||||
/**
|
||||
* Override the create() method to match the parameters of create() expected by FieldBuilder.
|
||||
*/
|
||||
public static create(field: ViewFieldRec) {
|
||||
return Disposable.create.call(this as any, null, field);
|
||||
// We copy Disposable.create() signature (the second one) to pacify typescript, but code must
|
||||
// use the first signature, which is compatible with old-style constructors.
|
||||
public static create<T extends new (...args: any[]) => any>(field: ViewFieldRec): InstanceType<T>;
|
||||
public static create<T extends new (...args: any[]) => any>(
|
||||
this: T, owner: IDisposableOwnerT<InstanceType<T>>|null, ...args: ConstructorParameters<T>): InstanceType<T>;
|
||||
public static create(...args: any[]) {
|
||||
return Disposable.create.call(this as any, null, ...args);
|
||||
}
|
||||
|
||||
protected options: SaveableObjObservable<any>;
|
||||
|
||||
Reference in New Issue
Block a user