mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
1654a2681f
Summary: This moves all client code to core, and makes minimal fix-ups to get grist and grist-core to compile correctly. The client works in core, but I'm leaving clean-up around the build and bundles to follow-up. Test Plan: existing tests pass; server-dev bundle looks sane Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2627
105 lines
4.3 KiB
TypeScript
105 lines
4.3 KiB
TypeScript
import {Disposable, dom} from 'grainjs';
|
|
|
|
export interface ISize {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
interface ISizeOpts {
|
|
// Don't reposition the editor as part of the size calculation.
|
|
calcOnly?: boolean;
|
|
}
|
|
|
|
// edgeMargin is how many pixels to leave before the edge of the browser window.
|
|
const edgeMargin = 12;
|
|
|
|
// How large the editor can get when it needs to shift to the left or upwards.
|
|
const maxShiftWidth = 560;
|
|
const maxShiftHeight = 400;
|
|
|
|
|
|
/**
|
|
* This class implements the placement and sizing of the cell editor, such as TextEditor and
|
|
* FormulaEditor. These try to match the size and position of the cell being edited, expanding
|
|
* when needed.
|
|
*
|
|
* This class also takes care of attaching the editor DOM and destroying it on disposal.
|
|
*/
|
|
export class EditorPlacement extends Disposable {
|
|
private _editorRoot: HTMLElement;
|
|
|
|
// - editorDom is the DOM to attach. It gets destroyed when EditorPlacement is disposed.
|
|
// - cellRect is the bounding box of the cell being mirrored by the editor; the editor generally
|
|
// expands to match the size of the cell.
|
|
constructor(editorDom: HTMLElement, private _cellRect: ClientRect|DOMRect) {
|
|
super();
|
|
|
|
const editorRoot = this._editorRoot = dom('div.cell_editor', editorDom);
|
|
// To hide from the user the incorrectly-sized element, we set visibility to hidden, and
|
|
// reset it in _calcEditorSize() as soon as we have the sizes.
|
|
editorRoot.style.visibility = 'hidden';
|
|
|
|
document.body.appendChild(editorRoot);
|
|
this.onDispose(() => {
|
|
// When the editor is destroyed, destroy and remove its DOM.
|
|
dom.domDispose(editorRoot);
|
|
editorRoot.remove();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Calculate the size of the full editor and shift the editor if needed to give it more space.
|
|
* The position and size are applied to the editor unless {calcOnly: true} option is given.
|
|
*/
|
|
public calcSize(desiredSize: ISize, options: ISizeOpts = {}): ISize {
|
|
const maxRect = document.body.getBoundingClientRect();
|
|
|
|
const noShiftMaxWidth = maxRect.right - edgeMargin - this._cellRect.left;
|
|
const maxWidth = Math.min(maxRect.width - 2 * edgeMargin, Math.max(maxShiftWidth, noShiftMaxWidth));
|
|
const width = Math.min(maxWidth, Math.max(this._cellRect.width, desiredSize.width));
|
|
const left = Math.max(edgeMargin, Math.min(this._cellRect.left - maxRect.left, maxRect.width - edgeMargin - width));
|
|
|
|
const noShiftMaxHeight = maxRect.bottom - edgeMargin - this._cellRect.top;
|
|
const maxHeight = Math.min(maxRect.height - 2 * edgeMargin, Math.max(maxShiftHeight, noShiftMaxHeight));
|
|
const height = Math.min(maxHeight, Math.max(this._cellRect.height, desiredSize.height));
|
|
const top = Math.max(edgeMargin, Math.min(this._cellRect.top - maxRect.top, maxRect.height - edgeMargin - height));
|
|
|
|
// To hide from the user the split second before things are sized correctly, we set visibility
|
|
// to hidden until we can get the sizes. As soon as sizes are available, restore visibility.
|
|
if (!options.calcOnly) {
|
|
Object.assign(this._editorRoot.style, {
|
|
visibility: 'visible',
|
|
left: left + 'px',
|
|
top: top + 'px',
|
|
// Set the width (but not the height) of the outer container explicitly to accommodate the
|
|
// particular setup where a formula may include error details below -- these should
|
|
// stretch to the calculated width (so need an explicit value), but may be dynamic in
|
|
// height. (This feels hacky, but solves the problem.)
|
|
width: width + 'px',
|
|
});
|
|
}
|
|
|
|
return {width, height};
|
|
}
|
|
|
|
/**
|
|
* Calculate the size for the editable part of the editor, given in elem. This assumes that the
|
|
* size of the full editor differs from the editable part only in constant padding. The full
|
|
* editor may be shifted as part of this call.
|
|
*/
|
|
public calcSizeWithPadding(elem: HTMLElement, desiredElemSize: ISize, options: ISizeOpts = {}): ISize {
|
|
const rootRect = this._editorRoot.getBoundingClientRect();
|
|
const elemRect = elem.getBoundingClientRect();
|
|
const heightDelta = rootRect.height - elemRect.height;
|
|
const widthDelta = rootRect.width - elemRect.width;
|
|
const {width, height} = this.calcSize({
|
|
width: desiredElemSize.width + widthDelta,
|
|
height: desiredElemSize.height + heightDelta,
|
|
}, options);
|
|
return {
|
|
width: width - widthDelta,
|
|
height: height - heightDelta,
|
|
};
|
|
}
|
|
}
|