From 33299a19d86948051eef442825c0b3241d1ac619 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Apr 2023 11:55:53 -0400
Subject: fixed isContentActive=false to apply to stacking collections. fixed
 pile view to be faster and to work in fit content panels. fixed issues with
 hidden docs and freeformviews that act as lightboxes - hidden docs can be
 shown as the lightbox doc without modifying the hidden flag to allow
 collection state to be restored.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 107 ++++++++++++++-------
 1 file changed, 72 insertions(+), 35 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ff0d01f29..1fc4d9259 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } fro
 import { ImageField } from '../../../../fields/URLField';
 import { TraceMobx } from '../../../../fields/util';
 import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
-import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { aggregateBounds, emptyFunction, intersectRect, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -308,6 +308,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
 
     focus = (anchor: Doc, options: DocFocusOptions) => {
+        if (this._lightboxDoc) return;
         const xfToCollection = options?.docTransform ?? Transform.Identity();
         const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
         const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc);
@@ -327,7 +328,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     getView = async (doc: Doc): Promise<Opt<DocumentView>> => {
         return new Promise<Opt<DocumentView>>(res => {
-            doc.hidden && (doc.hidden = false);
+            if (doc.hidden && this._lightboxDoc !== doc) doc.hidden = false;
             const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
             findDoc(dv => res(dv));
         });
@@ -778,7 +779,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this._batch?.end();
     };
 
+    @action
     onClick = (e: React.MouseEvent) => {
+        if (this._lightboxDoc) this._lightboxDoc = undefined;
         if (this.onBrowseClickHandler()) {
             if (this.props.DocumentView?.()) {
                 this.onBrowseClickHandler().script.run({ documentView: this.props.DocumentView(), clientX: e.clientX, clientY: e.clientY });
@@ -1274,7 +1277,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
-                isContentActive={emptyFunction}
+                isContentActive={this.props.childContentsActive ?? emptyFunction}
                 focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
                 addDocTab={this.addDocTab}
                 addDocument={this.props.addDocument}
@@ -1320,13 +1323,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             case undefined:
             case OpenWhere.lightbox:
                 if (this.layoutDoc._isLightbox) {
-                    // _isLightbox docs have a script that will unset this overlay onClick
-                    this.layoutDoc[this.props.fieldKey] = new List<Doc>(doc instanceof Doc ? [doc] : doc);
+                    this._lightboxDoc = doc;
+                    return true;
+                } else if (this.childDocList?.includes(doc)) {
+                    if (doc.hidden) doc.hidden = false;
                     return true;
                 }
         }
         return this.props.addDocTab(doc, where);
     });
+    @observable _lightboxDoc: Opt<Doc>;
 
     getCalculatedPositions(params: { pair: { layout: Doc; data?: Doc }; index: number; collection: Doc }): PoolData {
         const childDoc = params.pair.layout;
@@ -1936,7 +1942,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             1000
         );
     };
-
+    lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30);
+    lightboxPanelHeight = () => Math.max(0, this.props.PanelHeight() - 30);
+    lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15);
     render() {
         TraceMobx();
         return (
@@ -1965,36 +1973,65 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     width: `${100 / (this.nativeDimScaling || 1)}%`,
                     height: this.props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
                 }}>
-                {this._firstRender ? this.placeholder : this.marqueeView}
-                {this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
-
-                {/* // uncomment to show snap lines */}
-                <div className="snapLines" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none' }}>
-                    <svg style={{ width: '100%', height: '100%' }}>
-                        {this._hLines?.map(l => (
-                            <line x1="0" y1={l} x2="1000" y2={l} stroke="black" />
-                        ))}
-                        {this._vLines?.map(l => (
-                            <line y1="0" x1={l} y2="1000" x2={l} stroke="black" />
-                        ))}
-                    </svg>
-                </div>
+                {this._lightboxDoc ? (
+                    <div style={{ padding: 15, width: '100%', height: '100%' }}>
+                        <DocumentView
+                            {...this.props}
+                            Document={this._lightboxDoc}
+                            DataDoc={undefined}
+                            PanelWidth={this.lightboxPanelWidth}
+                            PanelHeight={this.lightboxPanelHeight}
+                            NativeWidth={returnZero}
+                            NativeHeight={returnZero}
+                            onClick={this.onChildClickHandler}
+                            onKey={this.onKeyDown}
+                            onDoubleClick={this.onChildDoubleClickHandler}
+                            onBrowseClick={this.onBrowseClickHandler}
+                            docFilters={this.childDocFilters}
+                            docRangeFilters={this.childDocRangeFilters}
+                            searchFilterDocs={this.searchFilterDocs}
+                            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
+                            isContentActive={this.props.childContentsActive ?? emptyFunction}
+                            addDocTab={this.addDocTab}
+                            ScreenToLocalTransform={this.lightboxScreenToLocal}
+                            fitContentsToBox={undefined}
+                            focus={this.focus}
+                        />
+                    </div>
+                ) : (
+                    <>
+                        {this._firstRender ? this.placeholder : this.marqueeView}
+                        {this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
+
+                        {/* // uncomment to show snap lines */}
+                        <div className="snapLines" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none' }}>
+                            <svg style={{ width: '100%', height: '100%' }}>
+                                {this._hLines?.map(l => (
+                                    <line x1="0" y1={l} x2="1000" y2={l} stroke="black" />
+                                ))}
+                                {this._vLines?.map(l => (
+                                    <line y1="0" x1={l} y2="1000" x2={l} stroke="black" />
+                                ))}
+                            </svg>
+                        </div>
 
-                {this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ? (
-                    <div
-                        className="collectionFreeForm-groupDropper"
-                        ref={this.createGroupEventsTarget}
-                        style={{
-                            width: this.ChildDrag ? '10000' : '100%',
-                            height: this.ChildDrag ? '10000' : '100%',
-                            left: this.ChildDrag ? '-5000' : 0,
-                            top: this.ChildDrag ? '-5000' : 0,
-                            position: 'absolute',
-                            background: '#0009930',
-                            pointerEvents: 'all',
-                        }}
-                    />
-                ) : null}
+                        {this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ? (
+                            <div
+                                className="collectionFreeForm-groupDropper"
+                                ref={this.createGroupEventsTarget}
+                                style={{
+                                    width: this.ChildDrag ? '10000' : '100%',
+                                    height: this.ChildDrag ? '10000' : '100%',
+                                    left: this.ChildDrag ? '-5000' : 0,
+                                    top: this.ChildDrag ? '-5000' : 0,
+                                    position: 'absolute',
+                                    background: '#0009930',
+                                    pointerEvents: 'all',
+                                }}
+                            />
+                        ) : null}
+                    </>
+                )}
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 24d4782be0d1160e073e0040d6926206cf465859 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Apr 2023 12:08:52 -0400
Subject: fixed creating documents in a viewAll freeform view to not have
 degenerate scale/x/y coords

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1fc4d9259..56bb2601f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -141,7 +141,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @computed get fitToContentVals() {
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
-            scale: !this.childDocs.length ? 1 : Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)),
+            scale:
+                !this.childDocs.length || this.contentBounds.b === this.contentBounds.y || this.contentBounds.r - this.contentBounds.x
+                    ? 1
+                    : Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)),
         };
     }
     @computed get fitContentsToBox() {
-- 
cgit v1.2.3-70-g09d2


From 9629ab77ed15f71a80f2a8becabf944ce584fe18 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Apr 2023 12:12:56 -0400
Subject: from last

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 56bb2601f..3333befc6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -142,7 +142,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
             scale:
-                !this.childDocs.length || this.contentBounds.b === this.contentBounds.y || this.contentBounds.r - this.contentBounds.x
+                !this.childDocs.length || !Number.isFinite(this.contentBounds.b - this.contentBounds.y) || !Number.isFinite(this.contentBounds.r - this.contentBounds.x)
                     ? 1
                     : Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)),
         };
-- 
cgit v1.2.3-70-g09d2


From 4846ff09a02cce1da4f0b8984e387d7d204837f1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 26 Apr 2023 10:58:58 -0400
Subject: fixed filters - checkboxes generated when options are less than 20,
 added -undefined- as distinct value option. fixed pointer evcents for docs on
 pdfs

---
 src/client/util/CurrentUserUtils.ts                |   7 +-
 src/client/util/DragManager.ts                     |  18 +-
 src/client/views/FilterPanel.scss                  |  12 +-
 src/client/views/FilterPanel.tsx                   |  41 +++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   1 +
 src/client/views/nodes/DocumentView.tsx            |   2 +
 src/client/views/nodes/FilterBox.scss              | 189 ---------------------
 src/client/views/nodes/FilterBox.tsx               |   0
 .../views/nodes/formattedText/FormattedTextBox.tsx |   6 +-
 src/client/views/pdf/PDFViewer.tsx                 |   3 +-
 src/fields/Doc.ts                                  |   2 +-
 11 files changed, 57 insertions(+), 224 deletions(-)
 delete mode 100644 src/client/views/nodes/FilterBox.scss
 delete mode 100644 src/client/views/nodes/FilterBox.tsx

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 4a90edd49..5475873a9 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -49,6 +49,7 @@ interface Button {
     ignoreClick?: boolean;
     buttonText?: string;
     backgroundColor?: string;
+    waitForDoubleClickToClick?: boolean;
 
     // fields that do not correspond to DocumentOption fields
     scripts?: { script?: string; onClick?: string; onDoubleClick?: string }
@@ -613,8 +614,9 @@ export class CurrentUserUtils {
 
     static freeTools(): Button[] {
         return [
-            { title: "Bottom",    icon: "arrows-down-to-line",toolTip: "Make doc topmost",    btnType: ButtonType.ClickButton,  expertMode: false,                        funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
-            { title: "Top",       icon: "arrows-up-to-line",  toolTip: "Make doc bottommost", btnType: ButtonType.ClickButton,  expertMode: false,                        funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
+            { title: "Bottom",  icon: "arrows-down-to-line",toolTip: "Make doc topmost",                                   btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
+            { title: "Top",     icon: "arrows-up-to-line",  toolTip: "Make doc bottommost",                                btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
+            { title: "Z order", icon: "z",                  toolTip: "Bring Forward on Drag (double click to set for all)",waitForDoubleClickToClick:true, btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: 'toggleRaiseOnDrag(false, _readOnly_)', onDoubleClick:`{ return toggleRaiseOnDrag(true, _readOnly_)`}}, // Only when floating document is selected in freeform
         ]
     }
     static viewTools(): Button[] {
@@ -689,7 +691,6 @@ export class CurrentUserUtils {
             { title: "Fill",    icon: "fill-drip",     toolTip: "Background Fill Color",btnType: ButtonType.ColorButton,         expertMode: false,                                                                                                          ignoreClick: true, width: 20,  scripts: { script:  'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected
             { title: "Header",  icon: "heading",       toolTip: "Header Color",         btnType: ButtonType.ColorButton,         expertMode: false,                                                                                                          ignoreClick: true,             scripts: { script:  'return setHeaderColor(value, _readOnly_)'}},
             { title: "Overlay", icon: "layer-group",   toolTip: "Overlay",              btnType: ButtonType.ToggleButton,        expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'},       scripts: { onClick: 'toggleOverlay(_readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "Z order", icon: "z",             toolTip: "Bring Forward on Drag",btnType: ButtonType.ToggleButton,        expertMode: false, toolType:CollectionViewType.Freeform, funcs: {},                                                                                        scripts: { onClick: 'toggleRaiseOnDrag(_readOnly_)'}}, // Only when floating document is selected in freeform
             { title: "Back",    icon: "chevron-left",  toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
             { title: "Num", icon:"",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 404c85eb2..b6de5604d 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -11,6 +11,7 @@ import * as globalCssVariables from '../views/global/globalCssVariables.scss';
 import { Colors } from '../views/global/globalEnums';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { ScriptingGlobals } from './ScriptingGlobals';
+import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
@@ -597,7 +598,18 @@ export namespace DragManager {
     }
 }
 
-ScriptingGlobals.add(function toggleRaiseOnDrag(readOnly?: boolean) {
-    if (readOnly) return DragManager.GetRaiseWhenDragged() ? Colors.MEDIUM_BLUE : 'transparent';
-    DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged());
+ScriptingGlobals.add(function toggleRaiseOnDrag(forAllDocs: boolean, readOnly?: boolean) {
+    if (readOnly) {
+        if (SelectionManager.Views().length)
+            return SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged)
+                ? Colors.MEDIUM_BLUE
+                : SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged === false)
+                ? 'transparent'
+                : DragManager.GetRaiseWhenDragged()
+                ? Colors.MEDIUM_BLUE_ALT
+                : Colors.PINK;
+        return DragManager.GetRaiseWhenDragged() ? Colors.PINK : 'transparent';
+    }
+    if (!forAllDocs) SelectionManager.Views().map(dv => (dv.rootDoc.raiseWhenDragged ? (dv.rootDoc.raiseWhenDragged = undefined) : dv.rootDoc.raiseWhenDragged === false ? (dv.rootDoc.raiseWhenDragged = true) : (dv.rootDoc.raiseWhenDragged = false)));
+    else DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged());
 });
diff --git a/src/client/views/FilterPanel.scss b/src/client/views/FilterPanel.scss
index 7f907c8d4..c903f29ee 100644
--- a/src/client/views/FilterPanel.scss
+++ b/src/client/views/FilterPanel.scss
@@ -33,9 +33,10 @@
 // }
 
 .filterBox-select {
-    // width: 90%;
+    display: flex;
+    width: 100%;
     margin-top: 5px;
-    // margin-bottom: 15px;
+    background: white;
 }
 
 .filterBox-saveBookmark {
@@ -150,8 +151,8 @@
 .filterBox-treeView {
     display: flex;
     flex-direction: column;
-    width: 200px;
-    position: absolute;
+    width: 100%;
+    position: relative;
     right: 0;
     top: 0;
     z-index: 1;
@@ -184,6 +185,7 @@
         display: inline-block;
         width: 100%;
         margin-bottom: 10px;
-        //height: calc(100% - 30px);
+        margin-left: 5px;
+        overflow: auto;
     }
 }
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index d35494f26..a237249c1 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -51,10 +51,12 @@ export class FilterPanel extends React.Component<filterProps> {
 
         const keys = new Set<string>(noviceFields);
         this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
-        return Array.from(keys.keys())
+        const sortedKeys = Array.from(keys.keys())
             .filter(key => key[0])
             .filter(key => key[0] === '#' || key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
             .sort();
+        noviceFields.forEach(key => sortedKeys.splice(sortedKeys.indexOf(key), 1));
+        return [...noviceFields, ...sortedKeys];
     }
 
     /**
@@ -129,7 +131,7 @@ export class FilterPanel extends React.Component<filterProps> {
                 maxVal = Math.max(num, maxVal);
             }
         });
-        if (facetHeader === 'text' || (facetValues.rtFields / allCollectionDocs.length > 0.1 && facetValues.rtFields > 20)) {
+        if (facetHeader === 'text' || (facetValues.rtFields / allCollectionDocs.length > 0.1 && facetValues.strings.length > 20)) {
             this._chosenFacets.set(facetHeader, 'text');
         } else if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) {
         } else {
@@ -140,7 +142,7 @@ export class FilterPanel extends React.Component<filterProps> {
     facetValues = (facetHeader: string) => {
         const allCollectionDocs = new Set<Doc>();
         SearchBox.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
-        const set = new Set<string>();
+        const set = new Set<string>([String.fromCharCode(127) + '--undefined--']);
         if (facetHeader === 'tags')
             allCollectionDocs.forEach(child =>
                 Field.toString(child[facetHeader] as Field)
@@ -158,32 +160,29 @@ export class FilterPanel extends React.Component<filterProps> {
         let nonNumbers = 0;
 
         facetValues.map(val => Number.isNaN(Number(val)) && nonNumbers++);
-        const facetValueDocSet = (nonNumbers / facetValues.length > 0.1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => {
-            return facetValue;
-        });
-        return facetValueDocSet;
+        return nonNumbers / facetValues.length > 0.1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2));
     };
 
     render() {
         const options = this._allFacets.filter(facet => this.currentFacets.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet }));
         return (
-            <div className="filterBox-treeView" style={{ position: 'relative', width: '100%' }}>
-                <div className="filterBox-select-bool">
-                    <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._filterBoolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.filterBoolean)}>
-                        {['AND', 'OR'].map(bool => (
-                            <option value={bool} key={bool}>
-                                {bool}
-                            </option>
-                        ))}
-                    </select>
-                    <div className="filterBox-select-text">filters together</div>
-                </div>
-
+            <div className="filterBox-treeView">
                 <div className="filterBox-select">
-                    <Select placeholder="Add a filter..." options={options} isMulti={false} onChange={val => this.facetClick((val as UserOptions).value)} onKeyDown={e => e.stopPropagation()} value={null} closeMenuOnSelect={true} />
+                    <div style={{ width: '100%' }}>
+                        <Select placeholder="Add a filter..." options={options} isMulti={false} onChange={val => this.facetClick((val as UserOptions).value)} onKeyDown={e => e.stopPropagation()} value={null} closeMenuOnSelect={true} />
+                    </div>
+                    <div className="filterBox-select-bool">
+                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._filterBoolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.filterBoolean)}>
+                            {['AND', 'OR'].map(bool => (
+                                <option value={bool} key={bool}>
+                                    {bool}
+                                </option>
+                            ))}
+                        </select>
+                    </div>{' '}
                 </div>
 
-                <div className="filterBox-tree" key="tree" style={{ overflow: 'auto' }}>
+                <div className="filterBox-tree" key="tree">
                     {Array.from(this.activeFacets.keys()).map(facetHeader => (
                         <div>
                             {facetHeader}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3333befc6..719a39e8d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1972,6 +1972,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             : SnappingManager.GetIsDragging() && this.childDocs.includes(DragManager.docsBeingDragged.lastElement())
                             ? 'all'
                             : (this.props.pointerEvents?.() as any),
+                    textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
                     transform: `scale(${this.nativeDimScaling || 1})`,
                     width: `${100 / (this.nativeDimScaling || 1)}%`,
                     height: this.props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2ea0a6f19..38aa8db55 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -868,6 +868,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
+    docFilters = () => [...this.props.docFilters(), ...StrListCast(this.layoutDoc.docFilters)];
     contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
@@ -898,6 +899,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     docViewPath={this.props.viewPath}
                     thumbShown={this.thumbShown}
                     setContentView={this.setContentView}
+                    docFilters={this.docFilters}
                     NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
                     setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
diff --git a/src/client/views/nodes/FilterBox.scss b/src/client/views/nodes/FilterBox.scss
deleted file mode 100644
index 7f907c8d4..000000000
--- a/src/client/views/nodes/FilterBox.scss
+++ /dev/null
@@ -1,189 +0,0 @@
-.filterBox-flyout {
-    display: block;
-    text-align: left;
-    font-weight: 100;
-
-    .filterBox-flyout-facet {
-        background-color: white;
-        text-align: left;
-        display: inline-block;
-        position: relative;
-        width: 100%;
-
-        .filterBox-flyout-facet-check {
-            margin-right: 6px;
-        }
-    }
-}
-
-.filter-bookmark {
-    //display: flex;
-
-    .filter-bookmark-icon {
-        float: right;
-        margin-right: 10px;
-        margin-top: 7px;
-    }
-}
-
-// .filterBox-bottom {
-//     // position: fixed;
-//     // bottom: 0;
-//     // width: 100%;
-// }
-
-.filterBox-select {
-    // width: 90%;
-    margin-top: 5px;
-    // margin-bottom: 15px;
-}
-
-.filterBox-saveBookmark {
-    background-color: #e9e9e9;
-    border-radius: 11px;
-    padding-left: 8px;
-    padding-right: 8px;
-    padding-top: 5px;
-    padding-bottom: 5px;
-    margin: 8px;
-    display: flex;
-    font-size: 11px;
-    cursor: pointer;
-
-    &:hover {
-        background-color: white;
-    }
-
-    .filterBox-saveBookmark-icon {
-        margin-right: 6px;
-        margin-top: 4px;
-        margin-left: 2px;
-    }
-}
-
-.filterBox-select-scope,
-.filterBox-select-bool,
-.filterBox-addWrapper,
-.filterBox-select-matched,
-.filterBox-saveWrapper {
-    font-size: 10px;
-    justify-content: center;
-    justify-items: center;
-    padding-bottom: 10px;
-    display: flex;
-}
-
-.filterBox-addWrapper {
-    font-size: 11px;
-    width: 100%;
-}
-
-.filterBox-saveWrapper {
-    width: 100%;
-}
-
-// .filterBox-top {
-//     padding-bottom: 20px;
-//     border-bottom: 2px solid black;
-//     position: fixed;
-//     top: 0;
-//     width: 100%;
-// }
-
-.filterBox-select-scope {
-    padding-bottom: 20px;
-    border-bottom: 2px solid black;
-}
-
-.filterBox-title {
-    font-size: 15;
-    // border: 2px solid black;
-    width: 100%;
-    align-self: center;
-    text-align: center;
-    background-color: #d3d3d3;
-}
-
-.filterBox-select-bool {
-    margin-top: 6px;
-}
-
-.filterBox-select-text {
-    margin-right: 8px;
-    margin-left: 8px;
-    margin-top: 3px;
-}
-
-.filterBox-select-box {
-    margin-right: 2px;
-    font-size: 30px;
-    border: 0;
-    background: transparent;
-}
-
-.filterBox-selection {
-    border-radius: 6px;
-    border: none;
-    background-color: #e9e9e9;
-    padding: 2px;
-
-    &:hover {
-        background-color: white;
-    }
-}
-
-.filterBox-addFilter {
-    width: 120px;
-    background-color: #e9e9e9;
-    border-radius: 12px;
-    padding: 5px;
-    margin: 5px;
-    display: flex;
-    text-align: center;
-    justify-content: center;
-
-    &:hover {
-        background-color: white;
-    }
-}
-
-.filterBox-treeView {
-    display: flex;
-    flex-direction: column;
-    width: 200px;
-    position: absolute;
-    right: 0;
-    top: 0;
-    z-index: 1;
-    background-color: #9f9f9f;
-
-    .filterBox-tree {
-        z-index: 0;
-    }
-
-    .filterBox-addfacet {
-        display: inline-block;
-        width: 200px;
-        height: 30px;
-        text-align: left;
-
-        .filterBox-addFacetButton {
-            display: flex;
-            margin: auto;
-            cursor: pointer;
-        }
-
-        > div,
-        > div > div {
-            width: 100%;
-            height: 100%;
-        }
-    }
-
-    .filterBox-tree {
-        display: inline-block;
-        width: 100%;
-        margin-bottom: 10px;
-        //height: calc(100% - 30px);
-    }
-}
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 82a26fa86..399e6bfdf 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -852,7 +852,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         const optionItems = options && 'subitems' in options ? options.subitems : [];
         optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
         optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' });
-        optionItems.push({ description: !this.Document._singleLine ? 'Make Single Line' : 'Make Multi Line', event: () => (this.layoutDoc._singleLine = !this.layoutDoc._singleLine), icon: !this.Document._singleLine ? 'grip-lines' : 'bars' });
+        optionItems.push({
+            description: !this.Document._singleLine ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
+            event: () => (this.layoutDoc._singleLine = !this.layoutDoc._singleLine),
+            icon: !this.Document._singleLine ? 'grip-lines' : 'bars',
+        });
         optionItems.push({ description: `${this.Document._autoHeight ? 'Lock' : 'Auto'} Height`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: this.Document._autoHeight ? 'lock' : 'unlock' });
         !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
         this._downX = this._downY = Number.NaN;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 68241e61f..20803bba8 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -536,7 +536,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
                 setContentView={emptyFunction} // override setContentView to do nothing
-                pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone}
+                pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
+                childPointerEvents={'all'} // but freeform children need to get events to allow text editing, etc
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.props.fieldKey + '-annotations'}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b0033b977..0c2ee35fd 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1391,7 +1391,7 @@ export namespace Doc {
             return vals.some(v => v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
         }
         const fieldStr = Field.toString(fieldVal as Field);
-        return fieldStr.includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+        return fieldStr.includes(value) || (value === String.fromCharCode(127) + '--undefined--' && fieldVal === undefined); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
     }
 
     export function deiconifyView(doc: Doc) {
-- 
cgit v1.2.3-70-g09d2

