diff options
3 files changed, 74 insertions, 19 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 1d9245206..c287b7d44 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -478,7 +478,6 @@ export class CollectionSchemaView extends CollectionSubView() { this._colEles.forEach((colRef, i) => { const edgeStyle = i === index ? `solid 2px ${Colors.MEDIUM_BLUE}` : ''; const sorted = i === this.columnKeys.indexOf(this.sortField); - console.log(sorted) const cellEles = [ colRef, ...this.docsWithDrag.docs @@ -497,7 +496,7 @@ export class CollectionSchemaView extends CollectionSubView() { highlightSortedColumn = (field?: string, descending?: boolean) => { let index = -1; let highlightColors: string[] = []; - const rowCount: number = this._rowEles.size + 1; + const rowCount: number = this._docs.length + 1; if (field || this.sortField){ index = this.columnKeys.indexOf(field || this.sortField); const increment: number = 100/rowCount; @@ -530,7 +529,6 @@ export class CollectionSchemaView extends CollectionSubView() { getCellElement = (doc: Doc, fieldKey: string) => { const index = this.columnKeys.indexOf(fieldKey); - console.log(doc.title) const cell = this._rowEles.get(doc).children[1].children[index]; return cell; } diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index 5f758683d..3af3b1d61 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -22,8 +22,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro private _disposers: { [name: string]: IReactionDisposer } = {}; private _inputref: HTMLDivElement | null = null; + private _content: string = ''; _overlayDisposer?: () => void; @observable _editing: boolean = false; + @observable _displayedContent = ''; constructor(props: SchemaCellFieldProps) { super(props); @@ -50,12 +52,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro }, { fireImmediately: true } ); + this._content = this.props.GetValue() ?? ''; + this.setContent(this._content); } componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) { super.componentDidUpdate(prevProps); if (this._editing && this._props.editing === false) { - this._inputref?.innerText && this.finalizeEdit(this._inputref.innerText, false, true, false); + this.finalizeEdit(false, true, false); } else runInAction(() => { if (this._props.editing !== undefined) this._editing = this._props.editing; @@ -65,9 +69,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro componentWillUnmount(): void { this._overlayDisposer?.(); this._disposers.editing?.(); - this._inputref?.innerText && this.finalizeEdit(this._inputref.innerText, false, true, false); + this.finalizeEdit(false, true, false); } + @action + setContent = (content: string) => { + this._displayedContent = content; + }; + @action setIsFocused = (value: boolean) => { const wasFocused = this._editing; @@ -75,7 +84,52 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro return wasFocused !== this._editing; }; - onChange = (e: FormEvent<HTMLInputElement>) => { + get cursorPosition() { + const selection = window.getSelection(); + if (!selection || selection.rangeCount === 0 || !this._inputref) return null; + + const range = selection.getRangeAt(0); + const adjRange = range.cloneRange(); + + adjRange.selectNodeContents(this._inputref); + adjRange.setEnd(range.startContainer, range.startOffset); + + return adjRange.toString().length; + } + + restoreCursorPosition = (position: number | null) => { + const selection = window.getSelection(); + if (!selection || position === null || !this._inputref) return; + + const range = document.createRange(); + range.setStart(this._inputref, 0); + range.collapse(true); + + let currentPos = 0; + const setRange = (nodes: NodeList) => { + for (let i = 0; i < nodes.length; ++i) { + const node = nodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + if (!node.textContent) return; + const nextPos = currentPos + node.textContent.length; + if (position <= nextPos) { + range.setStart(node, position - currentPos); + range.collapse(true); + selection.removeAllRanges(); + selection.addRange(range); + return true; + } + currentPos = nextPos; + + } else if ((node.nodeType === Node.ELEMENT_NODE) && (setRange(node.childNodes))) return true; + } + return false; + } + }; + + onChange = (e: FormEvent<HTMLDivElement>) => { + const cursorPos = this.cursorPosition; const targVal = e.currentTarget.innerText; if (!(targVal.startsWith(':=') || targVal.startsWith('='))) { this._overlayDisposer?.(); @@ -83,6 +137,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro } else if (!this._overlayDisposer) { this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 }); } + this._content = targVal; + this.setContent(targVal); + setTimeout(() => this.restoreCursorPosition(cursorPos), 0); this._props.highlightCells?.(targVal); }; @@ -92,7 +149,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro switch (e.key) { case 'Tab': e.stopPropagation(); - this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false); + this.finalizeEdit(e.shiftKey, false, false); break; case 'Backspace': e.stopPropagation(); @@ -100,7 +157,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro case 'Enter': e.stopPropagation(); if (!e.ctrlKey) { - this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); + this.finalizeEdit(e.shiftKey, false, true); } break; case 'Escape': @@ -128,9 +185,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro }; @action - finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { - //if (invalid) raise error - if (this._props.SetValue(value, shiftDown, enterKey)) { + finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { + this.setContent(this._content); + if (this._props.SetValue(this._content, shiftDown, enterKey)) { this._editing = false; } else { this._editing = false; @@ -151,31 +208,32 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : '' } </span> - } + }; renderEditor = () => { return ( - <div + <div contentEditable - className="editableView-input" + className='editableView-static' ref={r => { this._inputref = r; }} style={{ overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }} - onBlur={e => this.finalizeEdit(this._inputref ? this._inputref.innerText : '', false, true, false)} + onBlur={e => this.finalizeEdit(false, true, false)} autoFocus onInput={this.onChange} onKeyDown={this.onKeyDown} onPointerDown={e => e.stopPropagation} onClick={e => e.stopPropagation} onPointerUp={e => e.stopPropagation} + dangerouslySetInnerHTML={{ __html: `<span>${this._displayedContent}</span>` }} > </div> ); - } + }; render() { const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n'); if ((this._editing && gval !== undefined)) { - return <div>{this.renderEditor()}</div>; + return <div className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`}>{this.renderEditor()}</div>; } else return ( this._props.contents instanceof ObjectField ? null : ( <div diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 17fff7bf1..74c001397 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -177,7 +177,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro width: '100%', pointerEvents: this.lockedInteraction ? 'none' : pointerEvents, }}> - <EditableView + <SchemaCellField highlightCells={this.adjustedHighlight} ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)} oneLine={this._props.oneLine} @@ -251,7 +251,6 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro e.stopPropagation(); } else !selectedCell(this._props) && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); } - console.log(this._props.Document.title); })} style={{ padding: this._props.padding, maxWidth: this._props.maxWidth?.(), |