From c31bb0d5d8c4d42fb5cd97b1582de0cae1b16ca0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 12 May 2022 12:17:12 -0400
Subject: fixed perfromance (flickering, speed) issues with having
 pointerEvents prop invalidate documents - switched to using a function to
 avoid flickering on PDFs of annotations in particular.

---
 src/client/views/nodes/ComparisonBox.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/ComparisonBox.tsx')

diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 78608b681..abb01c466 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -3,7 +3,7 @@ import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import { Doc, Opt } from '../../../fields/Doc';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, OmitKeys, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { undoBatch } from '../../util/UndoManager';
@@ -96,7 +96,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     Document={targetDoc}
                     DataDoc={undefined}
                     hideLinkButton={true}
-                    pointerEvents={"none"} />
+                    pointerEvents={returnNone} />
                 {clearButton(which)}
             </> :  // placeholder image if doc is missing
                 <div className="placeholder">
-- 
cgit v1.2.3-70-g09d2


From e40a1e248da90af698d5ff64bd5d63d11211e6dc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 13 May 2022 11:58:10 -0400
Subject: fixed crashing bug when quickly re-updating webbox (or other) icon. 
 fixed infinite loop in FilterBox.  changed TimeView to scale WebBox's.  fixed
 issues with timeView filters.  fixed bugs with webBox scrolling on startup,
 following links, etc.

---
 .../views/collections/CollectionTimeView.tsx       |  18 +--
 .../CollectionFreeFormLayoutEngines.tsx            |   2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 src/client/views/nodes/ComparisonBox.tsx           |   2 +-
 src/client/views/nodes/DocumentView.tsx            |  23 ++--
 src/client/views/nodes/FilterBox.tsx               |  10 +-
 src/client/views/nodes/WebBox.tsx                  | 136 +++++++++++----------
 src/client/views/pdf/Annotation.tsx                |  37 +++---
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 src/client/views/search/SearchBox.tsx              |   4 +-
 src/fields/Doc.ts                                  |  32 ++++-
 src/server/ApiManagers/UploadManager.ts            |  14 ++-
 12 files changed, 166 insertions(+), 118 deletions(-)

(limited to 'src/client/views/nodes/ComparisonBox.tsx')

diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index e63ea7151..4f6f45d2f 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -10,6 +10,7 @@ import { ComputedField, ScriptField } from "../../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { ScriptingGlobals } from "../../util/ScriptingGlobals";
 import { ContextMenu } from "../ContextMenu";
@@ -128,6 +129,7 @@ export class CollectionTimeView extends CollectionSubView() {
         }
     }
 
+    dontScaleFilter = (doc: Doc) => doc.type === DocumentType.RTF;
     @computed get contents() {
         return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : "none" }}
             onClick={this.contentsDown}>
@@ -137,6 +139,7 @@ export class CollectionTimeView extends CollectionSubView() {
                 childClickScript={this._childClickedScript}
                 viewDefDivClick={this._viewDefDivClick}
                 childFreezeDimensions={true}
+                dontScaleFilter={this.dontScaleFilter}
                 layoutEngine={this.layoutEngine} />
         </div>;
     }
@@ -174,7 +177,7 @@ export class CollectionTimeView extends CollectionSubView() {
             typeof (pair.layout[fieldKey]) === "string").filter(fieldKey => fieldKey[0] !== "_" && (fieldKey[0] !== "#" || fieldKey === "#") && (fieldKey === "tags" || fieldKey[0] === toUpper(fieldKey)[0])).map(fieldKey => keySet.add(fieldKey)));
         Array.from(keySet).map(fieldKey =>
             docItems.push({ description: ":" + fieldKey, event: () => this.layoutDoc._pivotField = fieldKey, icon: "compress-arrows-alt" }));
-        docItems.push({ description: ":(null)", event: () => this.layoutDoc._pivotField = undefined, icon: "compress-arrows-alt" });
+        docItems.push({ description: ":default", event: () => this.layoutDoc._pivotField = undefined, icon: "compress-arrows-alt" });
         ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" });
         const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
         ContextMenu.Instance.displayMenu(x, y, ":");
@@ -234,16 +237,17 @@ export class CollectionTimeView extends CollectionSubView() {
 }
 
 ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
+    const pivotField = StrCast(pivotDoc._pivotField) || "author";
     let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
     const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField));
     pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
     pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
-    pivotDoc["_prevPivotFields" + prevFilterIndex] = pivotDoc._pivotField;
+    pivotDoc["_prevPivotFields" + prevFilterIndex] = pivotField;
     pivotDoc._prevFilterIndex = ++prevFilterIndex;
-    runInAction(() => {
-        pivotDoc._docFilters = new List();
+    pivotDoc._docFilters = new List();
+    setTimeout(action(() => {
         const filterVals = (bounds.payload as string[]);
-        filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check"));
+        filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, "check"));
         const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc);
         if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) {
             if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
@@ -252,11 +256,11 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou
         }
         const newFilters = StrListCast(pivotDoc._docFilters);
         if (newFilters.length && originalFilter.length &&
-            newFilters[newFilters.length - 1] === originalFilter[originalFilter.length - 1]) {
+            newFilters.lastElement() === originalFilter.lastElement()) {
             pivotDoc._prevFilterIndex = --prevFilterIndex;
             pivotDoc["_prevDocFilter" + prevFilterIndex] = undefined;
             pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = undefined;
             pivotDoc["_prevPivotFields" + prevFilterIndex] = undefined;
         }
-    });
+    }));
 });
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 16c7df311..9de2cfcf9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -147,7 +147,7 @@ export function computePivotLayout(
     const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>();
 
     let nonNumbers = 0;
-    const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField);
+    const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField) || "author";
     childPairs.map(pair => {
         const lval = pivotFieldKey === "#" || pivotFieldKey === "tags" ? Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(k => k.startsWith("#")).map(k => k.substring(1)) :
             Cast(pair.layout[pivotFieldKey], listSpec("string"), null);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 19b6612b0..4f79d19ad 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -75,6 +75,7 @@ export type collectionFreeformViewProps = {
     scaleField?: string;
     noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
     engineProps?: any;
+    dontScaleFilter?: (doc: Doc) => boolean; // whether this collection should scale documents to fit their panel vs just scrolling them
     dontRenderDocuments?: boolean; // used for annotation overlays which need to distribute documents into different freeformviews with different mixBlendModes depending on whether they are transparent or not.  
     // However, this screws up interactions since only the top layer gets events.  so we render the freeformview a 3rd time with all documents in order to get interaction events (eg., marquee) but we don't actually want to display the documents.
 };
@@ -1197,10 +1198,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             layerProvider={this.props.layerProvider}
             dataProvider={this.childDataProvider}
             sizeProvider={this.childSizeProvider}
-            freezeDimensions={this.props.childFreezeDimensions}
+            freezeDimensions={BoolCast(this.props.Document.childFreezeDimensions, this.props.childFreezeDimensions)}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
             showTitle={this.props.childShowTitle}
+            dontScaleFilter={this.props.dontScaleFilter}
             dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
             pointerEvents={this.pointerEvents}
             jitterRotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index abb01c466..49cd39f43 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -87,7 +87,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             return whichDoc ? <>
                 <DocumentView
                     ref={(r) => {
-                        whichDoc !== targetDoc && r?.focus(targetDoc);
+                        whichDoc !== targetDoc && r?.focus(whichDoc);
                     }}
                     {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                     isContentActive={returnFalse}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e117be0c2..f30d093a1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -168,6 +168,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     radialMenu?: String[];
     LayoutTemplateString?: string;
     dontCenter?: "x" | "y" | "xy";
+    dontScaleFilter?: (doc: Doc) => boolean; // decides whether a document can be scaled to fit its container vs native size with scrolling
     ContentScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal
     NativeWidth?: () => number;
     NativeHeight?: () => number;
@@ -249,6 +250,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
         }
     }
+    @action
     cleanupHandlers(unbrush: boolean) {
         this._dropDisposer?.();
         this._multiTouchDisposer?.();
@@ -856,9 +858,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             this.props.isContentActive()) ? true : undefined;
     }
     @observable _retryThumb = 1;
-    thumbShown = () => !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
-        !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
-        !this._componentView?.isAnyChildContentActive?.() ? true : false
+    thumbShown = () => {
+        return !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
+            !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
+            !Doc.isBrushedHighlightedDegree(this.props.Document) &&
+            !this._componentView?.isAnyChildContentActive?.() ? true : false;
+    }
     @computed get contents() {
         TraceMobx();
         const audioView = !this.layoutDoc._showAudio ? (null) :
@@ -874,7 +879,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             {!this._retryThumb || !this.thumbShown() ? (null) :
-                <img style={{ background: "white", top: 0, position: "absolute" }} src={this.thumb} // + '?d=' + (new Date()).getTime()}
+                <img style={{ background: "white", top: 0, position: "relative" }} src={this.thumb} // + '?d=' + (new Date()).getTime()}
                     width={this.props.PanelWidth()} height={this.props.PanelHeight()}
                     onError={(e: any) => {
                         setTimeout(action(() => this._retryThumb = 0), 0);
@@ -1109,8 +1114,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     render() {
         TraceMobx();
         const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
-        const highlightColor = ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "orange"][highlightIndex];
-        const highlightStyle = ["solid", "dashed", "solid", "solid"][highlightIndex];
+        const highlightColor = ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "orange", "lightBlue"][highlightIndex];
+        const highlightStyle = ["solid", "dashed", "solid", "solid", "solid"][highlightIndex];
         const excludeTypes = !this.props.treeViewDoc && highlightIndex < 3 ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON];
         let highlighting = !this.props.disableDocBrushing && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
         highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]";  // bcz: hack to turn off highlighting onsidebar panel documents.  need to flag a document as not highlightable in a more direct way
@@ -1126,8 +1131,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             onKeyDown={this.onKeyDown}
             onPointerDown={this.onPointerDown}
             onClick={this.onClick}
-            onPointerEnter={e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document)}
-            onPointerLeave={e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document)}
+            onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))}
+            onPointerLeave={action(e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document))}
             style={{
                 display: this.hidden ? "inline" : undefined,
                 borderRadius: this.borderRounding,
@@ -1207,7 +1212,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
     @computed get shouldNotScale() {
         return (this.fitWidth && !this.nativeWidth) ||
-            this.props.ContainingCollectionView?.collectionViewType === CollectionViewType.Time ||
+            this.props.dontScaleFilter?.(this.Document) ||
             this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any);
     }
     @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); }
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index dc0ab5ec2..78adf63cb 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -96,17 +96,15 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 runInAction(() => this._loaded = true);
             }, { fireImmediately: true });
     }
-    @observable _allDocs = [] as Doc[];
+
     @computed get allDocs() {
         // trace();
+        const allDocs = new Set<Doc>();
         const targetDoc = FilterBox.targetDoc;
         if (this._loaded && targetDoc) {
-            const allDocs = new Set<Doc>();
-            const activeTabs = FilterBox.targetDocChildren;
-            SearchBox.foreachRecursiveDoc(activeTabs, (depth, doc) => allDocs.add(doc));
-            setTimeout(action(() => this._allDocs = Array.from(allDocs)));
+            SearchBox.foreachRecursiveDoc(FilterBox.targetDocChildren, (depth, doc) => allDocs.add(doc));
         }
-        return this._allDocs;
+        return Array.from(allDocs);
     }
 
     @computed get _allFacets() {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 64655ba0b..af7a2b941 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -40,7 +40,6 @@ import React = require("react");
 const { CreateImage } = require("./WebBoxRenderer");
 const _global = (window /* browser */ || global /* node */) as any;
 const htmlToText = require("html-to-text");
-
 @observer
 export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
@@ -52,7 +51,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     private _keyInput = React.createRef<HTMLInputElement>();
-    private _initialScroll: Opt<number>;
+    private _initialScroll: Opt<number> = NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop));
     private _sidebarRef = React.createRef<SidebarAnnos>();
     private _searchRef = React.createRef<HTMLInputElement>();
     private _searchString = "";
@@ -68,14 +67,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable private _iframeClick: HTMLIFrameElement | undefined = undefined;
     @observable private _iframe: HTMLIFrameElement | null = null;
     @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
-    @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight, 1500);
+    @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight);
     @computed get _url() { return this.webField?.toString() || ""; }
     @computed get _urlHash() { return this._url ? WebBox.urlHash(this._url) + "" : ""; }
-    @computed get scrollHeight() { return this._scrollHeight; }
+    @computed get scrollHeight() { return Math.max(this.layoutDoc[HeightSym](), this._scrollHeight); }
     @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
     @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
     @computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
-    @computed get webThumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url; }
+    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url }
 
     constructor(props: any) {
         super(props);
@@ -100,14 +99,49 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         return true;
     }
+    @action
     setScrollPos = (pos: number) => {
         if (!this._outerRef.current || this._outerRef.current.scrollHeight < pos) {
-            setTimeout(() => this.setScrollPos(pos), 250);
+            if (this._webPageHasBeenRendered) setTimeout(() => this.setScrollPos(pos), 250);
         } else {
             this._outerRef.current.scrollTop = pos;
             this._initialScroll = undefined;
         }
     }
+
+    lockout = false;
+    updateThumb = async () => {
+        const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
+        const scrollTop = NumCast(this.layoutDoc._scrollTop);
+        if (!this.lockout && this._iframe && !imageBitmap && scrollTop !== this.layoutDoc.thumbScrollTop) {
+            var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
+            if (!htmlString) {
+                htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
+            }
+            this.layoutDoc.thumb = undefined;
+            this.lockout = true; // lock to prevent multiple thumb updates.
+            const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
+            CreateImage(
+                this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
+                this._iframe.contentDocument?.styleSheets ?? [],
+                htmlString,
+                nativeWidth,
+                nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
+                scrollTop
+            ).then
+                ((data_url: any) => {
+                    VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then(
+                        returnedfilename => setTimeout(action(() => {
+                            this.lockout = false;
+                            this.layoutDoc.thumb = new ImageField(returnedfilename);
+                            this.layoutDoc.thumbScrollTop = scrollTop
+                        }), 500));
+                })
+                .catch(function (error: any) {
+                    console.error('oops, something went wrong!', error);
+                });
+        }
+    }
     async componentDidMount() {
         this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document.  this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
 
@@ -117,45 +151,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`);
             this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`);
         });
-        reaction(() => this.props.isSelected(),
+        reaction(() => this.props.isSelected() || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document),
             async (selected) => {
                 if (selected) {
                     this._webPageHasBeenRendered = true;
-                    setTimeout(action(() => {
-                        this._scrollHeight = Math.max(this.scrollHeight, this._iframe?.contentDocument?.body.scrollHeight || 0);
-                        if (this._initialScroll !== undefined) {
-                            this.setScrollPos(this._initialScroll);
-                        }
-                    }));
                 } else if ((!this.props.isContentActive() || SnappingManager.GetIsDragging()) &&   // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail)
                     !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && // don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty
                     LightboxView.LightboxDoc !== this.rootDoc) { // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty.
-                    const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
-                    if (this._iframe && !imageBitmap) {
-                        var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
-                        if (!htmlString) {
-                            htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
-                        }
-                        this.layoutDoc.thumb = undefined;
-                        const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
-                        CreateImage(
-                            this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
-                            this._iframe.contentDocument?.styleSheets ?? [],
-                            htmlString,
-                            nativeWidth,
-                            nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
-                            NumCast(this.layoutDoc._scrollTop)
-                        ).then
-                            ((data_url: any) => {
-                                VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then(
-                                    returnedfilename => setTimeout(action(() => this.layoutDoc.thumb = new ImageField(returnedfilename)), 500));
-                            })
-                            .catch(function (error: any) {
-                                console.error('oops, something went wrong!', error);
-                            });
-                    }
+                    this.updateThumb();
                 }
-            }, { fireImmediately: this.props.isSelected() });
+            }, { fireImmediately: this.props.isSelected() || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegree(this.props.Document) ? true : false) });
 
         this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight,
             autoHeight => {
@@ -183,21 +188,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
         }
 
-        var quickScroll = true;
         this._disposers.scrollReaction = reaction(() => NumCast(this.layoutDoc._scrollTop),
             (scrollTop) => {
-                if (quickScroll) this._initialScroll = scrollTop;
-                else {
-                    const viewTrans = StrCast(this.Document._viewTransition);
-                    const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
-                    const durationSecStr = viewTrans.match(/([0-9.]*)s/);
-                    const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
-                    this.goTo(scrollTop, duration);
-                }
+                const viewTrans = StrCast(this.Document._viewTransition);
+                const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
+                const durationSecStr = viewTrans.match(/([0-9.]*)s/);
+                const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
+                this.goTo(scrollTop, duration);
             },
             { fireImmediately: true }
         );
-        quickScroll = false;
     }
     @action componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
@@ -234,7 +234,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
 
     scrollFocus = (doc: Doc, smooth: boolean) => {
-        this.props.select(false); // hack to preven the webBox from being replaced with a thumbnail that currently doesn't show the the anchors
         if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth);
         if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(!smooth);
@@ -242,15 +241,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1;
         if (doc !== this.rootDoc && this._outerRef.current) {
             const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * .1, this.getScrollHeight());
-            if (scrollTo !== undefined) {
+            const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * .1,
+                Math.max(NumCast(doc.y) + doc[HeightSym](), this.getScrollHeight()));
+            if (scrollTo !== undefined && this._initialScroll === undefined) {
                 const focusSpeed = smooth ? 500 : 0;
-                this._initialScroll !== undefined && (this._initialScroll = scrollTo);
                 this.goTo(scrollTo, focusSpeed);
                 return focusSpeed;
+            } else if (!this._webPageHasBeenRendered || !this.getScrollHeight() || this._initialScroll !== undefined) {
+                this._initialScroll = scrollTo;
             }
         }
-        this._initialScroll = NumCast(this.layoutDoc._scrollTop);
         return undefined;
     }
 
@@ -324,6 +324,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @action
     iframeLoaded = (e: any) => {
         const iframe = this._iframe;
+        if (this._initialScroll !== undefined) {
+            this.setScrollPos(this._initialScroll);
+        }
         let requrlraw = decodeURIComponent(iframe?.contentWindow?.location.href.replace(Utils.prepend("") + "/corsProxy/", "") ?? this._url.toString());
         if (requrlraw !== this._url.toString()) {
             if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
@@ -342,8 +345,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (iframe?.contentDocument) {
             iframe.contentDocument.addEventListener("pointerup", this.iframeUp);
             iframe.contentDocument.addEventListener("pointerdown", this.iframeDown);
-            this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument.body.scrollHeight);
-            setTimeout(action(() => this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0)), 5000);
+            this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument.body.scrollHeight);
+            setTimeout(action(() => this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0)), 5000);
             iframe.setAttribute("enable-annotation", "true");
             iframe.contentDocument.addEventListener("click", undoBatch(action((e: MouseEvent) => {
                 let href = "";
@@ -374,29 +377,29 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @action
     setDashScrollTop = (scrollTop: number, timeout: number = 250) => {
-        const iframeHeight = Math.max(1000, this._scrollHeight - this.panelHeight());
-        timeout = scrollTop > iframeHeight ? 0 : timeout;
+        const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight());
         this._scrollTimer && clearTimeout(this._scrollTimer);
         this._scrollTimer = setTimeout(action(() => {
             this._scrollTimer = undefined;
             if (!LinkDocPreview.LinkInfo && this._outerRef.current &&
                 (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
-                this.layoutDoc._scrollTop = this._outerRef.current.scrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
+                this.layoutDoc.thumb = undefined;
+                this.layoutDoc.thumbScrollTop = undefined;
+                this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
             }
         }), timeout);
     }
 
     goTo = (scrollTop: number, duration: number) => {
         if (this._outerRef.current) {
-            const iframeHeight = Math.max(1000, this._scrollHeight - this.panelHeight());
-            scrollTop = scrollTop > iframeHeight + 50 ? iframeHeight : scrollTop;
+            const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight());
             if (duration) {
                 smoothScroll(duration, [this._outerRef.current], scrollTop);
                 this.setDashScrollTop(scrollTop, duration);
             } else {
                 this.setDashScrollTop(scrollTop);
             }
-        }
+        } else this._initialScroll = scrollTop;
     }
 
     forward = (checkAvailable?: boolean) => {
@@ -456,6 +459,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             if (url && !preview) {
                 this.dataDoc[this.fieldKey + "-history"] = new List<string>([...(history || []), url]);
                 this.layoutDoc._scrollTop = 0;
+                if (this._webPageHasBeenRendered) {
+                    this.layoutDoc.thumb = undefined;
+                    this.layoutDoc.thumbScrollTop = undefined;
+                }
                 future && (future.length = 0);
             }
             if (!preview) {
@@ -566,6 +573,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @computed get urlContent() {
         if (this._hackHide || (this.webThumb && (!this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc))) return (null);
+        this.props.thumbShown?.();
         const field = this.dataDoc[this.props.fieldKey];
         let view;
         if (field instanceof HtmlField) {
@@ -583,7 +591,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 style={{ pointerEvents: this._scrollTimer ? "none" : undefined }} // if we allow pointer events when scrolling is on, then reversing direction does not work smoothly
                 ref={action((r: HTMLIFrameElement | null) => this._iframe = r)} src={"https://crossorigin.me/https://cs.brown.edu"} />;
         }
-        setTimeout(action(() => this._webPageHasBeenRendered = true));
+        setTimeout(action(() => {
+            this._scrollHeight = Math.max(this._scrollHeight, this._iframe && this._iframe.contentDocument && this._iframe.contentDocument.body ? this._iframe.contentDocument.body.scrollHeight : 0);
+            if (this._initialScroll === undefined && !this._webPageHasBeenRendered) this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+            this._webPageHasBeenRendered = true;
+        }));
         return view;
     }
 
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 218f37f3d..fb2e33e2a 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -22,7 +22,11 @@ interface IAnnotationProps extends FieldViewProps {
 export
     class Annotation extends React.Component<IAnnotationProps> {
     render() {
-        return DocListCast(this.props.anno.textInlineAnnotations).map(a => <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} />);
+        return <div>
+            {DocListCast(this.props.anno.textInlineAnnotations).map(a =>
+                <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} />
+            )}
+        </div>
     }
 }
 
@@ -32,23 +36,10 @@ interface IRegionAnnotationProps extends IAnnotationProps {
 }
 @observer
 class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
-    private _disposers: { [name: string]: IReactionDisposer } = {};
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
 
-    @observable _brushed: boolean = false;
     @computed get annoTextRegion() { return Cast(this.props.document.annoTextRegion, Doc, null) || this.props.document; }
 
-    componentDidMount() {
-        this._disposers.brush = reaction(
-            () => this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion),
-            brushed => brushed !== undefined && runInAction(() => this._brushed = brushed !== 0)
-        );
-    }
-
-    componentWillUnmount() {
-        Object.values(this._disposers).forEach(disposer => disposer?.());
-    }
-
     @undoBatch
     deleteAnnotation = () => {
         const docAnnotations = DocListCast(this.props.dataDoc[this.props.fieldKey]);
@@ -91,15 +82,27 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     }
 
     render() {
-        return (<div className="htmlAnnotation" onPointerEnter={() => this.props.showInfo(this.props.anno)} onPointerLeave={() => this.props.showInfo(undefined)} onPointerDown={this.onPointerDown} ref={this._mainCont}
+        const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion);
+        return (<div className="htmlAnnotation" ref={this._mainCont}
+            onPointerEnter={action(() => {
+                Doc.BrushDoc(this.props.anno);
+                this.props.showInfo(this.props.anno);
+            })}
+            onPointerLeave={action(() => {
+                Doc.UnBrushDoc(this.props.anno);
+                this.props.showInfo(undefined);
+            })}
+            onPointerDown={this.onPointerDown}
             style={{
                 left: NumCast(this.props.document.x),
                 top: NumCast(this.props.document.y),
                 width: NumCast(this.props.document._width),
                 height: NumCast(this.props.document._height),
-                opacity: this._brushed ? 0.5 : undefined,
+                opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined,
                 pointerEvents: this.props.pointerEvents?.() as any,
-                backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor),
+                outline: brushed === Doc.DocBrushStatus.linkHighlighted ? "solid 1px lightBlue" : undefined,
+                backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? "orange" :
+                    StrCast(this.props.document.backgroundColor),
             }} >
         </div>);
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 608ba07ff..b0a5fc93b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -484,7 +484,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             CollectionView={undefined}
             ScreenToLocalTransform={this.overlayTransform}
             renderDepth={this.props.renderDepth + 1}
-        />;
+        />
     @computed get overlayTransparentAnnotations() { return this.renderAnnotations(this.transparentFilter, false); }
     @computed get overlayOpaqueAnnotations() { return this.renderAnnotations(this.opaqueFilter, false); }
     @computed get overlayClickableAnnotations() {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 3d36efbc4..2905e96d9 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -127,9 +127,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
         let newarray: Doc[] = [];
         var depth = 0;
+        let visited: Doc[] = [];
         while (docs.length > 0) {
             newarray = [];
-            docs.filter(d => d).forEach(d => {
+            docs.filter(d => d && !visited.includes(d)).forEach(d => {
+                visited.push(d);
                 const fieldKey = Doc.LayoutFieldKey(d);
                 const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
                 const data = d[annos ? fieldKey + "-annotations" : fieldKey];
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 50e5fcbc4..9de8d0831 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1016,12 +1016,28 @@ export namespace Doc {
         unbrushed = 0,
         protoBrushed = 1,
         selfBrushed = 2,
-        highlighted = 3
+        highlighted = 3,
+        linkHighlighted = 4,
     }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
     export function IsBrushedDegreeUnmemoized(doc: Doc) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return DocBrushStatus.unbrushed;
-        return brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
+        const status = brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
+        if (status === DocBrushStatus.unbrushed) {
+            const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement();
+            if (lastBrushed) {
+                for (var link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
+                    const a1 = Cast(link.anchor1, Doc, null);
+                    const a2 = Cast(link.anchor2, Doc, null);
+                    if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) ||
+                        (Doc.AreProtosEqual(Cast(a1.annotationOn, Doc, null), doc)) ||
+                        (Doc.AreProtosEqual(Cast(a2.annotationOn, Doc, null), doc))) {
+                        return DocBrushStatus.linkHighlighted;
+                    }
+                }
+            }
+        }
+        return status;
     }
     export function IsBrushedDegree(doc: Doc) {
         return computedFn(function IsBrushDegree(doc: Doc) {
@@ -1030,14 +1046,18 @@ export namespace Doc {
     }
     export function BrushDoc(doc: Doc) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
-        brushManager.BrushedDoc.set(doc, true);
-        brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
+        runInAction(() => {
+            brushManager.BrushedDoc.set(doc, true);
+            brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
+        });
         return doc;
     }
     export function UnBrushDoc(doc: Doc) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
-        brushManager.BrushedDoc.delete(doc);
-        brushManager.BrushedDoc.delete(Doc.GetProto(doc));
+        runInAction(() => {
+            brushManager.BrushedDoc.delete(doc);
+            brushManager.BrushedDoc.delete(Doc.GetProto(doc));
+        });
         return doc;
     }
 
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 83a2bc79b..cd85a7a65 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -271,10 +271,10 @@ export default class UploadManager extends ApiManager {
                 return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
                     const ext = extname(savedName).toLowerCase();
                     const { pngs, jpgs } = AcceptableMedia;
-                    const resizers = !origSuffix ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" }] : [
-                        { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: "_s" },
-                        { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" },
-                        { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: "_l" },
+                    const resizers = !origSuffix ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium }] : [
+                        { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Small },
+                        { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium },
+                        { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Large },
                     ];
                     let isImage = false;
                     if (pngs.includes(ext)) {
@@ -290,8 +290,10 @@ export default class UploadManager extends ApiManager {
                     }
                     if (isImage) {
                         resizers.forEach(resizer => {
-                            const path = serverPathToFile(Directory.images, filename + resizer.suffix + ext);
-                            createReadStream(savedName).pipe(resizer.resizer).pipe(createWriteStream(path));
+                            const path = serverPathToFile(Directory.images, InjectSize(filename, resizer.suffix) + ext);
+                            createReadStream(savedName).on("error", e => console.log("Resizing Read error:" + e))
+                                .pipe(resizer.resizer)
+                                .pipe(createWriteStream(path).on("error", e => console.log("Resizing write error: " + e)));
                         });
 
                     }
-- 
cgit v1.2.3-70-g09d2


From 6df80c76b4046ef1ac9e98e52f766dfaf540ead2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 20 May 2022 12:51:51 -0400
Subject: removed enumerables field stuff which was hacky and never used. 
 cleaned up some of currentUserUtils initialiazation.  fixed treeView sorting
 for 'none" which fixes problem with slide template.

---
 src/client/documents/Documents.ts                  |  24 --
 src/client/util/CurrentUserUtils.ts                | 242 +++++----------------
 .../views/collections/CollectionStackingView.tsx   |   1 -
 src/client/views/collections/TreeView.tsx          |   2 +-
 src/client/views/nodes/ComparisonBox.tsx           |   2 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |  14 --
 6 files changed, 57 insertions(+), 228 deletions(-)

(limited to 'src/client/views/nodes/ComparisonBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2dd8de089..4be9674f7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1406,30 +1406,6 @@ export namespace DocUtils {
         return undefined;
     }
 
-    export async function addFieldEnumerations(doc: Opt<Doc>, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) {
-        let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey);
-        if (!(optionsCollection instanceof Doc)) {
-            optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set`, system: true }, enumeratedFieldKey);
-            Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
-        }
-        const options = optionsCollection as Doc;
-        const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc);
-        const docFind = `options.data?.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`;
-        targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options }));
-        targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options }));
-        targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options }));
-        enumerations.map(enumeration => {
-            const found = DocListCast(options.data).find(d => d.title === enumeration.title);
-            if (found) {
-                found._backgroundColor = enumeration._backgroundColor || found._backgroundColor;
-                found._color = enumeration.color || found._color;
-            } else {
-                Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, { ...enumeration, system: true }));
-            }
-        });
-        return optionsCollection;
-    }
-
     // /**
     //  * 
     //  * @param dms Degree Minute Second format exif gps data
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 8fed6e940..e0580d3c4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -75,201 +75,68 @@ export class CurrentUserUtils {
     @observable public static searchPanelWidth: number = 0;
 
     // sets up the default User Templates - slideView,  headerView
-    static setupUserTemplateButtons(doc: Doc) {
-        // Prototype for mobile button (not sure if 'Advanced Item Prototypes' is ideal location)
-        if (doc["template-mobile-button"] === undefined) {
-            const queryTemplate = this.mobileButton({
-                title: "NEW MOBILE BUTTON",
-                onClick: undefined,
-            },
-                [this.createToolButton({
-                    ignoreClick: true,
-                    icon: "mobile",
-                    btnType: ButtonType.ToolButton,
-                    backgroundColor: "transparent"
-                }),
-                this.mobileTextContainer({},
-                    [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
-            doc["template-mobile-button"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile", btnType: ButtonType.ToolButton,
-            });
-        }
-
-        if (doc["template-button-slides"] === undefined) {
-            const slideTemplate = Docs.Create.MultirowDocument(
-                [
-                    Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
-                    Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
-                ],
-                { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
-            );
-            slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
-            doc["template-button-slides"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card",
-                btnType: ButtonType.ToolButton
-            });
-        }
-
-        if (doc["template-button-link"] === undefined) {  // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to.
-            const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _autoHeight: true, system: true }, "header")); // text needs to be a space to allow templateText to be created
-            linkTemplate.system = true;
-            Doc.GetProto(linkTemplate).layout =
-                "<div>" +
-                "    <FormattedTextBox {...props} dontSelectOnLoad={'true'} height='{this._headerHeight||75}px' ignoreAutoHeight={'true'} background='{this._headerColor||`lightGray`}' fieldKey={'header'}/>" +
-                "    <FormattedTextBox {...props} position='absolute' top='{(this._headerHeight||75)*scale}px' height='calc({100/scale}% - {this._headerHeight||75}px)' fieldKey={'text'}/>" +
-                "</div>";
-            (linkTemplate.proto as Doc).isTemplateDoc = makeTemplate(linkTemplate.proto as Doc, true, "linkView");
-
-            const rtf2 = {
-                doc: {
-                    type: "doc", content: [
-                        {
-                            type: "paragraph",
-                            content: [{
-                                type: "dashField",
-                                attrs: {
-                                    fieldKey: "src",
-                                    hideKey: false
-                                }
-                            }]
-                        },
-                        { type: "paragraph" },
-                        {
-                            type: "paragraph",
-                            content: [{
-                                type: "dashField",
-                                attrs: {
-                                    fieldKey: "dst",
-                                    hideKey: false
-                                }
-                            }]
-                        }]
+    static setupExperimentalTemplateButtons(doc: Doc) {
+        if (doc["template-experimental-buttons"] === undefined) {
+            const requiredTypeNameFields = [
+                {
+                    type: "slide", icon: "address-card", template: Docs.Create.MultirowDocument(
+                        [
+                            Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
+                            Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
+                        ],
+                        { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
+                    )
                 },
-                selection: { type: "text", anchor: 1, head: 1 },
-                storedMarks: []
-            };
-            linkTemplate.header = new RichTextField(JSON.stringify(rtf2), "");
-
-            doc["template-button-link"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true,
-                btnType: ButtonType.ToolButton
+                {
+                    type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, },
+                        [this.createToolButton({ ignoreClick: true, icon: "mobile", btnType: ButtonType.ToolButton, backgroundColor: "transparent" }),
+                        this.mobileTextContainer({},
+                            [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])
+                        ]
+                    )
+                },
+            ];
+            const requiredTypes = requiredTypeNameFields.map(({ type, icon, template }) => {
+                if (doc[`template-button-${type}`] === undefined) {
+                    template.isTemplateDoc = makeTemplate(template);
+                    doc[`template-button-${type}`] = CurrentUserUtils.createToolButton({
+                        onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+                        dragFactory: new PrefetchProxy(template) as any as Doc,
+                        title: type,
+                        icon,
+                        btnType: ButtonType.ToolButton,
+                    });
+                }
+                return doc[`template-button-${type}`] as Doc;
             });
-        }
 
-        // if (doc["template-button-switch"] === undefined) {
-        //     const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create;
-
-        //     const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40, system: true });
-        //     const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1, system: true });
-        //     const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, system: true });
-        //     const labelTemplate = {
-        //         doc: {
-        //             type: "doc", content: [{
-        //                 type: "paragraph",
-        //                 content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }]
-        //             }]
-        //         },
-        //         selection: { type: "text", anchor: 1, head: 1 },
-        //         storedMarks: []
-        //     };
-        //     Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS");
-        //     Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'");
-        //     // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'");
-        //     // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true");
-        //     Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]");
-        //     // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false");
-        //     const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true });
-        //     box.isTemplateDoc = makeTemplate(box, true, "switch");
-
-        //     doc["template-button-switch"] = CurrentUserUtils.createToolButton({
-        //         onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-        //         dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true,
-        //         btnType: ButtonType.ToolButton
-        //     });
-        // }
-
-        const requiredTypes = [
-            doc["template-button-slides"] as Doc,
-            doc["template-mobile-button"] as Doc,
-            doc["template-button-link"] as Doc,
-            //doc["template-button-switch"] as Doc]
-        ];
-        if (doc["template-buttons"] === undefined) {
-            doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
-                title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
+            doc["template-experimental-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
+                title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
                 hidden: ComputedField.MakeFunction("IsNoviceMode()") as any,
                 _stayInCollection: true, _hideContextMenu: true, _forceActive: true,
                 _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
             }));
-        } else {
-            const curButnTypes = Cast(doc["template-buttons"], Doc, null);
-            DocListCastAsync(curButnTypes.data).then(async curBtns => {
-                curBtns && await Promise.all(curBtns);
-                requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype));
-            });
         }
-        return doc["template-buttons"] as Doc;
+        return doc["template-experimental-buttons"] as Doc;
     }
 
     // setup the different note type skins
     static setupNoteTemplates(doc: Doc) {
-        if (doc["template-note-Note"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true, icon: "sticky-note",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Note");
-            doc["template-note-Note"] = new PrefetchProxy(noteView);
-        }
-        if (doc["template-note-Idea"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", backgroundColor: "pink", system: true, icon: "lightbulb",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea");
-            doc["template-note-Idea"] = new PrefetchProxy(noteView);
-        }
-        if (doc["template-note-Topic"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", backgroundColor: "lightblue", system: true, icon: "book-open",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic");
-            doc["template-note-Topic"] = new PrefetchProxy(noteView);
-        }
-        // if (doc["template-note-Todo"] === undefined) {
-        //     const noteView = Docs.Create.TextDocument("", {
-        //         title: "text", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption",
-        //         layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus"), system: true,
-        //         _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-        //     });
-        //     noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo");
-        //     doc["template-note-Todo"] = new PrefetchProxy(noteView);
-        // }
-        // const taskStatusValues = [
-        //     { title: "todo", _backgroundColor: "blue", color: "white", system: true },
-        //     { title: "in progress", _backgroundColor: "yellow", color: "black", system: true },
-        //     { title: "completed", _backgroundColor: "green", color: "white", system: true }
-        // ];
-        // if (doc.fieldTypes === undefined) {
-        //     doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations", system: true });
-        //     DocUtils.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues);
-        // }
-
         if (doc["template-notes"] === undefined) {
-            doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc], // doc["template-note-Todo"] as any as Doc],
-                { title: "Note Layouts", _height: 75, system: true }));
-        } else {
-            const curNoteTypes = Cast(doc["template-notes"], Doc, null);
-            const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc];
-            DocListCastAsync(curNoteTypes.data).then(async curNotes => {
-                curNotes && await Promise.all(curNotes);
-                requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype));
-            });
+            const requiredTypeNameFields = [
+                { type: "Note", backgroundColor: "yellow", icon: "sticky-note" },
+                { type: "Idea", backgroundColor: "pink", icon: "lightbulb" },
+                { type: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
+            const requiredTypes = requiredTypeNameFields.map(({ type, backgroundColor, icon }) =>
+                doc[`template-note-${type}`] as Doc ??
+                (() => {
+                    const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor, system: true, icon });
+                    noteView.isTemplateDoc = makeTemplate(noteView, true, type);
+                    return doc[`template-note-${type}`] = new PrefetchProxy(noteView);
+                })());
+
+            doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument(requiredTypes, { title: "Note Layouts", _height: 75, system: true }));
         }
 
         return doc["template-notes"] as Doc;
@@ -277,11 +144,12 @@ export class CurrentUserUtils {
 
     // creates Note templates, and initial "user" templates
     static setupDocTemplates(doc: Doc) {
-        const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc);
-        const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
-        const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
         if (doc.templateDocs === undefined) {
-            doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
+            doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([
+                CurrentUserUtils.setupNoteTemplates(doc),
+                CurrentUserUtils.setupExperimentalTemplateButtons(doc),
+                CurrentUserUtils.setupClickEditorTemplates(doc)
+            ], {
                 title: "template layouts", _xMargin: 0, system: true,
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
             }));
@@ -717,7 +585,7 @@ export class CurrentUserUtils {
     static async setupToolsBtnPanel(doc: Doc) {
         // setup a masonry view of all he creators
         const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
-        const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
+        const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc);
 
         doc["tabs-button-tools"] = undefined;
 
@@ -1260,7 +1128,7 @@ export class CurrentUserUtils {
         doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
         doc.title = Doc.CurrentUserEmail;
         doc._raiseWhenDragged = true;
-        doc._showLabel = false;
+        doc._showLabel = true;
         doc._showMenuLabel = true;
         doc.textAlign = StrCast(doc.textAlign, "left");
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4338dedcc..4630b3bf2 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -482,7 +482,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (value && this.columnHeaders) {
             const schemaHdrField = new SchemaHeaderField(value);
             this.columnHeaders.push(schemaHdrField);
-            DocUtils.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: "schemaHdrField.color" }]);
             return true;
         }
         return false;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c004b4d49..65f8fe248 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -895,7 +895,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
         }
 
-        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion));
+        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
         const rowWidth = () => panelWidth() - treeBulletWidth();
         const treeViewRefs = new Map<Doc, TreeView | undefined>();
         return docs.filter(child => child instanceof Doc).map((child, i) => {
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 49cd39f43..5ea6d567a 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -76,7 +76,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         const clearButton = (which: string) => {
             return <div className={`clear-button ${which}`}
                 onPointerDown={e => e.stopPropagation()} // prevent triggering slider movement in registerSliding 
-                onClick={e => this.clearDoc(e, `compareBox-${which}`)}>
+                onClick={e => this.clearDoc(e, which)}>
                 <FontAwesomeIcon className={`clear-button ${which}`} icon={"times"} size="sm" />
             </div>;
         };
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 34908e54b..1a8352b72 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -58,7 +58,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     _textBoxDoc: Doc;
     _fieldKey: string;
     _fieldStringRef = React.createRef<HTMLSpanElement>();
-    @observable _showEnumerables: boolean = false;
     @observable _dashDoc: Doc | undefined;
 
     constructor(props: IDashFieldViewInternal) {
@@ -110,7 +109,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                         r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r));
                         r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false));
                         r?.addEventListener("pointerdown", action((e) => {
-                            this._showEnumerables = true;
                             e.stopPropagation();
                         }));
                     }} >
@@ -124,7 +122,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     @action
     fieldSpanKeyDown = (e: KeyboardEvent, span: HTMLSpanElement) => {
         if (e.key === "Enter") {  // handle the enter key by "submitting" the current text to Dash's database. 
-            e.ctrlKey && DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: span.textContent! }]);
             this.updateText(span.textContent!, true);
             e.preventDefault();// prevent default to avoid a newline from being generated and wiping out this field view
         }
@@ -142,7 +139,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
 
     @action
     updateText = (nodeText: string, forceMatch: boolean) => {
-        this._showEnumerables = false;
         if (nodeText) {
             const newText = nodeText.startsWith(":=") || nodeText.startsWith("=:=") ? ":=-computed-" : nodeText;
 
@@ -154,7 +150,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                 (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title)));
                 if (modText) {
                     //  elementfieldSpan.innerHTML = this._dashDoc![this._fieldKey as string] = modText;
-                    DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, []);
                     Doc.SetInPlace(this._dashDoc!, this._fieldKey, modText, true);
                 } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
                 else if (nodeText.startsWith(":=")) {
@@ -178,13 +173,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         }
     }
 
-    // display a collection of all the enumerable values for this field
-    onPointerDownEnumerables = async (e: any) => {
-        e.stopPropagation();
-        const collview = await DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: this._fieldKey }]);
-        collview instanceof Doc && this.props.tbox.props.addDocTab(collview, "add:right");
-    }
-
 
     // clicking on the label creates a pivot view collection of all documents
     // in the same collection.  The pivot field is the fieldKey of this label
@@ -220,8 +208,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
 
             {this.props.fieldKey.startsWith("#") ? (null) : this.fieldValueContent}
 
-            {!this._showEnumerables ? (null) : <div className="dashFieldView-enumerables" onPointerDown={this.onPointerDownEnumerables} />}
-
         </div >;
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

