From 69153ed435cbbc10637563b8bb576a80f8c0693f Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Mon, 17 Jun 2024 12:07:00 -0400
Subject: schema cell editable field class started

---
 .../collectionSchema/SchemaCellField.tsx           | 195 +++++++++++++++++++++
 1 file changed, 195 insertions(+)
 create mode 100644 src/client/views/collections/collectionSchema/SchemaCellField.tsx

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
new file mode 100644
index 000000000..5f758683d
--- /dev/null
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -0,0 +1,195 @@
+import { IReactionDisposer, action, makeObservable, observable, reaction, runInAction } from "mobx";
+import { ObservableReactComponent } from "../../ObservableReactComponent";
+import { observer } from "mobx-react";
+import { OverlayView } from "../../OverlayView";
+import { DocumentIconContainer } from "../../nodes/DocumentIcon";
+import React, { FormEvent } from "react";
+import { FieldView, FieldViewProps } from "../../nodes/FieldView";
+import { ObjectField } from "../../../../fields/ObjectField";
+
+export interface SchemaCellFieldProps {
+    contents: any;
+    fieldContents?: FieldViewProps;
+    editing?: boolean;
+    oneLine?: boolean;
+    highlightCells?: (text: string) => void;
+    GetValue(): string | undefined;
+    SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
+}
+
+@observer
+export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldProps> {
+
+    private _disposers: { [name: string]: IReactionDisposer } = {};
+    private _inputref: HTMLDivElement | null = null;
+    _overlayDisposer?: () => void;
+    @observable _editing: boolean = false;
+
+    constructor(props: SchemaCellFieldProps) {
+        super(props);
+        makeObservable(this);
+    }
+
+    componentDidMount(): void {
+        this._disposers.editing = reaction(
+            () => this._editing,
+            editing => {
+                if (editing) {
+                    setTimeout(() => {
+                        if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) {
+                            this._overlayDisposer?.();
+                            this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+                            this._props.highlightCells?.(this._props.GetValue() ?? '');
+                        } 
+                    });
+                } else {
+                    this._overlayDisposer?.();
+                    this._overlayDisposer = undefined;
+                    this._props.highlightCells?.('');
+                }
+            },
+            { fireImmediately: true }
+        );
+    }
+
+    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);
+        } else
+            runInAction(() => {
+                if (this._props.editing !== undefined) this._editing = this._props.editing;
+            });
+    }
+
+    componentWillUnmount(): void {
+        this._overlayDisposer?.();
+        this._disposers.editing?.();
+        this._inputref?.innerText && this.finalizeEdit(this._inputref.innerText, false, true, false);
+    }
+
+    @action
+    setIsFocused = (value: boolean) => {
+        const wasFocused = this._editing;
+        this._editing = value;
+        return wasFocused !== this._editing;
+    };
+
+    onChange = (e: FormEvent<HTMLInputElement>) => {
+        const targVal = e.currentTarget.innerText;
+        if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
+            this._overlayDisposer?.();
+            this._overlayDisposer = undefined;
+        } else if (!this._overlayDisposer) {
+            this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+        }
+        this._props.highlightCells?.(targVal);
+    };
+
+    @action
+    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+        if (e.nativeEvent.defaultPrevented) return; // hack .. DashFieldView grabs native events, but react ignores stoppedPropagation and preventDefault, so we need to check it here
+        switch (e.key) {
+            case 'Tab':
+                e.stopPropagation();
+                this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false);
+                break;
+            case 'Backspace':
+                e.stopPropagation();
+                break;
+            case 'Enter':
+                e.stopPropagation();
+                if (!e.ctrlKey) {
+                    this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true);
+                }
+                break;
+            case 'Escape':
+                e.stopPropagation();
+                this._editing = false;
+                break;
+            case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': //prettier-ignore
+                e.stopPropagation();
+                break;
+            case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': //prettier-ignore
+                break;
+            // eslint-disable-next-line no-fallthrough
+            default:
+                break;
+        }
+    };
+
+
+    @action
+    onClick = (e?: React.MouseEvent) => {
+        if (this._props.editing !== false) {
+            e?.nativeEvent.stopPropagation();
+            this._editing = true;
+        }
+    };
+
+    @action
+    finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
+        //if (invalid) raise error
+        if (this._props.SetValue(value, shiftDown, enterKey)) {
+            this._editing = false;
+        } else {
+            this._editing = false;
+            !lostFocus &&
+                setTimeout(
+                    action(() => {
+                        this._editing = true;
+                    }),
+                    0
+                );
+        }
+    }
+
+    staticDisplay = () => {
+        return <span className='editableView-static'>
+        {
+            // eslint-disable-next-line react/jsx-props-no-spreading
+            this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : ''
+        }
+        </span>
+    }
+
+    renderEditor = () => {
+        return (
+            <div
+            contentEditable
+            className="editableView-input"
+            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)}
+            autoFocus
+            onInput={this.onChange}
+            onKeyDown={this.onKeyDown}
+            onPointerDown={e => e.stopPropagation}
+            onClick={e => e.stopPropagation}
+            onPointerUp={e => e.stopPropagation}
+            >
+            </div>
+        );
+    }
+
+    render() {
+        const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
+        if ((this._editing && gval !== undefined)) {
+            return <div>{this.renderEditor()}</div>;
+        } else return (
+            this._props.contents instanceof ObjectField ? null : (
+                <div
+                    className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`}
+                    style={{
+                        minHeight: '10px',
+                        whiteSpace: this._props.oneLine ? 'nowrap' : 'pre-line',
+                        width: '100%',
+                    }}
+                    onClick={this.onClick}>
+                    {this.staticDisplay()}
+                </div>
+            )
+        );
+    }
+
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From d207cf565968167c59b16baf6ca5ce2543c680ea Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 20 Jun 2024 01:57:07 -0400
Subject: cursor position consistency for schema cell field

---
 .../collectionSchema/CollectionSchemaView.tsx      |  4 +-
 .../collectionSchema/SchemaCellField.tsx           | 86 ++++++++++++++++++----
 .../collectionSchema/SchemaTableCell.tsx           |  3 +-
 3 files changed, 74 insertions(+), 19 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

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?.(), 
-- 
cgit v1.2.3-70-g09d2


From 20128eb11d5146e9f199d04a94ca9a6b5ac109d7 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 20 Jun 2024 14:33:28 -0400
Subject: some progress on eq text highlighting

---
 .../collectionSchema/CollectionSchemaView.scss     |  5 +++
 .../collectionSchema/CollectionSchemaView.tsx      |  4 ++-
 .../collectionSchema/SchemaCellField.tsx           | 37 +++++++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 ++++
 .../collectionSchema/SchemaTableCell.tsx           |  6 +++-
 5 files changed, 48 insertions(+), 10 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index d1f1e3a13..6b53eb1cc 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -313,3 +313,8 @@
     }
 }
 
+.schemaField-editing {
+    outline: none;
+}
+
+
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c287b7d44..5c8a84163 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -533,7 +533,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         return cell;
     }
 
-    findCellRefs = (text: string) => {
+    findCellRefs = (text: string, retRawMatches?: boolean) => {
         const pattern = /(this|d(\d+))\.(\w+)/g;
         interface Match { docRef: string; field: string; }
 
@@ -545,6 +545,8 @@ export class CollectionSchemaView extends CollectionSubView() {
             matches.push({ docRef, field: match[3] });
         }
 
+        if (retRawMatches) return matches;
+
         const cells: Array<any> = [];
         matches.forEach((match: Match) => {
             const {docRef, field} = match;
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 3af3b1d61..4ba8c8469 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -15,6 +15,7 @@ export interface SchemaCellFieldProps {
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
     SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
+    func: (text: string, raw: boolean) => HTMLDivElement[] | [];
 }
 
 @observer
@@ -72,10 +73,25 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
+    chunkContent = (content: string) => {
+        const matches = this._props.func(content, true);
+        const cells = this._props.func(content, false);
+        let chunkedText = content;
+        let matchNum = 0;
+        matches.forEach((docRef, field) => {
+            console.log('cell: ' + cells[matchNum] + ' border: ' + cells[matchNum].style.borderTop)
+            chunkedText = chunkedText.replace(`d5.type`, `<span style="color: ${cells[matchNum].style.borderTop.replace('2px solid', '')}">d5.type</span>`);
+            ++matchNum;
+        })
+        return chunkedText;
+    }
+
     @action 
     setContent = (content: string) => {
-        this._displayedContent = content;
-    };
+        console.log(this.chunkContent(content));
+        this._displayedContent = this.chunkContent(content);
+        console.log('displayed: ' + this._displayedContent);
+    }
 
     @action
     setIsFocused = (value: boolean) => {
@@ -126,10 +142,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             }
             return false;
         }
+
+        setRange(this._inputref.childNodes);
     };
 
     onChange = (e: FormEvent<HTMLDivElement>) => {
         const cursorPos = this.cursorPosition;
+        const prevVal = this._content;
         const targVal = e.currentTarget.innerText;
         if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
             this._overlayDisposer?.();
@@ -138,8 +157,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
         }
         this._content = targVal;
-        this.setContent(targVal);
-        setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
+        if (this._props.func(targVal, true).length > this._props.func(prevVal, true).length) {
+            this.setContent(targVal);
+            setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
+        }
         this._props.highlightCells?.(targVal);
     };
 
@@ -208,15 +229,15 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : ''
         }
         </span>
-    };
+    }
 
     renderEditor = () => {
         return (
             <div 
             contentEditable
-            className='editableView-static'
+            className='schemaField-editing'
             ref={r => { this._inputref = r; }}
-            style={{ overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
+            style={{ outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
             onBlur={e => this.finalizeEdit(false, true, false)}
             autoFocus
             onInput={this.onChange}
@@ -228,7 +249,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             >
             </div>
         );
-    };
+    }
 
     render() {
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 4902a49ff..121605a2b 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -122,6 +122,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
     highlightCells = (text: string) => this.schemaView?.highlightCells(text);
+    equationHighlightRef = (text: string) => {
+    
+    }
+    eqHighlightFunc = (text: string, raw: boolean) => {return this.schemaView.findCellRefs(text, raw)};
     render() {
         return (
             <div
@@ -164,6 +168,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
                         <SchemaTableCell
+                            func={this.eqHighlightFunc}
+                            equationHighlightRef={this.schemaView._cellHighlightColors}
                             highlightCells={this.highlightCells}
                             isolatedSelection={this.isolatedSelection}
                             key={key}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 74c001397..74ee46065 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -3,7 +3,7 @@
 /* eslint-disable no-use-before-define */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Popup, Size, Type } from 'browndash-components';
-import { action, computed, makeObservable, observable } from 'mobx';
+import { ObservableMap, action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
 import * as React from 'react';
@@ -62,6 +62,9 @@ export interface SchemaTableCellProps {
     rowSelected: () => boolean;
     isolatedSelection: [boolean, boolean];
     highlightCells: (text: string) => void;
+    equationHighlightRef: ObservableMap<HTMLDivElement, string>;
+    func: (text: string, raw: boolean) => HTMLDivElement[] | [];
+
 }
 
 function selectedCell(props: SchemaTableCellProps) {
@@ -179,6 +182,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                 }}>
                 <SchemaCellField
                     highlightCells={this.adjustedHighlight}
+                    func={this._props.func}
                     ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
                     oneLine={this._props.oneLine}
                     contents={undefined}
-- 
cgit v1.2.3-70-g09d2


From 83a2f119bf908d07e08ac89171e73d2211e1eb8f Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 20 Jun 2024 17:50:00 -0400
Subject: eq highlight working 70%

---
 .../collectionSchema/SchemaCellField.tsx           | 35 +++++++++++++++-------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           |  1 +
 3 files changed, 27 insertions(+), 11 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 4ba8c8469..6663fb68f 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -6,12 +6,15 @@ import { DocumentIconContainer } from "../../nodes/DocumentIcon";
 import React, { FormEvent } from "react";
 import { FieldView, FieldViewProps } from "../../nodes/FieldView";
 import { ObjectField } from "../../../../fields/ObjectField";
+import { Doc } from "../../../../fields/Doc";
+import { DocumentView } from "../../nodes/DocumentView";
 
 export interface SchemaCellFieldProps {
     contents: any;
     fieldContents?: FieldViewProps;
     editing?: boolean;
     oneLine?: boolean;
+    Document: Doc;
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
     SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
@@ -33,7 +36,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         makeObservable(this);
     }
 
+    get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
+
     componentDidMount(): void {
+        this._content = this.props.GetValue() ?? '';
+        this.setContent(this._content);
         this._disposers.editing = reaction(
             () => this._editing,
             editing => {
@@ -43,6 +50,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._props.GetValue() ?? '');
+                            this.setContent(this._content);
                         } 
                     });
                 } else {
@@ -53,8 +61,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             },
             { fireImmediately: true }
         );
-        this._content = this.props.GetValue() ?? '';
-        this.setContent(this._content);
     }
 
     componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) {
@@ -74,13 +80,24 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     }
 
     chunkContent = (content: string) => {
-        const matches = this._props.func(content, true);
+        const pattern = /(this|d(\d+))\.(\w+)/g;
+        interface Match { docRef: string; field: string; }
+
+        const matches: Match[] = [];
+        let match: RegExpExecArray | null;
+
+        while ((match = pattern.exec(content)) !== null) {
+            const docRef = match[1] === 'this' ? match[1] : match[2]; 
+            matches.push({ docRef, field: match[3] });
+        }
+
         const cells = this._props.func(content, false);
         let chunkedText = content;
         let matchNum = 0;
-        matches.forEach((docRef, field) => {
-            console.log('cell: ' + cells[matchNum] + ' border: ' + cells[matchNum].style.borderTop)
-            chunkedText = chunkedText.replace(`d5.type`, `<span style="color: ${cells[matchNum].style.borderTop.replace('2px solid', '')}">d5.type</span>`);
+        matches.forEach((match: Match) => {
+            const {docRef, field} = match;
+            // const refToUse = docRef === 'this' ? `${this.docIndex}` : docRef;
+            chunkedText = chunkedText.replace(`d${docRef}.${field}`, `<span style="color: ${cells[matchNum].style.borderTop.replace('2px solid', '')}">d${docRef}.${field}</span>`);
             ++matchNum;
         })
         return chunkedText;
@@ -88,9 +105,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action 
     setContent = (content: string) => {
-        console.log(this.chunkContent(content));
         this._displayedContent = this.chunkContent(content);
-        console.log('displayed: ' + this._displayedContent);
     }
 
     @action
@@ -157,11 +172,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
         }
         this._content = targVal;
+        this._props.highlightCells?.(targVal);
         if (this._props.func(targVal, true).length > this._props.func(prevVal, true).length) {
             this.setContent(targVal);
             setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
         }
-        this._props.highlightCells?.(targVal);
     };
 
     @action
@@ -245,7 +260,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             onPointerDown={e => e.stopPropagation}
             onClick={e => e.stopPropagation}
             onPointerUp={e => e.stopPropagation}
-            dangerouslySetInnerHTML={{ __html: `<span>${this._displayedContent}</span>` }}
+            dangerouslySetInnerHTML={{ __html: this._displayedContent }}
             >
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 121605a2b..c0ad95141 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -131,7 +131,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             <div
                 className="schema-row"
                 onPointerDown={e => this.setCursorIndex(e.clientY)}
-                style={{ height: this._props.PanelHeight(), backgroundColor: this._props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
+                style={{ height: this._props.PanelHeight()}}
                 ref={(row: HTMLDivElement | null) => {
                     row && this.schemaView?.addRowRef?.(this.Document, row);
                     this._ref = row;
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 74ee46065..3233e363a 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -181,6 +181,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                     pointerEvents: this.lockedInteraction ? 'none' : pointerEvents,
                 }}>
                 <SchemaCellField
+                    Document={this._props.Document}
                     highlightCells={this.adjustedHighlight}
                     func={this._props.func}
                     ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
-- 
cgit v1.2.3-70-g09d2


From 24fad06cbd2e273bb6729f21956e35243e602bb7 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 21 Jun 2024 12:37:47 -0400
Subject: fixed bug where equation didn't save in cell field on reloading
 (batching issue)

---
 .../views/collections/collectionSchema/CollectionSchemaView.tsx    | 2 +-
 src/client/views/collections/collectionSchema/SchemaCellField.tsx  | 7 +++++--
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx  | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 6838662c7..308520154 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -587,7 +587,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             const color = randomRGBColor();
             const doc = info[0]; 
             const field = info[1];
-            const key = `${doc}_${field}`;
+            const key = `${doc[Id]}_${field}`;
             const cell = this.getCellElement(doc, field);
             if (!this._cellHighlightColors.has(key)) {this._cellHighlightColors.set(key, new Array<string>(`solid 2px ${color[0]}`, color[1]))}
             cell.style.border = this._cellHighlightColors.get(key)[0];
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 6663fb68f..dcfa4f6f2 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -39,8 +39,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
     componentDidMount(): void {
-        this._content = this.props.GetValue() ?? '';
-        this.setContent(this._content);
+        setTimeout(() => { 
+            this._content = this._props.GetValue() ?? '';
+            this.setContent(this._content);
+        }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
         this._disposers.editing = reaction(
             () => this._editing,
             editing => {
@@ -50,6 +52,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._props.GetValue() ?? '');
+                            if (this._props.Document.type === 'collection') console.log('highlight: ' + this._props.GetValue())
                             this.setContent(this._content);
                         } 
                     });
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 3233e363a..94fd9ec7d 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -152,6 +152,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
 
     // parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability
     cleanupField = (field: string) => {
+        if (field === ':=d6.type + d4.type + d3.type') console.log(true)
         const idPattern = /idToDoc\((.*?)\)/g;
         let modField = field.slice();
         let matches;
-- 
cgit v1.2.3-70-g09d2


From 7f9d92b3e1d0ca433c732936eae767095c9a5e7f Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 22 Jun 2024 15:47:12 -0400
Subject: work on cell field (numerous bugs fixed: spaces now make new divs,
 invalid refs no longer break things, valid->invalid ref causes update
 properly)

---
 .../collectionSchema/CollectionSchemaView.tsx      |  9 ++-
 .../collectionSchema/SchemaCellField.tsx           | 79 ++++++++++++++--------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  5 +-
 .../collectionSchema/SchemaTableCell.tsx           |  4 +-
 4 files changed, 59 insertions(+), 38 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 308520154..9c4eda3b8 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -533,7 +533,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         return cell;
     }
 
-    findCellRefs = (text: string, retRawMatches?: boolean) => {
+    findCellRefs = (text: string) => {
         const pattern = /(this|d(\d+))\.(\w+)/g;
         interface Match { docRef: string; field: string; }
 
@@ -545,13 +545,12 @@ export class CollectionSchemaView extends CollectionSubView() {
             matches.push({ docRef, field: match[3] });
         }
 
-        if (retRawMatches) return matches;
-
         const cells: Array<any> = [];
         matches.forEach((match: Match) => {
             const {docRef, field} = match;
-            const doc = DocumentManager.Instance.DocumentViews[Number(docRef)].Document;
-            if (this.columnKeys.includes(field)) {cells.push([doc, field])}
+            const docView = DocumentManager.Instance.DocumentViews[Number(docRef)];
+            const doc = docView?.Document ?? undefined;
+            if (this.columnKeys.includes(field) && this._docs.includes(doc)) {cells.push([doc, field])}
         })
 
         return cells;
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index dcfa4f6f2..e2aa27a95 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -18,7 +18,7 @@ export interface SchemaCellFieldProps {
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
     SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
-    func: (text: string, raw: boolean) => HTMLDivElement[] | [];
+    getCells: (text: string) => HTMLDivElement[] | [];
 }
 
 @observer
@@ -26,7 +26,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _inputref: HTMLDivElement | null = null;
-    private _content: string = '';
+    private _unrenderedContent: string = '';
     _overlayDisposer?: () => void;
     @observable _editing: boolean = false;
     @observable _displayedContent = '';
@@ -40,8 +40,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     componentDidMount(): void {
         setTimeout(() => { 
-            this._content = this._props.GetValue() ?? '';
-            this.setContent(this._content);
+            this._unrenderedContent = this._props.GetValue() ?? '';
+            this.setContent(this._unrenderedContent, true);
         }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
         this._disposers.editing = reaction(
             () => this._editing,
@@ -52,8 +52,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._props.GetValue() ?? '');
-                            if (this._props.Document.type === 'collection') console.log('highlight: ' + this._props.GetValue())
-                            this.setContent(this._content);
+                            this.setContent(this._unrenderedContent, true);
                         } 
                     });
                 } else {
@@ -82,33 +81,44 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
-    chunkContent = (content: string) => {
-        const pattern = /(this|d(\d+))\.(\w+)/g;
-        interface Match { docRef: string; field: string; }
+    makeSpans = (content: string) => {
+        let chunkedText = content;
+        chunkedText = chunkedText.replace(/ +/g, (match) => {
+            const spanSpaces = '&nbsp;'.repeat(match.length);
+            return `<span>${spanSpaces}</span>`;
+        });
 
-        const matches: Match[] = [];
+        const pattern = /(this|d(\d+))\.(\w+)/g;
+        const matches: string[] = [];
         let match: RegExpExecArray | null;
 
+        const cells: Map<string, HTMLDivElement> = new Map();
+
         while ((match = pattern.exec(content)) !== null) {
-            const docRef = match[1] === 'this' ? match[1] : match[2]; 
-            matches.push({ docRef, field: match[3] });
+            const cell = this._props.getCells(match[0]);
+            if (cell.length) {
+                matches.push(match[0]);
+                cells.set(match[0], cell[0])
+            }
         }
 
-        const cells = this._props.func(content, false);
-        let chunkedText = content;
         let matchNum = 0;
-        matches.forEach((match: Match) => {
-            const {docRef, field} = match;
+        matches.forEach((match: string) => {
             // const refToUse = docRef === 'this' ? `${this.docIndex}` : docRef;
-            chunkedText = chunkedText.replace(`d${docRef}.${field}`, `<span style="color: ${cells[matchNum].style.borderTop.replace('2px solid', '')}">d${docRef}.${field}</span>`);
+            chunkedText = chunkedText.replace(match, `<span style="color: ${cells.get(match)?.style.borderTop.replace('2px solid', '')}">${match}</span>`);
             ++matchNum;
         })
+
         return chunkedText;
     }
 
     @action 
-    setContent = (content: string) => {
-        this._displayedContent = this.chunkContent(content);
+    setContent = (content: string, restoreCursorPos?: boolean) => {
+        this._displayedContent = this.makeSpans(content);
+        if (restoreCursorPos) { 
+            const cursorPos = this.cursorPosition;
+            setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
+        }
     }
 
     @action
@@ -164,9 +174,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         setRange(this._inputref.childNodes);
     };
 
+    shouldUpdate = (prevVal: string, currVal: string) => {
+        if (this._props.getCells(currVal).length !== this._props.getCells(prevVal).length) return true;
+        //if (contains self-ref pattern)
+    };
+
     onChange = (e: FormEvent<HTMLDivElement>) => {
-        const cursorPos = this.cursorPosition;
-        const prevVal = this._content;
+        const prevVal = this._unrenderedContent;
         const targVal = e.currentTarget.innerText;
         if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
             this._overlayDisposer?.();
@@ -174,12 +188,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._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
-        if (this._props.func(targVal, true).length > this._props.func(prevVal, true).length) {
-            this.setContent(targVal);
-            setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
-        }
+        if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
     };
 
     @action
@@ -206,6 +217,18 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': //prettier-ignore
                 e.stopPropagation();
                 break;
+            case ' ':
+                e.stopPropagation();
+                setTimeout(() => {
+                    this.setContent(this._unrenderedContent);
+                    const cursorPos = this.cursorPosition;
+                    setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
+                }
+                , 0);
+                break;
+            case 'u': // for some reason 'u' otherwise exits the editor
+                e.stopPropagation();
+                break;
             case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': //prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
@@ -225,8 +248,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
-        this.setContent(this._content);
-        if (this._props.SetValue(this._content, shiftDown, enterKey)) {
+        this.setContent(this._unrenderedContent);
+        if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
             this._editing = false;
         } else {
             this._editing = false;
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 6f6b6decf..f4320dc09 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -125,9 +125,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     equationHighlightRef = (text: string) => {
     
     }
-    eqHighlightFunc = (text: string, raw: boolean) => {
-        const info = this.schemaView.findCellRefs(text, raw);
-        if (raw) return info;
+    eqHighlightFunc = (text: string) => {
+        const info = this.schemaView.findCellRefs(text);
         const cells: HTMLDivElement[] = [];
         info.forEach(info => {cells.push(this.schemaView.getCellElement(info[0], info[1]))})
         return cells;
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 94fd9ec7d..ab384a487 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -63,7 +63,7 @@ export interface SchemaTableCellProps {
     isolatedSelection: [boolean, boolean];
     highlightCells: (text: string) => void;
     equationHighlightRef: ObservableMap<HTMLDivElement, string>;
-    func: (text: string, raw: boolean) => HTMLDivElement[] | [];
+    func: (text: string) => HTMLDivElement[] | [];
 
 }
 
@@ -184,7 +184,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                 <SchemaCellField
                     Document={this._props.Document}
                     highlightCells={this.adjustedHighlight}
-                    func={this._props.func}
+                    getCells={this._props.func}
                     ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
                     oneLine={this._props.oneLine}
                     contents={undefined}
-- 
cgit v1.2.3-70-g09d2


From fc1fd8902b090b75c81347a37cce15145322b4e2 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 22 Jun 2024 23:55:38 -0400
Subject: moving row no longer messes up cell field (of course it was
 batching...)

---
 src/client/views/EditableView.tsx                              |  2 +-
 .../views/collections/collectionSchema/SchemaCellField.tsx     | 10 ++++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 78977bcb8..8e48b4c11 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -193,7 +193,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     @action
     onClick = (e?: React.MouseEvent) => {
         this._props.onClick && this._props.onClick();
-        if (this._props.editing !== false) {
+        if (this._props.editing) {
             e?.nativeEvent.stopPropagation();
             if (this._ref.current && this._props.showMenuOnLoad) {
                 this._props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y);
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e2aa27a95..ffda334ec 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -34,15 +34,17 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     constructor(props: SchemaCellFieldProps) {
         super(props);
         makeObservable(this);
+        setTimeout(() => { 
+            this._unrenderedContent = this._props.GetValue() ?? '';
+            this.setContent(this._unrenderedContent, true);
+        }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
     }
 
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
     componentDidMount(): void {
-        setTimeout(() => { 
-            this._unrenderedContent = this._props.GetValue() ?? '';
-            this.setContent(this._unrenderedContent, true);
-        }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
+        this._unrenderedContent = this._props.GetValue() ?? '';
+        this.setContent(this._unrenderedContent, true);
         this._disposers.editing = reaction(
             () => this._editing,
             editing => {
-- 
cgit v1.2.3-70-g09d2


From 4c56da7db9feb018e004354bb6bf333d3890d91b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 23 Jun 2024 00:12:31 -0400
Subject: text cursor icon in cell

---
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index ffda334ec..08231dd91 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -280,7 +280,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             contentEditable
             className='schemaField-editing'
             ref={r => { this._inputref = r; }}
-            style={{ outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
+            style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
             onBlur={e => this.finalizeEdit(false, true, false)}
             autoFocus
             onInput={this.onChange}
-- 
cgit v1.2.3-70-g09d2


From 1775ceb9b840ab73194eb84e673ef692c1fef454 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 23 Jun 2024 00:25:19 -0400
Subject: drag text highlighting

---
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 08231dd91..fc191014c 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -288,6 +288,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             onPointerDown={e => e.stopPropagation}
             onClick={e => e.stopPropagation}
             onPointerUp={e => e.stopPropagation}
+            onPointerMove={e => {e.stopPropagation(); e.preventDefault()}}
             dangerouslySetInnerHTML={{ __html: this._displayedContent }}
             >
             </div>
-- 
cgit v1.2.3-70-g09d2


From 9fab1b3ac096138fba3a99a2515ec44b526a3956 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 23 Jun 2024 02:54:24 -0400
Subject: text highlight works with 'this.' format

---
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 7 +++++--
 src/client/views/collections/collectionSchema/SchemaRowBox.tsx    | 2 ++
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 8 ++++----
 3 files changed, 11 insertions(+), 6 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index fc191014c..aa6c382ef 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -53,7 +53,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                         if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) {
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-                            this._props.highlightCells?.(this._props.GetValue() ?? '');
+                            this._props.highlightCells?.(this._unrenderedContent);
                             this.setContent(this._unrenderedContent, true);
                         } 
                     });
@@ -98,15 +98,18 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
         while ((match = pattern.exec(content)) !== null) {
             const cell = this._props.getCells(match[0]);
+            //console.log(cell)
             if (cell.length) {
                 matches.push(match[0]);
                 cells.set(match[0], cell[0])
             }
         }
 
+        //console.log(cells)
+
         let matchNum = 0;
         matches.forEach((match: string) => {
-            // const refToUse = docRef === 'this' ? `${this.docIndex}` : docRef;
+            const adjMatch = match.replace('this.', `d${this.docIndex}`)
             chunkedText = chunkedText.replace(match, `<span style="color: ${cells.get(match)?.style.borderTop.replace('2px solid', '')}">${match}</span>`);
             ++matchNum;
         })
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f4320dc09..45f178815 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -22,6 +22,7 @@ import { ContextMenu } from '../../ContextMenu';
 import { CollectionFreeFormView } from '../collectionFreeForm';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { infoState } from '../collectionFreeForm/CollectionFreeFormInfoState';
 
 interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -129,6 +130,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         const info = this.schemaView.findCellRefs(text);
         const cells: HTMLDivElement[] = [];
         info.forEach(info => {cells.push(this.schemaView.getCellElement(info[0], info[1]))})
+        console.log('info: ' + info + ' cells: ' + cells);
         return cells;
     };
     render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index ab384a487..6ccada48c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -144,10 +144,10 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
         return { color, textDecoration, fieldProps, cursor, pointerEvents };
     }
         
-    adjustedHighlight = (field: string) => {
+    adjustSelfReference = (field: string) => {
         const pattern = /\bthis.\b/g;  
         const modField = field.replace(pattern, `d${this.docIndex}.`);
-        this._props.highlightCells(modField);
+        return modField;
     }
 
     // parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability
@@ -183,8 +183,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                 }}>
                 <SchemaCellField
                     Document={this._props.Document}
-                    highlightCells={this.adjustedHighlight}
-                    getCells={this._props.func}
+                    highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))}
+                    getCells={(text: string) => this._props.func(this.adjustSelfReference(text))}
                     ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
                     oneLine={this._props.oneLine}
                     contents={undefined}
-- 
cgit v1.2.3-70-g09d2


From b2691d6119dfa1f192ac6eb19650f44742b253f5 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 23 Jun 2024 03:36:21 -0400
Subject: col filling (really external setting of cell fieldval) works properly
 (reaction); moved 'remove doc' option to bottom of row menu

---
 .../collectionSchema/CollectionSchemaView.tsx           |  6 +++---
 .../collections/collectionSchema/SchemaCellField.tsx    | 17 +++++++++++------
 .../views/collections/collectionSchema/SchemaRowBox.tsx | 13 ++++++-------
 .../collections/collectionSchema/SchemaTableCell.tsx    |  4 +---
 4 files changed, 21 insertions(+), 19 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 9c4eda3b8..2a84efa7c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -829,9 +829,9 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.closeColumnMenu();
     };
 
-    setCellValues = (key: string, value: string) => {
-        if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing &&Doc.SetField(doc, key, value)); // if only one cell selected, fill all
-        else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); // else only fill selected cells
+    setColumnValues = (key: string, value: string) => {
+        if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing &&Doc.SetField(doc, key, value)); 
+        else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); 
         return true;
     };
 
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index aa6c382ef..e85bf75e6 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -36,7 +36,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         makeObservable(this);
         setTimeout(() => { 
             this._unrenderedContent = this._props.GetValue() ?? '';
-            this.setContent(this._unrenderedContent, true);
+            this.setContent(this._unrenderedContent);
         }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
     }
 
@@ -65,6 +65,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             },
             { fireImmediately: true }
         );
+        this._disposers.fieldUpdate = reaction(
+            () => this._props.GetValue(),
+            fieldVal => {
+                this._unrenderedContent = fieldVal ?? '';
+                this.setContent(this._unrenderedContent);
+            }
+        )
     }
 
     componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) {
@@ -79,7 +86,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     componentWillUnmount(): void {
         this._overlayDisposer?.();
-        this._disposers.editing?.();
+        Object.values(this._disposers).forEach(disposer => disposer?.());
         this.finalizeEdit(false, true, false);
     }
 
@@ -98,15 +105,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
         while ((match = pattern.exec(content)) !== null) {
             const cell = this._props.getCells(match[0]);
-            //console.log(cell)
             if (cell.length) {
                 matches.push(match[0]);
                 cells.set(match[0], cell[0])
             }
         }
 
-        //console.log(cells)
-
         let matchNum = 0;
         matches.forEach((match: string) => {
             const adjMatch = match.replace('this.', `d${this.docIndex}`)
@@ -237,6 +241,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': //prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
+            case 'P':
+                break;
             default:
                 break;
         }
@@ -253,7 +259,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
-        this.setContent(this._unrenderedContent);
         if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
             this._editing = false;
         } else {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 45f178815..d2c0d891f 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -60,11 +60,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
 
     openContextMenu = (x: number, y: number) => {
         ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: `Close doc`,
-            event: () => this.schemaView.removeDoc(this.Document),
-            icon: 'minus',
-        });
         ContextMenu.Instance.addItem({
             description: this.Document._lockedSchemaEditing ? 'Unlock field editing' : 'Lock field editing',
             event: () => this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing,
@@ -75,6 +70,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             event: () => this._props.addDocTab(this.Document, OpenWhere.addRight),
             icon: 'magnifying-glass',
         });
+        ContextMenu.Instance.addItem({
+            description: `Close doc`,
+            event: () => this.schemaView.removeDoc(this.Document),
+            icon: 'minus',
+        });
         const childDocs = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)])
         if (this.Document.type === 'collection' && childDocs.length) {
                 ContextMenu.Instance.addItem({
@@ -119,7 +119,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl);
     deselectCell = () => this.schemaView?.deselectAllCells();
     selectedCells = () => this.schemaView?._selectedDocs;
-    setColumnValues = (field: any, value: any) => this.schemaView?.setCellValues(field, value) ?? false;
+    setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
     columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
     highlightCells = (text: string) => this.schemaView?.highlightCells(text);
@@ -130,7 +130,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         const info = this.schemaView.findCellRefs(text);
         const cells: HTMLDivElement[] = [];
         info.forEach(info => {cells.push(this.schemaView.getCellElement(info[0], info[1]))})
-        console.log('info: ' + info + ' cells: ' + cells);
         return cells;
     };
     render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 6ccada48c..aa8401502 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -145,14 +145,12 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
     }
         
     adjustSelfReference = (field: string) => {
-        const pattern = /\bthis.\b/g;  
-        const modField = field.replace(pattern, `d${this.docIndex}.`);
+        const modField = field.replace(/\bthis.\b/g, `d${this.docIndex}.`);
         return modField;
     }
 
     // parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability
     cleanupField = (field: string) => {
-        if (field === ':=d6.type + d4.type + d3.type') console.log(true)
         const idPattern = /idToDoc\((.*?)\)/g;
         let modField = field.slice();
         let matches;
-- 
cgit v1.2.3-70-g09d2


From 9197630d59f4ae4624e3b47b794e0a5fa7bc080d Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Mon, 24 Jun 2024 12:14:51 -0400
Subject: Work on persistent sort highlight + equation highlight inteeraction

---
 .../collectionSchema/CollectionSchemaView.tsx      | 30 ++++++++++++----------
 .../collectionSchema/SchemaCellField.tsx           | 11 ++++----
 2 files changed, 23 insertions(+), 18 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 2a84efa7c..018fd35b5 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -101,7 +101,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _colBeingDragged: boolean = false;
     @observable _colKeysFiltered: boolean = false;
     @observable _cellTags: ObservableMap = new ObservableMap<Doc, Array<string>>();
-    @observable _highlightedCells: Array<[doc: Doc, field: string]> = [];
+    @observable _highlightedCellsInfo: Array<[doc: Doc, field: string]> = [];
     @observable _cellHighlightColors: ObservableMap = new ObservableMap<[doc: Doc, field: string], string[]>();
     @observable _docs: Doc[] = [];
     
@@ -124,6 +124,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         return selected;
     }
 
+    @computed get highlightedCells() {
+        return this._highlightedCellsInfo.map(info => this.getCellElement(info[0], info[1]));
+    }
+
     @computed get documentKeys() {
         return Array.from(this.fieldInfos.keys());
     }
@@ -199,8 +203,8 @@ export class CollectionSchemaView extends CollectionSubView() {
             {fireImmediately: true}
         )
         this._disposers.sortHighlight = reaction(
-            () => [this.sortField, this._docs, this._selectedDocs, this._highlightedCells], 
-            () => {this.sortField && setTimeout(() => this.highlightSortedColumn(), 5)},
+            () => [this.sortField, this._docs, this._selectedDocs, this._highlightedCellsInfo], 
+            () => {this.sortField && setTimeout(() => this.highlightSortedColumn(), 0)},
             {fireImmediately: true}
         )
     }
@@ -517,12 +521,15 @@ export class CollectionSchemaView extends CollectionSubView() {
             ];
             const cellCount = cellEles.length;
             for (let ele = 0; ele < cellCount; ++ele){
+                const toHighlight = cellEles[ele];
+                if (!this.highlightedCells.includes(toHighlight)){
                 const style = highlight ? desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}` : '';
-                cellEles[ele].style.borderLeft = style;
-                cellEles[ele].style.borderRight = style;
+                toHighlight.style.borderLeft = style;
+                toHighlight.style.borderRight = style;
+                }
             }
             cellEles[0].style.borderTop = highlight ? desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}` : '';
-            if (!(cellCount < rowCount)) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` :  `${highlightColors[cellCount - 1]}` : ''; 
+            if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index)) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` :  `${highlightColors[cellCount - 1]}` : ''; 
         });
         
     }
@@ -557,11 +564,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     removeCellHighlights = () => {
-        this._highlightedCells.forEach(info => {
-            const cell = this.getCellElement(info[0], info[1]);
-            cell.style.border = ''; cell.style.backgroundColor = '';
-        });
-        this._highlightedCells = [];
+        this.highlightedCells.forEach(cell => {cell.style.border = ''; cell.style.backgroundColor = '';});
+        this._highlightedCellsInfo = [];
     }
 
     highlightCells = (text: string) => {
@@ -581,8 +585,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
 
         const cellsToHighlight = this.findCellRefs(text);
-        this._highlightedCells = [...cellsToHighlight];
-        this._highlightedCells.forEach(info => {
+        this._highlightedCellsInfo = [...cellsToHighlight];
+        this._highlightedCellsInfo.forEach(info => {
             const color = randomRGBColor();
             const doc = info[0]; 
             const field = info[1];
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e85bf75e6..ccd15cbd0 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -92,10 +92,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     makeSpans = (content: string) => {
         let chunkedText = content;
-        chunkedText = chunkedText.replace(/ +/g, (match) => {
-            const spanSpaces = '&nbsp;'.repeat(match.length);
-            return `<span>${spanSpaces}</span>`;
-        });
 
         const pattern = /(this|d(\d+))\.(\w+)/g;
         const matches: string[] = [];
@@ -123,6 +119,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
+        console.log('content: ' + content)
         this._displayedContent = this.makeSpans(content);
         if (restoreCursorPos) { 
             const cursorPos = this.cursorPosition;
@@ -147,6 +144,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         adjRange.selectNodeContents(this._inputref);
         adjRange.setEnd(range.startContainer, range.startOffset);
 
+        console.log(adjRange.toString().length)
+
         return adjRange.toString().length; 
     }
 
@@ -228,9 +227,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 break;
             case ' ':
                 e.stopPropagation();
+                console.log('deteected')
+                let cursorPos = 0;
+                if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
                 setTimeout(() => {
                     this.setContent(this._unrenderedContent);
-                    const cursorPos = this.cursorPosition;
                     setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
                 }
                 , 0);
-- 
cgit v1.2.3-70-g09d2


From 227a289e49019ad1e9f634b098bb564bd4a8e743 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Mon, 24 Jun 2024 13:49:43 -0400
Subject: cell/column highlight interactions (maybe some minor bugs left but at
 least 95%)

---
 src/client/views/EditableView.tsx                  |  8 +---
 .../collectionSchema/CollectionSchemaView.tsx      | 44 +++++++++++++++-------
 .../collectionSchema/SchemaCellField.tsx           | 24 ++++++++----
 3 files changed, 49 insertions(+), 27 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 8e48b4c11..0c09e12de 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -193,7 +193,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     @action
     onClick = (e?: React.MouseEvent) => {
         this._props.onClick && this._props.onClick();
-        if (this._props.editing) {
+        if (this._props.editing !== false) {
             e?.nativeEvent.stopPropagation();
             if (this._ref.current && this._props.showMenuOnLoad) {
                 this._props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y);
@@ -203,11 +203,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
             }
         }
     };
-
-    // checkForInvalidText = (text: string) => {
-    //     const regX = new RegExp(new Array<string>(...this._props.prohibitedText), 'g')
-    // }
-
+    
     @action
     finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
         //if (invalid) raise error
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 018fd35b5..48c34c647 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -102,8 +102,9 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _colKeysFiltered: boolean = false;
     @observable _cellTags: ObservableMap = new ObservableMap<Doc, Array<string>>();
     @observable _highlightedCellsInfo: Array<[doc: Doc, field: string]> = [];
-    @observable _cellHighlightColors: ObservableMap = new ObservableMap<[doc: Doc, field: string], string[]>();
+    @observable _cellHighlightColors: ObservableMap = new ObservableMap<string, string[]>();
     @observable _docs: Doc[] = [];
+    @observable _inCellSelectMode: boolean = false;
     
     // target HTMLelement portal for showing a popup menu to edit cell values.
     public get MenuTarget() {
@@ -488,13 +489,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                     .filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)) && !sorted)
                     .map(doc => this._rowEles.get(doc).children[1].children[i]),
             ];
-            !sorted && (cellEles[0].style.borderTop = edgeStyle);
             cellEles.forEach(ele => {
-                if (ele === cellEles[0] && sorted) return;
+                if (sorted || this.highlightedCells.includes(ele)) return;
+                ele.style.borderTop = ele === cellEles[0] ? edgeStyle : '';
                 ele.style.borderLeft = edgeStyle;
                 ele.style.borderRight = edgeStyle;
+                ele.style.borderBottom = ele === cellEles.slice(-1)[0] ? edgeStyle : '';
             });
-            !sorted && (cellEles.slice(-1)[0].style.borderBottom = edgeStyle);
         });
 
     highlightSortedColumn = (field?: string, descending?: boolean) => {
@@ -521,15 +522,14 @@ export class CollectionSchemaView extends CollectionSubView() {
             ];
             const cellCount = cellEles.length;
             for (let ele = 0; ele < cellCount; ++ele){
-                const toHighlight = cellEles[ele];
-                if (!this.highlightedCells.includes(toHighlight)){
+                const currCell = cellEles[ele];
+                if (this.highlightedCells.includes(currCell)) continue;
                 const style = highlight ? desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}` : '';
-                toHighlight.style.borderLeft = style;
-                toHighlight.style.borderRight = style;
-                }
+                currCell.style.borderLeft = style;
+                currCell.style.borderRight = style;
             }
             cellEles[0].style.borderTop = highlight ? desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}` : '';
-            if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index)) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` :  `${highlightColors[cellCount - 1]}` : ''; 
+            if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index) && !this.highlightedCells.includes(cellEles[cellCount - 1])) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` :  `${highlightColors[cellCount - 1]}` : ''; 
         });
         
     }
@@ -568,6 +568,20 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._highlightedCellsInfo = [];
     }
 
+    restoreCellHighlights = () => {
+        this._highlightedCellsInfo.forEach(info => {
+            const doc = info[0];
+            const field = info[1];
+            const key = `${doc[Id]}_${field}`;
+            const cell = this.getCellElement(doc, field);
+            const color = this._cellHighlightColors.get(key)[0];
+            cell.style.borderTop = color;
+            cell.style.borderLeft = color;
+            cell.style.borderRight = color;
+            cell.style.borderBottom = color;
+        });
+    }
+
     highlightCells = (text: string) => {
         this.removeCellHighlights();
 
@@ -690,10 +704,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                 colRef.style.borderTop = '';
 
                 this.childDocs.forEach(doc => {
-                    if (!(this._selectedDocs.includes(doc) && i === this._selectedCol)) {
-                        this._rowEles.get(doc).children[1].children[i].style.borderLeft = '';
-                        this._rowEles.get(doc).children[1].children[i].style.borderRight = '';
-                        this._rowEles.get(doc).children[1].children[i].style.borderBottom = '';
+                    const cell = this._rowEles.get(doc).children[1].children[i];
+                    if (!(this._selectedDocs.includes(doc) && i === this._selectedCol) && !(this.highlightedCells.includes(cell))) {
+                        cell.style.borderLeft = '';
+                        cell.style.borderRight = '';
+                        cell.style.borderBottom = '';
                     }
                 });
             });
@@ -1178,6 +1193,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             if (newIndex !== this._draggedColIndex) this.moveColumn(this._draggedColIndex, newIndex ?? this._draggedColIndex);
             this._draggedColIndex = newIndex || this._draggedColIndex;
             this.highlightSortedColumn(); //TODO: Make this more efficient
+            this.restoreCellHighlights();
             !(this.sortField && this._draggedColIndex === this.columnKeys.indexOf(this.sortField)) && this.highlightDraggedColumn(newIndex ?? this._draggedColIndex);
         }
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index ccd15cbd0..e13763b45 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, action, makeObservable, observable, reaction, runInAction } from "mobx";
+import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from "mobx";
 import { ObservableReactComponent } from "../../ObservableReactComponent";
 import { observer } from "mobx-react";
 import { OverlayView } from "../../OverlayView";
@@ -30,6 +30,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     _overlayDisposer?: () => void;
     @observable _editing: boolean = false;
     @observable _displayedContent = '';
+    @observable _inCellSelectMode: boolean = false;
 
     constructor(props: SchemaCellFieldProps) {
         super(props);
@@ -40,6 +41,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
     }
 
+    @computed get inCellSelectMode() {
+        return 
+    }
+
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
     componentDidMount(): void {
@@ -90,6 +95,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
+    generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
+       return `<span style="color: ${cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`
+    }
+
     makeSpans = (content: string) => {
         let chunkedText = content;
 
@@ -109,8 +118,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
         let matchNum = 0;
         matches.forEach((match: string) => {
-            const adjMatch = match.replace('this.', `d${this.docIndex}`)
-            chunkedText = chunkedText.replace(match, `<span style="color: ${cells.get(match)?.style.borderTop.replace('2px solid', '')}">${match}</span>`);
+            chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
             ++matchNum;
         })
 
@@ -222,8 +230,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 e.stopPropagation();
                 this._editing = false;
                 break;
-            case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': //prettier-ignore
+            case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': // prettier-ignore
                 e.stopPropagation();
+                break;
+            case '+': case '*': case '/': case '%': // prettier-ignore
+
                 break;
             case ' ':
                 e.stopPropagation();
@@ -239,12 +250,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             case 'u': // for some reason 'u' otherwise exits the editor
                 e.stopPropagation();
                 break;
-            case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': //prettier-ignore
+            case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': // prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
-            case 'P':
-                break;
             default:
+                console.log('default called')
                 break;
         }
     };
-- 
cgit v1.2.3-70-g09d2


From 6a3d0cc899020710d5b9aabe164649c686467024 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 01:14:06 -0400
Subject: progress on refSelect (single click to add cell to equation)

---
 .../collectionSchema/CollectionSchemaView.tsx      | 135 +++++++++++----------
 .../collectionSchema/SchemaCellField.tsx           |  25 ++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |   8 +-
 .../collectionSchema/SchemaTableCell.tsx           |  11 +-
 4 files changed, 106 insertions(+), 73 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 48c34c647..c3dc4bad6 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -42,6 +42,7 @@ import { truncate } from 'lodash';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { TbHemispherePlus } from 'react-icons/tb';
 import { docs_v1 } from 'googleapis';
+import { SchemaCellField } from './SchemaCellField';
 
 const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
 
@@ -104,7 +105,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _highlightedCellsInfo: Array<[doc: Doc, field: string]> = [];
     @observable _cellHighlightColors: ObservableMap = new ObservableMap<string, string[]>();
     @observable _docs: Doc[] = [];
-    @observable _inCellSelectMode: boolean = false;
+    @observable _referenceSelectMode = {enabled: false, currEditing: undefined}
     
     // target HTMLelement portal for showing a popup menu to edit cell values.
     public get MenuTarget() {
@@ -113,7 +114,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @computed get _selectedDocs() {
         // get all selected documents then filter out any whose parent is not this schema document
-        const selected = DocumentView.SelectedDocs().filter(doc => this.docs.includes(doc));
+        const selected = DocumentView.SelectedDocs().filter(doc => this.docs.includes(doc) && this._selectedCells.includes(doc));
         if (!selected.length) {
             // if no schema doc is directly selected, test if a child of a schema doc is selected (such as in the preview window)
             const childOfSchemaDoc = DocumentView.SelectedDocs().find(sel => DocumentView.getContextPath(sel, true).includes(this.Document));
@@ -651,7 +652,19 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectCell = (doc: Doc, col: number, shiftKey: boolean, ctrlKey: boolean) => {
+    selectCell = (doc: Doc | undefined, col: number, shiftKey: boolean, ctrlKey: boolean) => {
+        if (!doc) return;
+
+        if (this._referenceSelectMode.enabled) {
+            const docIndex = DocumentView.getDocViewIndex(doc);
+            const field = this.columnKeys[col];
+            const refToAdd = `d${docIndex}.${field}`
+            const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
+            editedField?.appendText(refToAdd);
+            editedField?.setupRefSelect(false);
+            return;
+        }
+
         this.closeColumnMenu();
         if (!shiftKey && !ctrlKey) this.clearSelection();
         !this._selectedCells && (this._selectedCells = []);
@@ -1015,64 +1028,64 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._filterSearchValue = e.target.value;
     };
 
-    @computed get newFieldMenu() {
-        return (
-            <div className="schema-new-key-options">
-                <div className="schema-key-type-option">
-                    <input
-                        type="radio"
-                        name="newFieldType"
-                        checked={this._newFieldType === ColumnType.Number}
-                        onChange={action(() => {
-                            this._newFieldType = ColumnType.Number;
-                            this._newFieldDefault = 0;
-                        })}
-                    />
-                    number
-                </div>
-                <div className="schema-key-type-option">
-                    <input
-                        type="radio"
-                        name="newFieldType"
-                        checked={this._newFieldType === ColumnType.Boolean}
-                        onChange={action(() => {
-                            this._newFieldType = ColumnType.Boolean;
-                            this._newFieldDefault = false;
-                        })}
-                    />
-                    boolean
-                </div>
-                <div className="schema-key-type-option">
-                    <input
-                        type="radio"
-                        name="newFieldType"
-                        checked={this._newFieldType === ColumnType.String}
-                        onChange={action(() => {
-                            this._newFieldType = ColumnType.String;
-                            this._newFieldDefault = '';
-                        })}
-                    />
-                    string
-                </div>
-                <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
-                <div className="schema-key-warning">{this._newFieldWarning}</div>
-                <div
-                    className="schema-column-menu-button"
-                    onPointerDown={action(() => {
-                        if (this.documentKeys.includes(this._menuValue)) {
-                            this._newFieldWarning = 'Field already exists';
-                        } else if (this._menuValue.length === 0) {
-                            this._newFieldWarning = 'Field cannot be an empty string';
-                        } else {
-                            this.setKey(this._menuValue, this._newFieldDefault);
-                        }
-                        this._columnMenuIndex = undefined;
-                    })}>
-                    done
-                </div>
-            </div>
-        );
-    }
+    // @computed get newFieldMenu() {
+    //     return (
+    //         <div className="schema-new-key-options">
+    //             <div className="schema-key-type-option">
+    //                 <input
+    //                     type="radio"
+    //                     name="newFieldType"
+    //                     checked={this._newFieldType === ColumnType.Number}
+    //                     onChange={action(() => {
+    //                         this._newFieldType = ColumnType.Number;
+    //                         this._newFieldDefault = 0;
+    //                     })}
+    //                 />
+    //                 number
+    //             </div>
+    //             <div className="schema-key-type-option">
+    //                 <input
+    //                     type="radio"
+    //                     name="newFieldType"
+    //                     checked={this._newFieldType === ColumnType.Boolean}
+    //                     onChange={action(() => {
+    //                         this._newFieldType = ColumnType.Boolean;
+    //                         this._newFieldDefault = false;
+    //                     })}
+    //                 />
+    //                 boolean
+    //             </div>
+    //             <div className="schema-key-type-option">
+    //                 <input
+    //                     type="radio"
+    //                     name="newFieldType"
+    //                     checked={this._newFieldType === ColumnType.String}
+    //                     onChange={action(() => {
+    //                         this._newFieldType = ColumnType.String;
+    //                         this._newFieldDefault = '';
+    //                     })}
+    //                 />
+    //                 string
+    //             </div>
+    //             <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
+    //             <div className="schema-key-warning">{this._newFieldWarning}</div>
+    //             <div
+    //                 className="schema-column-menu-button"
+    //                 onPointerDown={action(() => {
+    //                     if (this.documentKeys.includes(this._menuValue)) {
+    //                         this._newFieldWarning = 'Field already exists';
+    //                     } else if (this._menuValue.length === 0) {
+    //                         this._newFieldWarning = 'Field cannot be an empty string';
+    //                     } else {
+    //                         this.setKey(this._menuValue, this._newFieldDefault);
+    //                     }
+    //                     this._columnMenuIndex = undefined;
+    //                 })}>
+    //                 done
+    //             </div>
+    //         </div>
+    //     );
+    // }
 
     onKeysPassiveWheel = (e: WheelEvent) => {
         // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e13763b45..ea46fb432 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -15,6 +15,8 @@ export interface SchemaCellFieldProps {
     editing?: boolean;
     oneLine?: boolean;
     Document: Doc;
+    fieldKey: string;
+    refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
     SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
@@ -41,10 +43,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
     }
 
-    @computed get inCellSelectMode() {
-        return 
-    }
-
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
     componentDidMount(): void {
@@ -66,6 +64,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                     this._overlayDisposer?.();
                     this._overlayDisposer = undefined;
                     this._props.highlightCells?.('');
+                    this.setupRefSelect(false);
                 }
             },
             { fireImmediately: true }
@@ -127,7 +126,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
-        console.log('content: ' + content)
         this._displayedContent = this.makeSpans(content);
         if (restoreCursorPos) { 
             const cursorPos = this.cursorPosition;
@@ -135,6 +133,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
     }
 
+    @action
+    appendText = (text: string) => {
+        this._unrenderedContent += text;
+        this.setContent(this._unrenderedContent);
+    }
+
     @action
     setIsFocused = (value: boolean) => {
         const wasFocused = this._editing;
@@ -209,6 +213,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
     };
 
+    setupRefSelect = (enabled: boolean) => {
+        const properties = this._props.refSelectModeInfo;
+        properties.enabled = enabled;
+        properties.currEditing = enabled ? this : undefined;
+    }
+
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.nativeEvent.defaultPrevented) return; // hack .. DashFieldView grabs native events, but react ignores stoppedPropagation and preventDefault, so we need to check it here
@@ -234,7 +244,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 e.stopPropagation();
                 break;
             case '+': case '*': case '/': case '%': // prettier-ignore
-
+                this.setupRefSelect(true);
                 break;
             case ' ':
                 e.stopPropagation();
@@ -249,12 +259,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 break;
             case 'u': // for some reason 'u' otherwise exits the editor
                 e.stopPropagation();
+                this.setupRefSelect(false);
                 break;
             case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': // prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
             default:
-                console.log('default called')
+                this.setupRefSelect(false);
                 break;
         }
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index d2c0d891f..b15804d41 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -96,6 +96,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         return ''
     }
 
+    @computed get refSelectModeInfo() {
+        return this.schemaView._referenceSelectMode;
+    }
+
     @computed get menuInfos() {
         const infos: Array<IconProp> = [];
         if (this.Document._lockedSchemaEditing) infos.push('lock');
@@ -123,9 +127,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
     highlightCells = (text: string) => this.schemaView?.highlightCells(text);
-    equationHighlightRef = (text: string) => {
-    
-    }
     eqHighlightFunc = (text: string) => {
         const info = this.schemaView.findCellRefs(text);
         const cells: HTMLDivElement[] = [];
@@ -174,6 +175,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
                         <SchemaTableCell
+                            refSelectModeInfo={this.refSelectModeInfo}
                             func={this.eqHighlightFunc}
                             equationHighlightRef={this.schemaView._cellHighlightColors}
                             highlightCells={this.highlightCells}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index aa8401502..75b31315e 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -64,7 +64,7 @@ export interface SchemaTableCellProps {
     highlightCells: (text: string) => void;
     equationHighlightRef: ObservableMap<HTMLDivElement, string>;
     func: (text: string) => HTMLDivElement[] | [];
-
+    refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
 }
 
 function selectedCell(props: SchemaTableCellProps) {
@@ -78,7 +78,7 @@ function selectedCell(props: SchemaTableCellProps) {
 @observer
 export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> {
 
-    @observable _highlighted: boolean = false;
+    // private _fieldRef: SchemaCellField | null = null;
 
     constructor(props: SchemaTableCellProps) {
         super(props);
@@ -143,6 +143,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
         const pointerEvents: 'all' | 'none' = !readOnly && isRowActive() ? 'all' : 'none';
         return { color, textDecoration, fieldProps, cursor, pointerEvents };
     }
+
+    // @action
+    // appendTextToField = (text: string) => {
+    //     this._fieldRef?.appendText(text);
+    // }
         
     adjustSelfReference = (field: string) => {
         const modField = field.replace(/\bthis.\b/g, `d${this.docIndex}.`);
@@ -180,6 +185,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                     pointerEvents: this.lockedInteraction ? 'none' : pointerEvents,
                 }}>
                 <SchemaCellField
+                    fieldKey={this._props.fieldKey}
+                    refSelectModeInfo={this._props.refSelectModeInfo}
                     Document={this._props.Document}
                     highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))}
                     getCells={(text: string) => this._props.func(this.adjustSelfReference(text))}
-- 
cgit v1.2.3-70-g09d2


From 434fe9b5f27a14dc7bddeea9628abe4aaa62ce21 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 01:56:34 -0400
Subject: scrolling for field text

---
 src/client/views/EditableView.scss                                | 8 +++++++-
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 4 ++++
 2 files changed, 11 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
index d2f11f5e1..fa4542ac4 100644
--- a/src/client/views/EditableView.scss
+++ b/src/client/views/EditableView.scss
@@ -3,11 +3,17 @@
     overflow-wrap: break-word;
     word-wrap: break-word;
     hyphens: auto;
-    overflow: hidden;
+    overflow-y: auto;
     height: 100%;
     width: 100%;
     min-width: 20;
     text-overflow: ellipsis;
+    -ms-overflow-style: none; 
+    scrollbar-width: none; 
+}
+
+.editableView-container-editing::-webkit-scrollbar {
+    display: none; 
 }
 
 .editableView-container-editing-oneLine {
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index ea46fb432..9d9fcbd1f 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -94,6 +94,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
+    // @computed get lastChar(){
+    //     this.
+    // }
+
     generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
        return `<span style="color: ${cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`
     }
-- 
cgit v1.2.3-70-g09d2


From 3809bb004617a20fd631388d9cf404fa34c3ad52 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 02:57:44 -0400
Subject: refselect consistency

---
 .../collectionSchema/SchemaCellField.tsx           | 24 +++++++++++++---------
 1 file changed, 14 insertions(+), 10 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 9d9fcbd1f..84b4d3462 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -45,6 +45,16 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
+    @computed get lastChar(){
+        const text = this._unrenderedContent.slice();
+        for (let i = text.length - 1; i > 0; --i) {
+            if (text.charCodeAt(i) !== 160 && text.charCodeAt(i) !== 32) {
+                return text[i];
+            }
+        }
+        return null;
+    }
+
     componentDidMount(): void {
         this._unrenderedContent = this._props.GetValue() ?? '';
         this.setContent(this._unrenderedContent, true);
@@ -94,10 +104,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
-    // @computed get lastChar(){
-    //     this.
-    // }
-
     generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
        return `<span style="color: ${cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`
     }
@@ -215,6 +221,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
+        console.log(this.lastChar === '+');
+        if (this.lastChar === '+') this.setupRefSelect(true);
+        else this.setupRefSelect(false);
     };
 
     setupRefSelect = (enabled: boolean) => {
@@ -247,12 +256,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': // prettier-ignore
                 e.stopPropagation();
                 break;
-            case '+': case '*': case '/': case '%': // prettier-ignore
-                this.setupRefSelect(true);
-                break;
             case ' ':
                 e.stopPropagation();
-                console.log('deteected')
                 let cursorPos = 0;
                 if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
                 setTimeout(() => {
@@ -263,13 +268,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 break;
             case 'u': // for some reason 'u' otherwise exits the editor
                 e.stopPropagation();
-                this.setupRefSelect(false);
                 break;
             case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': // prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
             default:
-                this.setupRefSelect(false);
                 break;
         }
     };
@@ -285,6 +288,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
+        // while (this.lastChar === '+') { this._unrenderedContent = this._unrenderedContent.slice(0, -1); }
         if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
             this._editing = false;
         } else {
-- 
cgit v1.2.3-70-g09d2


From 54559c677ac3a91e72680b5b7c889d63439edf58 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 12:10:05 -0400
Subject: focus is no longer lost

---
 src/client/util/SelectionManager.ts                |  1 +
 .../collectionSchema/CollectionSchemaView.tsx      | 26 ++++++++++++----------
 .../collectionSchema/SchemaCellField.tsx           | 11 ++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  3 +++
 .../collectionSchema/SchemaTableCell.tsx           |  8 +++++++
 5 files changed, 32 insertions(+), 17 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 0b942116c..fc494583f 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -58,6 +58,7 @@ export class SelectionManager {
     });
 
     public static DeselectAll = (except?: Doc): void => {
+        
         const found = this.Instance.SelectedViews.find(dv => dv.Document === except);
         runInAction(() => {
             if (LinkManager.Instance) {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c3dc4bad6..3b5a32ca7 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -634,6 +634,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     clearSelection = () => {
+        if (this._referenceSelectMode.enabled) return;
         DocumentView.DeselectAll();
         this.deselectAllCells();
     };
@@ -651,20 +652,19 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
     };
 
-    @action
-    selectCell = (doc: Doc | undefined, col: number, shiftKey: boolean, ctrlKey: boolean) => {
+    selectReference = (doc: Doc | undefined, col: number) => {
         if (!doc) return;
+        const docIndex = DocumentView.getDocViewIndex(doc);
+        const field = this.columnKeys[col];
+        const refToAdd = `d${docIndex}.${field}`
+        const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
+        editedField?.appendText(refToAdd);
+        editedField?.setupRefSelect(false);
+        return;
+    }
 
-        if (this._referenceSelectMode.enabled) {
-            const docIndex = DocumentView.getDocViewIndex(doc);
-            const field = this.columnKeys[col];
-            const refToAdd = `d${docIndex}.${field}`
-            const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
-            editedField?.appendText(refToAdd);
-            editedField?.setupRefSelect(false);
-            return;
-        }
-
+    @action
+    selectCell = (doc: Doc, col: number, shiftKey: boolean, ctrlKey: boolean) => {
         this.closeColumnMenu();
         if (!shiftKey && !ctrlKey) this.clearSelection();
         !this._selectedCells && (this._selectedCells = []);
@@ -687,12 +687,14 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     deselectCell = (doc: Doc) => {
+        console.log('single deselect called')
         this._selectedCells && (this._selectedCells = this._selectedCells.filter(d => d !== doc));
         if (this.rowIndex(doc) === this._lowestSelectedIndex) this._lowestSelectedIndex = Math.min(...this._selectedDocs.map(d => this.rowIndex(d)));
     };
 
     @action
     deselectAllCells = () => {
+        console.log('deselectall called')
         this._selectedCells = [];
         this._lowestSelectedIndex = -1;
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 84b4d3462..06d3926a8 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -62,6 +62,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             () => this._editing,
             editing => {
                 if (editing) {
+                    if (this.lastChar !== '+') this.setupRefSelect(false);
                     setTimeout(() => {
                         if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) {
                             this._overlayDisposer?.();
@@ -145,8 +146,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action
     appendText = (text: string) => {
-        this._unrenderedContent += text;
-        this.setContent(this._unrenderedContent);
+        const newText = this._unrenderedContent.concat(text);
+        this.onChange(undefined, newText);
     }
 
     @action
@@ -209,9 +210,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         //if (contains self-ref pattern)
     };
 
-    onChange = (e: FormEvent<HTMLDivElement>) => {
+    onChange = (e: FormEvent<HTMLDivElement> | undefined, newText?: string) => {
         const prevVal = this._unrenderedContent;
-        const targVal = e.currentTarget.innerText;
+        const targVal = newText ?? e!.currentTarget.innerText; // TODO: bang
         if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
             this._overlayDisposer?.();
             this._overlayDisposer = undefined;
@@ -319,7 +320,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             className='schemaField-editing'
             ref={r => { this._inputref = r; }}
             style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
-            onBlur={e => this.finalizeEdit(false, true, false)}
+            onBlur={e => {this._props.refSelectModeInfo.enabled ? setTimeout(() => {this.setIsFocused(true)}, 1000) : this.finalizeEdit(false, true, false)}}
             autoFocus
             onInput={this.onChange}
             onKeyDown={this.onKeyDown}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index b15804d41..3f5c2a90e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -23,6 +23,7 @@ import { CollectionFreeFormView } from '../collectionFreeForm';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { infoState } from '../collectionFreeForm/CollectionFreeFormInfoState';
+import { TbShieldX } from 'react-icons/tb';
 
 interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -127,6 +128,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
     highlightCells = (text: string) => this.schemaView?.highlightCells(text);
+    selectReference = (doc: Doc, col: number) => {this.schemaView.selectReference(doc, col)}
     eqHighlightFunc = (text: string) => {
         const info = this.schemaView.findCellRefs(text);
         const cells: HTMLDivElement[] = [];
@@ -175,6 +177,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
                         <SchemaTableCell
+                            selectReference={this.selectReference}
                             refSelectModeInfo={this.refSelectModeInfo}
                             func={this.eqHighlightFunc}
                             equationHighlightRef={this.schemaView._cellHighlightColors}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 75b31315e..ef46c44da 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -65,6 +65,7 @@ export interface SchemaTableCellProps {
     equationHighlightRef: ObservableMap<HTMLDivElement, string>;
     func: (text: string) => HTMLDivElement[] | [];
     refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
+    selectReference: (doc: Doc, col: number) => void;
 }
 
 function selectedCell(props: SchemaTableCellProps) {
@@ -254,6 +255,13 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                 className="schema-table-cell"
                 onContextMenu={e => StopEvent(e)}
                 onPointerDown={action(e => {
+                    if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)){
+                        e.stopPropagation();
+                        e.preventDefault();
+                        this._props.selectReference(this._props.Document, this._props.col);
+                        return;
+                    }
+
                     const shift: boolean = e.shiftKey;
                     const ctrl: boolean = e.ctrlKey;
                     if (this._props.isRowActive?.()) {
-- 
cgit v1.2.3-70-g09d2


From aad1ca740bcbad129dc23a5d8f71e3caae787d43 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 12:26:00 -0400
Subject: cursor position reset properly, appendtext has atCursor option

---
 .../collectionSchema/CollectionSchemaView.tsx        |  2 +-
 .../collections/collectionSchema/SchemaCellField.tsx | 20 +++++++++++++-------
 2 files changed, 14 insertions(+), 8 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 3b5a32ca7..32106e3be 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -658,7 +658,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const field = this.columnKeys[col];
         const refToAdd = `d${docIndex}.${field}`
         const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
-        editedField?.appendText(refToAdd);
+        editedField?.appendText(refToAdd, true);
         editedField?.setupRefSelect(false);
         return;
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 06d3926a8..8c4c1cd76 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -45,8 +45,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
-    @computed get lastChar(){
-        const text = this._unrenderedContent.slice();
+    @computed get lastCharBeforeCursor(){
+        const pos = this.cursorPosition;
+        const content = this._unrenderedContent;
+        const text = this._unrenderedContent.substring(0, pos ?? content.length);
         for (let i = text.length - 1; i > 0; --i) {
             if (text.charCodeAt(i) !== 160 && text.charCodeAt(i) !== 32) {
                 return text[i];
@@ -62,7 +64,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             () => this._editing,
             editing => {
                 if (editing) {
-                    if (this.lastChar !== '+') this.setupRefSelect(false);
+                    if (this.lastCharBeforeCursor !== '+') this.setupRefSelect(false);
                     setTimeout(() => {
                         if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) {
                             this._overlayDisposer?.();
@@ -145,9 +147,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     }
 
     @action
-    appendText = (text: string) => {
-        const newText = this._unrenderedContent.concat(text);
+    appendText = (text: string, atCursorPos?: boolean) => {
+        const content = this._unrenderedContent;
+        const cursorPos = this.cursorPosition;
+        const robustPos = cursorPos ?? content.length;
+        const newText = atCursorPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
         this.onChange(undefined, newText);
+        setTimeout(() => this.restoreCursorPosition(robustPos + text.length), 0);
     }
 
     @action
@@ -222,8 +228,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
-        console.log(this.lastChar === '+');
-        if (this.lastChar === '+') this.setupRefSelect(true);
+        console.log(this.lastCharBeforeCursor === '+');
+        if (this.lastCharBeforeCursor === '+') this.setupRefSelect(true);
         else this.setupRefSelect(false);
     };
 
-- 
cgit v1.2.3-70-g09d2


From f8232f2d210df5dcce352a51df7079095b1d1123 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 13:17:54 -0400
Subject: enhanced refselect logic

---
 .../collectionSchema/CollectionSchemaView.tsx      |  3 ---
 .../collectionSchema/SchemaCellField.tsx           | 28 +++++++++++-----------
 2 files changed, 14 insertions(+), 17 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 32106e3be..583829d6c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -296,7 +296,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     break;
                 }
                 case 'P': {
-                    console.log(this._cellHighlightColors)
                     break;
                 }
                 default:
@@ -687,14 +686,12 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     deselectCell = (doc: Doc) => {
-        console.log('single deselect called')
         this._selectedCells && (this._selectedCells = this._selectedCells.filter(d => d !== doc));
         if (this.rowIndex(doc) === this._lowestSelectedIndex) this._lowestSelectedIndex = Math.min(...this._selectedDocs.map(d => this.rowIndex(d)));
     };
 
     @action
     deselectAllCells = () => {
-        console.log('deselectall called')
         this._selectedCells = [];
         this._lowestSelectedIndex = -1;
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 8c4c1cd76..72d89adc3 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -57,6 +57,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         return null;
     }
 
+    @computed get refSelectConditionMet() {
+        const char = this.lastCharBeforeCursor;
+        return char === '+' || char === '*' || char === '/' || char === '%' || char === '=';
+    }
+
     componentDidMount(): void {
         this._unrenderedContent = this._props.GetValue() ?? '';
         this.setContent(this._unrenderedContent, true);
@@ -64,13 +69,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             () => this._editing,
             editing => {
                 if (editing) {
-                    if (this.lastCharBeforeCursor !== '+') this.setupRefSelect(false);
+                    this.setupRefSelect(this.refSelectConditionMet);
                     setTimeout(() => {
                         if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) {
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._unrenderedContent);
-                            this.setContent(this._unrenderedContent, true);
+                            this.setContent(this._unrenderedContent);
+                            setTimeout(() => this.setCursorPosition(this._unrenderedContent.length), 0);
                         } 
                     });
                 } else {
@@ -139,11 +145,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
+        const pos = this.cursorPosition;
         this._displayedContent = this.makeSpans(content);
-        if (restoreCursorPos) { 
-            const cursorPos = this.cursorPosition;
-            setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
-        }
+        restoreCursorPos && setTimeout(() => this.setCursorPosition(pos), 0);
     }
 
     @action
@@ -153,7 +157,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         const robustPos = cursorPos ?? content.length;
         const newText = atCursorPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
         this.onChange(undefined, newText);
-        setTimeout(() => this.restoreCursorPosition(robustPos + text.length), 0);
+        setTimeout(() => this.setCursorPosition(robustPos + text.length), 0);
     }
 
     @action
@@ -173,12 +177,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         adjRange.selectNodeContents(this._inputref);
         adjRange.setEnd(range.startContainer, range.startOffset);
 
-        console.log(adjRange.toString().length)
-
         return adjRange.toString().length; 
     }
 
-    restoreCursorPosition = (position: number | null) => {
+    setCursorPosition = (position: number | null) => {
         const selection = window.getSelection();
         if (!selection || position === null || !this._inputref) return; 
     
@@ -228,9 +230,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
-        console.log(this.lastCharBeforeCursor === '+');
-        if (this.lastCharBeforeCursor === '+') this.setupRefSelect(true);
-        else this.setupRefSelect(false);
+        this.setupRefSelect(this.refSelectConditionMet);
     };
 
     setupRefSelect = (enabled: boolean) => {
@@ -269,7 +269,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
                 setTimeout(() => {
                     this.setContent(this._unrenderedContent);
-                    setTimeout(() => this.restoreCursorPosition(cursorPos), 0);
+                    setTimeout(() => this.setCursorPosition(cursorPos), 0);
                 }
                 , 0);
                 break;
-- 
cgit v1.2.3-70-g09d2


From a9494a1959430ffb3f501ef59f699aabc3748c7d Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 25 Jun 2024 13:49:35 -0400
Subject: changing cursor position updates refselectmode

---
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 72d89adc3..7bdfaa587 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -219,6 +219,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     };
 
     onChange = (e: FormEvent<HTMLDivElement> | undefined, newText?: string) => {
+        console.log('onchange called')
         const prevVal = this._unrenderedContent;
         const targVal = newText ?? e!.currentTarget.innerText; // TODO: bang
         if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
@@ -230,6 +231,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
+        console.log('cursorpos: ' + this.cursorPosition + ' char: ' + this.lastCharBeforeCursor);
         this.setupRefSelect(this.refSelectConditionMet);
     };
 
@@ -262,6 +264,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 break;
             case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': // prettier-ignore
                 e.stopPropagation();
+                setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0)
                 break;
             case ' ':
                 e.stopPropagation();
@@ -330,7 +333,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             autoFocus
             onInput={this.onChange}
             onKeyDown={this.onKeyDown}
-            onPointerDown={e => e.stopPropagation}
+            onPointerDown={e => {e.stopPropagation(); setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0)}} //timeout callback ensures that refSelectMode is properly set
             onClick={e => e.stopPropagation}
             onPointerUp={e => e.stopPropagation}
             onPointerMove={e => {e.stopPropagation(); e.preventDefault()}}
-- 
cgit v1.2.3-70-g09d2


From 830121ffc5d3d7ba9c5bd48771b6927d24dfce59 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 26 Jun 2024 13:10:47 -0400
Subject: removing 0s from settimeut + minor sorted col highlight color change

---
 .../collectionSchema/CollectionSchemaView.tsx      |  4 ++--
 .../collectionSchema/SchemaCellField.tsx           | 22 +++++++++++++---------
 2 files changed, 15 insertions(+), 11 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 583829d6c..57327a008 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -206,7 +206,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         )
         this._disposers.sortHighlight = reaction(
             () => [this.sortField, this._docs, this._selectedDocs, this._highlightedCellsInfo], 
-            () => {this.sortField && setTimeout(() => this.highlightSortedColumn(), 0)},
+            () => {this.sortField && setTimeout(() => this.highlightSortedColumn())},
             {fireImmediately: true}
         )
     }
@@ -505,7 +505,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (field || this.sortField){
             index = this.columnKeys.indexOf(field || this.sortField);
             const increment: number = 100/rowCount;
-            for (let i = 0; i < rowCount; ++i){
+            for (let i = 1; i <= rowCount; ++i){
                 const adjColor = ClientUtils.lightenRGB(16, 66, 230, increment * i);
                 highlightColors.push(`solid 2px rgb(${adjColor[0]}, ${adjColor[1]}, ${adjColor[2]})`);
             }
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 7bdfaa587..8e751f4ba 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -40,11 +40,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         setTimeout(() => { 
             this._unrenderedContent = this._props.GetValue() ?? '';
             this.setContent(this._unrenderedContent);
-        }, 0); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
+        }); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
     }
 
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
+    get selfRefPattern() {return `d${this.docIndex}.${this._props.fieldKey}`};
+
     @computed get lastCharBeforeCursor(){
         const pos = this.cursorPosition;
         const content = this._unrenderedContent;
@@ -76,7 +78,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._unrenderedContent);
                             this.setContent(this._unrenderedContent);
-                            setTimeout(() => this.setCursorPosition(this._unrenderedContent.length), 0);
+                            setTimeout(() => this.setCursorPosition(this._unrenderedContent.length));
                         } 
                     });
                 } else {
@@ -114,7 +116,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     }
 
     generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
-       return `<span style="color: ${cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`
+        const selfRef = text === this.selfRefPattern;
+        return `<span style="text-decoration: ${selfRef ? 'underline' : 'none'}; text-decoration-color: red; color: ${selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`;
     }
 
     makeSpans = (content: string) => {
@@ -147,7 +150,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
         this._displayedContent = this.makeSpans(content);
-        restoreCursorPos && setTimeout(() => this.setCursorPosition(pos), 0);
+        restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     }
 
     @action
@@ -157,7 +160,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         const robustPos = cursorPos ?? content.length;
         const newText = atCursorPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
         this.onChange(undefined, newText);
-        setTimeout(() => this.setCursorPosition(robustPos + text.length), 0);
+        setTimeout(() => this.setCursorPosition(robustPos + text.length));
     }
 
     @action
@@ -219,7 +222,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     };
 
     onChange = (e: FormEvent<HTMLDivElement> | undefined, newText?: string) => {
-        console.log('onchange called')
         const prevVal = this._unrenderedContent;
         const targVal = newText ?? e!.currentTarget.innerText; // TODO: bang
         if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
@@ -231,7 +233,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
-        console.log('cursorpos: ' + this.cursorPosition + ' char: ' + this.lastCharBeforeCursor);
         this.setupRefSelect(this.refSelectConditionMet);
     };
 
@@ -272,7 +273,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
                 setTimeout(() => {
                     this.setContent(this._unrenderedContent);
-                    setTimeout(() => this.setCursorPosition(cursorPos), 0);
+                    setTimeout(() => this.setCursorPosition(cursorPos));
                 }
                 , 0);
                 break;
@@ -298,7 +299,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     @action
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
-        // while (this.lastChar === '+') { this._unrenderedContent = this._unrenderedContent.slice(0, -1); }
+        if (this._unrenderedContent.replace(this.selfRefPattern, '') !== this._unrenderedContent) {
+            console.log('error'); this._editing = false; return;
+        }
+        
         if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
             this._editing = false;
         } else {
-- 
cgit v1.2.3-70-g09d2


From 2437028db1f273350b0422da0ef3a5f520ffce59 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 26 Jun 2024 13:48:25 -0400
Subject: self-reference warning added

---
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 6 +++++-
 src/client/views/collections/collectionSchema/SchemaRowBox.tsx    | 2 +-
 src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 4 ++--
 3 files changed, 8 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 8e751f4ba..27ca37c2b 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -33,6 +33,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @observable _editing: boolean = false;
     @observable _displayedContent = '';
     @observable _inCellSelectMode: boolean = false;
+    @observable _dependencyMessageShown: boolean = false;
 
     constructor(props: SchemaCellFieldProps) {
         super(props);
@@ -300,7 +301,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @action
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
         if (this._unrenderedContent.replace(this.selfRefPattern, '') !== this._unrenderedContent) {
-            console.log('error'); this._editing = false; return;
+            this._dependencyMessageShown ? this._dependencyMessageShown = false :
+            alert("Circular dependency detected. Please update the field.")
+            this._dependencyMessageShown = true;
+            return;
         }
         
         if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 3f5c2a90e..c9feeac6b 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -179,7 +179,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                         <SchemaTableCell
                             selectReference={this.selectReference}
                             refSelectModeInfo={this.refSelectModeInfo}
-                            func={this.eqHighlightFunc}
+                            eqHighlightFunc={this.eqHighlightFunc}
                             equationHighlightRef={this.schemaView._cellHighlightColors}
                             highlightCells={this.highlightCells}
                             isolatedSelection={this.isolatedSelection}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index ef46c44da..016ab5e69 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -63,7 +63,7 @@ export interface SchemaTableCellProps {
     isolatedSelection: [boolean, boolean];
     highlightCells: (text: string) => void;
     equationHighlightRef: ObservableMap<HTMLDivElement, string>;
-    func: (text: string) => HTMLDivElement[] | [];
+    eqHighlightFunc: (text: string) => HTMLDivElement[] | [];
     refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
     selectReference: (doc: Doc, col: number) => void;
 }
@@ -190,7 +190,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                     refSelectModeInfo={this._props.refSelectModeInfo}
                     Document={this._props.Document}
                     highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))}
-                    getCells={(text: string) => this._props.func(this.adjustSelfReference(text))}
+                    getCells={(text: string) => this._props.eqHighlightFunc(this.adjustSelfReference(text))}
                     ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
                     oneLine={this._props.oneLine}
                     contents={undefined}
-- 
cgit v1.2.3-70-g09d2


From 8ceaba8b8264f5519de732cc603dcd276b4b4f4d Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 28 Jun 2024 01:49:10 -0400
Subject: header text no longer shifts left on hover

---
 src/client/documents/Documents.ts                  |  6 +++++
 src/client/util/Scripting.ts                       |  9 ++++++--
 .../collectionSchema/CollectionSchemaView.scss     |  1 -
 .../collectionSchema/SchemaCellField.tsx           |  4 +++-
 .../collectionSchema/SchemaColumnHeader.tsx        |  6 ++---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 +----
 .../collectionSchema/SchemaTableCell.tsx           | 26 +++++++++++++++++-----
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/KeyValueBox.tsx             |  2 +-
 9 files changed, 43 insertions(+), 19 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dabbf9591..1b1608cd5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -143,7 +143,12 @@ class ListInfo extends FInfo {
     fieldType? = FInfoFieldType.list;
     values?: List<any>[] = [];
 }
+class MapInfo extends FInfo {
+    fieldType? = FInfoFieldType.list;
+    values?: List<any>[] = [];
+}
 type BOOLt = BoolInfo | boolean;
+type MAPt = MapInfo | Map<any, any>;
 type NUMt = NumInfo | number;
 type STRt = StrInfo | string;
 type LISTt = ListInfo | List<any>;
@@ -229,6 +234,7 @@ export class DocumentOptions {
     _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
     _childrenSharedWithSchema?: BOOLt = new BoolInfo("whether this document's children are displayed in its parent schema view", false);
     _lockedSchemaEditing?: BOOLt = new BoolInfo("", false);
+    _schemaInputs?: LISTt = new ListInfo('user inputs to schema field', false)
 
     dataViz_title?: string;
     dataViz_line?: string;
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 6ef592ef2..c7aa56c1e 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -183,14 +183,19 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde
     );
 }
 
+ScriptField.CompileScript(value, {}, true, undefined, DocumentIconContainer.getTransformer());
+//addreturn = true
+//capturedvariables = undefined
+//
+
 export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult {
-    const captured = options.capturedVariables ?? {};
+    const captured = options.capturedVariables ?? {}; 
     const signature = Object.keys(captured).reduce((p, v) => {
         const formatCapture = (obj: any) => `${v}=${obj instanceof RefField ? 'XXX' : obj.toString()}`;
         if (captured[v] instanceof Array) return p + (captured[v] as any).map(formatCapture);
         return p + formatCapture(captured[v]);
     }, '');
-    const found = ScriptField.GetScriptFieldCache(script + ':' + signature);
+    const found = ScriptField.GetScriptFieldCache(script + ':' + signature); // if already compiled, found is the result; cache set below
     if (found) return found as CompiledScript;
     const { requiredType = '', addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options;
     if (options.params && !options.params.this) options.params.this = Doc.name;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 6b53eb1cc..425b67fa9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -155,7 +155,6 @@
     padding: 0;
     z-index: 1;
     border: 1px solid $medium-gray;
-    //overflow: hidden;
 
     .schema-column-title {
         flex-grow: 2;
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 27ca37c2b..c7c483df8 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -321,11 +321,13 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
     }
 
+    //<FieldView {...this._props.fieldContents}/>
+
     staticDisplay = () => {
         return <span className='editableView-static'>
         {
             // eslint-disable-next-line react/jsx-props-no-spreading
-            this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : ''
+            this._props.fieldContents ?  <FieldView {...this._props.fieldContents}/> : ''
         }
         </span>
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index d16cde1f8..83a136737 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -237,11 +237,11 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                     }}>
                     <div className="schema-column-resizer left" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex)} />
 
-                    <div>{this.editableView}</div>
+                    <div className="schema-header-text">{this.editableView}</div>
 
                     <div className="schema-header-menu">
-                        <div className="schema-header-button">
-                            {this.displayButton ? this.headerButton : null}
+                        <div className="schema-header-button" style={{opacity: this.displayButton ? '1.0' : '0.0'}}>
+                            {this.headerButton}
                         </div>
                     </div>  
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index c9feeac6b..077d95c57 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -97,10 +97,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         return ''
     }
 
-    @computed get refSelectModeInfo() {
-        return this.schemaView._referenceSelectMode;
-    }
-
     @computed get menuInfos() {
         const infos: Array<IconProp> = [];
         if (this.Document._lockedSchemaEditing) infos.push('lock');
@@ -178,7 +174,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                     {this.schemaView?.columnKeys?.map((key, index) => (
                         <SchemaTableCell
                             selectReference={this.selectReference}
-                            refSelectModeInfo={this.refSelectModeInfo}
+                            refSelectModeInfo={this.schemaView._referenceSelectMode}
                             eqHighlightFunc={this.eqHighlightFunc}
                             equationHighlightRef={this.schemaView._cellHighlightColors}
                             highlightCells={this.highlightCells}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 016ab5e69..c0e1743a5 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -16,7 +16,7 @@ import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field, IdToDoc } from '../../../../fields/Doc';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { ColumnType } from '../../../../fields/SchemaHeaderField';
-import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast, toList } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue, ScriptCast, StrCast, toList } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { FInfo, FInfoFieldType } from '../../../documents/Documents';
 import { dropActionType } from '../../../util/DropActionTypes';
@@ -35,6 +35,7 @@ import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { ContextMenu } from '../../ContextMenu';
 import { SchemaCellField } from './SchemaCellField';
+import { ComputedField } from '../../../../fields/ScriptField';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -80,6 +81,7 @@ function selectedCell(props: SchemaTableCellProps) {
 export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> {
 
     // private _fieldRef: SchemaCellField | null = null;
+    private _submittedValue: string = '';
 
     constructor(props: SchemaTableCellProps) {
         super(props);
@@ -157,19 +159,31 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
 
     // parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability
     cleanupField = (field: string) => {
-        const idPattern = /idToDoc\((.*?)\)/g;
         let modField = field.slice();
+        let eqSymbol: string = '';
+        if (modField.startsWith('=')) {modField = modField.substring(1); eqSymbol += '=';}
+        if (modField.startsWith(':=')) {modField = modField.substring(2); eqSymbol += ':=';}
+
+        const idPattern = /idToDoc\((.*?)\)/g;
         let matches;
         let results = new Array<[id: string, func: string]>();
         while ((matches = idPattern.exec(field)) !== null) {results.push([matches[0], matches[1].replace(/"/g, '')]); }
         results.forEach((idFuncPair) => {modField = modField.replace(idFuncPair[0], 'd' + (DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1]))).toString());})
-        if (modField.charAt(modField.length - 1) === ';') modField = modField.substring(0, modField.length - 1);
+
+        for (let i = 0; i < modField.length; ++i){
+            
+        }
+
+        if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1);
+
+        const inQuotes = (field: string) => {return ((field.startsWith('`') && field.endsWith('`')) || (field.startsWith("'") && field.endsWith("'")) || (field.startsWith('"') && field.endsWith('"')))}
+        if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1);
         
         const selfRefPattern = `d${this.docIndex}.${this._props.fieldKey}`
         const selfRefRegX = RegExp(selfRefPattern, 'g');
         if (selfRefRegX.exec(modField) !== null) { return 'Invalid'}
 
-        return modField;
+        return eqSymbol + modField;
     }
 
     @computed get defaultCellContent() {
@@ -196,7 +210,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                     contents={undefined}
                     fieldContents={fieldProps}
                     editing={selectedCell(this._props) ? undefined : false}
-                    GetValue={() => this.cleanupField(Field.toKeyValueString(fieldProps.Document, this._props.fieldKey, SnappingManager.MetaKey))}
+                    ////const script = ScriptCast(fieldProps.Document[this._props.fieldKey]).rawscript;
+                    GetValue={() => ScriptCast(fieldProps.Document[this._props.fieldKey])?.rawscript ?? ''}
                     SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
@@ -205,6 +220,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                         }
                         const hasNoLayout =  Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto
                         const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout);
+                        this._submittedValue = value;
                         this._props.finishEdit?.();
                         return ret;
                     }, 'edit schema cell')}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 818d26956..40da661c0 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -118,7 +118,7 @@ export class FieldView extends React.Component<FieldViewProps> {
         const field = this.fieldval;
         // prettier-ignore
         if (field instanceof Doc)  return <p> <b>{field.title?.toString()}</b></p>;
-        if (field === undefined) return <p>{'<null>'}</p>;
+        if (field === undefined) return <p>{''}</p>;
         if (field instanceof DateField) return <p>{field.date.toLocaleString()}</p>;
         if (field instanceof List) return <div> {field.map(f => Field.toString(f)).join(', ')} </div>;
         if (field instanceof WebField) return <p>{Field.toString(field.url.href)}</p>;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 66e210c03..bc6633f23 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -88,7 +88,7 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const type: 'computed' | 'script' | false = rawvalue.startsWith(':=') ? 'computed' : rawvalue.startsWith('$=') ? 'script' : false;
         rawvalue = type ? rawvalue.substring(2) : rawvalue;
         rawvalue = rawvalue.replace(/.*\(\((.*)\)\)/, 'dashCallChat(_setCacheResult_, this, `$1`)');
-        const value = ["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(rawvalue as any) ? rawvalue : '`' + rawvalue + '`';
+        const value = (["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(rawvalue as any)) ? rawvalue : '`' + rawvalue + '`';
 
         let script = ScriptField.CompileScript(rawvalue, {}, true, undefined, DocumentIconContainer.getTransformer());
         if (!script.compiled) {
-- 
cgit v1.2.3-70-g09d2


From 3dd0a92767972736f415341c0b6e06e6e3a242b1 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Mon, 1 Jul 2024 16:38:24 -0400
Subject: highlighting then un-highlighting a selected cell with equations now
 properly maintains original select highlight

---
 src/client/views/EditableView.tsx                     |  1 -
 .../collectionSchema/CollectionSchemaView.tsx         | 19 +++++++++++++++----
 .../collections/collectionSchema/SchemaCellField.tsx  |  8 ++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx     | 13 ++-----------
 .../collections/collectionSchema/SchemaTableCell.tsx  | 10 +++-------
 5 files changed, 26 insertions(+), 25 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 0c09e12de..af6a43555 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -206,7 +206,6 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     
     @action
     finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
-        //if (invalid) raise error
         if (this._props.SetValue(value, shiftDown, enterKey)) {
             this._editing = false;
             this._props.isEditingCallback?.(false);
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 7a90b3505..b81cfa821 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -606,12 +606,24 @@ export class CollectionSchemaView extends CollectionSubView() {
         return cells;
     }
 
+    selectionOverlap = (doc: Doc): [boolean, boolean] => {
+        const docs = this.docsWithDrag.docs;
+        const index = this.rowIndex(doc);
+        const selectedBelow: boolean = this._selectedDocs.includes(docs[index + 1]);
+        const selectedAbove: boolean = this._selectedDocs.includes(docs[index - 1]);
+        return [selectedAbove, selectedBelow];
+    }
+
     removeCellHighlights = () => {
         this._highlightedCellsInfo.forEach(info => {
             const doc = info[0];
             const field = info[1];
             const cell = this.getCellElement(doc, field);
-            if (!(this._selectedDocs.includes(doc) && this._selectedCol === this.columnKeys.indexOf(field))) cell.style.border = ''; 
+            if (this._selectedDocs.includes(doc) && this._selectedCol === this.columnKeys.indexOf(field)) {
+                cell.style.border = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                if (this.selectionOverlap(doc)[0]) cell.style.borderTop = '';
+                if (this.selectionOverlap(doc)[1]) cell.style.borderBottom = '';
+            } else cell.style.border = '';
             cell.style.backgroundColor = '';});
         this._highlightedCellsInfo = [];
     }
@@ -741,7 +753,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
-        console.log('called')
         if (de.complete.columnDragData) {
             setTimeout(() => {this.setColDrag(false);});
             e.stopPropagation();
@@ -881,8 +892,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.closeColumnMenu();
     };
 
-    setColumnValues = (key: string, value: string) => {
-        if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing &&Doc.SetField(doc, key, value)); 
+    setCellValues = (key: string, value: string) => {
+        if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); 
         else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); 
         return true;
     };
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index c7c483df8..e1059b8fc 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -95,7 +95,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             () => this._props.GetValue(),
             fieldVal => {
                 this._unrenderedContent = fieldVal ?? '';
-                this.setContent(this._unrenderedContent);
+                this.finalizeEdit(false, false, false);
             }
         )
     }
@@ -246,6 +246,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.nativeEvent.defaultPrevented) return; // hack .. DashFieldView grabs native events, but react ignores stoppedPropagation and preventDefault, so we need to check it here
+        // if (e.metaKey) {
+        //     e.stopPropagation();
+        //     e.preventDefault();
+        // }
         switch (e.key) {
             case 'Tab':
                 e.stopPropagation();
@@ -302,7 +306,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
         if (this._unrenderedContent.replace(this.selfRefPattern, '') !== this._unrenderedContent) {
             this._dependencyMessageShown ? this._dependencyMessageShown = false :
-            alert("Circular dependency detected. Please update the field.")
+            alert(`Circular dependency detected. Please update the field at ${this.selfRefPattern}.`)
             this._dependencyMessageShown = true;
             return;
         }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9ac7a24b2..2410b2793 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -101,23 +101,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         return infos;
     }
 
-    @computed get isolatedSelection() {
-        const toReturn: [boolean, boolean] = [true, true];
-        const docs = this.schemaView.docsWithDrag.docs;
-        const selectedBelow: boolean = this.schemaView?._selectedDocs.includes(docs[this.rowIndex + 1]);
-        const selectedAbove: boolean = this.schemaView?._selectedDocs.includes(docs[this.rowIndex - 1]);
-        toReturn[0] = selectedAbove;
-        toReturn[1] = selectedBelow;
-        return toReturn;
-    }
-
+    isolatedSelection = (doc: Doc) => {return this.schemaView?.selectionOverlap(doc)};
     setCursorIndex = (mouseY: number) => this.schemaView?.setRelCursorIndex(mouseY);
     selectedCol = () => this.schemaView._selectedCol;
     getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
     selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl);
     deselectCell = () => this.schemaView?.deselectAllCells();
     selectedCells = () => this.schemaView?._selectedDocs;
-    setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
+    setColumnValues = (field: any, value: any) => this.schemaView?.setCellValues(field, value) ?? false;
     columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
     highlightCells = (text: string) => this.schemaView?.highlightCells(text);
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1f5684151..e2a05da7f 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -60,7 +60,7 @@ export interface SchemaTableCellProps {
     autoFocus?: boolean; // whether to set focus on creation, othwerise wait for a click
     rootSelected?: () => boolean;
     rowSelected: () => boolean;
-    isolatedSelection: [boolean, boolean];
+    isolatedSelection: (doc: Doc) => [boolean, boolean];
     highlightCells: (text: string) => void;
     equationHighlightRef: ObservableMap<HTMLDivElement, string>;
     eqHighlightFunc: (text: string) => HTMLDivElement[] | [];
@@ -174,10 +174,6 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
 
         const inQuotes = (field: string) => {return ((field.startsWith('`') && field.endsWith('`')) || (field.startsWith("'") && field.endsWith("'")) || (field.startsWith('"') && field.endsWith('"')))}
         if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1);
-        
-        const selfRefPattern = `d${this.docIndex}.${this._props.fieldKey}`
-        const selfRefRegX = RegExp(selfRefPattern, 'g');
-        if (selfRefRegX.exec(modField) !== null) { return 'Invalid'}
 
         return eqSymbol + modField;
     }
@@ -255,8 +251,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
         const sides: Array<string | undefined> = [];
         sides[0] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // left
         sides[1] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // right
-        sides[2] = (!this._props.isolatedSelection[0] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top
-        sides[3] = (!this._props.isolatedSelection[1] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom
+        sides[2] = (!this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top
+        sides[3] = (!this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom
         return sides;
     }
 
-- 
cgit v1.2.3-70-g09d2


From 32771d4b202a8552815c7f4459d5ac5142401292 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 3 Jul 2024 04:40:55 -0400
Subject: schemacell refactor started

---
 .../collectionSchema/SchemaCellField.tsx           | 119 ++++++++++++++++++++-
 .../collectionSchema/SchemaTableCell.tsx           |   2 +-
 2 files changed, 116 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e1059b8fc..5048bf899 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -8,6 +8,15 @@ import { FieldView, FieldViewProps } from "../../nodes/FieldView";
 import { ObjectField } from "../../../../fields/ObjectField";
 import { Doc } from "../../../../fields/Doc";
 import { DocumentView } from "../../nodes/DocumentView";
+import { date } from "serializr";
+import { createRoot } from "react-dom/client";
+import DatePicker from "react-datepicker";
+import { emptyFunction } from "../../../../Utils";
+import { DateField } from "../../../../fields/DateField";
+
+enum EleType {
+    plainText, fieldReference, date, boolean
+}
 
 export interface SchemaCellFieldProps {
     contents: any;
@@ -34,6 +43,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @observable _displayedContent = '';
     @observable _inCellSelectMode: boolean = false;
     @observable _dependencyMessageShown: boolean = false;
+    @observable _displayedElements: JSX.Element[] = [];
 
     constructor(props: SchemaCellFieldProps) {
         super(props);
@@ -101,6 +111,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     }
 
     componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) {
+        this.addReactComponents();
         super.componentDidUpdate(prevProps);
         if (this._editing && this._props.editing === false) {
             this.finalizeEdit(false, true, false);
@@ -116,12 +127,31 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
-    generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
+    addReactComponents = () => {
+        if (!this._inputref) return;
+
+        const dateRefs = Array.from(this._inputref.querySelectorAll('.date-placeholder'));
+
+        dateRefs.forEach(ref => {
+            const root = createRoot(ref);
+            root.render(<DatePicker dateFormat="Pp" selected={new Date()} onChange={emptyFunction} />);
+        })
+    }
+
+    generateSpan = (text: string, cell: HTMLDivElement | undefined): JSX.Element => {
         const selfRef = text === this.selfRefPattern;
-        return `<span style="text-decoration: ${selfRef ? 'underline' : 'none'}; text-decoration-color: red; color: ${selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`;
+        return (
+            <span style={{
+                textDecoration: selfRef ? 'underline' : 'none', 
+                textDecorationColor: 'red', 
+                color: selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}}>
+                {text}
+            </span>
+        );
     }
 
     makeSpans = (content: string) => {
+        const spans: JSX.Element[] = [];
         let chunkedText = content;
 
         const pattern = /(this|d(\d+))\.(\w+)/g;
@@ -140,13 +170,89 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
         let matchNum = 0;
         matches.forEach((match: string) => {
-            chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
+            chunkedText = chunkedText.replace(match, '');
+            spans.push(this.generateSpan(match, cells.get(match)));
             ++matchNum;
         })
 
+        chunkedText = chunkedText.replace(/{{date}}/g, `<span class="date-placeholder">placeholder text</span>`);
+        console.log(chunkedText)
+
         return chunkedText;
     }
 
+    verifyCellRef = (text: string): [string, HTMLDivElement | undefined] | undefined => {
+        const pattern = /(this|d(\d+))\.(\w+)/g;
+        let matchedText: string = '';
+        let matchedCell: HTMLDivElement | undefined = undefined; 
+        let match: RegExpExecArray | null;
+
+        while ((match = pattern.exec(text)) !== null) {
+            const cells = this._props.getCells(match[0]);
+            if (cells.length) {
+                matchedText = match[0];
+                matchedCell = cells[0];
+            }
+        }
+
+        if (!matchedText && !matchedCell) return undefined;
+        else return [matchedText, matchedCell];
+    }
+
+    elementsFromText = (chunks: string[]): JSX.Element[] => {
+        const eles: any[] = [];
+
+        chunks.forEach(text => {
+            const cellRef = this.verifyCellRef(text);
+            if (cellRef) {
+                eles.push(this.generateSpan(cellRef[0], cellRef[1]));
+            } else if (!text.replace('{{date}}', '')){
+                eles.push(<DatePicker dateFormat="Pp" selected={new Date()} onChange={emptyFunction} />);
+            } else if (!text.replace('{{boolean}}', '')) {
+                eles.push(<div>boolean thing</div>);
+            } else {
+                eles.push(<span>{text}</span>);
+            }
+        });
+
+        return eles;
+    }
+
+    parseElements = () => {
+        let string: string = this._unrenderedContent;
+        if (string.startsWith(':')) string = string.slice(1);
+        if (string.startsWith('=')) string = string.slice(1);
+
+        const chunks: string[] = [];
+
+        let subStr: string = '';
+        let currChar = '';
+        for (let i = 0; i < string.length; i++){
+            currChar = string[i];
+            if ((currChar === ' ' && subStr.trim()) || (currChar !== ' ' && !subStr.trim())) {
+                chunks.push(subStr);
+                subStr = currChar;
+            } else {
+                subStr += currChar;
+            }
+        }
+
+        if (subStr) {chunks.push(subStr)};
+
+        return this.elementsFromText(chunks);
+    }
+
+    // `<input
+    //     style={{ marginRight: 4 }}
+    //     type="checkbox"
+    //     checked={BoolCast(this._props.Document[this._props.fieldKey])}
+    //     onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
+    //         if ((value?.nativeEvent as any).shiftKey) {
+    //             this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? ''));
+    //         } else Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? ''));
+    //     })}
+    // />`
+
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
@@ -235,6 +341,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._props.highlightCells?.(targVal);
         if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
         this.setupRefSelect(this.refSelectConditionMet);
+        console.log(this.parseElements());
     };
 
     setupRefSelect = (enabled: boolean) => {
@@ -351,8 +458,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             onClick={e => e.stopPropagation}
             onPointerUp={e => e.stopPropagation}
             onPointerMove={e => {e.stopPropagation(); e.preventDefault()}}
-            dangerouslySetInnerHTML={{ __html: this._displayedContent }}
+            suppressContentEditableWarning={true}
+            //dangerouslySetInnerHTML={{ __html: this._displayedContent }}
             >
+                {this.parseElements().map((ele, index) => {
+                    return <div key={index}>{ele}</div>
+                })}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e2a05da7f..7d29e40cc 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -389,7 +389,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp
         const { pointerEvents } = SchemaTableCell.renderProps(this._props);
         return (
             <>
-                <div style={{ pointerEvents: 'none' }}>
+                <div style={{ pointerEvents: 'none'}}>
                     <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={emptyFunction} />
                 </div>
                 {pointerEvents === 'none' ? null : (
-- 
cgit v1.2.3-70-g09d2


From bb890c23b367374d9da7eb10d879ebbf48dc4e77 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 6 Jul 2024 02:31:27 -0400
Subject: wheel spinning

---
 .../collectionSchema/SchemaCellField.tsx           | 44 +++++++++++-----------
 1 file changed, 22 insertions(+), 22 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 5048bf899..3be9167fe 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -111,7 +111,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     }
 
     componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) {
-        this.addReactComponents();
         super.componentDidUpdate(prevProps);
         if (this._editing && this._props.editing === false) {
             this.finalizeEdit(false, true, false);
@@ -127,24 +126,25 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
-    addReactComponents = () => {
-        if (!this._inputref) return;
+    // addReactComponents = () => {
+    //     if (!this._inputref) return;
 
-        const dateRefs = Array.from(this._inputref.querySelectorAll('.date-placeholder'));
+    //     const dateRefs = Array.from(this._inputref.querySelectorAll('.date-placeholder'));
 
-        dateRefs.forEach(ref => {
-            const root = createRoot(ref);
-            root.render(<DatePicker dateFormat="Pp" selected={new Date()} onChange={emptyFunction} />);
-        })
-    }
+    //     dateRefs.forEach(ref => {
+    //         const root = createRoot(ref);
+    //         root.render(<DatePicker dateFormat="Pp" selected={new Date} onChange={emptyFunction} />);
+    //     })
+    // }
 
     generateSpan = (text: string, cell: HTMLDivElement | undefined): JSX.Element => {
         const selfRef = text === this.selfRefPattern;
+        const color: string | undefined = cell?.style.borderTop.replace('2px solid', '');
         return (
             <span style={{
                 textDecoration: selfRef ? 'underline' : 'none', 
                 textDecorationColor: 'red', 
-                color: selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}}>
+                color: selfRef ? 'gray' : color}}>
                 {text}
             </span>
         );
@@ -176,7 +176,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         })
 
         chunkedText = chunkedText.replace(/{{date}}/g, `<span class="date-placeholder">placeholder text</span>`);
-        console.log(chunkedText)
 
         return chunkedText;
     }
@@ -206,10 +205,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             const cellRef = this.verifyCellRef(text);
             if (cellRef) {
                 eles.push(this.generateSpan(cellRef[0], cellRef[1]));
-            } else if (!text.replace('{{date}}', '')){
+            } else if (text && !text.replace('{{date}}', '')){
                 eles.push(<DatePicker dateFormat="Pp" selected={new Date()} onChange={emptyFunction} />);
-            } else if (!text.replace('{{boolean}}', '')) {
-                eles.push(<div>boolean thing</div>);
+            } else if (text && !text.replace('{{boolean}}', '')) {
+                eles.push(<span>boolean thing</span>);
             } else {
                 eles.push(<span>{text}</span>);
             }
@@ -218,8 +217,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         return eles;
     }
 
-    parseElements = () => {
-        let string: string = this._unrenderedContent;
+    parseElements = (content: string) => {
+        let string: string = content;
         if (string.startsWith(':')) string = string.slice(1);
         if (string.startsWith('=')) string = string.slice(1);
 
@@ -229,7 +228,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         let currChar = '';
         for (let i = 0; i < string.length; i++){
             currChar = string[i];
-            if ((currChar === ' ' && subStr.trim()) || (currChar !== ' ' && !subStr.trim())) {
+            if (((string.charCodeAt(i) === 32 || string.charCodeAt(i) === 160) && subStr.trim()) || (currChar !== ' ' && !subStr.trim())) {
                 chunks.push(subStr);
                 subStr = currChar;
             } else {
@@ -256,7 +255,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
-        this._displayedContent = this.makeSpans(content);
+        this._displayedContent = content;
+        this._displayedElements = this.parseElements(content);
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     }
 
@@ -339,9 +339,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
-        if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
+        if (this.parseElements(targVal).length > this.parseElements(this._displayedContent).length) this.setContent(targVal, true);
         this.setupRefSelect(this.refSelectConditionMet);
-        console.log(this.parseElements());
+        console.log(this.parseElements(targVal));
     };
 
     setupRefSelect = (enabled: boolean) => {
@@ -461,8 +461,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             suppressContentEditableWarning={true}
             //dangerouslySetInnerHTML={{ __html: this._displayedContent }}
             >
-                {this.parseElements().map((ele, index) => {
-                    return <div key={index}>{ele}</div>
+                {this._displayedElements.map((ele, index) => {
+                    return <span key={index}>{ele}</span>;
                 })}
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From e7235baa7ed998908dec8bf48e4c244594aa76bb Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 8 Sep 2024 18:42:12 -0400
Subject: schema changes reverted

---
 .../collectionSchema/CollectionSchemaView.tsx      |   3 +-
 .../collectionSchema/SchemaCellField.tsx           | 123 +--------------------
 .../collectionSchema/SchemaColumnHeader.tsx        |   2 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   5 +-
 .../collectionSchema/SchemaTableCell.tsx           |   2 +-
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      |   9 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 7 files changed, 16 insertions(+), 130 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 12c342b9f..59ccec71f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -46,7 +46,6 @@ import { SchemaCellField } from './SchemaCellField';
 import { threadId } from 'worker_threads';
 import { FontIconBox } from '../../nodes/FontIconBox/FontIconBox';
 
-// eslint-disable-next-line @typescript-eslint/no-var-requires
 const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
 
 export const FInfotoColType: { [key: string]: ColumnType } = {
@@ -1539,4 +1538,4 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
             </div>
         );
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 3be9167fe..e1059b8fc 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -8,15 +8,6 @@ import { FieldView, FieldViewProps } from "../../nodes/FieldView";
 import { ObjectField } from "../../../../fields/ObjectField";
 import { Doc } from "../../../../fields/Doc";
 import { DocumentView } from "../../nodes/DocumentView";
-import { date } from "serializr";
-import { createRoot } from "react-dom/client";
-import DatePicker from "react-datepicker";
-import { emptyFunction } from "../../../../Utils";
-import { DateField } from "../../../../fields/DateField";
-
-enum EleType {
-    plainText, fieldReference, date, boolean
-}
 
 export interface SchemaCellFieldProps {
     contents: any;
@@ -43,7 +34,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @observable _displayedContent = '';
     @observable _inCellSelectMode: boolean = false;
     @observable _dependencyMessageShown: boolean = false;
-    @observable _displayedElements: JSX.Element[] = [];
 
     constructor(props: SchemaCellFieldProps) {
         super(props);
@@ -126,32 +116,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this.finalizeEdit(false, true, false);
     }
 
-    // addReactComponents = () => {
-    //     if (!this._inputref) return;
-
-    //     const dateRefs = Array.from(this._inputref.querySelectorAll('.date-placeholder'));
-
-    //     dateRefs.forEach(ref => {
-    //         const root = createRoot(ref);
-    //         root.render(<DatePicker dateFormat="Pp" selected={new Date} onChange={emptyFunction} />);
-    //     })
-    // }
-
-    generateSpan = (text: string, cell: HTMLDivElement | undefined): JSX.Element => {
+    generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
         const selfRef = text === this.selfRefPattern;
-        const color: string | undefined = cell?.style.borderTop.replace('2px solid', '');
-        return (
-            <span style={{
-                textDecoration: selfRef ? 'underline' : 'none', 
-                textDecorationColor: 'red', 
-                color: selfRef ? 'gray' : color}}>
-                {text}
-            </span>
-        );
+        return `<span style="text-decoration: ${selfRef ? 'underline' : 'none'}; text-decoration-color: red; color: ${selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`;
     }
 
     makeSpans = (content: string) => {
-        const spans: JSX.Element[] = [];
         let chunkedText = content;
 
         const pattern = /(this|d(\d+))\.(\w+)/g;
@@ -170,93 +140,17 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
         let matchNum = 0;
         matches.forEach((match: string) => {
-            chunkedText = chunkedText.replace(match, '');
-            spans.push(this.generateSpan(match, cells.get(match)));
+            chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
             ++matchNum;
         })
 
-        chunkedText = chunkedText.replace(/{{date}}/g, `<span class="date-placeholder">placeholder text</span>`);
-
         return chunkedText;
     }
 
-    verifyCellRef = (text: string): [string, HTMLDivElement | undefined] | undefined => {
-        const pattern = /(this|d(\d+))\.(\w+)/g;
-        let matchedText: string = '';
-        let matchedCell: HTMLDivElement | undefined = undefined; 
-        let match: RegExpExecArray | null;
-
-        while ((match = pattern.exec(text)) !== null) {
-            const cells = this._props.getCells(match[0]);
-            if (cells.length) {
-                matchedText = match[0];
-                matchedCell = cells[0];
-            }
-        }
-
-        if (!matchedText && !matchedCell) return undefined;
-        else return [matchedText, matchedCell];
-    }
-
-    elementsFromText = (chunks: string[]): JSX.Element[] => {
-        const eles: any[] = [];
-
-        chunks.forEach(text => {
-            const cellRef = this.verifyCellRef(text);
-            if (cellRef) {
-                eles.push(this.generateSpan(cellRef[0], cellRef[1]));
-            } else if (text && !text.replace('{{date}}', '')){
-                eles.push(<DatePicker dateFormat="Pp" selected={new Date()} onChange={emptyFunction} />);
-            } else if (text && !text.replace('{{boolean}}', '')) {
-                eles.push(<span>boolean thing</span>);
-            } else {
-                eles.push(<span>{text}</span>);
-            }
-        });
-
-        return eles;
-    }
-
-    parseElements = (content: string) => {
-        let string: string = content;
-        if (string.startsWith(':')) string = string.slice(1);
-        if (string.startsWith('=')) string = string.slice(1);
-
-        const chunks: string[] = [];
-
-        let subStr: string = '';
-        let currChar = '';
-        for (let i = 0; i < string.length; i++){
-            currChar = string[i];
-            if (((string.charCodeAt(i) === 32 || string.charCodeAt(i) === 160) && subStr.trim()) || (currChar !== ' ' && !subStr.trim())) {
-                chunks.push(subStr);
-                subStr = currChar;
-            } else {
-                subStr += currChar;
-            }
-        }
-
-        if (subStr) {chunks.push(subStr)};
-
-        return this.elementsFromText(chunks);
-    }
-
-    // `<input
-    //     style={{ marginRight: 4 }}
-    //     type="checkbox"
-    //     checked={BoolCast(this._props.Document[this._props.fieldKey])}
-    //     onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
-    //         if ((value?.nativeEvent as any).shiftKey) {
-    //             this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? ''));
-    //         } else Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? ''));
-    //     })}
-    // />`
-
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
-        this._displayedContent = content;
-        this._displayedElements = this.parseElements(content);
+        this._displayedContent = this.makeSpans(content);
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     }
 
@@ -339,9 +233,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
-        if (this.parseElements(targVal).length > this.parseElements(this._displayedContent).length) this.setContent(targVal, true);
+        if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
         this.setupRefSelect(this.refSelectConditionMet);
-        console.log(this.parseElements(targVal));
     };
 
     setupRefSelect = (enabled: boolean) => {
@@ -458,12 +351,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             onClick={e => e.stopPropagation}
             onPointerUp={e => e.stopPropagation}
             onPointerMove={e => {e.stopPropagation(); e.preventDefault()}}
-            suppressContentEditableWarning={true}
-            //dangerouslySetInnerHTML={{ __html: this._displayedContent }}
+            dangerouslySetInnerHTML={{ __html: this._displayedContent }}
             >
-                {this._displayedElements.map((ele, index) => {
-                    return <span key={index}>{ele}</span>;
-                })}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 40509c41b..9f6478041 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -249,4 +249,4 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                 </div>
         );
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 72f5d8c25..ec94a8077 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -24,7 +24,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { infoState } from '../collectionFreeForm/CollectionFreeFormInfoState';
 import { TbShieldX } from 'react-icons/tb';
-import { DocumentType } from '../../../documents/DocumentTypes';
 
 interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -78,7 +77,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             icon: 'minus',
         });
         const childDocs = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)])
-        if (childDocs.length) {
+        if (this.Document.type === 'collection' && childDocs.length) {
                 ContextMenu.Instance.addItem({
                 description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema',
                 event: () => {
@@ -197,4 +196,4 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             </div>
         );
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 7d29e40cc..e2a05da7f 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -389,7 +389,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp
         const { pointerEvents } = SchemaTableCell.renderProps(this._props);
         return (
             <>
-                <div style={{ pointerEvents: 'none'}}>
+                <div style={{ pointerEvents: 'none' }}>
                     <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={emptyFunction} />
                 </div>
                 {pointerEvents === 'none' ? null : (
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index dcdd52c73..8273f3e09 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -375,7 +375,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             if (res && this._callCount === origCount) {
                 this._suggestedTemplates = [];
-                this._GPTLoading = false;
                 const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
                 this.createGeneratedTemplates(templates, 500, 500);
             }
@@ -714,7 +713,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 try {
                     const renderedImages: Doc[] = await Promise.all(
                         calls.map(async ([fieldNum, col]) => {
-                            const sysPrompt = 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' + fieldContent + ' **** The user prompt is: ' + col.desc;
+                            const sysPrompt = 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' + fieldContent + ' **** The user prompt is: ' + col.desc;
                             
                             const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
                             console.log(sysPrompt, prompt);
@@ -852,7 +851,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
             if (res && this._callCount === origCount) {
-                this._GPTLoading = false;
 
                 const assignments: {[templateTitle: string]: {[field: string]: string}} = JSON.parse(res);
                 const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = [];
@@ -889,7 +887,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
         const renderedTemplates: Doc[] = await Promise.all(renderedTemplatePromises);
         
-        setTimeout(() => { this.setGSuggestedTemplates(renderedTemplates) });
+        setTimeout(() => { this.setGSuggestedTemplates(renderedTemplates); this._GPTLoading = false });
     };
 
     @action setExpandedView = (info: {icon: ImageField, doc: Doc} | undefined) => {
@@ -908,6 +906,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             <div className={`docCreatorMenu-templates-view`}>
                 {this._expandedPreview ? 
                 <div className='docCreatorMenu-expanded-template-preview'>
+                    <img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
                     <div className='right-buttons-panel'>
                         <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.setExpandedView(undefined))}> 
                             <FontAwesomeIcon icon='minimize'/>
@@ -1618,7 +1617,7 @@ export class FieldFuncs {
             _rotation: opts.rotation,
         });
 
-        //setTimeout(() => {console.log('called', RichTextMenu.Instance), RichTextMenu.Instance?.setFontField('#4CE4D4', 'fontColor')}, 2000);
+        docWithBasicOpts._layout_hideScroll = true;
 
         return docWithBasicOpts;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 54e6c0add..e091657a8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2100,7 +2100,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
                         }}
                         style={{
                             width: this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
-                            overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
+                            overflow: this.layoutDoc._createDocOnCR || this.layoutDoc._layout_hideScroll ? 'hidden' : this.layout_autoHeight ? 'visible' : undefined,
                         }}
                         onScroll={this.onScroll}
                         onDrop={this.ondrop}>
-- 
cgit v1.2.3-70-g09d2


From e0b354b275c3a025b93f93815bd1828ba9cec5a8 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 18 Sep 2024 20:43:14 -0400
Subject: fixed filtering; cells update properly with input

---
 .../collectionSchema/CollectionSchemaView.tsx      | 48 ++++++++++-
 .../collectionSchema/SchemaCellField.tsx           | 12 +--
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 97 ++++++++++++++--------
 3 files changed, 115 insertions(+), 42 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 59ccec71f..9623b0d12 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -45,6 +45,7 @@ import { docs_v1 } from 'googleapis';
 import { SchemaCellField } from './SchemaCellField';
 import { threadId } from 'worker_threads';
 import { FontIconBox } from '../../nodes/FontIconBox/FontIconBox';
+import { SnappingManager } from '../../../util/SnappingManager';
 
 const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
 
@@ -1271,6 +1272,49 @@ export class CollectionSchemaView extends CollectionSubView() {
         return toReturn;
     }
 
+    @computed get filteredDocs() {
+        const childDocFilters = this.childDocFilters();
+        const childFiltersByRanges = this.childDocRangeFilters();
+        const searchDocs = this.searchFilterDocs();
+
+        const docsforFilter: Doc[] = [];
+        this._docs.forEach(d => {
+            // dragging facets
+            const dragged = this._props.childFilters?.().some(f => f.includes(ClientUtils.noDragDocsFilter));
+            if (dragged && SnappingManager.CanEmbed && DragManager.docsBeingDragged.includes(d)) return;
+            let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0;
+            if (notFiltered) {
+                notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0;
+                const fieldKey = Doc.LayoutFieldKey(d);
+                const isAnnotatableDoc = d[fieldKey] instanceof List && !(d[fieldKey] as List<Doc>)?.some(ele => !(ele instanceof Doc));
+                const docChildDocs = d[isAnnotatableDoc ? fieldKey + '_annotations' : fieldKey];
+                const sidebarDocs = isAnnotatableDoc && d[fieldKey + '_sidebar'];
+                if (docChildDocs !== undefined || sidebarDocs !== undefined) {
+                    let subDocs = [...DocListCast(docChildDocs), ...DocListCast(sidebarDocs)];
+                    if (subDocs.length > 0) {
+                        let newarray: Doc[] = [];
+                        notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, childFiltersByRanges, d).length);
+                        while (subDocs.length > 0 && !notFiltered) {
+                            newarray = [];
+                            // eslint-disable-next-line no-loop-func
+                            subDocs.forEach(t => {
+                                const docFieldKey = Doc.LayoutFieldKey(t);
+                                const isSubDocAnnotatable = t[docFieldKey] instanceof List && !(t[docFieldKey] as List<Doc>)?.some(ele => !(ele instanceof Doc));
+                                notFiltered =
+                                    notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
+                                DocListCast(t[isSubDocAnnotatable ? docFieldKey + '_annotations' : docFieldKey]).forEach(newdoc => newarray.push(newdoc));
+                                isSubDocAnnotatable && DocListCast(t[docFieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
+                            });
+                            subDocs = newarray;
+                        }
+                    }
+                }
+            }
+            notFiltered && docsforFilter.push(d);
+        });
+        return docsforFilter;
+    }
+
     @computed get docs() {
         let docsFromChildren: Doc[] = [];
 
@@ -1279,7 +1323,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             let docsNotAlreadyDisplayed = this.subCollectionDocs(d, true).filter(dc => !this._docs.includes(dc));
             docsFromChildren = docsFromChildren.concat(docsNotAlreadyDisplayed);
         });
-        let docs = this._docs.concat(docsFromChildren);
+        let docs = this.filteredDocs;
 
         return docs;
     }
@@ -1288,7 +1332,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const numbers: Doc[] = [];
         const strings: Doc[] = []; 
 
-        this._docs.forEach(doc => {
+        this.docs.forEach(doc => {
             if (!isNaN(Number(Field.toString(doc[field] as FieldType)))) numbers.push(doc);
             else strings.push(doc);
         });
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e1059b8fc..1ee79fa0b 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -151,6 +151,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
         this._displayedContent = this.makeSpans(content);
+        console.log('print', content);
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     }
 
@@ -217,10 +218,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         setRange(this._inputref.childNodes);
     };
 
-    shouldUpdate = (prevVal: string, currVal: string) => {
-        if (this._props.getCells(currVal).length !== this._props.getCells(prevVal).length) return true;
-        //if (contains self-ref pattern)
-    };
+    //This function checks if a visual update (eg. coloring a cell reference) should be made. It's meant to
+    //save on processing upkeep vs. constantly rerendering, but I think the savings are minimal for now
+    // shouldUpdate = (prevVal: string, currVal: string) => {
+    //     if (this._props.getCells(currVal).length !== this._props.getCells(prevVal).length) return true;
+    // };
 
     onChange = (e: FormEvent<HTMLDivElement> | undefined, newText?: string) => {
         const prevVal = this._unrenderedContent;
@@ -233,7 +235,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
-        if (this.shouldUpdate(prevVal, targVal)) {this.setContent(targVal, true)};
+        this.setContent(targVal, true);
         this.setupRefSelect(this.refSelectConditionMet);
     };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 01d5bc83b..8afd1bbf1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -604,7 +604,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             }
         })
 
-        validTemplates = validTemplates.map(title => TemplateLayouts.fieldByTitle(title));
+        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
 
         return validTemplates;
     };
@@ -667,7 +667,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             const field: Field = template.fields[Number(info.number)];
                             const col = this.getColByTitle(title);
     
-                            const doc = FieldFuncs.TextField({
+                            const doc = FieldUtils.TextField({
                                 tl: field.tl, 
                                 br: field.br }, 
                                 template.height, 
@@ -692,7 +692,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const createGeneratedImage = async(fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
             const field: Field = template.fields[Number(fieldNum)];
-            const doc = FieldFuncs.ImageField({
+            const doc = FieldUtils.ImageField({
                 tl: field.tl, 
                 br: field.br }, 
                 template.height, 
@@ -755,7 +755,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const field: Field = template.fields[Number(f)];
             const col = strCol[1];
 
-            const doc = (col.type === TemplateFieldType.VISUAL ? FieldFuncs.ImageField : FieldFuncs.TextField)({
+            const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)({
                 tl: field.tl, 
                 br: field.br }, 
                 template.height, 
@@ -771,7 +771,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
 
         template.decorations.forEach(dec => {
-            const doc = FieldFuncs.FreeformField({
+            const doc = FieldUtils.FreeformField({
                 tl: dec.tl, 
                 br: dec.br }, 
                 template.height, 
@@ -856,7 +856,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
-                    const template = TemplateLayouts.fieldByTitle(tempTitle);
+                    const template = TemplateLayouts.getTemplateByTitle(tempTitle);
                     if (!template) return;
                     const toObj = Object.entries(assignment).reduce((a, [fieldNum, colTitle]) => {
                         a[Number(fieldNum)] = this.getColByTitle(colTitle);
@@ -1468,14 +1468,45 @@ export type Col = {
 }
 
 type Field = {
-    tl: [number, number], 
-    br: [number, number], 
-    types?: TemplateFieldType[], 
-    sizes?: TemplateFieldSize[], 
-    description?: string;
+    tl: [number, number];
+    br: [number, number];
     opts: FieldOpts;
-    subfields?: ['freeform' | 'stacking' | 'carousel', Field[]];
-};
+    subfields?: Field[];
+    types?: TemplateFieldType[];
+    sizes?: TemplateFieldSize[];
+    isDecoration?: boolean;
+    description?: string;
+}
+
+// class ContentField implements Field {
+//     tl: [number, number];
+//     br: [number, number];
+//     opts: FieldOpts;
+//     subfields?: Field[];
+//     types?: TemplateFieldType[];
+//     sizes?: TemplateFieldSize[];
+//     description?: string;
+
+//     constructor( tl: [number, number], br: [number, number], 
+//                         opts: FieldOpts, subfields?: Field[], 
+//                         types?: TemplateFieldType[], 
+//                         sizes?: TemplateFieldSize[], 
+//                         description?: string) {
+//         this.tl = tl;
+//         this.br = br;
+//         this.opts = opts;
+//         this.subfields = subfields;
+//         this.types = types;
+//         this.sizes = sizes;
+//         this.description = description;
+//     }
+
+//     render = (content: any): Doc => {
+//         return new Doc;
+//     }
+// }
+
+type DecorationField = Field;
 
 type InkDecoration = {
 
@@ -1505,13 +1536,24 @@ export interface FieldOpts {
     //animation?: boolean;
     fontBold?: boolean;
     fontTransform?: 'uppercase' | 'lowercase';
+    fieldViewType?: 'freeform' | 'stacked';
 }
 
 interface TemplateOpts extends FieldOpts {
 
 }
 
-export class FieldFuncs {
+export class FieldUtils {
+
+    public static contentFields = (fields: Field[]) => {
+        let toRet: Field[] = [];
+        fields.forEach(field => {
+            if (!field.isDecoration) { toRet.push(field) };
+            toRet = toRet.concat(FieldUtils.contentFields(field.subfields ?? []));
+        });
+
+        return toRet;
+    }
 
     public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
         const words: string[] = text.split(/\s+/).filter(Boolean);
@@ -1555,9 +1597,6 @@ export class FieldFuncs {
         
         return currFontSize - 1;
     };
-    
-    
-    
 
     private static getDimensions = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number): {width: number, height: number, coord: {x: number, y: number}} => {
         const l = coords.tl[0] * parentHeight / 2; const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
@@ -1570,7 +1609,7 @@ export class FieldFuncs {
     }
 
     public static FreeformField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
+        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
         const docWithBasicOpts = (Docs.Create.FreeformDocument)([], {  
             isDefaultTemplateDoc: true, 
@@ -1592,7 +1631,7 @@ export class FieldFuncs {
     }
 
     public static TextField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
+        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
         const bool = true;
 
@@ -1603,7 +1642,7 @@ export class FieldFuncs {
             title: title, 
             x: coord.x, 
             y: coord.y, 
-            _text_fontSize: `${FieldFuncs.calculateFontSize(width, height, content, true)}` ,
+            _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}` ,
             backgroundColor: opts.backgroundColor ?? '',
             text_fontColor: opts.color,
             contentBold: opts.fontBold,
@@ -1623,7 +1662,7 @@ export class FieldFuncs {
     }
 
     public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
+        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
         const doc = Docs.Create.ImageDocument(content, {  
             isDefaultTemplateDoc: true, 
@@ -1647,7 +1686,7 @@ export class FieldFuncs {
     }
 
     public static CarouselField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
-        const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
+        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
         const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height/2}` })
 
@@ -1664,7 +1703,7 @@ export class TemplateLayouts {
         ) as TemplateDocInfos[];
     }
 
-    public static fieldByTitle = (title: string): TemplateDocInfos | undefined => {
+    public static getTemplateByTitle = (title: string): TemplateDocInfos | undefined => {
         switch (title){
             case 'fourfield1':
                 return TemplateLayouts.FourField001;
@@ -1984,18 +2023,6 @@ export class TemplateLayouts {
                 borderWidth: '8',
                 rotation: 45,
             },
-            subfields: [
-                'freeform',
-                [{
-                    tl: [-2, -2], 
-                    br: [2, 2], 
-                    types: [TemplateFieldType.VISUAL],
-                    sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                    opts: {
-                        rotation: 315,
-                    }
-                }]
-            ]
         }, {
             tl: [-.7, .2], 
             br: [.7, .46], 
-- 
cgit v1.2.3-70-g09d2


From d8a43b76f101a2f38ef1e3e9cbf8ec036468481d Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 22 Sep 2024 15:29:28 -0400
Subject: header comments + change to cellfield updating

---
 .../collectionSchema/CollectionSchemaView.tsx      | 22 +++++++++-
 .../collectionSchema/SchemaCellField.tsx           | 48 +++++++++++++++-------
 .../collectionSchema/SchemaColumnHeader.tsx        |  6 +--
 .../collections/collectionSchema/SchemaRowBox.tsx  | 11 ++---
 .../collectionSchema/SchemaTableCell.tsx           | 15 ++++---
 5 files changed, 69 insertions(+), 33 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 0e5a1e6b6..11a4e88f9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -495,6 +495,26 @@ export class CollectionSchemaView extends CollectionSubView() {
         return adjIndex;
     };
 
+    @action
+    setRelCursorIndex = (mouseY: number) => {
+        this._mouseCoordinates.y = mouseY; // updates this.rowDropIndex computed value to overwrite the old cached value
+
+        const rowHeight = CollectionSchemaView._rowHeight;
+        const adjInitMouseY = mouseY - rowHeight - 100; // rowHeight: height of the column menu cells | 100: height of the top menu
+        const yOffset = this._lowestSelectedIndex * rowHeight;
+
+        const heights = this._selectedDocs.map(() => this.rowHeightFunc());
+        let index: number = 0;
+        heights.reduce((total, curr, i) => {
+            if (total <= adjInitMouseY && total + curr >= adjInitMouseY) {
+                if (adjInitMouseY <= total + curr) index = i;
+                else index = i + 1;
+            }
+            return total + curr;
+        }, yOffset);
+        this._relCursorIndex = index;
+    };
+
     highlightDraggedColumn = (index: number) =>
         this._colEles.forEach((colRef, i) => {
             const edgeStyle = i === index ? `solid 2px ${Colors.MEDIUM_BLUE}` : '';
@@ -731,7 +751,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const field = this.columnKeys[col];
         const refToAdd = `d${docIndex}.${field}`
         const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
-        editedField?.appendText(refToAdd, true);
+        editedField?.insertText(refToAdd, true);
         editedField?.setupRefSelect(false);
         return;
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 1ee79fa0b..72dcc00e6 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -9,6 +9,16 @@ import { ObjectField } from "../../../../fields/ObjectField";
 import { Doc } from "../../../../fields/Doc";
 import { DocumentView } from "../../nodes/DocumentView";
 
+/**
+ * The SchemaCellField renders text in schema cells while the user is editing, and updates the
+ * contents of the field based on user input. It handles some cell-side logic for equations, such
+ * as how equations are broken up within the text.
+ * 
+ * The current implementation parses innerHTML to create spans based on the text in the cell. 
+ * A more robust/safer approach would directly add elements in the react structure, but this
+ * has been challenging to implement.  
+ */
+
 export interface SchemaCellFieldProps {
     contents: any;
     fieldContents?: FieldViewProps;
@@ -147,20 +157,30 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         return chunkedText;
     }
 
+    /**
+     * Sets the rendered content of the cell to save user inputs. 
+     * @param content the content to set
+     * @param restoreCursorPos whether the cursor should be set back to where it was rather than the 0th index; should usually be true
+     */
     @action 
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
         this._displayedContent = this.makeSpans(content);
-        console.log('print', content);
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     }
 
+    //Called from schemaview when a cell is selected to add a reference to the equation
+    /**
+     * Inserts text at the given index.
+     * @param text The text to append.
+     * @param atPos he index at which to insert the text. If empty, defaults to end.
+     */
     @action
-    appendText = (text: string, atCursorPos?: boolean) => {
+    insertText = (text: string, atPos?: boolean) => {
         const content = this._unrenderedContent;
         const cursorPos = this.cursorPosition;
         const robustPos = cursorPos ?? content.length;
-        const newText = atCursorPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
+        const newText = atPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
         this.onChange(undefined, newText);
         setTimeout(() => this.setCursorPosition(robustPos + text.length));
     }
@@ -172,6 +192,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         return wasFocused !== this._editing;
     };
 
+    /**
+     * Gets the cursor's position index within the text being edited.
+     */
     get cursorPosition() {
         const selection = window.getSelection();
         if (!selection || selection.rangeCount === 0 || !this._inputref) return null; 
@@ -185,6 +208,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         return adjRange.toString().length; 
     }
 
+
     setCursorPosition = (position: number | null) => {
         const selection = window.getSelection();
         if (!selection || position === null || !this._inputref) return; 
@@ -220,9 +244,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     //This function checks if a visual update (eg. coloring a cell reference) should be made. It's meant to
     //save on processing upkeep vs. constantly rerendering, but I think the savings are minimal for now
-    // shouldUpdate = (prevVal: string, currVal: string) => {
-    //     if (this._props.getCells(currVal).length !== this._props.getCells(prevVal).length) return true;
-    // };
+    shouldUpdate = (prevVal: string, currVal: string) => {
+        if (this._props.getCells(currVal).length !== this._props.getCells(prevVal).length) return true;
+    };
 
     onChange = (e: FormEvent<HTMLDivElement> | undefined, newText?: string) => {
         const prevVal = this._unrenderedContent;
@@ -235,7 +259,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
         this._unrenderedContent = targVal;
         this._props.highlightCells?.(targVal);
-        this.setContent(targVal, true);
+        if (this.shouldUpdate(prevVal, targVal)) this.setContent(targVal, true);
         this.setupRefSelect(this.refSelectConditionMet);
     };
 
@@ -248,10 +272,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.nativeEvent.defaultPrevented) return; // hack .. DashFieldView grabs native events, but react ignores stoppedPropagation and preventDefault, so we need to check it here
-        // if (e.metaKey) {
-        //     e.stopPropagation();
-        //     e.preventDefault();
-        // }
+
         switch (e.key) {
             case 'Tab':
                 e.stopPropagation();
@@ -295,7 +316,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
     };
 
-
     @action
     onClick = (e?: React.MouseEvent) => {
         if (this._props.editing !== false) {
@@ -312,6 +332,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             this._dependencyMessageShown = true;
             return;
         }
+
+        this.setContent(this._unrenderedContent);
         
         if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
             this._editing = false;
@@ -327,8 +349,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         }
     }
 
-    //<FieldView {...this._props.fieldContents}/>
-
     staticDisplay = () => {
         return <span className='editableView-static'>
         {
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 6da236d82..3495c5ab4 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -5,23 +5,19 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, setupMoveUpEvents } from '../../../../ClientUtils';
 import { emptyFunction } from '../../../../Utils';
-import { Colors } from '../../global/globalEnums';
 import './CollectionSchemaView.scss';
 import { EditableView } from '../../EditableView';
 import { ObservableReactComponent } from '../../ObservableReactComponent';
 import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider';
 import { FieldViewProps } from '../../nodes/FieldView';
-import { Doc, Field } from '../../../../fields/Doc';
+import { Doc } from '../../../../fields/Doc';
 import { dropActionType } from '../../../util/DropActionTypes';
 import { Transform } from '../../../util/Transform';
 import { SchemaTableCell } from './SchemaTableCell';
 import { DocCast } from '../../../../fields/Types';
 import { computedFn } from 'mobx-utils';
 import { CollectionSchemaView } from './CollectionSchemaView';
-import { SnappingManager } from '../../../util/SnappingManager';
 import { undoable } from '../../../util/UndoManager';
-import { FInfo } from '../../../documents/Documents';
-import { ColumnType } from '../../../../fields/SchemaHeaderField';
 import { IconButton, Size } from 'browndash-components';
 
 export enum SchemaFieldType {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index ec94a8077..b928a5c67 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -25,6 +25,12 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { infoState } from '../collectionFreeForm/CollectionFreeFormInfoState';
 import { TbShieldX } from 'react-icons/tb';
 
+/**
+ * The SchemaRowBox renders a doc as a row of cells, with each cell representing
+ * one field value of the doc. It mostly handles communication from the SchemaView 
+ * to each SchemaCell, passing down necessary functions are props.
+ */
+
 interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
 }
@@ -51,10 +57,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         return this.schemaView.Document;
     }
 
-    @computed get rowIndex() {
-        return this.schemaView?.rowIndex(this.Document) ?? -1;
-    }
-
     componentDidMount(): void {
         this._props.setContentViewBox?.(this);
     }
@@ -164,7 +166,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                             selectReference={this.selectReference}
                             refSelectModeInfo={this.schemaView._referenceSelectMode}
                             eqHighlightFunc={this.eqHighlightFunc}
-                            equationHighlightRef={this.schemaView._cellHighlightColors}
                             highlightCells={this.highlightCells}
                             isolatedSelection={this.isolatedSelection}
                             key={key}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e2a05da7f..1bca3c84d 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -30,12 +30,17 @@ import { Colors } from '../../global/globalEnums';
 import { DocumentView } from '../../nodes/DocumentView';
 import { FieldViewProps } from '../../nodes/FieldView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
-import { CollectionSchemaView, FInfotoColType } from './CollectionSchemaView';
+import { FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
-import { ContextMenu } from '../../ContextMenu';
 import { SchemaCellField } from './SchemaCellField';
 
+/**
+ * SchemaTableCells make up the majority of the visual representation of the SchemaView.
+ * They are rendered for each cell in the SchemaView, and each represents one field value
+ * of a doc. Editing the content of the cell changes the corresponding doc's field value. 
+ */
+
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
@@ -62,7 +67,6 @@ export interface SchemaTableCellProps {
     rowSelected: () => boolean;
     isolatedSelection: (doc: Doc) => [boolean, boolean];
     highlightCells: (text: string) => void;
-    equationHighlightRef: ObservableMap<HTMLDivElement, string>;
     eqHighlightFunc: (text: string) => HTMLDivElement[] | [];
     refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
     selectReference: (doc: Doc, col: number) => void;
@@ -143,11 +147,6 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
         return { color, textDecoration, fieldProps, cursor, pointerEvents };
     }
 
-    // @action
-    // appendTextToField = (text: string) => {
-    //     this._fieldRef?.appendText(text);
-    // }
-        
     adjustSelfReference = (field: string) => {
         const modField = field.replace(/\bthis.\b/g, `d${this.docIndex}.`);
         return modField;
-- 
cgit v1.2.3-70-g09d2


From cf45abf8ada938caddb226c825166d4acdee3086 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 29 Sep 2024 19:55:40 -0400
Subject: linting

---
 .../collectionSchema/CollectionSchemaView.tsx      | 56 +++++++++-------------
 .../collectionSchema/SchemaCellField.tsx           |  4 +-
 .../collectionSchema/SchemaColumnHeader.tsx        |  6 +--
 .../collections/collectionSchema/SchemaRowBox.tsx  | 29 +++++------
 .../collectionSchema/SchemaTableCell.tsx           |  8 +---
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      |  4 ++
 6 files changed, 44 insertions(+), 63 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 11a4e88f9..51b3e1532 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -7,16 +7,15 @@ import * as React from 'react';
 import { ClientUtils, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils';
 import { emptyFunction } from '../../../../Utils';
 import { Doc, DocListCast, Field, FieldType, IdToDoc, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
-import { AclPrivate, DocData } from '../../../../fields/DocSymbols';
+import { DocData } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { ColumnType } from '../../../../fields/SchemaHeaderField';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, NumCast, StrCast } from '../../../../fields/Types';
 import { DocUtils } from '../../../documents/DocUtils';
 import { Docs, DocumentOptions, FInfo } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { dropActionType } from '../../../util/DropActionTypes';
-import { SettingsManager } from '../../../util/SettingsManager';
 import { undoBatch, undoable } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { EditableView } from '../../EditableView';
@@ -31,20 +30,9 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { ActionButton } from '@adobe/react-spectrum';
-import { CollectionMasonryViewFieldRow } from '../CollectionMasonryViewFieldRow';
-import { Func } from 'mocha';
-import { CollectionView } from '../CollectionView';
-import { listSpec } from '../../../../fields/Schema';
-import { GetEffectiveAcl } from '../../../../fields/util';
 import { ContextMenuProps } from '../../ContextMenuItem';
-import { truncate } from 'lodash';
 import { DocumentManager } from '../../../util/DocumentManager';
-import { TbHemispherePlus } from 'react-icons/tb';
-import { docs_v1 } from 'googleapis';
 import { SchemaCellField } from './SchemaCellField';
-import { threadId } from 'worker_threads';
-import { FontIconBox } from '../../nodes/FontIconBox/FontIconBox';
 import { SnappingManager } from '../../../util/SnappingManager';
 
 /**
@@ -458,7 +446,7 @@ export class CollectionSchemaView extends CollectionSubView() {
      * @returns column index
      */
     findColDropIndex = (mouseX: number) => {
-        let xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0,0)[0] + CollectionSchemaView._rowMenuWidth; 
+        const xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0,0)[0] + CollectionSchemaView._rowMenuWidth; 
         let index: number | undefined;
         this.displayColumnWidths.reduce((total, curr, i) => {
             if (total <= mouseX && total + curr >= mouseX) {
@@ -562,7 +550,7 @@ export class CollectionSchemaView extends CollectionSubView() {
      */
     highlightSortedColumn = (field?: string, descending?: boolean) => {
         let index = -1;
-        let highlightColors: string[] = [];
+        const highlightColors: string[] = [];
         const rowCount: number = this._containedDocs.length + 1;
         if (field || this.sortField){
             index = this.columnKeys.indexOf(field || this.sortField);
@@ -1169,20 +1157,20 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     /**
-     * Gets docs contained by collections within the schema
+     * Gets docs contained by collections within the schema. Currently defunct.
      * @param doc 
      * @param displayed 
      * @returns 
      */
-    subCollectionDocs = (doc: Doc, displayed: boolean) => {
-        const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]);
-        let collections: Array<Doc> = [];
-        if (displayed) collections = childDocs.filter(d => d.type === 'collection' && d._childrenSharedWithSchema);
-        else collections = childDocs.filter(d => d.type === 'collection' && !d._childrenSharedWithSchema);
-        let toReturn: Doc[] = [...childDocs];
-        collections.forEach(d => toReturn = toReturn.concat(this.subCollectionDocs(d, displayed)));
-        return toReturn;
-    }
+    // subCollectionDocs = (doc: Doc, displayed: boolean) => {
+    //     const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]);
+    //     let collections: Array<Doc> = [];
+    //     if (displayed) collections = childDocs.filter(d => d.type === 'collection' && d._childrenSharedWithSchema);
+    //     else collections = childDocs.filter(d => d.type === 'collection' && !d._childrenSharedWithSchema);
+    //     let toReturn: Doc[] = [...childDocs];
+    //     collections.forEach(d => toReturn = toReturn.concat(this.subCollectionDocs(d, displayed)));
+    //     return toReturn;
+    // }
 
     /**
      * Applies any filters active on the schema to filter out docs that don't match.
@@ -1234,16 +1222,16 @@ export class CollectionSchemaView extends CollectionSubView() {
      * Returns all child docs of the schema and child docs of contained collections that satisfy applied filters.
      */
     @computed get docs() {
-        let docsFromChildren: Doc[] = [];
+        //let docsFromChildren: Doc[] = [];
 
-        const displayedCollections = this.childDocs.filter(d => d.type === 'collection' && d._childrenSharedWithSchema);
-        displayedCollections.forEach(d => {
-            let docsNotAlreadyDisplayed = this.subCollectionDocs(d, true).filter(dc => !this._containedDocs.includes(dc));
-            docsFromChildren = docsFromChildren.concat(docsNotAlreadyDisplayed);
-        });
-        let docs = this.filteredDocs;
+        // Functionality for adding child docs
+        //const displayedCollections = this.childDocs.filter(d => d.type === 'collection' && d._childrenSharedWithSchema);
+        // displayedCollections.forEach(d => {
+        //     let docsNotAlreadyDisplayed = this.subCollectionDocs(d, true).filter(dc => !this._containedDocs.includes(dc));
+        //     docsFromChildren = docsFromChildren.concat(docsNotAlreadyDisplayed);
+        // });
 
-        return docs;
+        return this.filteredDocs;;
     }
 
     /**
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 72dcc00e6..065544ac9 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -148,10 +148,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             }
         }
 
-        let matchNum = 0;
         matches.forEach((match: string) => {
             chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
-            ++matchNum;
         })
 
         return chunkedText;
@@ -365,7 +363,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             className='schemaField-editing'
             ref={r => { this._inputref = r; }}
             style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
-            onBlur={e => {this._props.refSelectModeInfo.enabled ? setTimeout(() => {this.setIsFocused(true)}, 1000) : this.finalizeEdit(false, true, false)}}
+            onBlur={() => {this._props.refSelectModeInfo.enabled ? setTimeout(() => {this.setIsFocused(true)}, 1000) : this.finalizeEdit(false, true, false)}}
             autoFocus
             onInput={this.onChange}
             onKeyDown={this.onKeyDown}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 3495c5ab4..cf4fe4ef4 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -147,7 +147,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                         this._altTitle = undefined;
                         this._props.finishEdit?.();
                         return true;
-                    } else if (enterKey) this.updateAlt(value);
+                    }
                     this._props.finishEdit?.(); 
                     return true;
                 }, 'edit column header')}
@@ -157,7 +157,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
 
     public static isDefaultField = (key: string) => {
         const defaultPattern = /EmptyColumnKey/;
-        let isDefault: boolean = (defaultPattern.exec(key) != null);
+        const isDefault: boolean = (defaultPattern.exec(key) != null);
         return isDefault;
     }
 
@@ -220,7 +220,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                         setupMoveUpEvents(
                             this,
                             e,
-                            e => {return this._inputRef?.setIsEditing(false) ?? false},
+                            () => {return this._inputRef?.setIsEditing(false) ?? false},
                             emptyFunction,
                             emptyFunction,
                             );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index b928a5c67..a8a4ef2c2 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -3,27 +3,21 @@ import { computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
-import { CgClose, CgLock, CgLockUnlock, CgMenu } from 'react-icons/cg';
-import { FaExternalLinkAlt } from 'react-icons/fa';
 import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
 import { emptyFunction } from '../../../../Utils';
-import { Doc, DocListCast, FieldResult } from '../../../../fields/Doc';
+import { Doc } from '../../../../fields/Doc';
 import { BoolCast } from '../../../../fields/Types';
 import { Transform } from '../../../util/Transform';
 import { undoable } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
-import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { OpenWhere } from '../../nodes/OpenWhere';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { ContextMenu } from '../../ContextMenu';
-import { CollectionFreeFormView } from '../collectionFreeForm';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { infoState } from '../collectionFreeForm/CollectionFreeFormInfoState';
-import { TbShieldX } from 'react-icons/tb';
 
 /**
  * The SchemaRowBox renders a doc as a row of cells, with each cell representing
@@ -78,16 +72,17 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             event: () => this.schemaView.removeDoc(this.Document),
             icon: 'minus',
         });
-        const childDocs = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)])
-        if (this.Document.type === 'collection' && childDocs.length) {
-                ContextMenu.Instance.addItem({
-                description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema',
-                event: () => {
-                    this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema; 
-                },
-                icon: this.Document._childrenSharedWithSchema ? 'minus' : 'plus',
-            });
-        }
+        // Defunct option to add child docs of collections to the main schema
+        // const childDocs = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)])
+        // if (this.Document.type === 'collection' && childDocs.length) {
+        //         ContextMenu.Instance.addItem({
+        //         description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema',
+        //         event: () => {
+        //             this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema; 
+        //         },
+        //         icon: this.Document._childrenSharedWithSchema ? 'minus' : 'plus',
+        //     });
+        // }
         ContextMenu.Instance.displayMenu(x, y, undefined, false);
     }
 
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1bca3c84d..247739fd2 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -3,7 +3,7 @@
 /* eslint-disable no-use-before-define */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Popup, Size, Type } from 'browndash-components';
-import { ObservableMap, action, computed, makeObservable, observable } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
 import * as React from 'react';
@@ -161,14 +161,10 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
 
         const idPattern = /idToDoc\((.*?)\)/g;
         let matches;
-        let results = new Array<[id: string, func: string]>();
+        const results = new Array<[id: string, func: string]>();
         while ((matches = idPattern.exec(field)) !== null) {results.push([matches[0], matches[1].replace(/"/g, '')]); }
         results.forEach((idFuncPair) => {modField = modField.replace(idFuncPair[0], 'd' + (DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1]))).toString());})
 
-        for (let i = 0; i < modField.length; ++i){
-            
-        }
-
         if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1);
 
         const inQuotes = (field: string) => {return ((field.startsWith('`') && field.endsWith('`')) || (field.startsWith("'") && field.endsWith("'")) || (field.startsWith('"') && field.endsWith('"')))}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index bb9ea7e17..5d5c35dce 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -2181,4 +2181,8 @@ export class TemplateLayouts {
 //         }]
 //     };
 
+}
+
+export class ContentField extends Field {
+    
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 431a03690ed131e4bb925cec465d91adfb0d9421 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 30 Sep 2024 18:26:59 -0400
Subject: fixed so that you can't set the author field from the schema view.
 fixed schema view to not trigger cell updates after cells have been unmounted
 (e.g, so that dragging a tab over a schema vew doesn't crash)

---
 .../collectionSchema/SchemaCellField.tsx           |  190 +-
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 2115 +++++++++++---------
 2 files changed, 1226 insertions(+), 1079 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 065544ac9..e26dd9646 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -1,22 +1,22 @@
-import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from "mobx";
-import { ObservableReactComponent } from "../../ObservableReactComponent";
-import { observer } from "mobx-react";
-import { OverlayView } from "../../OverlayView";
-import { DocumentIconContainer } from "../../nodes/DocumentIcon";
-import React, { FormEvent } from "react";
-import { FieldView, FieldViewProps } from "../../nodes/FieldView";
-import { ObjectField } from "../../../../fields/ObjectField";
-import { Doc } from "../../../../fields/Doc";
-import { DocumentView } from "../../nodes/DocumentView";
+import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { ObservableReactComponent } from '../../ObservableReactComponent';
+import { observer } from 'mobx-react';
+import { OverlayView } from '../../OverlayView';
+import { DocumentIconContainer } from '../../nodes/DocumentIcon';
+import React, { FormEvent } from 'react';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { ObjectField } from '../../../../fields/ObjectField';
+import { Doc } from '../../../../fields/Doc';
+import { DocumentView } from '../../nodes/DocumentView';
 
 /**
  * The SchemaCellField renders text in schema cells while the user is editing, and updates the
  * contents of the field based on user input. It handles some cell-side logic for equations, such
  * as how equations are broken up within the text.
- * 
- * The current implementation parses innerHTML to create spans based on the text in the cell. 
+ *
+ * The current implementation parses innerHTML to create spans based on the text in the cell.
  * A more robust/safer approach would directly add elements in the react structure, but this
- * has been challenging to implement.  
+ * has been challenging to implement.
  */
 
 export interface SchemaCellFieldProps {
@@ -26,7 +26,7 @@ export interface SchemaCellFieldProps {
     oneLine?: boolean;
     Document: Doc;
     fieldKey: string;
-    refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
+    refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined };
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
     SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
@@ -35,7 +35,6 @@ export interface SchemaCellFieldProps {
 
 @observer
 export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldProps> {
-
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _inputref: HTMLDivElement | null = null;
     private _unrenderedContent: string = '';
@@ -48,7 +47,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     constructor(props: SchemaCellFieldProps) {
         super(props);
         makeObservable(this);
-        setTimeout(() => { 
+        setTimeout(() => {
             this._unrenderedContent = this._props.GetValue() ?? '';
             this.setContent(this._unrenderedContent);
         }); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function
@@ -56,9 +55,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
 
     get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore
 
-    get selfRefPattern() {return `d${this.docIndex}.${this._props.fieldKey}`};
+    get selfRefPattern() {
+        return `d${this.docIndex}.${this._props.fieldKey}`;
+    }
 
-    @computed get lastCharBeforeCursor(){
+    @computed get lastCharBeforeCursor() {
         const pos = this.cursorPosition;
         const content = this._unrenderedContent;
         const text = this._unrenderedContent.substring(0, pos ?? content.length);
@@ -90,7 +91,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                             this._props.highlightCells?.(this._unrenderedContent);
                             this.setContent(this._unrenderedContent);
                             setTimeout(() => this.setCursorPosition(this._unrenderedContent.length));
-                        } 
+                        }
                     });
                 } else {
                     this._overlayDisposer?.();
@@ -104,10 +105,11 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         this._disposers.fieldUpdate = reaction(
             () => this._props.GetValue(),
             fieldVal => {
+                console.log('Update: ' + this._props.Document.title, this._props.fieldKey, fieldVal);
                 this._unrenderedContent = fieldVal ?? '';
                 this.finalizeEdit(false, false, false);
             }
-        )
+        );
     }
 
     componentDidUpdate(prevProps: Readonly<SchemaCellFieldProps>) {
@@ -120,7 +122,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             });
     }
 
+    _unmounted = false;
     componentWillUnmount(): void {
+        this._unmounted = true;
+        console.log('Unmount: ' + this._props.Document.title, this._props.fieldKey);
         this._overlayDisposer?.();
         Object.values(this._disposers).forEach(disposer => disposer?.());
         this.finalizeEdit(false, true, false);
@@ -129,7 +134,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     generateSpan = (text: string, cell: HTMLDivElement | undefined) => {
         const selfRef = text === this.selfRefPattern;
         return `<span style="text-decoration: ${selfRef ? 'underline' : 'none'}; text-decoration-color: red; color: ${selfRef ? 'gray' : cell?.style.borderTop.replace('2px solid', '')}">${text}</span>`;
-    }
+    };
 
     makeSpans = (content: string) => {
         let chunkedText = content;
@@ -144,28 +149,28 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             const cell = this._props.getCells(match[0]);
             if (cell.length) {
                 matches.push(match[0]);
-                cells.set(match[0], cell[0])
+                cells.set(match[0], cell[0]);
             }
         }
 
         matches.forEach((match: string) => {
             chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
-        })
+        });
 
         return chunkedText;
-    }
+    };
 
     /**
-     * Sets the rendered content of the cell to save user inputs. 
+     * Sets the rendered content of the cell to save user inputs.
      * @param content the content to set
      * @param restoreCursorPos whether the cursor should be set back to where it was rather than the 0th index; should usually be true
      */
-    @action 
+    @action
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
         this._displayedContent = this.makeSpans(content);
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
-    }
+    };
 
     //Called from schemaview when a cell is selected to add a reference to the equation
     /**
@@ -181,7 +186,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         const newText = atPos ? content.slice(0, robustPos) + text + content.slice(cursorPos ?? content.length) : this._unrenderedContent.concat(text);
         this.onChange(undefined, newText);
         setTimeout(() => this.setCursorPosition(robustPos + text.length));
-    }
+    };
 
     @action
     setIsFocused = (value: boolean) => {
@@ -195,32 +200,31 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
      */
     get cursorPosition() {
         const selection = window.getSelection();
-        if (!selection || selection.rangeCount === 0 || !this._inputref) return null; 
-    
+        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; 
+        return adjRange.toString().length;
     }
 
-
     setCursorPosition = (position: number | null) => {
         const selection = window.getSelection();
-        if (!selection || position === null || !this._inputref) return; 
-    
+        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.nodeType === Node.TEXT_NODE) {
                     if (!node.textContent) return;
                     const nextPos = currentPos + node.textContent.length;
                     if (position <= nextPos) {
@@ -231,11 +235,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                         return true;
                     }
                     currentPos = nextPos;
-
-                } else if ((node.nodeType === Node.ELEMENT_NODE) && (setRange(node.childNodes))) return true;
+                } else if (node.nodeType === Node.ELEMENT_NODE && setRange(node.childNodes)) return true;
             }
             return false;
-        }
+        };
 
         setRange(this._inputref.childNodes);
     };
@@ -265,7 +268,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
         const properties = this._props.refSelectModeInfo;
         properties.enabled = enabled;
         properties.currEditing = enabled ? this : undefined;
-    }
+    };
 
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
@@ -289,9 +292,12 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 e.stopPropagation();
                 this._editing = false;
                 break;
-            case 'ArrowUp': case 'ArrowDown': case 'ArrowLeft': case 'ArrowRight': // prettier-ignore
+            case 'ArrowUp':
+            case 'ArrowDown':
+            case 'ArrowLeft':
+            case 'ArrowRight': // prettier-ignore
                 e.stopPropagation();
-                setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0)
+                setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0);
                 break;
             case ' ':
                 e.stopPropagation();
@@ -300,13 +306,16 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 setTimeout(() => {
                     this.setContent(this._unrenderedContent);
                     setTimeout(() => this.setCursorPosition(cursorPos));
-                }
-                , 0);
+                }, 0);
                 break;
             case 'u': // for some reason 'u' otherwise exits the editor
                 e.stopPropagation();
                 break;
-            case 'Shift': case 'Alt': case 'Meta': case 'Control': case ':': // prettier-ignore
+            case 'Shift':
+            case 'Alt':
+            case 'Meta':
+            case 'Control':
+            case ':': // prettier-ignore
                 break;
             // eslint-disable-next-line no-fallthrough
             default:
@@ -323,66 +332,63 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     };
 
     @action
-    finalizeEdit(shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
+    finalizeEdit = (shiftDown: boolean, lostFocus: boolean, enterKey: boolean) => {
+        if (this._unmounted) {
+            return;
+        }
         if (this._unrenderedContent.replace(this.selfRefPattern, '') !== this._unrenderedContent) {
-            this._dependencyMessageShown ? this._dependencyMessageShown = false :
-            alert(`Circular dependency detected. Please update the field at ${this.selfRefPattern}.`)
+            if (this._dependencyMessageShown) {
+                this._dependencyMessageShown = false;
+            } else alert(`Circular dependency detected. Please update the field at ${this.selfRefPattern}.`);
             this._dependencyMessageShown = true;
             return;
         }
 
         this.setContent(this._unrenderedContent);
-        
-        if (this._props.SetValue(this._unrenderedContent, shiftDown, enterKey)) {
-            this._editing = false;
-        } else {
-            this._editing = false;
-            !lostFocus &&
-                setTimeout(
-                    action(() => {
-                        this._editing = true;
-                    }),
-                    0
-                );
+
+        if (!this._props.SetValue(this._unrenderedContent, shiftDown, enterKey) && !lostFocus) {
+            setTimeout(action(() => (this._editing = true)));
         }
-    }
+        this._editing = false;
+    };
 
     staticDisplay = () => {
-        return <span className='editableView-static'>
-        {
-            // eslint-disable-next-line react/jsx-props-no-spreading
-            this._props.fieldContents ?  <FieldView {...this._props.fieldContents}/> : ''
-        }
-        </span>
-    }
+        return <span className="editableView-static">{this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : ''}</span>;
+    };
 
     renderEditor = () => {
         return (
-            <div 
-            contentEditable
-            className='schemaField-editing'
-            ref={r => { this._inputref = r; }}
-            style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, }}
-            onBlur={() => {this._props.refSelectModeInfo.enabled ? setTimeout(() => {this.setIsFocused(true)}, 1000) : this.finalizeEdit(false, true, false)}}
-            autoFocus
-            onInput={this.onChange}
-            onKeyDown={this.onKeyDown}
-            onPointerDown={e => {e.stopPropagation(); setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0)}} //timeout callback ensures that refSelectMode is properly set
-            onClick={e => e.stopPropagation}
-            onPointerUp={e => e.stopPropagation}
-            onPointerMove={e => {e.stopPropagation(); e.preventDefault()}}
-            dangerouslySetInnerHTML={{ __html: this._displayedContent }}
-            >
-            </div>
+            <div
+                contentEditable
+                className="schemaField-editing"
+                ref={r => {
+                    this._inputref = r;
+                }}
+                style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20 }}
+                onBlur={() => (this._props.refSelectModeInfo.enabled ? setTimeout(() => this.setIsFocused(true), 1000) : this.finalizeEdit(false, true, false))}
+                autoFocus
+                onInput={this.onChange}
+                onKeyDown={this.onKeyDown}
+                onPointerDown={e => {
+                    e.stopPropagation();
+                    setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0);
+                }} //timeout callback ensures that refSelectMode is properly set
+                onClick={e => e.stopPropagation}
+                onPointerUp={e => e.stopPropagation}
+                onPointerMove={e => {
+                    e.stopPropagation();
+                    e.preventDefault();
+                }}
+                dangerouslySetInnerHTML={{ __html: this._displayedContent }}></div>
         );
-    }
+    };
 
     render() {
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
-        if ((this._editing && gval !== undefined)) {
+        if (this._editing && gval !== undefined) {
             return <div className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`}>{this.renderEditor()}</div>;
-        } else return (
-            this._props.contents instanceof ObjectField ? null : (
+        } else
+            return this._props.contents instanceof ObjectField ? null : (
                 <div
                     className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`}
                     style={{
@@ -393,8 +399,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                     onClick={this.onClick}>
                     {this.staticDisplay()}
                 </div>
-            )
-        );
+            );
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 5d5c35dce..32aded9de 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -1,50 +1,42 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { Colors } from 'browndash-components';
+import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
+import { IDisposer } from 'mobx-utils';
 import * as React from 'react';
-import { ClientUtils, returnAll, returnFalse, returnNone, returnOne, returnZero, setupMoveUpEvents } from '../../../../ClientUtils';
+import ReactLoading from 'react-loading';
+import { ClientUtils, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
+import { emptyFunction } from '../../../../Utils';
 import { Doc, NumListCast, StrListCast } from '../../../../fields/Doc';
-import { DocCast, ImageCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { Id } from '../../../../fields/FieldSymbols';
+import { DocCast, ImageCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction } from '../../../../Utils';
+import { Networking } from '../../../Network';
+import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
+import { Docs } from '../../../documents/Documents';
+import { DragManager } from '../../../util/DragManager';
+import { MakeTemplate } from '../../../util/DropConverter';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { UndoManager, undoable } from '../../../util/UndoManager';
+import { LightboxView } from '../../LightboxView';
 import { ObservableReactComponent } from '../../ObservableReactComponent';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
 import { DocumentView, DocumentViewInternal } from '../DocumentView';
+import { FieldViewProps } from '../FieldView';
+import { OpenWhere } from '../OpenWhere';
 import { DataVizBox } from './DataVizBox';
 import './DocCreatorMenu.scss';
-import { Id } from '../../../../fields/FieldSymbols';
-import { Colors, IconButton, Size } from 'browndash-components';
-import { MakeTemplate } from '../../../util/DropConverter';
-import { DragManager } from '../../../util/DragManager';
-import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
-import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
-import { Docs } from '../../../documents/Documents';
-import { OpenWhere } from '../OpenWhere';
-import { IDisposer } from 'mobx-utils';
-import { LightboxView } from '../../LightboxView';
-import ReactLoading from 'react-loading';
-import { CollectionStackingView } from '../../collections/CollectionStackingView';
-import { FieldViewProps } from '../FieldView';
-import { CollectionViewType } from '../../../documents/DocumentTypes';
-import { dropActionType } from '../../../util/DropActionTypes';
-import { ImageBox } from '../ImageBox';
-import { a } from '@react-spring/web';
-import { RichTextMenu } from '../formattedText/RichTextMenu';
-import e from 'cors';
-import { Networking } from '../../../Network';
 
 export enum LayoutType {
-    Stacked = 'stacked', 
-    Grid = 'grid', 
-    Row = 'row', 
-    Column = 'column', 
-    Custom = 'custom'
+    Stacked = 'stacked',
+    Grid = 'grid',
+    Row = 'row',
+    Column = 'column',
+    Custom = 'custom',
 }
 
 @observer
 export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
-
     static Instance: DocCreatorMenu;
 
     private _disposers: { [name: string]: IDisposer } = {};
@@ -54,13 +46,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _templateDocs: Doc[] = [];
     @observable _selectedTemplate: Doc | undefined = undefined;
     @observable _columns: Col[] = [];
-    @observable _selectedCols: {title: string, type: string, desc: string}[] | undefined = [];
+    @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
-    @observable _layout: {type: LayoutType, yMargin: number, xMargin: number, columns?: number, repeat: number} = {type: LayoutType.Grid, yMargin: 0, xMargin: 0, repeat: 0};
+    @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.Grid, yMargin: 0, xMargin: 0, repeat: 0 };
     @observable _layoutPreview: boolean = true;
     @observable _layoutPreviewScale: number = 1;
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
-    @observable _expandedPreview: {icon: ImageField, doc: Doc} | undefined = undefined;
+    @observable _expandedPreview: { icon: ImageField; doc: Doc } | undefined = undefined;
 
     @observable _suggestedTemplates: Doc[] = [];
     @observable _GPTOpt: boolean = false;
@@ -76,7 +68,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _hoveredLayoutPreview: number | undefined = undefined;
     @observable _mouseX: number = -1;
     @observable _mouseY: number = -1;
-    @observable _startPos?: {x: number, y: number};
+    @observable _startPos?: { x: number; y: number };
     @observable _shouldDisplay: boolean = false;
 
     @observable _menuContent: 'templates' | 'options' | 'saved' | 'dashboard' = 'templates';
@@ -87,10 +79,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _snapPt: any;
     @observable _resizeHdlId: string = '';
     @observable _resizing: boolean = false;
-    @observable _offset: {x: number, y: number} = {x: 0, y: 0};
+    @observable _offset: { x: number; y: number } = { x: 0, y: 0 };
     @observable _resizeUndo: UndoManager.Batch | undefined = undefined;
-    @observable _initDimensions: {width: number, height: number, x?: number, y?: number} = {width: 300, height: 400, x: undefined, y: undefined};
-    @observable _menuDimensions: {width: number, height: number} = {width: 400, height: 400};
+    @observable _initDimensions: { width: number; height: number; x?: number; y?: number } = { width: 300, height: 400, x: undefined, y: undefined };
+    @observable _menuDimensions: { width: number; height: number } = { width: 400, height: 400 };
     @observable _editing: boolean = false;
 
     constructor(props: any) {
@@ -100,32 +92,40 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         //setTimeout(() => this.generateTemplates(''));
     }
 
-    @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz };
-    @action setTemplateDocs = (docs: Doc[]) => {this._templateDocs = docs.map(doc => doc.annotationOn ? DocCast(doc.annotationOn):doc)};
-    @action setGSuggestedTemplates = (docs: Doc[]) => {this._suggestedTemplates = docs};
+    @action setDataViz = (dataViz: DataVizBox) => {
+        this._dataViz = dataViz;
+    };
+    @action setTemplateDocs = (docs: Doc[]) => {
+        this._templateDocs = docs.map(doc => (doc.annotationOn ? DocCast(doc.annotationOn) : doc));
+    };
+    @action setGSuggestedTemplates = (docs: Doc[]) => {
+        this._suggestedTemplates = docs;
+    };
 
     @computed get docsToRender() {
         return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
     }
 
-    @computed get rowsCount(){
+    @computed get rowsCount() {
         switch (this._layout.type) {
-            case LayoutType.Row: case LayoutType.Stacked: 
+            case LayoutType.Row:
+            case LayoutType.Stacked:
                 return 1;
             case LayoutType.Column:
                 return this.docsToRender.length;
             case LayoutType.Grid:
                 return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0;
-            default: 
+            default:
                 return 0;
         }
     }
 
-    @computed get columnsCount(){
+    @computed get columnsCount() {
         switch (this._layout.type) {
             case LayoutType.Row:
                 return this.docsToRender.length;
-            case LayoutType.Column: case LayoutType.Stacked: 
+            case LayoutType.Column:
+            case LayoutType.Stacked:
                 return 1;
             case LayoutType.Grid:
                 return this._layout.columns ?? 0;
@@ -140,31 +140,33 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @computed get fieldsInfos(): Col[] {
         const colInfo = this._dataViz?.colsInfo;
-        return this.selectedFields.map(field => {
-            const fieldInfo = colInfo?.get(field);
-
-            const col: Col = {
-                title: field,
-                type: fieldInfo?.type ?? TemplateFieldType.UNSET,
-                desc: fieldInfo?.desc ?? '',
-                sizes: fieldInfo?.sizes ?? [TemplateFieldSize.MEDIUM]
-            };
-
-            if (fieldInfo?.defaultContent !== undefined) {
-                col.defaultContent = fieldInfo.defaultContent;
-            }
+        return this.selectedFields
+            .map(field => {
+                const fieldInfo = colInfo?.get(field);
+
+                const col: Col = {
+                    title: field,
+                    type: fieldInfo?.type ?? TemplateFieldType.UNSET,
+                    desc: fieldInfo?.desc ?? '',
+                    sizes: fieldInfo?.sizes ?? [TemplateFieldSize.MEDIUM],
+                };
+
+                if (fieldInfo?.defaultContent !== undefined) {
+                    col.defaultContent = fieldInfo.defaultContent;
+                }
 
-            return col;
-        }).concat(this._columns);
+                return col;
+            })
+            .concat(this._columns);
     }
 
-    @computed get canMakeDocs(){
+    @computed get canMakeDocs() {
         return this._selectedTemplate !== undefined && this._layout !== undefined;
     }
 
-    get bounds(): {t: number, b: number, l: number, r: number} {
+    get bounds(): { t: number; b: number; l: number; r: number } {
         const rect = this._ref?.getBoundingClientRect();
-        const bounds = {t: rect?.top ?? 0, b: rect?.bottom ?? 0, l: rect?.left ?? 0, r: rect?.right ?? 0};
+        const bounds = { t: rect?.top ?? 0, b: rect?.bottom ?? 0, l: rect?.left ?? 0, r: rect?.right ?? 0 };
         return bounds;
     }
 
@@ -179,8 +181,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 clickEv.preventDefault();
                 func();
             }, 'create docs')
-        )
-    }
+        );
+    };
 
     @action
     onPointerDown = (e: PointerEvent) => {
@@ -214,10 +216,21 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     componentDidMount() {
         document.addEventListener('pointerdown', this.onPointerDown, true);
         document.addEventListener('pointerup', this.onPointerUp);
-        this._disposers.templates = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon));
-        this._disposers.gpt = reaction(() => this._suggestedTemplates.slice(), (docs) => docs.map(this.getIcon));
+        this._disposers.templates = reaction(
+            () => this._templateDocs.slice(),
+            docs => docs.map(this.getIcon)
+        );
+        this._disposers.gpt = reaction(
+            () => this._suggestedTemplates.slice(),
+            docs => docs.map(this.getIcon)
+        );
         //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
-        this._disposers.lightbox = reaction(() => LightboxView.LightboxDoc(), doc => { doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu()});
+        this._disposers.lightbox = reaction(
+            () => LightboxView.LightboxDoc(),
+            doc => {
+                doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu();
+            }
+        );
         //this._disposers.fields = reaction(() => this._dataViz?.axes, cols => this._selectedCols = cols?.map(col => { return {title: col, type: '', desc: ''}}))
     }
 
@@ -227,12 +240,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         document.removeEventListener('pointerup', this.onPointerUp);
     }
 
-    updateIcons = (docs: Doc[]) => { docs.map(this.getIcon) }
+    updateIcons = (docs: Doc[]) => {
+        docs.map(this.getIcon);
+    };
 
     @action
     updateSelectedCols = (cols: string[]) => {
-        this._selectedCols
-    }
+        this._selectedCols;
+    };
 
     @action
     toggleDisplay = (x: number, y: number) => {
@@ -246,10 +261,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     @action
-    closeMenu = () => { this._shouldDisplay = false };
+    closeMenu = () => {
+        this._shouldDisplay = false;
+    };
 
     @action
-    openMenu = () => { 
+    openMenu = () => {
         const allTemplates = this._templateDocs.concat(this._suggestedTemplates);
         this._shouldDisplay = true;
         this.updateIcons(allTemplates);
@@ -285,7 +302,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         await new Promise<any>(res => { setTimeout(() => { res(this._interactionLock = undefined)})});
         }); // prettier-ignore
         return true;
-    }
+    };
 
     @action
     onDrag = (e: any): boolean => {
@@ -294,12 +311,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._initDimensions.x = this._pageX;
         this._initDimensions.y = this._pageY;
         return true;
-    }
+    };
 
     getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => {
         const [w, h] = [this._initDimensions.width, this._initDimensions.height];
         const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y];
-        let vals: {scale: {x: number, y: number}, refPt: [number, number], transl: {x: number, y: number}};
+        let vals: { scale: { x: number; y: number }; refPt: [number, number]; transl: { x: number; y: number } };
         switch (dragHdl) {
             case 'topLeft':    vals = { scale: { x: 1 - moveX / w, y: 1 -moveY / h },  refPt: [this.bounds.r, this.bounds.b], transl: {x: moveX, y: moveY } }; break;
             case 'topRight':   vals = { scale: { x: 1 + moveX / w, y: 1 -moveY / h },  refPt: [this.bounds.l, this.bounds.b], transl: {x: 0, y: moveY } }; break;
@@ -314,11 +331,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return vals;
     };
 
-    resizeView = (refPt: number[], scale: { x: number; y: number }, translation: {x: number, y: number}) => {
-        const refCent = [refPt[0], refPt[1]] // fixed reference point for resize (ie, a point that doesn't move)
+    resizeView = (refPt: number[], scale: { x: number; y: number }, translation: { x: number; y: number }) => {
+        const refCent = [refPt[0], refPt[1]]; // fixed reference point for resize (ie, a point that doesn't move)
         if (this._initDimensions.x === undefined) this._initDimensions.x = this._pageX;
         if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY;
-        const {height, width, x, y} = this._initDimensions;
+        const { height, width, x, y } = this._initDimensions;
 
         this._menuDimensions.width = Math.max(300, scale.x * width);
         this._menuDimensions.height = Math.max(200, scale.y * height);
@@ -330,10 +347,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const docView = DocumentView.getDocumentView(doc);
         if (docView) {
             docView.ComponentView?.updateIcon?.();
-            return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500));;
+            return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500));
         }
         return undefined;
-    };
+    }
 
     @action updateSelectedTemplate = (template: Doc) => {
         if (this._selectedTemplate === template) {
@@ -353,10 +370,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     isSelectedLayout = (layout: DataVizTemplateLayout) => {
-        return this._layout.xMargin === layout.layout.xMargin
-        && this._layout.yMargin === layout.layout.yMargin 
-        && this._layout.type === layout.layout.type 
-        && this._layout.columns === layout.columns;
+        return this._layout.xMargin === layout.layout.xMargin && this._layout.yMargin === layout.layout.yMargin && this._layout.type === layout.layout.type && this._layout.columns === layout.columns;
     };
 
     @action
@@ -365,7 +379,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const origCount = this._callCount;
 
         let prompt: string = `(#${origCount}) Please generate for the fields:`;
-        this.selectedFields?.forEach(field => prompt += ` ${field},`)
+        this.selectedFields?.forEach(field => (prompt += ` ${field},`));
         prompt += ` (-----NOT A FIELD-----) Additional prompt: ${inputText}`;
 
         this._GPTLoading = true;
@@ -375,37 +389,43 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             if (res && this._callCount === origCount) {
                 this._suggestedTemplates = [];
-                const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
+                const templates: { template_type: string; fieldVals: { title: string; tlx: string; tly: string; brx: string; bry: string }[] }[] = JSON.parse(res);
                 this.createGeneratedTemplates(templates, 500, 500);
             }
         } catch (err) {
             console.error(err);
-        } 
+        }
     };
 
     @action
-    createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => { 
+    createGeneratedTemplates = (layouts: { template_type: string; fieldVals: { title: string; tlx: string; tly: string; brx: string; bry: string }[] }[], tempWidth: number, tempHeight: number) => {
         const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
         const GPTTemplates: Doc[] = [];
 
         layouts.forEach(layout => {
             const fields: Doc[] = layout.fieldVals.map(field => {
-                const left: number = Number(field.tlx) * tempWidth / 2;    const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore
-                const right: number = Number(field.brx) * tempWidth / 2;   const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore
-                const height = bottom - top; 
-                const width = right - left; 
-                const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/\$\$/g, ''), x: left, y: top });
+                const left: number = (Number(field.tlx) * tempWidth) / 2;
+                const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore
+                const right: number = (Number(field.brx) * tempWidth) / 2;
+                const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore
+                const height = bottom - top;
+                const width = right - left;
+                const doc = !field.title.includes('$$')
+                    ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height / 2}` })
+                    : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/\$\$/g, ''), x: left, y: top });
                 return doc;
             });
 
             const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400000, y: 400000 });
 
             mainCollection.addDocument(template);
-            
+
             GPTTemplates.push(template);
         });
 
-        setTimeout(() => {this.setGSuggestedTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100);
+        setTimeout(() => {
+            this.setGSuggestedTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/
+        }, 100);
 
         this.forceUpdate();
     };
@@ -421,9 +441,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._templateDocs.splice(this._templateDocs.indexOf(doc), 1);
     };
 
-
-
-    testTemplate = async() => { 
+    testTemplate = async () => {
         // const temp = TemplateLayouts.FourField001;
         // const title: Doc = FieldFuncs.TextField({tl: temp.fields[0].tl, br: temp.fields[0].br}, temp.height, temp.width, 'title', 'Title', {backgroundColor: 'transparent'});
         // const image: Doc = FieldFuncs.ImageField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.height, temp.width, 'title', '', {borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10, rotation: 40});
@@ -453,7 +471,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         try {
             const res = await gptImageCall('Image of panda eating a cookie');
 
-            if (res){
+            if (res) {
                 const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res });
 
                 console.log(result);
@@ -461,15 +479,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         } catch (e) {
             console.log(e);
         }
-        
     };
 
     @action addField = () => {
-        const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', sizes: []}])
+        const newFields: Col[] = this._columns.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]);
         this._columns = newFields;
     };
 
-    @action removeField = (field: {title: string, type: string, desc: string}) => {
+    @action removeField = (field: { title: string; type: string; desc: string }) => {
         if (this._dataViz?.axes.includes(field.title)) {
             this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title));
         } else {
@@ -483,11 +500,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             }
 
             if (this._columns.length === 1) {
-                this._columns = []  
+                this._columns = [];
             } else {
                 this._columns.splice(this._columns.indexOf(toRemove[0]), 1);
             }
-        }   
+        }
     };
 
     @action setColTitle = (column: Col, title: string) => {
@@ -530,13 +547,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this.forceUpdate();
     };
 
-    generateGPTImage = async(prompt: string): Promise<string | undefined> => {
-        console.log(prompt)
+    generateGPTImage = async (prompt: string): Promise<string | undefined> => {
+        console.log(prompt);
 
         try {
             const res = await gptImageCall(prompt);
 
-            if (res){
+            if (res) {
                 const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res });
                 const source = ClientUtils.prepend(result[0].accessPaths.agnostic.client);
                 return source;
@@ -544,12 +561,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         } catch (e) {
             console.log(e);
         }
-    }
+    };
 
     matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => {
-        const colMatchesField = (col: Col, field : Field) => { return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type) };
+        const colMatchesField = (col: Col, field: Field) => {
+            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
+        };
 
-        const matches: number[][] = Array(template.fields.length).fill([]).map(() => []);
+        const matches: number[][] = Array(template.fields.length)
+            .fill([])
+            .map(() => []);
 
         template.fields.forEach((field, i) => {
             cols.forEach((col, v) => {
@@ -576,8 +597,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 }
             }
             return false;
-        }
-    
+        };
+
         for (let v = 0; v < fieldsCt; ++v) {
             used.fill(false);
             augmentingPath(v);
@@ -592,7 +613,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return count;
     };
 
-
     findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
         let validTemplates: any[] = [];
         templates.forEach(template => {
@@ -602,7 +622,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             if (this.maxMatches(numFields, matches) === numFields) {
                 validTemplates.push(template.title);
             }
-        })
+        });
 
         validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
 
@@ -613,12 +633,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     //     if (field.subfields) {
     //         const doc = FieldFuncs.FreeformField({
-    //             tl: field.tl, 
-    //             br: field.br }, 
-    //             template.height, 
-    //             template.width, 
-    //             column.title, 
-    //             '', 
+    //             tl: field.tl,
+    //             br: field.br },
+    //             template.height,
+    //             template.width,
+    //             column.title,
+    //             '',
     //             field.opts
     //         );
 
@@ -634,10 +654,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     /**
      * Populates a preset template framework with content from a datavizbox or any AI-generated content.
      * @param template the preloaded template framework being filled in
-     * @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz 
+     * @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz
      * @returns a doc containing the fully rendered template
      */
-    fillPresetTemplate = async(template: TemplateDocInfos, assignments: {[field: string]: Col}): Promise<Doc> => {
+    fillPresetTemplate = async (template: TemplateDocInfos, assignments: { [field: string]: Col }): Promise<Doc> => {
         const wordLimit = (size: TemplateFieldSize) => {
             switch (size) {
                 case TemplateFieldSize.TINY:
@@ -650,44 +670,43 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     return 50;
                 case TemplateFieldSize.HUGE:
                     return 100;
-                default: 
+                default:
                     return 10;
             }
-        }
+        };
 
-        const renderTextCalls = async(): Promise<Doc[]> => {
+        const renderTextCalls = async (): Promise<Doc[]> => {
             const rendered: Doc[] = [];
 
             if (GPTTextCalls.length) {
-
                 try {
                     const prompt = fieldContent + GPTTextAssignment;
-    
+
                     const res = await gptAPICall(prompt, GPTCallType.FILL);
-    
-                    if (res){
-    
-                        const assignments: {[title: string]: {number: string, content: string}} = JSON.parse(res);
+
+                    if (res) {
+                        const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
                         //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
                         Object.entries(assignments).forEach(([title, info]) => {
                             const field: Field = template.fields[Number(info.number)];
                             const col = this.getColByTitle(title);
-    
-                            const doc = FieldUtils.TextField({
-                                tl: field.tl, 
-                                br: field.br }, 
-                                template.height, 
-                                template.width, 
-                                col.title, 
-                                info.content ?? '', 
+
+                            const doc = FieldUtils.TextField(
+                                {
+                                    tl: field.tl,
+                                    br: field.br,
+                                },
+                                template.height,
+                                template.width,
+                                col.title,
+                                info.content ?? '',
                                 field.opts
                             );
-    
+
                             rendered.push(doc);
                         });
-    
                     }
-                } catch(err) {
+                } catch (err) {
                     console.log(err);
                 }
             }
@@ -695,23 +714,25 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             return rendered;
         };
 
-        const createGeneratedImage = async(fieldNum: string, col: Col, prompt: string) => {
+        const createGeneratedImage = async (fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
             const field: Field = template.fields[Number(fieldNum)];
-            const doc = FieldUtils.ImageField({
-                tl: field.tl, 
-                br: field.br }, 
-                template.height, 
-                template.width, 
-                col.title, 
-                url ?? '', 
+            const doc = FieldUtils.ImageField(
+                {
+                    tl: field.tl,
+                    br: field.br,
+                },
+                template.height,
+                template.width,
+                col.title,
+                url ?? '',
                 field.opts
             );
 
             return doc;
-        }
+        };
 
-        const renderImageCalls = async(): Promise<Doc[]> => {
+        const renderImageCalls = async (): Promise<Doc[]> => {
             const rendered: Doc[] = [];
             const calls = GPTIMGCalls;
 
@@ -719,24 +740,28 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 try {
                     const renderedImages: Doc[] = await Promise.all(
                         calls.map(async ([fieldNum, col]) => {
-                            const sysPrompt = 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' + fieldContent + ' **** The user prompt is: ' + col.desc;
-                            
+                            const sysPrompt =
+                                'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
+                                fieldContent +
+                                ' **** The user prompt is: ' +
+                                col.desc;
+
                             const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
                             console.log(sysPrompt, prompt);
-                            
+
                             return createGeneratedImage(fieldNum, col, prompt);
                         })
                     );
-                
+
                     const renderedTemplates: Doc[] = await Promise.all(renderedImages);
                     renderedTemplates.forEach(doc => rendered.push(doc));
-                } catch (e){
+                } catch (e) {
                     console.log(e);
                 }
             }
 
             return rendered;
-        }
+        };
 
         const fields: Doc[] = [];
 
@@ -748,9 +773,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const stringifyGPTInfo = (calls: [string, Col][]): string => {
             let string: string = '*** COLUMN INFO:';
             calls.forEach(([fieldNum, col]) => {
-                string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`
+                string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`;
             });
-            return string += ' ***';
+            return (string += ' ***');
         };
 
         const GPTTextAssignment = stringifyGPTInfo(GPTTextCalls);
@@ -761,45 +786,49 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const field: Field = template.fields[Number(f)];
             const col = strCol[1];
 
-            const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)({
-                tl: field.tl, 
-                br: field.br }, 
-                template.height, 
-                template.width, 
-                col.title, 
-                col.defaultContent ?? '', 
+            const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)(
+                {
+                    tl: field.tl,
+                    br: field.br,
+                },
+                template.height,
+                template.width,
+                col.title,
+                col.defaultContent ?? '',
                 field.opts
             );
 
-            fieldContent += `--- Field #${f} (title: ${col.title}): ${col.defaultContent ?? ''} ---`
+            fieldContent += `--- Field #${f} (title: ${col.title}): ${col.defaultContent ?? ''} ---`;
 
             fields.push(doc);
         });
 
         template.decorations.forEach(dec => {
-            const doc = FieldUtils.FreeformField({
-                tl: dec.tl, 
-                br: dec.br }, 
-                template.height, 
-                template.width, 
-                '', 
-                '', 
-                dec.opts,
+            const doc = FieldUtils.FreeformField(
+                {
+                    tl: dec.tl,
+                    br: dec.br,
+                },
+                template.height,
+                template.width,
+                '',
+                '',
+                dec.opts
             );
 
             fields.push(doc);
         });
 
         const createMainDoc = (): Doc => {
-            const main = Docs.Create.FreeformDocument(fields, { 
-                _height: template.height, 
-                _width: template.width, 
-                title: template.title, 
+            const main = Docs.Create.FreeformDocument(fields, {
+                _height: template.height,
+                _width: template.width,
+                title: template.title,
                 backgroundColor: template.opts.backgroundColor,
-                _layout_borderRounding: `${template.opts.cornerRounding}px` ?? '0px', 
+                _layout_borderRounding: `${template.opts.cornerRounding}px` ?? '0px',
                 borderWidth: template.opts.borderWidth,
                 borderColor: template.opts.borderColor,
-                x: 40000, 
+                x: 40000,
                 y: 40000,
             });
 
@@ -807,40 +836,46 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             mainCollection.addDocument(main);
 
             return main;
-        }
+        };
 
         const textCalls = await renderTextCalls();
         const imageCalls = await renderImageCalls();
 
-        textCalls.forEach(doc => {fields.push(doc)});
-        imageCalls.forEach(doc => {fields.push(doc)});
+        textCalls.forEach(doc => {
+            fields.push(doc);
+        });
+        imageCalls.forEach(doc => {
+            fields.push(doc);
+        });
 
         return createMainDoc();
-    }
+    };
 
     compileFieldDescriptions = (templates: TemplateDocInfos[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
-            descriptions += `----------  NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `
+            descriptions += `----------  NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `;
             template.fields.forEach((field, index) => {
-                descriptions += `{Field #${index}: ${field.description}} `
+                descriptions += `{Field #${index}: ${field.description}} `;
             });
         });
 
         return descriptions;
     };
 
-    compileColDescriptions = (cols: Col[]): string =>  {
+    compileColDescriptions = (cols: Col[]): string => {
         let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:';
-        cols.forEach(col => descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `);
+        cols.forEach(col => (descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `));
 
         return descriptions;
     };
 
-    getColByTitle = (title: string) => { return this.fieldsInfos.filter(col => col.title === title)[0]; };
+    getColByTitle = (title: string) => {
+        return this.fieldsInfos.filter(col => col.title === title)[0];
+    };
 
     @action
-    assignColsToFields = async(templates: TemplateDocInfos[], cols: Col[]): Promise<[TemplateDocInfos, {[field: number]: Col}][]> => {
+    assignColsToFields = async (templates: TemplateDocInfos[], cols: Col[]): Promise<[TemplateDocInfos, { [field: number]: Col }][]> => {
         const fieldDescriptions: string = this.compileFieldDescriptions(templates);
         const colDescriptions: string = this.compileColDescriptions(cols);
 
@@ -857,24 +892,26 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
             if (res && this._callCount === origCount) {
-
-                const assignments: {[templateTitle: string]: {[field: string]: string}} = JSON.parse(res);
-                const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = [];
+                const assignments: { [templateTitle: string]: { [field: string]: string } } = JSON.parse(res);
+                const brokenDownAssignments: [TemplateDocInfos, { [field: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
                     const template = TemplateLayouts.getTemplateByTitle(tempTitle);
                     if (!template) return;
-                    const toObj = Object.entries(assignment).reduce((a, [fieldNum, colTitle]) => {
-                        a[Number(fieldNum)] = this.getColByTitle(colTitle);
-                        return a;
-                    }, {} as { [field: number]: Col }); 
-                    brokenDownAssignments.push([template, toObj])
-                })
+                    const toObj = Object.entries(assignment).reduce(
+                        (a, [fieldNum, colTitle]) => {
+                            a[Number(fieldNum)] = this.getColByTitle(colTitle);
+                            return a;
+                        },
+                        {} as { [field: number]: Col }
+                    );
+                    brokenDownAssignments.push([template, toObj]);
+                });
                 return brokenDownAssignments;
             }
         } catch (err) {
             console.error(err);
-        } 
+        }
 
         return [];
     };
@@ -884,178 +921,200 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const cols = this.fieldsInfos;
         const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates);
-        
+
         const assignments: [TemplateDocInfos, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
-        
-        const renderedTemplatePromises: Promise<Doc>[] = assignments.map(([template, assignments]) => 
-            this.fillPresetTemplate(template, assignments)
-        );
-    
+
+        const renderedTemplatePromises: Promise<Doc>[] = assignments.map(([template, assignments]) => this.fillPresetTemplate(template, assignments));
+
         const renderedTemplates: Doc[] = await Promise.all(renderedTemplatePromises);
-        
-        setTimeout(() => { this.setGSuggestedTemplates(renderedTemplates); this._GPTLoading = false });
+
+        setTimeout(() => {
+            this.setGSuggestedTemplates(renderedTemplates);
+            this._GPTLoading = false;
+        });
     };
 
-    @action setExpandedView = (info: {icon: ImageField, doc: Doc} | undefined) => {
+    @action setExpandedView = (info: { icon: ImageField; doc: Doc } | undefined) => {
         this._expandedPreview = info;
-    }
+    };
 
-    get templatesPreviewContents(){
+    get templatesPreviewContents() {
         const renderedTemplates: Doc[] = [];
 
-        const GPTOptions = 
-            <div></div>
+        const GPTOptions = <div></div>;
 
-            //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
+        //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
 
         return (
             <div className={`docCreatorMenu-templates-view`}>
-                {this._expandedPreview ? 
-                <div className='docCreatorMenu-expanded-template-preview'>
-                    <img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
-                    <div className='right-buttons-panel'>
-                        <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.setExpandedView(undefined))}> 
-                            <FontAwesomeIcon icon='minimize'/>
-                        </button>
-                        <button className='docCreatorMenu-menu-button section-reveal-options top-right-lower' onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._templateDocs.push(this._expandedPreview.doc))}>
-                            <FontAwesomeIcon icon='plus' color='white'/>
-                        </button>
-                    </div>
-                </div> 
-                :
-                <div>
-                    <div className='docCreatorMenu-section' style={{height: this._GPTOpt ? 200 : 200}}>
-                        <div className='docCreatorMenu-section-topbar'>
-                            <div className='docCreatorMenu-section-title'>Suggested Templates</div>
-                            <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._menuContent = 'dashboard'))}>
-                                <FontAwesomeIcon icon='gear'/>
+                {this._expandedPreview ? (
+                    <div className="docCreatorMenu-expanded-template-preview">
+                        <img className="docCreatorMenu-preview-image expanded" src={this._expandedPreview.icon!.url.href.replace('.png', '_o.png')} />
+                        <div className="right-buttons-panel">
+                            <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => this.setExpandedView(undefined))}>
+                                <FontAwesomeIcon icon="minimize" />
+                            </button>
+                            <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._templateDocs.push(this._expandedPreview.doc))}>
+                                <FontAwesomeIcon icon="plus" color="white" />
                             </button>
                         </div>
-                        <div className='docCreatorMenu-templates-preview-window' style={{justifyContent: this._GPTLoading || this._menuDimensions.width > 400 ? 'center' : ''}}>
-                            {this._GPTLoading ? (
-                                <div className="loading-spinner">
-                                    <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
-                                </div>
-                            ) : (
-                            this._suggestedTemplates?.map(doc => 
-                                ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info =>
-                                    <div 
-                                    className='docCreatorMenu-preview-window'
-                                    style={{
-                                        border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                                        boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
-                                    }}
-                                    onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
-                                        <button className='option-button left' onPointerDown={e => this.setUpButtonClick(e, () => {this.setExpandedView(info)})}>
-                                            <FontAwesomeIcon icon='magnifying-glass' color='white'/>
-                                        </button>   
-                                        <button className='option-button right' onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(info.doc))}>
-                                            <FontAwesomeIcon icon='plus' color='white'/>
-                                        </button>
-                                        <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
-                                    </div>
-                            ))}
-                        </div>
-                        <div className='docCreatorMenu-GPT-options'>
-                            <div className='docCreatorMenu-GPT-options-container'>
-                                <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generatePresetTemplates())}>
-                                    <FontAwesomeIcon icon='arrows-rotate'/>
+                    </div>
+                ) : (
+                    <div>
+                        <div className="docCreatorMenu-section" style={{ height: this._GPTOpt ? 200 : 200 }}>
+                            <div className="docCreatorMenu-section-topbar">
+                                <div className="docCreatorMenu-section-title">Suggested Templates</div>
+                                <button className="docCreatorMenu-menu-button section-reveal-options" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._menuContent = 'dashboard')))}>
+                                    <FontAwesomeIcon icon="gear" />
                                 </button>
                             </div>
-                            {this._GPTOpt ? GPTOptions : null }
-                        </div>
-                </div>
-                <hr className='docCreatorMenu-option-divider full no-margin'/>
-                <div className='docCreatorMenu-section'>
-                    <div className='docCreatorMenu-section-topbar'>
-                        <div className='docCreatorMenu-section-title'>Your Templates</div>
-                        <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
-                            <FontAwesomeIcon icon='gear'/>
-                        </button>
-                    </div>
-                    <div className='docCreatorMenu-templates-preview-window' style={{justifyContent: this._menuDimensions.width > 400 ? 'center' : ''}}>
-                        <div className='docCreatorMenu-preview-window empty' onPointerDown={e => this.testTemplate()}>
-                            <FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
+                            <div className="docCreatorMenu-templates-preview-window" style={{ justifyContent: this._GPTLoading || this._menuDimensions.width > 400 ? 'center' : '' }}>
+                                {this._GPTLoading ? (
+                                    <div className="loading-spinner">
+                                        <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
+                                    </div>
+                                ) : (
+                                    this._suggestedTemplates
+                                        ?.map(doc => ({ icon: ImageCast(doc.icon), doc }))
+                                        .filter(info => info.icon && info.doc)
+                                        .map(info => (
+                                            <div
+                                                className="docCreatorMenu-preview-window"
+                                                style={{
+                                                    border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                                                    boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                                                }}
+                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
+                                                <button
+                                                    className="option-button left"
+                                                    onPointerDown={e =>
+                                                        this.setUpButtonClick(e, () => {
+                                                            this.setExpandedView(info);
+                                                        })
+                                                    }>
+                                                    <FontAwesomeIcon icon="magnifying-glass" color="white" />
+                                                </button>
+                                                <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(info.doc))}>
+                                                    <FontAwesomeIcon icon="plus" color="white" />
+                                                </button>
+                                                <img className="docCreatorMenu-preview-image" src={info.icon!.url.href.replace('.png', '_o.png')} />
+                                            </div>
+                                        ))
+                                )}
+                            </div>
+                            <div className="docCreatorMenu-GPT-options">
+                                <div className="docCreatorMenu-GPT-options-container">
+                                    <button className="docCreatorMenu-menu-button" onPointerDown={e => this.setUpButtonClick(e, () => this.generatePresetTemplates())}>
+                                        <FontAwesomeIcon icon="arrows-rotate" />
+                                    </button>
+                                </div>
+                                {this._GPTOpt ? GPTOptions : null}
+                            </div>
                         </div>
-                        {this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => {
-                            if (renderedTemplates.includes(info.doc)) return undefined;
-                            renderedTemplates.push(info.doc);
-                            return (<div 
-                            className='docCreatorMenu-preview-window'
-                            style={{
-                                border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                                boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
-                            }}
-                            onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
-                                <button className='option-button left' onPointerDown={e => this.setUpButtonClick(e, () => {this.editTemplate(info.doc)})}>
-                                    <FontAwesomeIcon icon='pencil' color='black'/>
-                                </button>
-                                <button className='option-button right' onPointerDown={e => this.setUpButtonClick(e, () => {this.removeTemplate(info.doc)})}>
-                                    <FontAwesomeIcon icon='trash' color='black'/>
+                        <hr className="docCreatorMenu-option-divider full no-margin" />
+                        <div className="docCreatorMenu-section">
+                            <div className="docCreatorMenu-section-topbar">
+                                <div className="docCreatorMenu-section-title">Your Templates</div>
+                                <button className="docCreatorMenu-menu-button section-reveal-options" onPointerDown={e => this.setUpButtonClick(e, () => (this._GPTOpt = !this._GPTOpt))}>
+                                    <FontAwesomeIcon icon="gear" />
                                 </button>
-                                <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
                             </div>
-                        )})}
+                            <div className="docCreatorMenu-templates-preview-window" style={{ justifyContent: this._menuDimensions.width > 400 ? 'center' : '' }}>
+                                <div className="docCreatorMenu-preview-window empty" onPointerDown={e => this.testTemplate()}>
+                                    <FontAwesomeIcon icon="plus" color="rgb(160, 160, 160)" />
+                                </div>
+                                {this._templateDocs
+                                    .map(doc => ({ icon: ImageCast(doc.icon), doc }))
+                                    .filter(info => info.icon && info.doc)
+                                    .map(info => {
+                                        if (renderedTemplates.includes(info.doc)) return undefined;
+                                        renderedTemplates.push(info.doc);
+                                        return (
+                                            <div
+                                                className="docCreatorMenu-preview-window"
+                                                style={{
+                                                    border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                                                    boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                                                }}
+                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
+                                                <button
+                                                    className="option-button left"
+                                                    onPointerDown={e =>
+                                                        this.setUpButtonClick(e, () => {
+                                                            this.editTemplate(info.doc);
+                                                        })
+                                                    }>
+                                                    <FontAwesomeIcon icon="pencil" color="black" />
+                                                </button>
+                                                <button
+                                                    className="option-button right"
+                                                    onPointerDown={e =>
+                                                        this.setUpButtonClick(e, () => {
+                                                            this.removeTemplate(info.doc);
+                                                        })
+                                                    }>
+                                                    <FontAwesomeIcon icon="trash" color="black" />
+                                                </button>
+                                                <img className="docCreatorMenu-preview-image" src={info.icon!.url.href.replace('.png', '_o.png')} />
+                                            </div>
+                                        );
+                                    })}
+                            </div>
                         </div>
                     </div>
-                </div>
-                }
+                )}
             </div>
         );
     }
 
-    get savedLayoutsPreviewContents(){
+    get savedLayoutsPreviewContents() {
         return (
-            <div className='docCreatorMenu-preview-container'>
-               {this._savedLayouts.map((layout, index) => 
-                <div 
-                    className='docCreatorMenu-preview-window'
-                    style={{
-                        border: this.isSelectedLayout(layout) ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                        boxShadow: this.isSelectedLayout(layout) ? `0 0 15px rgba(68, 118, 247, .8)` : ''
-                    }}
-                    onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedSavedLayout(layout)))}
-                    >
-                    {this.layoutPreviewContents(87, layout, true, index)}
-                </div>
-               )}
+            <div className="docCreatorMenu-preview-container">
+                {this._savedLayouts.map((layout, index) => (
+                    <div
+                        className="docCreatorMenu-preview-window"
+                        style={{
+                            border: this.isSelectedLayout(layout) ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                            boxShadow: this.isSelectedLayout(layout) ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                        }}
+                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedSavedLayout(layout)))}>
+                        {this.layoutPreviewContents(87, layout, true, index)}
+                    </div>
+                ))}
             </div>
         );
     }
 
-    @action updateXMargin = (input: string) => { this._layout.xMargin = Number(input) };
-    @action updateYMargin = (input: string) => { this._layout.yMargin = Number(input) };
-    @action updateColumns = (input: string) => { this._layout.columns = Number(input) };
+    @action updateXMargin = (input: string) => {
+        this._layout.xMargin = Number(input);
+    };
+    @action updateYMargin = (input: string) => {
+        this._layout.yMargin = Number(input);
+    };
+    @action updateColumns = (input: string) => {
+        this._layout.columns = Number(input);
+    };
 
     get layoutConfigOptions() {
         const optionInput = (icon: string, func: Function, def?: number, key?: string, noMargin?: boolean) => {
             return (
-                <div className='docCreatorMenu-option-container small no-margin' key={key} style={{marginTop: noMargin ? '0px' : ''}}
-                >
-                    <div className='docCreatorMenu-option-title config layout-config'>
-                        <FontAwesomeIcon icon={icon as any}/>
+                <div className="docCreatorMenu-option-container small no-margin" key={key} style={{ marginTop: noMargin ? '0px' : '' }}>
+                    <div className="docCreatorMenu-option-title config layout-config">
+                        <FontAwesomeIcon icon={icon as any} />
                     </div>
-                    <input defaultValue={def} onInput={(e) => func(e.currentTarget.value)} className='docCreatorMenu-input config layout-config'/>
+                    <input defaultValue={def} onInput={e => func(e.currentTarget.value)} className="docCreatorMenu-input config layout-config" />
                 </div>
             );
-        }
+        };
 
         switch (this._layout.type) {
             case LayoutType.Row:
-                return (
-                    <div className='docCreatorMenu-configuration-bar'>
-                        {optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '0')}
-                    </div>
-                    );
+                return <div className="docCreatorMenu-configuration-bar">{optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '0')}</div>;
             case LayoutType.Column:
-                return (
-                    <div className='docCreatorMenu-configuration-bar'>
-                        {optionInput('arrows-up-down', this.updateYMargin, this._layout.yMargin, '1')}
-                    </div>
-                    );
+                return <div className="docCreatorMenu-configuration-bar">{optionInput('arrows-up-down', this.updateYMargin, this._layout.yMargin, '1')}</div>;
             case LayoutType.Grid:
                 return (
-                    <div className='docCreatorMenu-configuration-bar'>
+                    <div className="docCreatorMenu-configuration-bar">
                         {optionInput('arrows-up-down', this.updateYMargin, this._layout.xMargin, '2')}
                         {optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '3')}
                         {optionInput('table-columns', this.updateColumns, this._layout.columns, '4', true)}
@@ -1072,9 +1131,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     //     return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'});
     // }
 
-    screenToLocalTransform = () =>
-    this._props
-        .ScreenToLocalTransform();
+    screenToLocalTransform = () => this._props.ScreenToLocalTransform();
 
     layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, small: boolean = false, id?: number) => {
         const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate;
@@ -1084,10 +1141,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const docWidth: number = Number(doc._width);
         const docHeight: number = Number(doc._height);
-        const horizontalSpan: number = (docWidth + layout.xMargin) * (altLayout ? altLayout.columns : this.columnsCount) - layout.xMargin;;
+        const horizontalSpan: number = (docWidth + layout.xMargin) * (altLayout ? altLayout.columns : this.columnsCount) - layout.xMargin;
         const verticalSpan: number = (docHeight + layout.yMargin) * (altLayout ? altLayout.rows : this.rowsCount) - layout.yMargin;
         const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
-        const scaledDown = (input: number) => {return input / (largerSpan / outerSpan * this._layoutPreviewScale)}
+        const scaledDown = (input: number) => {
+            return input / ((largerSpan / outerSpan) * this._layoutPreviewScale);
+        };
         const fontSize = Math.min(scaledDown(docWidth / 3), scaledDown(docHeight / 3));
 
         return (
@@ -1114,220 +1173,275 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             //         {null}
             //     </CollectionFreeFormView>
             // </div>
-            <div className='docCreatorMenu-layout-preview-window-wrapper' id={String(id) ?? undefined}>
-                <div className='docCreatorMenu-zoom-button-container'>
-                    <button 
-                        className='docCreatorMenu-zoom-button'
-                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreviewScale *= 1.25))}>
-                            <FontAwesomeIcon icon={'minus'}/>
+            <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}>
+                <div className="docCreatorMenu-zoom-button-container">
+                    <button className="docCreatorMenu-zoom-button" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._layoutPreviewScale *= 1.25)))}>
+                        <FontAwesomeIcon icon={'minus'} />
                     </button>
-                    <button 
-                        className='docCreatorMenu-zoom-button zoom-in'
-                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreviewScale *= .75))}>
-                            <FontAwesomeIcon icon={'plus'}/>
+                    <button className="docCreatorMenu-zoom-button zoom-in" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._layoutPreviewScale *= 0.75)))}>
+                        <FontAwesomeIcon icon={'plus'} />
                     </button>
-                    {altLayout ? <button 
-                        className='docCreatorMenu-zoom-button trash'
-                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._savedLayouts.splice(this._savedLayouts.indexOf(altLayout), 1)))}>
-                            <FontAwesomeIcon icon={'trash'}/>
-                    </button> : null}
+                    {altLayout ? (
+                        <button className="docCreatorMenu-zoom-button trash" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._savedLayouts.splice(this._savedLayouts.indexOf(altLayout), 1)))}>
+                            <FontAwesomeIcon icon={'trash'} />
+                        </button>
+                    ) : null}
                 </div>
-                {<div 
-                id={String(id) ?? undefined}
-                className={`docCreatorMenu-layout-preview-window ${small ? 'small' : ''}`}
-                style={{
-                    gridTemplateColumns: `repeat(${altLayout ? altLayout.columns : this.columnsCount}, ${scaledDown(docWidth)}px`,
-                    gridTemplateRows: `${scaledDown(docHeight)}px`,
-                    gridAutoRows: `${scaledDown(docHeight)}px`,
-                    rowGap: `${scaledDown(layout.yMargin)}px`,
-                    columnGap: `${scaledDown(layout.xMargin)}px` 
-                }}>
-                    {this._layout.type === LayoutType.Stacked ? 
-                    <div 
-                    className='docCreatorMenu-layout-preview-item'
-                    style={{
-                        width: scaledDown(docWidth), 
-                        height: scaledDown(docHeight),
-                        fontSize: fontSize,
-                    }}
-                    >
-                        All
-                    </div> : 
-                    this.docsToRender.map(num => 
-                        <div 
-                        onMouseEnter={() => this._dataViz?.setSpecialHighlightedRow(num)}
-                        onMouseLeave={() => this._dataViz?.setSpecialHighlightedRow(undefined)}
-                        className='docCreatorMenu-layout-preview-item'
+                {
+                    <div
+                        id={String(id) ?? undefined}
+                        className={`docCreatorMenu-layout-preview-window ${small ? 'small' : ''}`}
                         style={{
-                            width: scaledDown(docWidth), 
-                            height: scaledDown(docHeight),
-                            fontSize: fontSize,
-                        }}
-                        >
-                            {num}
-                        </div>
-                    )}
-
-                </div>}
+                            gridTemplateColumns: `repeat(${altLayout ? altLayout.columns : this.columnsCount}, ${scaledDown(docWidth)}px`,
+                            gridTemplateRows: `${scaledDown(docHeight)}px`,
+                            gridAutoRows: `${scaledDown(docHeight)}px`,
+                            rowGap: `${scaledDown(layout.yMargin)}px`,
+                            columnGap: `${scaledDown(layout.xMargin)}px`,
+                        }}>
+                        {this._layout.type === LayoutType.Stacked ? (
+                            <div
+                                className="docCreatorMenu-layout-preview-item"
+                                style={{
+                                    width: scaledDown(docWidth),
+                                    height: scaledDown(docHeight),
+                                    fontSize: fontSize,
+                                }}>
+                                All
+                            </div>
+                        ) : (
+                            this.docsToRender.map(num => (
+                                <div
+                                    onMouseEnter={() => this._dataViz?.setSpecialHighlightedRow(num)}
+                                    onMouseLeave={() => this._dataViz?.setSpecialHighlightedRow(undefined)}
+                                    className="docCreatorMenu-layout-preview-item"
+                                    style={{
+                                        width: scaledDown(docWidth),
+                                        height: scaledDown(docHeight),
+                                        fontSize: fontSize,
+                                    }}>
+                                    {num}
+                                </div>
+                            ))
+                        )}
+                    </div>
+                }
             </div>
         );
-    }
-
-    get optionsMenuContents(){
-        const layoutEquals = (layout: DataVizTemplateLayout) => {
+    };
 
-        } //TODO: ADD LATER
+    get optionsMenuContents() {
+        const layoutEquals = (layout: DataVizTemplateLayout) => {}; //TODO: ADD LATER
 
         const layoutOption = (option: LayoutType, optStyle?: {}, specialFunc?: Function) => {
             return (
-                <div 
-                    className="docCreatorMenu-dropdown-option" 
+                <div
+                    className="docCreatorMenu-dropdown-option"
                     style={optStyle}
-                    onPointerDown={e => this.setUpButtonClick(e, () => {specialFunc?.(); runInAction(() => this._layout.type = option)})}>
+                    onPointerDown={e =>
+                        this.setUpButtonClick(e, () => {
+                            specialFunc?.();
+                            runInAction(() => (this._layout.type = option));
+                        })
+                    }>
                     {option}
                 </div>
             );
-        }
+        };
 
         const selectionBox = (width: number, height: number, icon: string, specClass?: string, options?: JSX.Element[], manual?: boolean): JSX.Element => {
-            return (<div className='docCreatorMenu-option-container'>
-                <div className={`docCreatorMenu-option-title config ${specClass}`} style={{width: width * .4, height: height}}>
-                    <FontAwesomeIcon icon={icon as any}/>
+            return (
+                <div className="docCreatorMenu-option-container">
+                    <div className={`docCreatorMenu-option-title config ${specClass}`} style={{ width: width * 0.4, height: height }}>
+                        <FontAwesomeIcon icon={icon as any} />
+                    </div>
+                    {manual ? (
+                        <input className={`docCreatorMenu-input config ${specClass}`} style={{ width: width * 0.6, height: height }} />
+                    ) : (
+                        <select className={`docCreatorMenu-input config ${specClass}`} style={{ width: width * 0.6, height: height }}>
+                            {options}
+                        </select>
+                    )}
                 </div>
-                {manual ? <input className={`docCreatorMenu-input config ${specClass}`} style={{width: width * .6, height: height}}/> :
-                <select className={`docCreatorMenu-input config ${specClass}`} style={{width: width * .6, height: height}}>
-                    {options}
-                </select>
-                }
-            </div>);
-        }
+            );
+        };
 
         const repeatOptions = [0, 1, 2, 3, 4, 5];
 
         return (
-            <div className='docCreatorMenu-menu-container'>
-                <div className='docCreatorMenu-option-container layout'>
-                    <div className='docCreatorMenu-dropdown-hoverable'>
+            <div className="docCreatorMenu-menu-container">
+                <div className="docCreatorMenu-option-container layout">
+                    <div className="docCreatorMenu-dropdown-hoverable">
                         <div className="docCreatorMenu-option-title">{this._layout.type ? this._layout.type.toUpperCase() : 'Choose Layout'}</div>
                         <div className="docCreatorMenu-dropdown-content">
                             {layoutOption(LayoutType.Stacked)}
-                            {layoutOption(LayoutType.Grid, undefined, () => {if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length))})}
+                            {layoutOption(LayoutType.Grid, undefined, () => {
+                                if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length));
+                            })}
                             {layoutOption(LayoutType.Row)}
                             {layoutOption(LayoutType.Column)}
-                            {layoutOption(LayoutType.Custom, {borderBottom: `0px`})}
+                            {layoutOption(LayoutType.Custom, { borderBottom: `0px` })}
                         </div>
                     </div>
-                    <button 
-                        className='docCreatorMenu-menu-button preview-toggle'
-                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreview = !this._layoutPreview))}>
-                        <FontAwesomeIcon icon={this._layoutPreview ? 'minus' : 'magnifying-glass'}/>
+                    <button className="docCreatorMenu-menu-button preview-toggle" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._layoutPreview = !this._layoutPreview)))}>
+                        <FontAwesomeIcon icon={this._layoutPreview ? 'minus' : 'magnifying-glass'} />
                     </button>
                 </div>
-                {this._layout.type ? this.layoutConfigOptions: null}
-                {this._layoutPreview ? this.layoutPreviewContents(this._menuDimensions.width * .75) : null}
-                {selectionBox(60, 20, 'repeat', undefined, repeatOptions.map(num => <option onPointerDown={e => this._layout.repeat = num}>{`${num}x`}</option>))}
-                <hr className='docCreatorMenu-option-divider'/>
-                <div className='docCreatorMenu-general-options-container'>
+                {this._layout.type ? this.layoutConfigOptions : null}
+                {this._layoutPreview ? this.layoutPreviewContents(this._menuDimensions.width * 0.75) : null}
+                {selectionBox(
+                    60,
+                    20,
+                    'repeat',
+                    undefined,
+                    repeatOptions.map(num => <option onPointerDown={e => (this._layout.repeat = num)}>{`${num}x`}</option>)
+                )}
+                <hr className="docCreatorMenu-option-divider" />
+                <div className="docCreatorMenu-general-options-container">
                     <button
-                        className='docCreatorMenu-save-layout-button'
-                        onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction,
-                            undoable(clickEv => {
-                                clickEv.stopPropagation();
-                                if (!this._selectedTemplate) return;
-                                const layout: DataVizTemplateLayout = {template: this._selectedTemplate, layout: {type: this._layout.type, xMargin: this._layout.xMargin, yMargin:this._layout.yMargin, repeat: 0}, columns: this.columnsCount, rows: this.rowsCount, docsNumList: this.docsToRender};
-                                if (!this._savedLayouts.includes(layout)) { this._savedLayouts.push(layout) };
-                            }, 'make docs') 
-                        )
-                    }>
-                        <FontAwesomeIcon icon='floppy-disk'/>
+                        className="docCreatorMenu-save-layout-button"
+                        onPointerDown={e =>
+                            setupMoveUpEvents(
+                                this,
+                                e,
+                                returnFalse,
+                                emptyFunction,
+                                undoable(clickEv => {
+                                    clickEv.stopPropagation();
+                                    if (!this._selectedTemplate) return;
+                                    const layout: DataVizTemplateLayout = {
+                                        template: this._selectedTemplate,
+                                        layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
+                                        columns: this.columnsCount,
+                                        rows: this.rowsCount,
+                                        docsNumList: this.docsToRender,
+                                    };
+                                    if (!this._savedLayouts.includes(layout)) {
+                                        this._savedLayouts.push(layout);
+                                    }
+                                }, 'make docs')
+                            )
+                        }>
+                        <FontAwesomeIcon icon="floppy-disk" />
                     </button>
-                    <button 
-                        className='docCreatorMenu-create-docs-button'
-                        style={{backgroundColor: this.canMakeDocs ? '' : 'rgb(155, 155, 155)', border: this.canMakeDocs ? '' : 'solid 2px rgb(180, 180, 180)'}}
-                        onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction,
+                    <button
+                        className="docCreatorMenu-create-docs-button"
+                        style={{ backgroundColor: this.canMakeDocs ? '' : 'rgb(155, 155, 155)', border: this.canMakeDocs ? '' : 'solid 2px rgb(180, 180, 180)' }}
+                        onPointerDown={e =>
+                            setupMoveUpEvents(
+                                this,
+                                e,
+                                returnFalse,
+                                emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
                                     if (!this._selectedTemplate) return;
-                                    const templateInfo: DataVizTemplateInfo = {doc: this._selectedTemplate, layout: this._layout, referencePos: {x: this._pageX + 450, y: this._pageY}, columns: this.columnsCount};
+                                    const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplate, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
                                     this._dataViz?.createDocsFromTemplate(templateInfo);
-                                }, 'make docs') 
+                                }, 'make docs')
                             )
                         }>
-                         <FontAwesomeIcon icon='plus'/>
+                        <FontAwesomeIcon icon="plus" />
                     </button>
                 </div>
             </div>
         );
     }
 
-    get dashboardContents(){
+    get dashboardContents() {
         const sizes: string[] = ['tiny', 'small', 'medium', 'large', 'huge'];
 
         const fieldPanel = (field: Col) => {
             return (
-                <div className='field-panel'> 
-                    <div className='top-bar'>
-                        <span className='field-title'>{`${field.title} Field`}</span>
-                        <button className='docCreatorMenu-menu-button section-reveal-options no-margin' onPointerDown={e => this.setUpButtonClick(e, this.addField)} style={{position: 'absolute', right: '0px'}}>
-                            <FontAwesomeIcon icon='minus'/>
+                <div className="field-panel">
+                    <div className="top-bar">
+                        <span className="field-title">{`${field.title} Field`}</span>
+                        <button className="docCreatorMenu-menu-button section-reveal-options no-margin" onPointerDown={e => this.setUpButtonClick(e, this.addField)} style={{ position: 'absolute', right: '0px' }}>
+                            <FontAwesomeIcon icon="minus" />
                         </button>
                     </div>
-                    <div className='opts-bar'> 
-                        <div className='opt-box'>
-                            <div className='top-bar'> Title </div>
-                            <textarea className='content' style={{width: '100%', height: 'calc(100% - 20px)'}} defaultValue={field.title} placeholder={'Enter title'} onChange={(e) => this.setColTitle(field, e.target.value)}/>
+                    <div className="opts-bar">
+                        <div className="opt-box">
+                            <div className="top-bar"> Title </div>
+                            <textarea className="content" style={{ width: '100%', height: 'calc(100% - 20px)' }} defaultValue={field.title} placeholder={'Enter title'} onChange={e => this.setColTitle(field, e.target.value)} />
                         </div>
-                        <div className='opt-box'>
-                            <div className='top-bar'> Type </div>
-                            <div className='content'>
-                                <span className='type-display'>{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}</span>
-                                <div className='bubbles'>
-                                    <input className='bubble' type="radio" name="type" onClick={() => {this.setColType(field, TemplateFieldType.TEXT)}}/> 
-                                    <div className='text'>Text</div>
-                                    <input className='bubble' type="radio" name="type" onClick={() => {this.setColType(field, TemplateFieldType.VISUAL)}}/> 
-                                    <div className='text'>File</div>
+                        <div className="opt-box">
+                            <div className="top-bar"> Type </div>
+                            <div className="content">
+                                <span className="type-display">{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}</span>
+                                <div className="bubbles">
+                                    <input
+                                        className="bubble"
+                                        type="radio"
+                                        name="type"
+                                        onClick={() => {
+                                            this.setColType(field, TemplateFieldType.TEXT);
+                                        }}
+                                    />
+                                    <div className="text">Text</div>
+                                    <input
+                                        className="bubble"
+                                        type="radio"
+                                        name="type"
+                                        onClick={() => {
+                                            this.setColType(field, TemplateFieldType.VISUAL);
+                                        }}
+                                    />
+                                    <div className="text">File</div>
                                 </div>
                             </div>
                         </div>
                     </div>
-                    <div className='sizes-box'>
-                        <div className='top-bar'> Valid Sizes </div>
-                        <div className='content'>
-                            <div className='bubbles'>
-                                {sizes.map(size => <>
-                                    <input className='bubble' type="checkbox" name="type" checked={field.sizes.includes(size as TemplateFieldSize)} onChange={(e) => {this.modifyColSizes(field, size as TemplateFieldSize, e.target.checked)}}/> 
-                                    <div className='text'>{size}</div>
-                                </>)}
+                    <div className="sizes-box">
+                        <div className="top-bar"> Valid Sizes </div>
+                        <div className="content">
+                            <div className="bubbles">
+                                {sizes.map(size => (
+                                    <>
+                                        <input
+                                            className="bubble"
+                                            type="checkbox"
+                                            name="type"
+                                            checked={field.sizes.includes(size as TemplateFieldSize)}
+                                            onChange={e => {
+                                                this.modifyColSizes(field, size as TemplateFieldSize, e.target.checked);
+                                            }}
+                                        />
+                                        <div className="text">{size}</div>
+                                    </>
+                                ))}
                             </div>
                         </div>
                     </div>
-                    <div className='desc-box'>
-                        <div className='top-bar'> Description </div>
-                        <textarea className='content' onChange={(e) => this.setColDesc(field, e.target.value)} defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc } placeholder={this._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description to help with template generation.'} />
+                    <div className="desc-box">
+                        <div className="top-bar"> Description </div>
+                        <textarea
+                            className="content"
+                            onChange={e => this.setColDesc(field, e.target.value)}
+                            defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc}
+                            placeholder={this._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description to help with template generation.'}
+                        />
                     </div>
                 </div>
-            )
-        }    
+            );
+        };
 
         return (
-        <div className='docCreatorMenu-dashboard-view'>
-            <div className='topbar'>
-                <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}>
-                    <FontAwesomeIcon icon='plus'/>
-                </button>
-                <button className='docCreatorMenu-menu-button section-reveal-options float-right' onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._menuContent = 'templates'))}>
-                    <FontAwesomeIcon icon='arrow-left'/>
-                </button>
-            </div>
-            <div className='panels-container'>
-                {this.fieldsInfos.map(field => fieldPanel(field))}
+            <div className="docCreatorMenu-dashboard-view">
+                <div className="topbar">
+                    <button className="docCreatorMenu-menu-button section-reveal-options" onPointerDown={e => this.setUpButtonClick(e, this.addField)}>
+                        <FontAwesomeIcon icon="plus" />
+                    </button>
+                    <button className="docCreatorMenu-menu-button section-reveal-options float-right" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._menuContent = 'templates')))}>
+                        <FontAwesomeIcon icon="arrow-left" />
+                    </button>
+                </div>
+                <div className="panels-container">{this.fieldsInfos.map(field => fieldPanel(field))}</div>
             </div>
-        </div>
         );
     }
 
-    get renderSelectedViewType(){
-        switch (this._menuContent){
+    get renderSelectedViewType() {
+        switch (this._menuContent) {
             case 'templates':
                 return this.templatesPreviewContents;
             case 'options':
@@ -1341,7 +1455,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     }
 
-    get resizePanes(){
+    get resizePanes() {
         const ref = this._ref?.getBoundingClientRect();
         const height: number = ref?.height ?? 0;
         const width: number = ref?.width ?? 0;
@@ -1362,90 +1476,96 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const topButton = (icon: string, opt: string, func: Function, tag: string) => {
             return (
                 <div className={`top-button-container ${tag} ${opt === this._menuContent ? 'selected' : ''}`}>
-                    <div 
+                    <div
                         className="top-button-content"
-                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => {func()}))}>
-                        <FontAwesomeIcon icon={icon as any}/>
+                        onPointerDown={e =>
+                            this.setUpButtonClick(e, () =>
+                                runInAction(() => {
+                                    func();
+                                })
+                            )
+                        }>
+                        <FontAwesomeIcon icon={icon as any} />
                     </div>
                 </div>
             );
-        }
+        };
 
-        const onPreviewSelected = () => {this._menuContent = 'templates'}
-        const onSavedSelected = () => {this._menuContent = 'dashboard'}
+        const onPreviewSelected = () => {
+            this._menuContent = 'templates';
+        };
+        const onSavedSelected = () => {
+            this._menuContent = 'dashboard';
+        };
         const onOptionsSelected = () => {
             this._menuContent = 'options';
             if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length));
-        }
-
+        };
 
         return (
-            <div className='docCreatorMenu'>
-                {!this._shouldDisplay ? undefined : 
-                <div
-                    className="docCreatorMenu-cont"
-                    ref={r => this._ref = r}
-                    style={{
-                        display: '',
-                        left: this._pageX,
-                        top: this._pageY,
-                        width: this._menuDimensions.width,
-                        height: this._menuDimensions.height,
-                        background: SnappingManager.userBackgroundColor,
-                        color: SnappingManager.userColor,
-                    }}>
+            <div className="docCreatorMenu">
+                {!this._shouldDisplay ? undefined : (
+                    <div
+                        className="docCreatorMenu-cont"
+                        ref={r => (this._ref = r)}
+                        style={{
+                            display: '',
+                            left: this._pageX,
+                            top: this._pageY,
+                            width: this._menuDimensions.width,
+                            height: this._menuDimensions.height,
+                            background: SnappingManager.userBackgroundColor,
+                            color: SnappingManager.userColor,
+                        }}>
                         {this.resizePanes}
-                        <div 
-                        className='docCreatorMenu-menu'
-                        onPointerDown={e =>
-                            setupMoveUpEvents(
-                                this,
-                                e,
-                                (e) => {
-                                    this._dragging = true;
-                                    this._startPos = {x: 0, y: 0};
-                                    this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0);
-                                    this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0);
-                                    document.addEventListener('pointermove', this.onDrag);
-                                    return true;
-                                },
-                                emptyFunction,
-                                undoable(clickEv => {
-                                    clickEv.stopPropagation();
-                                }, 'drag menu')
-                            )
-                        }
-                        >
-                            <div className='docCreatorMenu-top-buttons-container'>
+                        <div
+                            className="docCreatorMenu-menu"
+                            onPointerDown={e =>
+                                setupMoveUpEvents(
+                                    this,
+                                    e,
+                                    e => {
+                                        this._dragging = true;
+                                        this._startPos = { x: 0, y: 0 };
+                                        this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0);
+                                        this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0);
+                                        document.addEventListener('pointermove', this.onDrag);
+                                        return true;
+                                    },
+                                    emptyFunction,
+                                    undoable(clickEv => {
+                                        clickEv.stopPropagation();
+                                    }, 'drag menu')
+                                )
+                            }>
+                            <div className="docCreatorMenu-top-buttons-container">
                                 {topButton('table-cells', 'templates', onPreviewSelected, 'left')}
                                 {topButton('bars', 'options', onOptionsSelected, 'middle')}
                                 {topButton('floppy-disk', 'saved', onSavedSelected, 'right')}
                             </div>
-                            <button 
-                                className='docCreatorMenu-menu-button close-menu'
-                                onPointerDown={e => this.setUpButtonClick(e, this.closeMenu)}>
-                                <FontAwesomeIcon icon={'minus'}/>
+                            <button className="docCreatorMenu-menu-button close-menu" onPointerDown={e => this.setUpButtonClick(e, this.closeMenu)}>
+                                <FontAwesomeIcon icon={'minus'} />
                             </button>
                         </div>
                         {this.renderSelectedViewType}
-                </div>
-                }
+                    </div>
+                )}
             </div>
-            )
-        }
+        );
+    }
 }
 
 export interface DataVizTemplateInfo {
     doc: Doc;
-    layout: {type: LayoutType, xMargin: number, yMargin: number, repeat: number};
+    layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number };
     columns: number;
-    referencePos: {x: number, y: number};
+    referencePos: { x: number; y: number };
 }
 
 export interface DataVizTemplateLayout {
     template: Doc;
     docsNumList: number[];
-    layout: {type: LayoutType, xMargin: number, yMargin: number, repeat: number};
+    layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number };
     columns: number;
     rows: number;
 }
@@ -1453,7 +1573,7 @@ export interface DataVizTemplateLayout {
 export enum TemplateFieldType {
     TEXT = 'text',
     VISUAL = 'visual',
-    UNSET = 'unset'
+    UNSET = 'unset',
 }
 
 export enum TemplateFieldSize {
@@ -1461,17 +1581,16 @@ export enum TemplateFieldSize {
     SMALL = 'small',
     MEDIUM = 'medium',
     LARGE = 'large',
-    HUGE = 'huge'
+    HUGE = 'huge',
 }
 
-
 export type Col = {
     sizes: TemplateFieldSize[];
     desc: string;
     title: string;
     type: TemplateFieldType;
     defaultContent?: string;
-}
+};
 
 type Field = {
     tl: [number, number];
@@ -1482,7 +1601,7 @@ type Field = {
     sizes?: TemplateFieldSize[];
     isDecoration?: boolean;
     description?: string;
-}
+};
 
 // class ContentField implements Field {
 //     tl: [number, number];
@@ -1493,10 +1612,10 @@ type Field = {
 //     sizes?: TemplateFieldSize[];
 //     description?: string;
 
-//     constructor( tl: [number, number], br: [number, number], 
-//                         opts: FieldOpts, subfields?: Field[], 
-//                         types?: TemplateFieldType[], 
-//                         sizes?: TemplateFieldSize[], 
+//     constructor( tl: [number, number], br: [number, number],
+//                         opts: FieldOpts, subfields?: Field[],
+//                         types?: TemplateFieldType[],
+//                         sizes?: TemplateFieldSize[],
 //                         description?: string) {
 //         this.tl = tl;
 //         this.br = br;
@@ -1514,9 +1633,7 @@ type Field = {
 
 type DecorationField = Field;
 
-type InkDecoration = {
-
-}
+type InkDecoration = {};
 
 type TemplateDecorations = Field | InkDecoration;
 
@@ -1545,85 +1662,86 @@ export interface FieldOpts {
     fieldViewType?: 'freeform' | 'stacked';
 }
 
-interface TemplateOpts extends FieldOpts {
-
-}
+interface TemplateOpts extends FieldOpts {}
 
 export class FieldUtils {
-
     public static contentFields = (fields: Field[]) => {
         let toRet: Field[] = [];
         fields.forEach(field => {
-            if (!field.isDecoration) { toRet.push(field) };
+            if (!field.isDecoration) {
+                toRet.push(field);
+            }
             toRet = toRet.concat(FieldUtils.contentFields(field.subfields ?? []));
         });
 
         return toRet;
-    }
+    };
 
     public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
         const words: string[] = text.split(/\s+/).filter(Boolean);
 
-        let currFontSize = 1; 
+        let currFontSize = 1;
         let rowsCount = 1;
         let currTextHeight = currFontSize * rowsCount * 2;
-    
+
         while (currTextHeight <= contHeight) {
             let wordIndex = 0;
             let currentRowWidth = 0;
             let wordsInCurrRow = 0;
             rowsCount = 1;
-    
+
             while (wordIndex < words.length) {
                 const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize * .5;
+                const wordWidth = word.length * currFontSize * 0.5;
                 //console.log(wordWidth)
-    
+
                 if (currentRowWidth + wordWidth <= contWidth) {
                     currentRowWidth += wordWidth;
                     ++wordsInCurrRow;
                 } else {
-                    if (words.length !== 1 && words.length > wordsInCurrRow){ 
+                    if (words.length !== 1 && words.length > wordsInCurrRow) {
                         rowsCount++;
-                        currentRowWidth = wordWidth; 
+                        currentRowWidth = wordWidth;
                         wordsInCurrRow = 1;
                     } else {
                         break;
                     }
                 }
-    
-                wordIndex++;    
+
+                wordIndex++;
             }
-    
+
             currTextHeight = rowsCount * currFontSize * 2;
             //console.log(rowsCount, currFontSize, currTextHeight)
-    
+
             currFontSize += 1;
         }
-        
+
         return currFontSize - 1;
     };
 
-    private static getDimensions = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number): {width: number, height: number, coord: {x: number, y: number}} => {
-        const l = coords.tl[0] * parentHeight / 2; const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
-        const r = coords.br[0] * parentHeight / 2; const b = coords.br[1] * parentWidth / 2; //prettier-ignore
+    private static getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
+        const l = (coords.tl[0] * parentHeight) / 2;
+        const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
+        const r = (coords.br[0] * parentHeight) / 2;
+        const b = coords.br[1] * parentWidth / 2; //prettier-ignore
         const width = r - l;
         const height = b - t;
-        const coord = {x: l, y: t};
+        const coord = { x: l, y: t };
         //console.log(coords, parentWidth, parentHeight, height);
-        return {width, height, coord};
-    }
+        return { width, height, coord };
+    };
 
-    public static FreeformField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+    public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
-        const docWithBasicOpts = (Docs.Create.FreeformDocument)([], {  
-            isDefaultTemplateDoc: true, 
-            _height: height, 
-            _width: width, 
-            title: title, 
-            x: coord.x, 
-            y: coord.y, 
+        const docWithBasicOpts = Docs.Create.FreeformDocument([], {
+            isDefaultTemplateDoc: true,
+            _height: height,
+            _width: width,
+            title: title,
+            x: coord.x,
+            y: coord.y,
             backgroundColor: opts.backgroundColor ?? '',
             _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
             borderColor: opts.borderColor,
@@ -1634,21 +1752,21 @@ export class FieldUtils {
         });
 
         return docWithBasicOpts;
-    }
+    };
 
-    public static TextField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+    public static TextField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
         const bool = true;
 
-        const docWithBasicOpts = (Docs.Create.TextDocument)(content, {   
+        const docWithBasicOpts = Docs.Create.TextDocument(content, {
             isDefaultTemplateDoc: true,
-            _height: height, 
-            _width: width, 
-            title: title, 
-            x: coord.x, 
-            y: coord.y, 
-            _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}` ,
+            _height: height,
+            _width: width,
+            title: title,
+            x: coord.x,
+            y: coord.y,
+            _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
             backgroundColor: opts.backgroundColor ?? '',
             text_fontColor: opts.color,
             contentBold: opts.fontBold,
@@ -1665,17 +1783,17 @@ export class FieldUtils {
         docWithBasicOpts._layout_hideScroll = true;
 
         return docWithBasicOpts;
-    }
+    };
 
-    public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+    public static ImageField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
-        const doc = Docs.Create.ImageDocument(content, {  
-            isDefaultTemplateDoc: true, 
-            _height: height, 
-            _width: width, 
-            title: title, 
-            x: coord.x, 
+        const doc = Docs.Create.ImageDocument(content, {
+            isDefaultTemplateDoc: true,
+            _height: height,
+            _width: width,
+            title: title,
+            x: coord.x,
             y: coord.y,
             _layout_fitWidth: false,
             backgroundColor: opts.backgroundColor ?? '',
@@ -1689,28 +1807,24 @@ export class FieldUtils {
         //setTimeout(() => {doc._height = height; doc._width = width}, 10);
 
         return doc;
-    }
+    };
 
-    public static CarouselField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
-        const {width, height, coord} = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+    public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
+        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
-        const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height/2}` })
+        const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
 
         return doc;
-    }
-    
+    };
 }
 
 export class TemplateLayouts {
-
     public static get allTemplates(): TemplateDocInfos[] {
-        return Object.values(TemplateLayouts).filter(
-            value => typeof value === 'object' && value !== null && 'title' in value
-        ) as TemplateDocInfos[];
+        return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as TemplateDocInfos[];
     }
 
     public static getTemplateByTitle = (title: string): TemplateDocInfos | undefined => {
-        switch (title){
+        switch (title) {
             case 'fourfield1':
                 return TemplateLayouts.FourField001;
             case 'fourfield2':
@@ -1728,173 +1842,187 @@ export class TemplateLayouts {
         }
 
         return undefined;
-    }
+    };
 
     public static FourField001: TemplateDocInfos = {
         title: 'fourfield1',
-        width: 416, 
-        height: 700, 
+        width: 416,
+        height: 700,
         opts: {
             backgroundColor: '#C0B887',
             cornerRounding: 20,
             borderColor: '#6B461F',
             borderWidth: '12',
         },
-        fields: [{
-            tl: [-.95, -1], 
-            br: [.95, -.85], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY],
-            description: 'A title field for very short text that contextualizes the content.',
-            opts: {
-                backgroundColor: 'transparent',
-                color: '#F1F0E9',
-                contentXCentering: 'h-center',
-                fontBold: true,
-            }
-        }, {
-            tl: [-.87, -.83], 
-            br: [.87, .2], 
-            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'The main focus of the template; could be an image, long text, etc.',
-            opts: {
-                cornerRounding: 20,
-                borderColor: '#8F5B25',
-                borderWidth: '6',
-                backgroundColor: '#CECAB9',
-            }
-        }, {
-            tl: [-.8, .2], 
-            br: [.8, .3],  
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: 'A caption for field #2, very short to short text that contextualizes the content of field #2',
-            opts: {
-                backgroundColor: 'transparent',
-                contentXCentering: 'h-center',
-                color: '#F1F0E9',
-            }
-        }, {
-            tl: [-.87, .37], 
-            br: [.87, .96], 
-            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A medium-sized field for medium/long text.',
-            opts: {
-                cornerRounding: 15,
-                borderColor: '#8F5B25', 
-                borderWidth: '6',
-                backgroundColor: '#CECAB9',
-            }
-        }],
+        fields: [
+            {
+                tl: [-0.95, -1],
+                br: [0.95, -0.85],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A title field for very short text that contextualizes the content.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: '#F1F0E9',
+                    contentXCentering: 'h-center',
+                    fontBold: true,
+                },
+            },
+            {
+                tl: [-0.87, -0.83],
+                br: [0.87, 0.2],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'The main focus of the template; could be an image, long text, etc.',
+                opts: {
+                    cornerRounding: 20,
+                    borderColor: '#8F5B25',
+                    borderWidth: '6',
+                    backgroundColor: '#CECAB9',
+                },
+            },
+            {
+                tl: [-0.8, 0.2],
+                br: [0.8, 0.3],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A caption for field #2, very short to short text that contextualizes the content of field #2',
+                opts: {
+                    backgroundColor: 'transparent',
+                    contentXCentering: 'h-center',
+                    color: '#F1F0E9',
+                },
+            },
+            {
+                tl: [-0.87, 0.37],
+                br: [0.87, 0.96],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium-sized field for medium/long text.',
+                opts: {
+                    cornerRounding: 15,
+                    borderColor: '#8F5B25',
+                    borderWidth: '6',
+                    backgroundColor: '#CECAB9',
+                },
+            },
+        ],
         decorations: [],
     };
 
     public static FourField002: TemplateDocInfos = {
         title: 'fourfield2',
-        width: 425, 
-        height: 778, 
+        width: 425,
+        height: 778,
         opts: {
-            backgroundColor: '#242425'
+            backgroundColor: '#242425',
         },
-        fields: [{
-            tl: [-.83, -.95], 
-            br: [.83, -.2], 
-            types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-            description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
-            opts: {
-                borderWidth: '8',
-                borderColor: '#F8E71C',
-            }
-        }, {
-            tl: [-.65, -.2], 
-            br: [.65, -.02], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY],
-            description: 'A tiny field for just a word or two of plain text.',
-            opts: {
-                backgroundColor: 'transparent',
-                color: 'white',
-                contentXCentering: 'h-center',
-                fontTransform: 'uppercase'
-            }
-        }, {
-            tl: [-.65, 0], 
-            br: [.65, .18], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY],
-            description: 'A tiny field for just a word or two of plain text.',
-            opts: {
-                backgroundColor: 'transparent',
-                color: 'white',
-                contentXCentering: 'h-center',
-                fontTransform: 'uppercase'
-            }
-        }, {
-            tl: [-.83, .2], 
-            br: [.83, .95], 
-            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus, or share focus with field 1.',
-            opts: {
-                borderWidth: '8',
-                borderColor: '#F8E71C',
-                color: 'white',
-                backgroundColor: '#242425',
-            }
-        }],
-        decorations: [{
-            tl: [-.8, -.075], 
-            br: [-.525, .075], 
-            opts: {
-                backgroundColor: '#F8E71C',
-                rotation: 45
-            }
-        }, {
-            tl: [-.3075, -.0245], 
-            br: [-.2175, .0245], 
-            opts: {
-                backgroundColor: '#F8E71C',
-                rotation: 45
-            }
-        }, {
-            tl: [-.045, -.0245], 
-            br: [.045, .0245], 
-            opts: {
-                backgroundColor: '#F8E71C',
-                rotation: 45
-            }
-        }, {
-            tl: [.2175, -.0245], 
-            br: [.3075, .0245], 
-            opts: {
-                backgroundColor: '#F8E71C',
-                rotation: 45
-            }
-        }, {
-            tl: [.525, -.075], 
-            br: [.8, .075], 
-            opts: {
-                backgroundColor: '#F8E71C',
-                rotation: 45
-            }
-        }
-
-        ]
+        fields: [
+            {
+                tl: [-0.83, -0.95],
+                br: [0.83, -0.2],
+                types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
+                opts: {
+                    borderWidth: '8',
+                    borderColor: '#F8E71C',
+                },
+            },
+            {
+                tl: [-0.65, -0.2],
+                br: [0.65, -0.02],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                    contentXCentering: 'h-center',
+                    fontTransform: 'uppercase',
+                },
+            },
+            {
+                tl: [-0.65, 0],
+                br: [0.65, 0.18],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                    contentXCentering: 'h-center',
+                    fontTransform: 'uppercase',
+                },
+            },
+            {
+                tl: [-0.83, 0.2],
+                br: [0.83, 0.95],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus, or share focus with field 1.',
+                opts: {
+                    borderWidth: '8',
+                    borderColor: '#F8E71C',
+                    color: 'white',
+                    backgroundColor: '#242425',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.8, -0.075],
+                br: [-0.525, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [-0.3075, -0.0245],
+                br: [-0.2175, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [-0.045, -0.0245],
+                br: [0.045, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [0.2175, -0.0245],
+                br: [0.3075, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [0.525, -0.075],
+                br: [0.8, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    rotation: 45,
+                },
+            },
+        ],
     };
 
     // public static FourField003: TemplateDocInfos = {
     //     title: 'fourfield3',
-    //     width: 477, 
-    //     height: 662, 
+    //     width: 477,
+    //     height: 662,
     //     opts: {
     //         backgroundColor: '#9E9C95'
     //     },
     //     fields: [{
-    //         tl: [-.875, -.9], 
-    //         br: [.875, .7], 
+    //         tl: [-.875, -.9],
+    //         br: [.875, .7],
     //         types: [TemplateFieldType.VISUAL],
     //         sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
     //         description: '',
@@ -1903,8 +2031,8 @@ export class TemplateLayouts {
     //             borderColor: '#E0E0DA',
     //         }
     //     }, {
-    //         tl: [-.95, .8], 
-    //         br: [-.1, .95], 
+    //         tl: [-.95, .8],
+    //         br: [-.1, .95],
     //         types: [TemplateFieldType.TEXT],
     //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
     //         description: '',
@@ -1914,8 +2042,8 @@ export class TemplateLayouts {
     //             contentXCentering: 'h-right',
     //         }
     //     }, {
-    //         tl: [.1, .8], 
-    //         br: [.95, .95], 
+    //         tl: [.1, .8],
+    //         br: [.95, .95],
     //         types: [TemplateFieldType.TEXT],
     //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
     //         description: '',
@@ -1926,8 +2054,8 @@ export class TemplateLayouts {
     //             contentXCentering: 'h-left'
     //         }
     //     }, {
-    //         tl: [0, -.9], 
-    //         br: [.85, -.66], 
+    //         tl: [0, -.9],
+    //         br: [.85, -.66],
     //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
     //         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
     //         description: '',
@@ -1937,8 +2065,8 @@ export class TemplateLayouts {
     //         }
     //     }],
     //     decorations: [{
-    //         tl: [-.025, .8], 
-    //         br: [.025, .95], 
+    //         tl: [-.025, .8],
+    //         br: [.025, .95],
     //         opts: {
     //             backgroundColor: '#E0E0DA',
     //         }
@@ -1947,242 +2075,257 @@ export class TemplateLayouts {
 
     public static FourField004: TemplateDocInfos = {
         title: 'fourfield4',
-        width: 414, 
-        height: 583, 
+        width: 414,
+        height: 583,
         opts: {
             backgroundColor: '#6CCAF0',
             borderColor: '#1088C3',
-            borderWidth: '10'
+            borderWidth: '10',
         },
-        fields: [{
-            tl: [-.86, -.92], 
-            br: [-.075, -.77], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY],
-            description: 'A tiny field for just a word or two of plain text.',
-            opts: {
-                backgroundColor: '#E2B4F5',
-                borderWidth: '9',
-                borderColor: '#9222F1',
-                contentXCentering: 'h-center'
-            }
-        }, {
-            tl: [.075, -.92], 
-            br: [.86, -.77], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY],
-            description: 'A tiny field for just a word or two of plain text.',
-            opts: {
-                backgroundColor: '#F5B4DD',
-                borderWidth: '9',
-                borderColor: '#E260F3',
-                contentXCentering: 'h-center'
-            }
-        }, {
-            tl: [-.81, -.64], 
-            br: [.81, .48], 
-            types: [TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A large to huge field for visual content that is the main content of the template.',
-            opts: {
-                borderWidth: '16',
-                borderColor: '#A2BD77',
-            }
-        }, {
-            tl: [-.86, .6], 
-            br: [.86, .92], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-            description: 'A medium to large field for text that describes the visual content above',
-            opts: {
-                borderWidth: '9',
-                borderColor: '#F0D601',
-                backgroundColor: '#F3F57D',
-            }
-        }],
-        decorations: [{
-            tl: [-.852, -.67], 
-            br: [.852, .51], 
-            opts: {
-                backgroundColor: 'transparent',
-                borderColor: '#007C0C',
-                borderWidth: '10',
-            }
-        }]
+        fields: [
+            {
+                tl: [-0.86, -0.92],
+                br: [-0.075, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#E2B4F5',
+                    borderWidth: '9',
+                    borderColor: '#9222F1',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [0.075, -0.92],
+                br: [0.86, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#F5B4DD',
+                    borderWidth: '9',
+                    borderColor: '#E260F3',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [-0.81, -0.64],
+                br: [0.81, 0.48],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A large to huge field for visual content that is the main content of the template.',
+                opts: {
+                    borderWidth: '16',
+                    borderColor: '#A2BD77',
+                },
+            },
+            {
+                tl: [-0.86, 0.6],
+                br: [0.86, 0.92],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field for text that describes the visual content above',
+                opts: {
+                    borderWidth: '9',
+                    borderColor: '#F0D601',
+                    backgroundColor: '#F3F57D',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.852, -0.67],
+                br: [0.852, 0.51],
+                opts: {
+                    backgroundColor: 'transparent',
+                    borderColor: '#007C0C',
+                    borderWidth: '10',
+                },
+            },
+        ],
     };
 
     public static ThreeField001: TemplateDocInfos = {
         title: 'threefield1',
-        width: 575, 
-        height: 770, 
+        width: 575,
+        height: 770,
         opts: {
-            backgroundColor: '#DDD3A9'
+            backgroundColor: '#DDD3A9',
         },
-        fields: [{
-            tl: [-.66, -.747], 
-            br: [.66, .247], 
-            types: [TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A medium to large field for visual content that is the central focus.',
-            opts: {
-                borderColor: 'yellow',
-                borderWidth: '8',
-                rotation: 45,
+        fields: [
+            {
+                tl: [-0.66, -0.747],
+                br: [0.66, 0.247],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large field for visual content that is the central focus.',
+                opts: {
+                    borderColor: 'yellow',
+                    borderWidth: '8',
+                    rotation: 45,
+                },
             },
-        }, {
-            tl: [-.7, .2], 
-            br: [.7, .46], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: 'A very small text field for one to a few words. A good caption for the image.',
-            opts: {
-                backgroundColor: 'transparent',
-                contentXCentering: 'h-center',
-            }
-        }, {
-            tl: [-.95, .5], 
-            br: [.95, .95], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-            description: 'A medium to large text field for a thorough description of the image. ',
-            opts: {
-                backgroundColor: 'transparent',
-                color: 'white'
-            }
-        }],
-        decorations: [{
-            tl: [.2, -1.32], 
-            br: [1.8, -.66], 
-            opts: {
-                backgroundColor: '#CEB155',
-                rotation: 45,
-            }
-        }, {
-            tl: [-1.8, -1.32], 
-            br: [-.2, -.66], 
-            opts: {
-                backgroundColor: '#CEB155',
-                rotation: 135,
-            }
-        }, {
-            tl: [.33, .75], 
-            br: [1.66, 1.25], 
-            opts: {
-                backgroundColor: '#CEB155',
-                rotation: 135,
-            }
-        }, {
-            tl: [-1.66, .75], 
-            br: [-.33, 1.25], 
-            opts: {
-                backgroundColor: '#CEB155',
-                rotation: 45,
-            }
-        }]
+            {
+                tl: [-0.7, 0.2],
+                br: [0.7, 0.46],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. A good caption for the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [-0.95, 0.5],
+                br: [0.95, 0.95],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large text field for a thorough description of the image. ',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [0.2, -1.32],
+                br: [1.8, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [-1.8, -1.32],
+                br: [-0.2, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 135,
+                },
+            },
+            {
+                tl: [0.33, 0.75],
+                br: [1.66, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 135,
+                },
+            },
+            {
+                tl: [-1.66, 0.75],
+                br: [-0.33, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 45,
+                },
+            },
+        ],
     };
 
     public static ThreeField002: TemplateDocInfos = {
         title: 'threefield2',
-        width: 477, 
-        height: 662, 
+        width: 477,
+        height: 662,
         opts: {
-            backgroundColor: '#9E9C95'
+            backgroundColor: '#9E9C95',
         },
-        fields: [{
-            tl: [-.875, -.9], 
-            br: [.875, .7], 
-            types: [TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A medium to large visual field for the main content of the template',
-            opts: {
-                borderWidth: '15',
-                borderColor: '#E0E0DA',
-            }
-        }, {
-            tl: [.1, .775], 
-            br: [.95, .975], 
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
-            opts: {
-                backgroundColor: 'transparent',
-                color: '#AF0D0D',
-                fontTransform: 'uppercase',
-                fontBold: true,
-                contentXCentering: 'h-left'
-            }
-        }, {
-            tl: [-.95, .775], 
-            br: [-.1, .975],
-            types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: 'A very small text field for one to a few words. The content should contextualize field 2.',
-            opts: {
-                backgroundColor: 'transparent',
-                color: 'black',
-                contentXCentering: 'h-right'
-            }
-        }],
-        decorations: [{
-            tl: [-.025, .8], 
-            br: [.025, .95], 
-            opts: {
-                backgroundColor: '#E0E0DA',
-            }
-        }]
+        fields: [
+            {
+                tl: [-0.875, -0.9],
+                br: [0.875, 0.7],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large visual field for the main content of the template',
+                opts: {
+                    borderWidth: '15',
+                    borderColor: '#E0E0DA',
+                },
+            },
+            {
+                tl: [0.1, 0.775],
+                br: [0.95, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: '#AF0D0D',
+                    fontTransform: 'uppercase',
+                    fontBold: true,
+                    contentXCentering: 'h-left',
+                },
+            },
+            {
+                tl: [-0.95, 0.775],
+                br: [-0.1, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should contextualize field 2.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'black',
+                    contentXCentering: 'h-right',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.025, 0.8],
+                br: [0.025, 0.95],
+                opts: {
+                    backgroundColor: '#E0E0DA',
+                },
+            },
+        ],
     };
 
-
-
-//     public static FourField002: TemplateDocInfos = {
-//         width: 450, 
-//         height: 600, 
-//         fields: [{
-//             tl: [-.6, -.9], 
-//             br: [.6, -.8], 
-//             types: [FieldType.TEXT],
-//             sizes: [FieldSize.TINY]
-//         }, {
-//             tl: [-.9, -.7], 
-//             br: [.9, .2], 
-//             types: [FieldType.TEXT, FieldType.VISUAL],
-//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
-//         }, {
-//             tl: [-.9, .3], 
-//             br: [-.05, .9], 
-//             types: [FieldType.TEXT],
-//             sizes: [FieldSize.TINY]
-//         }, {
-//             tl: [.05, .3], 
-//             br: [.9, .9], 
-//             types: [FieldType.TEXT, FieldType.VISUAL],
-//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
-//         }]
-//     };
-
-//     public static TwoFieldPlusCarousel: TemplateDocInfos = {
-//         width: 500, 
-//         height: 600, 
-//         fields: [{
-//             tl: [-.9, -.99], 
-//             br: [.9, -.7], 
-//             types: [FieldType.TEXT],
-//             sizes: [FieldSize.TINY]
-//         }, {
-//             tl: [-.9, -.65], 
-//             br: [.9, .35], 
-//             types: [],
-//             sizes: []
-//         }, {
-//             tl: [-.9, .4], 
-//             br: [.9, .95], 
-//             types: [FieldType.TEXT],
-//             sizes: [FieldSize.TINY]
-//         }]
-//     };
-
+    //     public static FourField002: TemplateDocInfos = {
+    //         width: 450,
+    //         height: 600,
+    //         fields: [{
+    //             tl: [-.6, -.9],
+    //             br: [.6, -.8],
+    //             types: [FieldType.TEXT],
+    //             sizes: [FieldSize.TINY]
+    //         }, {
+    //             tl: [-.9, -.7],
+    //             br: [.9, .2],
+    //             types: [FieldType.TEXT, FieldType.VISUAL],
+    //             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+    //         }, {
+    //             tl: [-.9, .3],
+    //             br: [-.05, .9],
+    //             types: [FieldType.TEXT],
+    //             sizes: [FieldSize.TINY]
+    //         }, {
+    //             tl: [.05, .3],
+    //             br: [.9, .9],
+    //             types: [FieldType.TEXT, FieldType.VISUAL],
+    //             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+    //         }]
+    //     };
+
+    //     public static TwoFieldPlusCarousel: TemplateDocInfos = {
+    //         width: 500,
+    //         height: 600,
+    //         fields: [{
+    //             tl: [-.9, -.99],
+    //             br: [.9, -.7],
+    //             types: [FieldType.TEXT],
+    //             sizes: [FieldSize.TINY]
+    //         }, {
+    //             tl: [-.9, -.65],
+    //             br: [.9, .35],
+    //             types: [],
+    //             sizes: []
+    //         }, {
+    //             tl: [-.9, .4],
+    //             br: [.9, .95],
+    //             types: [FieldType.TEXT],
+    //             sizes: [FieldSize.TINY]
+    //         }]
+    //     };
 }
-
-export class ContentField extends Field {
-    
-}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 111a4775788a52b218d5dbb49ef8c2d83d90ff3e Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 1 Oct 2024 04:17:34 -0400
Subject: added dompurify

---
 package-lock.json                                       | 17 +++++++++++++++++
 package.json                                            |  2 ++
 .../collections/collectionSchema/SchemaCellField.tsx    |  3 ++-
 3 files changed, 21 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/package-lock.json b/package-lock.json
index a47585c74..0bf5df2d5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -94,6 +94,7 @@
                 "D": "^1.0.0",
                 "d3": "^7.8.5",
                 "depcheck": "^1.4.7",
+                "dompurify": "^3.1.7",
                 "dotenv": "^16.4.5",
                 "eslint-webpack-plugin": "^4.1.0",
                 "exif": "^0.6.0",
@@ -265,6 +266,7 @@
                 "@types/cookie-session": "^2.0.48",
                 "@types/d3": "^7.4.3",
                 "@types/dom-mediacapture-record": "^1.0.19",
+                "@types/dompurify": "^3.0.5",
                 "@types/exif": "^0.6.5",
                 "@types/express": "^5.0.0",
                 "@types/express-session": "^1.17.10",
@@ -9253,6 +9255,15 @@
             "resolved": "https://registry.npmjs.org/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.4.tgz",
             "integrity": "sha512-zf2GwV/G6TdaLwpLDcGTIkHnXf8JEf/viMux+khqKQKDa8/8BAUtXXZS563GnvJ4Fg0PBLGAaFf2GekEVSZ6GQ=="
         },
+        "node_modules/@types/dompurify": {
+            "version": "3.0.5",
+            "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
+            "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
+            "dev": true,
+            "dependencies": {
+                "@types/trusted-types": "*"
+            }
+        },
         "node_modules/@types/eslint": {
             "version": "8.56.12",
             "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
@@ -9925,6 +9936,12 @@
             "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
             "dev": true
         },
+        "node_modules/@types/trusted-types": {
+            "version": "2.0.7",
+            "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+            "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+            "dev": true
+        },
         "node_modules/@types/unist": {
             "version": "3.0.3",
             "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
diff --git a/package.json b/package.json
index a1def81de..f0fa676a6 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
         "@types/cookie-session": "^2.0.48",
         "@types/d3": "^7.4.3",
         "@types/dom-mediacapture-record": "^1.0.19",
+        "@types/dompurify": "^3.0.5",
         "@types/exif": "^0.6.5",
         "@types/express": "^5.0.0",
         "@types/express-session": "^1.17.10",
@@ -173,6 +174,7 @@
         "D": "^1.0.0",
         "d3": "^7.8.5",
         "depcheck": "^1.4.7",
+        "dompurify": "^3.1.7",
         "dotenv": "^16.4.5",
         "eslint-webpack-plugin": "^4.1.0",
         "exif": "^0.6.0",
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index e26dd9646..84e7b62bf 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -8,6 +8,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { ObjectField } from '../../../../fields/ObjectField';
 import { Doc } from '../../../../fields/Doc';
 import { DocumentView } from '../../nodes/DocumentView';
+import DOMPurify from 'dompurify';
 
 /**
  * The SchemaCellField renders text in schema cells while the user is editing, and updates the
@@ -168,7 +169,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
     @action
     setContent = (content: string, restoreCursorPos?: boolean) => {
         const pos = this.cursorPosition;
-        this._displayedContent = this.makeSpans(content);
+        this._displayedContent = DOMPurify.sanitize(this.makeSpans(content));
         restoreCursorPos && setTimeout(() => this.setCursorPosition(pos));
     };
 
-- 
cgit v1.2.3-70-g09d2


From 695a757e1d5d3469a9871b0760c9dedeb073a489 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 4 Oct 2024 21:45:42 -0400
Subject: from last

---
 src/client/views/ContextMenu.tsx                   |  5 +-
 src/client/views/ContextMenuItem.tsx               |  3 +-
 src/client/views/EditableView.tsx                  | 57 +++++++++++-----------
 src/client/views/ScriptingRepl.scss                |  2 -
 .../collectionSchema/SchemaCellField.tsx           | 17 ++++---
 .../views/nodes/DataVizBox/components/TableBox.tsx | 18 ++++---
 6 files changed, 52 insertions(+), 50 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 98087e224..4b67ef704 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,6 +1,3 @@
-/* eslint-disable react/no-array-index-key */
-/* eslint-disable react/jsx-props-no-spreading */
-/* eslint-disable default-param-last */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -277,4 +274,4 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean }
             this._selectedIndex = Math.min(this.flatItems.length - 1, this._selectedIndex);
         }
     };
-}
\ No newline at end of file
+}
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 610032225..6f8f41bdd 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, makeObservable, observable, runInAction } from 'mobx';
@@ -95,4 +94,4 @@ export class ContextMenuItem extends ObservableReactComponent<ContextMenuProps &
         const submenu = this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this._props.closeMenu} />);
         return this.props.event || this._props.noexpand ? this.renderItem(submenu) : <div className="contextMenu-inlineMenu">{submenu}</div>;
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 9722b2d4b..612ecee62 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -7,7 +7,6 @@ import { DocumentIconContainer } from './nodes/DocumentIcon';
 import { FieldView, FieldViewProps } from './nodes/FieldView';
 import { ObservableReactComponent } from './ObservableReactComponent';
 import { OverlayView } from './OverlayView';
-import { Padding } from 'browndash-components';
 import { SchemaFieldType } from './collections/collectionSchema/SchemaColumnHeader';
 
 export interface EditableProps {
@@ -90,7 +89,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
                             this._overlayDisposer?.();
                             this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
                             this._props.highlightCells?.(this._props.GetValue() ?? '');
-                        } 
+                        }
                     });
                 } else {
                     this._overlayDisposer?.();
@@ -200,7 +199,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
             }
         }
     };
-    
+
     @action
     finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
         if (this._props.SetValue(value, shiftDown, enterKey)) {
@@ -235,7 +234,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     setIsEditing = (value: boolean) => {
         this._editing = value;
         return this._editing;
-    }
+    };
 
     renderEditor() {
         return this._props.autosuggestProps ? (
@@ -254,11 +253,11 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
                     onChange: this._props.autosuggestProps.onChange,
                 }}
             />
-        ) : ( this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? (
+        ) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? (
             <input
-                className="editableView-input" 
+                className="editableView-input"
                 ref={r => { this._inputref = r; }} // prettier-ignore
-                style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background}}
+                style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }}
                 placeholder={this._props.placeholder}
                 onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
                 defaultValue={this._props.GetValue()}
@@ -284,39 +283,41 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
                 onClick={this.stopPropagation}
                 onPointerUp={this.stopPropagation}
             />
-        ));
+        );
     }
 
     staticDisplay = () => {
         let toDisplay;
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
-        if (this._props.schemaFieldType === SchemaFieldType.Header){
-            toDisplay = <input className="editableView-input"
-            value={gval}
-            placeholder='Add key'
-            readOnly
-            style={{ display: this._props.display, overflow: 'auto', pointerEvents: 'none', fontSize: this._props.fontSize, width: '100%', margin: 0, background: this._props.background}}
-            // eslint-disable-next-line jsx-a11y/no-autofocus
-        />
+        if (this._props.schemaFieldType === SchemaFieldType.Header) {
+            toDisplay = (
+                <input
+                    className="editableView-input"
+                    value={gval}
+                    placeholder="Add key"
+                    readOnly
+                    style={{ display: this._props.display, overflow: 'auto', pointerEvents: 'none', fontSize: this._props.fontSize, width: '100%', margin: 0, background: this._props.background }}
+                />
+            );
         } else {
-            toDisplay = (<span className='editableView-static'
-            style={{
-                fontStyle: this._props.fontStyle,
-                fontSize: this._props.fontSize
-            }}>
-            {
-                // eslint-disable-next-line react/jsx-props-no-spreading
-                this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : '' as any
-            }
-        </span>)
+            toDisplay = (
+                <span
+                    className="editableView-static"
+                    style={{
+                        fontStyle: this._props.fontStyle,
+                        fontSize: this._props.fontSize,
+                    }}>
+                    {this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : (this.props.contents ?? '')}
+                </span>
+            );
         }
 
         return toDisplay;
-    }
+    };
 
     render() {
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
-        if ((this._editing && gval !== undefined)) {
+        if (this._editing && gval !== undefined) {
             return this._props.sizeToContent ? (
                 <div style={{ display: 'grid', minWidth: 100 }}>
                     <div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{this.renderEditor()}</div>
diff --git a/src/client/views/ScriptingRepl.scss b/src/client/views/ScriptingRepl.scss
index 5fe176920..adc82238e 100644
--- a/src/client/views/ScriptingRepl.scss
+++ b/src/client/views/ScriptingRepl.scss
@@ -35,8 +35,6 @@
     opacity: 0.3;
 }
 
-
-
 .scriptingObject-icon {
     padding: 3px;
     cursor: pointer;
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 84e7b62bf..ce41b2758 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -27,6 +27,7 @@ export interface SchemaCellFieldProps {
     oneLine?: boolean;
     Document: Doc;
     fieldKey: string;
+    // eslint-disable-next-line no-use-before-define
     refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined };
     highlightCells?: (text: string) => void;
     GetValue(): string | undefined;
@@ -301,13 +302,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
                 setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0);
                 break;
             case ' ':
-                e.stopPropagation();
-                let cursorPos = 0;
-                if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
-                setTimeout(() => {
-                    this.setContent(this._unrenderedContent);
-                    setTimeout(() => this.setCursorPosition(cursorPos));
-                }, 0);
+                {
+                    e.stopPropagation();
+                    const cursorPos = this.cursorPosition !== null ? this.cursorPosition + 1 : 0;
+                    setTimeout(() => {
+                        this.setContent(this._unrenderedContent);
+                        setTimeout(() => this.setCursorPosition(cursorPos));
+                    }, 0);
+                }
                 break;
             case 'u': // for some reason 'u' otherwise exits the editor
                 e.stopPropagation();
@@ -318,7 +320,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             case 'Control':
             case ':': // prettier-ignore
                 break;
-            // eslint-disable-next-line no-fallthrough
             default:
                 break;
         }
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 6cc773da0..fe596bc36 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
 import { Button, Colors, Type } from 'browndash-components';
 import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -18,6 +16,7 @@ import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
 import './Chart.scss';
 
+// eslint-disable-next-line @typescript-eslint/no-require-imports
 const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore
 
 interface TableBoxProps {
@@ -416,7 +415,7 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                                                           ? 'darkred'
                                                           : this._props.axes.length > 3 && this._props.axes[1] === col
                                                             ? 'darkblue'
-                                                            : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) 
+                                                            : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
                                                               ? 'darkcyan'
                                                               : undefined,
                                                 background: this.settingTitle
@@ -427,7 +426,7 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                                                         ? '#Fbdbdb'
                                                         : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] === col)
                                                           ? '#c6ebf7'
-                                                          : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) 
+                                                          : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
                                                             ? '#c2f0f4'
                                                             : undefined,
                                                 fontWeight: 'bolder',
@@ -448,8 +447,15 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                                             className={`tableBox-row ${this.columns[0]}`}
                                             onClick={e => this.tableRowClick(e, rowId)}
                                             style={{
-                                                background: rowId === this._props.specHighlightedRow ? 'lightblue' : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
-                                                border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : ''
+                                                background:
+                                                    rowId === this._props.specHighlightedRow
+                                                        ? 'lightblue'
+                                                        : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId)
+                                                          ? 'lightYellow'
+                                                          : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId)
+                                                            ? 'lightgrey'
+                                                            : '',
+                                                border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
                                             }}>
                                             {this.columns.map(col => {
                                                 let colSelected = false;
-- 
cgit v1.2.3-70-g09d2


From 2012b3ade1d4644115e3a59cf0a1deec07e23637 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 4 Oct 2024 21:51:25 -0400
Subject: from last

---
 src/client/views/EditableView.tsx                                 | 1 -
 src/client/views/ScriptingRepl.tsx                                | 3 +--
 src/client/views/collections/collectionSchema/SchemaCellField.tsx | 4 ++--
 3 files changed, 3 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 612ecee62..41079045b 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -239,7 +239,6 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     renderEditor() {
         return this._props.autosuggestProps ? (
             <Autosuggest
-                // eslint-disable-next-line react/jsx-props-no-spreading
                 {...this._props.autosuggestProps.autosuggestProps}
                 inputProps={{
                     className: 'editableView-input',
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 2de867746..e413c13e2 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/no-array-index-key */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
@@ -182,7 +181,7 @@ export class ScriptingRepl extends ObservableReactComponent<object> {
                     this.maybeScrollToBottom();
                     return;
                 }
-                const result = undoable(() => script.run({}, e => this.commands.push({ command: this.commandString, result: e as string })), 'run:' + this.commandString)();
+                const result = undoable(() => script.run({}, err => this.commands.push({ command: this.commandString, result: err })), 'run:' + this.commandString)();
                 if (result.success) {
                     this.commands.push({ command: this.commandString, result: result.result });
                     this.commandsHistory.push(this.commandString);
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index ce41b2758..3924ed087 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -155,8 +155,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
             }
         }
 
-        matches.forEach((match: string) => {
-            chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
+        matches.forEach(m => {
+            chunkedText = chunkedText.replace(m, this.generateSpan(m, cells.get(m)));
         });
 
         return chunkedText;
-- 
cgit v1.2.3-70-g09d2


From 6ae5bd63d5355a03dba099a149532e7c6b1fd74a Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 9 Oct 2024 16:58:33 -0400
Subject: small changes for pull request; removed schema type reference in
 editableview; a couple lint changes

---
 package-lock.json                                      |  6 +++---
 src/client/views/EditableView.tsx                      |  7 ++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx      |  2 +-
 .../collections/collectionSchema/SchemaCellField.tsx   |  4 ++--
 .../collectionSchema/SchemaColumnHeader.tsx            |  3 ++-
 src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx   |  2 +-
 src/client/views/nodes/ImageBox.tsx                    | 18 +++++++++---------
 7 files changed, 22 insertions(+), 20 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaCellField.tsx')

diff --git a/package-lock.json b/package-lock.json
index 3b1ea2017..c49821f9d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17447,9 +17447,9 @@
             }
         },
         "node_modules/dompurify": {
-            "version": "3.1.6",
-            "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
-            "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
+            "version": "3.1.7",
+            "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz",
+            "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ=="
         },
         "node_modules/domutils": {
             "version": "3.1.0",
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 9722b2d4b..9974fc63b 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -54,7 +54,8 @@ export interface EditableProps {
     placeholder?: string;
     wrap?: string; // nowrap, pre-wrap, etc
 
-    schemaFieldType?: SchemaFieldType;
+    inputString?: boolean;
+    inputStringPlaceholder?: string;
     prohibitedText?: Array<string>;
     onClick?: () => void;
     updateAlt?: (newAlt: string) => void;
@@ -290,10 +291,10 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     staticDisplay = () => {
         let toDisplay;
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
-        if (this._props.schemaFieldType === SchemaFieldType.Header){
+        if (this._props.inputString){
             toDisplay = <input className="editableView-input"
             value={gval}
-            placeholder='Add key'
+            placeholder={this._props.inputStringPlaceholder}
             readOnly
             style={{ display: this._props.display, overflow: 'auto', pointerEvents: 'none', fontSize: this._props.fontSize, width: '100%', margin: 0, background: this._props.background}}
             // eslint-disable-next-line jsx-a11y/no-autofocus
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0cc63d632..d2bc8f2c2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1221,7 +1221,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
      * Function that creates a drawing--a group of ink strokes--to go with the smart draw function.
      */
     @undoBatch
-    createDrawingDoc = (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
+    createDrawingDoc = (strokeData: [InkData, string, string][], opts: DrawingOptions) => {
         this._drawing = [];
         const xf = this.screenToFreeformContentsXf;
         strokeData.forEach((stroke: [InkData, string, string]) => {
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 84e7b62bf..dab494c0e 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -5,7 +5,7 @@ import { OverlayView } from '../../OverlayView';
 import { DocumentIconContainer } from '../../nodes/DocumentIcon';
 import React, { FormEvent } from 'react';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
-import { ObjectField } from '../../../../fields/ObjectField';
+import { FieldType, ObjectField } from '../../../../fields/ObjectField';
 import { Doc } from '../../../../fields/Doc';
 import { DocumentView } from '../../nodes/DocumentView';
 import DOMPurify from 'dompurify';
@@ -21,7 +21,7 @@ import DOMPurify from 'dompurify';
  */
 
 export interface SchemaCellFieldProps {
-    contents: any;
+    contents: FieldType;
     fieldContents?: FieldViewProps;
     editing?: boolean;
     oneLine?: boolean;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index c5cdac8af..207e1deac 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -135,7 +135,8 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                 placeholder={'Add key'}
                 updateAlt={this.updateAlt} // alternate title to display
                 updateSearch={this.updateKeyDropdown}
-                schemaFieldType={SchemaFieldType.Header} 
+                inputString={true}
+                inputStringPlaceholder={'Add key'}
                 GetValue={() => {
                     if (SchemaColumnHeader.isDefaultField(this.fieldKey)) return '';
                     else if (this._altTitle) return this._altTitle;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 44f743a97..ad47b7848 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -943,7 +943,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     removeDocument={returnFalse}
                     PanelWidth={() => this._menuDimensions.width - 10}
                     PanelHeight={() => this._menuDimensions.height - 60}
-                    ScreenToLocalTransform={Transform.Identity}
+                    ScreenToLocalTransform={() => new Transform(-this._pageX,-this._pageY, 1)}
                     renderDepth={5}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={emptyFunction}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 226fad977..c156c80e4 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -124,15 +124,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             { fireImmediately: true, delay: 1000 }
         );
         const { layoutDoc } = this;
-        // this._disposers.path = reaction(
-        //     () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
-        //     ({ nativeSize, width }) => {
-        //         if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
-        //             this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
-        //         }
-        //     },
-        //     { fireImmediately: true }
-        // );
+        this._disposers.path = reaction(
+            () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
+            ({ nativeSize, width }) => {
+                if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
+                    this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
+                }
+            },
+            { fireImmediately: true }
+        );
         this._disposers.scroll = reaction(
             () => this.layoutDoc.layout_scrollTop,
             sTop => {
-- 
cgit v1.2.3-70-g09d2

