From b9483279f4a778e0cc997e304b4f0b87e6ec1e5d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 15 Apr 2020 00:29:00 -0400
Subject: changed collection chrome filter to just open filter sidebar.  fixed
 scrollbar to make sure that all datapoints are included.  simplified filter
 documents to have only a datadocument.

---
 .../views/collections/CollectionViewChromes.tsx    | 316 ++++++---------------
 1 file changed, 81 insertions(+), 235 deletions(-)

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

diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 66f627083..cef85e148 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -6,7 +6,6 @@ import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
-import { ScriptField } from "../../../new_fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils";
 import { DragManager } from "../../util/DragManager";
@@ -16,8 +15,6 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss";
 import { CollectionViewType } from "./CollectionView";
 import { CollectionView } from "./CollectionView";
 import "./CollectionViewChromes.scss";
-import * as Autosuggest from 'react-autosuggest';
-import KeyRestrictionRow from "./KeyRestrictionRow";
 const datepicker = require('js-datepicker');
 
 interface CollectionViewChromeProps {
@@ -84,62 +81,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     private _picker: any;
     private _commandRef = React.createRef<HTMLInputElement>();
     private _viewRef = React.createRef<HTMLInputElement>();
-    private _autosuggestRef = React.createRef<Autosuggest>();
     @observable private _currentKey: string = "";
-    @observable private _viewSpecsOpen: boolean = false;
-    @observable private _dateWithinValue: string = "";
-    @observable private _dateValue: Date | string = "";
-    @observable private _keyRestrictions: [JSX.Element, string][] = [];
-    @observable private suggestions: string[] = [];
-    @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); }
-
-    getFilters = (script: string) => {
-        const re: any = /(!)?\(\(\(doc\.(\w+)\s+&&\s+\(doc\.\w+\s+as\s+\w+\)\.includes\(\"(\w+)\"\)/g;
-        const arr: any[] = re.exec(script);
-        const toReturn: Filter[] = [];
-        if (arr !== null) {
-            const filter: Filter = {
-                key: arr[2],
-                value: arr[3],
-                contains: (arr[1] === "!") ? false : true,
-            };
-            toReturn.push(filter);
-            script = script.replace(arr[0], "");
-            if (re.exec(script) !== null) {
-                toReturn.push(...this.getFilters(script));
-            }
-            else { return toReturn; }
-        }
-        return toReturn;
-    }
-
-    addKeyRestrictions = (fields: Filter[]) => {
-
-        if (fields.length !== 0) {
-            for (let i = 0; i < fields.length; i++) {
-                this._keyRestrictions.push([<KeyRestrictionRow field={fields[i].key} value={fields[i].value} key={Utils.GenerateGuid()} contains={fields[i].contains} script={(value: string) => runInAction(() => this._keyRestrictions[i][1] = value)} />, ""]);
-
-            }
-            if (this._keyRestrictions.length === 1) {
-                this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]);
-            }
-        }
-        else {
-            this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]);
-            this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={false} script={(value: string) => runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]);
-        }
-    }
 
     componentDidMount = () => {
-
-        let fields: Filter[] = [];
-        if (this.filterValue) {
-            const string = this.filterValue.script.originalScript;
-            fields = this.getFilters(string);
-        }
-
         runInAction(() => {
-            this.addKeyRestrictions(fields);
             // chrome status is one of disabled, collapsed, or visible. this determines initial state from document
             const chromeStatus = this.props.CollectionView.props.Document._chromeStatus;
             if (chromeStatus) {
@@ -158,7 +103,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @undoBatch
     viewChanged = (e: React.ChangeEvent) => {
         //@ts-ignore
-        this.props.CollectionView.props.Document._viewType = e.target.selectedOptions[0].value;
+        this.document._viewType = e.target.selectedOptions[0].value;
     }
 
     commandChanged = (e: React.ChangeEvent) => {
@@ -167,104 +112,93 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     }
 
     @action
-    openViewSpecs = (e: React.SyntheticEvent) => {
-        if (this._viewSpecsOpen) this.closeViewSpecs();
-        else {
-            this._viewSpecsOpen = true;
-
-            //@ts-ignore
-            if (!e.target?.classList[0]?.startsWith("qs")) {
-                this.closeDatePicker();
-            }
-
-            e.stopPropagation();
-            document.removeEventListener("pointerdown", this.closeViewSpecs);
-            document.addEventListener("pointerdown", this.closeViewSpecs);
-        }
+    toggleViewSpecs = (e: React.SyntheticEvent) => {
+        this.document._facetWidth = this.document._facetWidth ? 0 : 200;
+        e.stopPropagation();
     }
 
     @action closeViewSpecs = () => {
-        this._viewSpecsOpen = false;
-        document.removeEventListener("pointerdown", this.closeViewSpecs);
-    }
-
-    @action
-    openDatePicker = (e: React.PointerEvent) => {
-        this.openViewSpecs(e);
-        if (this._picker) {
-            this._picker.alwaysShow = true;
-            this._picker.show();
-            // TODO: calendar is offset when zoomed in/out
-            // this._picker.calendar.style.position = "absolute";
-            // let transform = this.props.CollectionView.props.ScreenToLocalTransform();
-            // let x = parseInt(this._picker.calendar.style.left) / transform.Scale;
-            // let y = parseInt(this._picker.calendar.style.top) / transform.Scale;
-            // this._picker.calendar.style.left = x;
-            // this._picker.calendar.style.top = y;
-
-            e.stopPropagation();
-        }
-    }
-
-    @action
-    addKeyRestriction = (e: React.MouseEvent) => {
-        const index = this._keyRestrictions.length;
-        this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[index][1] = value)} />, ""]);
-
-        this.openViewSpecs(e);
-    }
-
-    @action.bound
-    applyFilter = (e: React.MouseEvent) => {
-
-        this.openViewSpecs(e);
-
-        const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")";
-        const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0;
-        const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0;
-        const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0;
-        const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7;
-        let dateRestrictionScript = "";
-        if (this._dateValue instanceof Date) {
-            const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset);
-            const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1);
-            dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
-        }
-        else {
-            const createdDate = new Date(this._dateValue);
-            if (!isNaN(createdDate.getTime())) {
-                const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset);
-                const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1);
-                dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
-            }
-        }
-        const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ?
-            `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
-            `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
-            "true";
+        this.document._facetWidth = 0;
+    }
+
+    // @action
+    // openDatePicker = (e: React.PointerEvent) => {
+    //     if (this._picker) {
+    //         this._picker.alwaysShow = true;
+    //         this._picker.show();
+    //         // TODO: calendar is offset when zoomed in/out
+    //         // this._picker.calendar.style.position = "absolute";
+    //         // let transform = this.props.CollectionView.props.ScreenToLocalTransform();
+    //         // let x = parseInt(this._picker.calendar.style.left) / transform.Scale;
+    //         // let y = parseInt(this._picker.calendar.style.top) / transform.Scale;
+    //         // this._picker.calendar.style.left = x;
+    //         // this._picker.calendar.style.top = y;
+
+    //         e.stopPropagation();
+    //     }
+    // }
+
+    // <input className="collectionViewBaseChrome-viewSpecsMenu-rowRight"
+    //     id={Utils.GenerateGuid()}
+    //     ref={this.datePickerRef}
+    //     value={this._dateValue instanceof Date ? this._dateValue.toLocaleDateString() : this._dateValue}
+    //     onChange={(e) => runInAction(() => this._dateValue = e.target.value)}
+    //     onPointerDown={this.openDatePicker}
+    //     placeholder="Value" />
+    // @action.bound
+    // applyFilter = (e: React.MouseEvent) => {
+    //     const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")";
+    //     const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0;
+    //     const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0;
+    //     const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0;
+    //     const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7;
+    //     let dateRestrictionScript = "";
+    //     if (this._dateValue instanceof Date) {
+    //         const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset);
+    //         const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1);
+    //         dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
+    //     }
+    //     else {
+    //         const createdDate = new Date(this._dateValue);
+    //         if (!isNaN(createdDate.getTime())) {
+    //             const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset);
+    //             const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1);
+    //             dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
+    //         }
+    //     }
+    //     const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ?
+    //         `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
+    //         `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
+    //         "true";
+
+    //     this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name });
+    // }
+
+    // datePickerRef = (node: HTMLInputElement) => {
+    //     if (node) {
+    //         try {
+    //             this._picker = datepicker("#" + node.id, {
+    //                 disabler: (date: Date) => date > new Date(),
+    //                 onSelect: (instance: any, date: Date) => runInAction(() => {}), //  this._dateValue = date),
+    //                 dateSelected: new Date()
+    //             });
+    //         } catch (e) {
+    //             console.log("date picker exception:" + e);
+    //         }
+    //     }
+    // }
 
-        this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name });
-    }
-
-    @action
-    closeDatePicker = () => {
-        if (this._picker) {
-            this._picker.alwaysShow = false;
-            this._picker.hide();
-        }
-        document.removeEventListener("pointerdown", this.closeDatePicker);
-    }
 
     @action
     toggleCollapse = () => {
-        this.props.CollectionView.props.Document._chromeStatus = this.props.CollectionView.props.Document._chromeStatus === "enabled" ? "collapsed" : "enabled";
+        this.document._chromeStatus = this.document._chromeStatus === "enabled" ? "collapsed" : "enabled";
         if (this.props.collapse) {
             this.props.collapse(this.props.CollectionView.props.Document._chromeStatus !== "enabled");
         }
     }
 
     subChrome = () => {
-        const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
+        const collapsed = this.document._chromeStatus !== "enabled";
         if (collapsed) return null;
         switch (this.props.type) {
             case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
@@ -279,13 +213,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         return this.props.CollectionView.props.Document;
     }
 
-    @action.bound
-    clearFilter = () => {
-        this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name });
-        this._keyRestrictions = [];
-        this.addKeyRestrictions([]);
-    }
-
     private dropDisposer?: DragManager.DragDropDisposer;
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.dropDisposer && this.dropDisposer();
@@ -304,48 +231,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         return true;
     }
 
-    datePickerRef = (node: HTMLInputElement) => {
-        if (node) {
-            try {
-                this._picker = datepicker("#" + node.id, {
-                    disabler: (date: Date) => date > new Date(),
-                    onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
-                    dateSelected: new Date()
-                });
-            } catch (e) {
-                console.log("date picker exception:" + e);
-            }
-        }
-    }
-
-    renderSuggestion = (suggestion: string) => {
-        return <p>{suggestion}</p>;
-    }
-    getSuggestionValue = (suggestion: string) => suggestion;
-
-    @action
-    onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
-        this._currentKey = newValue;
-    }
-    onSuggestionFetch = async ({ value }: { value: string }) => {
-        const sugg = await this.getKeySuggestions(value);
-        runInAction(() => this.suggestions = sugg);
-    }
-    @action
-    onSuggestionClear = () => {
-        this.suggestions = [];
-    }
-    getKeySuggestions = async (value: string): Promise<string[]> => {
-        return this._buttonizableCommands.filter(c => c.title.indexOf(value) !== -1).map(c => c.title);
-    }
-
-    autoSuggestDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
-    }
-
-    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
-    private _sensitivity: number = 16;
-
     dragViewDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, (e, down, delta) => {
             const vtype = this.props.CollectionView.collectionViewType;
@@ -367,7 +252,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                     { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY));
             return true;
         }, emptyFunction, emptyFunction);
-        this._startDragPosition = { x: e.clientX, y: e.clientY };
     }
 
     render() {
@@ -392,7 +276,12 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
                             <FontAwesomeIcon icon="caret-up" size="2x" />
                         </button>
-                        <div className="collectionViewBaseChrome-template" style={{ marginLeft: 25, display: collapsed ? "none" : undefined }}>
+                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
+                            <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.toggleViewSpecs} >
+                                <FontAwesomeIcon icon="filter" size="2x" />
+                            </div>
+                        </div>
+                        <div className="collectionViewBaseChrome-template" style={{ display: collapsed ? "none" : undefined }}>
                             <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}>
                                 <div className="commandEntry-drop">
                                     <FontAwesomeIcon icon="bullseye" size="2x"></FontAwesomeIcon>
@@ -414,49 +303,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                                 </select>
                             </div>
                         </div>
-                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
-                            <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.openViewSpecs} >
-                                <FontAwesomeIcon icon="filter" size="2x" />
-                            </div>
-                            <div className="collectionViewBaseChrome-viewSpecsMenu"
-                                onPointerDown={this.openViewSpecs}
-                                style={{
-                                    height: this._viewSpecsOpen ? "fit-content" : "0px",
-                                    overflow: this._viewSpecsOpen ? "initial" : "hidden"
-                                }}>
-                                {this._keyRestrictions.map(i => i[0])}
-                                <div className="collectionViewBaseChrome-viewSpecsMenu-row">
-                                    <div className="collectionViewBaseChrome-viewSpecsMenu-rowLeft">
-                                        CREATED WITHIN:
-                                    </div>
-                                    <select className="collectionViewBaseChrome-viewSpecsMenu-rowMiddle"
-                                        style={{ textTransform: "uppercase", textAlign: "center" }}
-                                        value={this._dateWithinValue}
-                                        onChange={(e) => runInAction(() => this._dateWithinValue = e.target.value)}>
-                                        <option value="1d">1 day of</option>
-                                        <option value="3d">3 days of</option>
-                                        <option value="1w">1 week of</option>
-                                        <option value="2w">2 weeks of</option>
-                                        <option value="1m">1 month of</option>
-                                        <option value="2m">2 months of</option>
-                                        <option value="6m">6 months of</option>
-                                        <option value="1y">1 year of</option>
-                                    </select>
-                                    <input className="collectionViewBaseChrome-viewSpecsMenu-rowRight"
-                                        id={Utils.GenerateGuid()}
-                                        ref={this.datePickerRef}
-                                        value={this._dateValue instanceof Date ? this._dateValue.toLocaleDateString() : this._dateValue}
-                                        onChange={(e) => runInAction(() => this._dateValue = e.target.value)}
-                                        onPointerDown={this.openDatePicker}
-                                        placeholder="Value" />
-                                </div>
-                                <div className="collectionViewBaseChrome-viewSpecsMenu-lastRow">
-                                    <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.addKeyRestriction}> ADD KEY RESTRICTION </button>
-                                    <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.applyFilter}> APPLY FILTER </button>
-                                    <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.clearFilter}> CLEAR </button>
-                                </div>
-                            </div>
-                        </div>
                         <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{ display: collapsed ? "none" : undefined }}>
                             <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
                                 <div className="commandEntry-drop">
-- 
cgit v1.2.3-70-g09d2


From d5c0ed9a29593583a4180973f854106dc10d4b30 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 15 Apr 2020 02:32:47 -0400
Subject: moved filter to right side of collection.  got rid of back button in
 pivot view - click background.

---
 src/Utils.ts                                       | 10 +++--
 .../views/collections/CollectionTimeView.tsx       | 30 +++++++--------
 src/client/views/collections/CollectionView.scss   |  4 +-
 src/client/views/collections/CollectionView.tsx    | 43 +++++++++++++++-------
 .../views/collections/CollectionViewChromes.scss   |  8 +++-
 .../views/collections/CollectionViewChromes.tsx    | 12 +++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  3 +-
 8 files changed, 69 insertions(+), 43 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index a8cde0624..58f272ba5 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -475,7 +475,9 @@ export function setupMoveUpEvents(
     e: React.PointerEvent,
     moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
     upEvent: (e: PointerEvent) => void,
-    clickEvent: (e: PointerEvent) => void) {
+    clickEvent: (e: PointerEvent) => void,
+    stopPropagation: boolean = true
+) {
     (target as any)._downX = (target as any)._lastX = e.clientX;
     (target as any)._downY = (target as any)._lastY = e.clientY;
 
@@ -499,8 +501,10 @@ export function setupMoveUpEvents(
         document.removeEventListener("pointermove", _moveEvent);
         document.removeEventListener("pointerup", _upEvent);
     };
-    e.stopPropagation();
-    e.preventDefault();
+    if (stopPropagation) {
+        e.stopPropagation();
+        e.preventDefault();
+    }
     document.removeEventListener("pointermove", _moveEvent);
     document.removeEventListener("pointerup", _upEvent);
     document.addEventListener("pointermove", _moveEvent);
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 31b720b81..1760e2419 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -72,8 +72,22 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         }), returnFalse, emptyFunction);
     }
 
+    contentsDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, returnFalse, action(() => {
+            let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex);
+            if (prevFilterIndex > 0) {
+                prevFilterIndex--;
+                this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField);
+                this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
+                this.props.Document._prevFilterIndex = prevFilterIndex;
+            } else {
+                this.props.Document._docFilters = new List([]);
+            }
+        }), false);
+    }
+
     @computed get contents() {
-        return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
+        return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }} onPointerDown={this.contentsDown}>
             <CollectionFreeFormView {...this.props} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
@@ -132,20 +146,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
             color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
         };
         return <div className={"pivotKeyEntry"}>
-            <button className="collectionTimeView-backBtn"
-                onClick={action(() => {
-                    let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex);
-                    if (prevFilterIndex > 0) {
-                        prevFilterIndex--;
-                        this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField);
-                        this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
-                        this.props.Document._prevFilterIndex = prevFilterIndex;
-                    } else {
-                        this.props.Document._docFilters = new List([]);
-                    }
-                })}>
-                back
-            </button>
             <EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
         </div>;
     }
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index a0b73b90f..d43dd387a 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -20,7 +20,7 @@
         top: 55%;
         border: 1px black solid;
         z-index: 2;
-        left: -10px;
+        right: -10px;
     }
     .collectionTimeView-treeView {
         display: flex;
@@ -28,7 +28,7 @@
         width: 200px;
         height: 100%;
         position: absolute;
-        left: 0;
+        right: 0;
         top: 0;
 
         .collectionTimeView-addfacet {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 831691f8c..0a3577bc7 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List';
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils';
+import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { ImageUtils } from '../../util/Import & Export/ImageUtils';
@@ -45,6 +45,7 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { ObjectField } from '../../../new_fields/ObjectField';
 import CollectionMapView from './CollectionMapView';
+import { Transform } from 'prosemirror-transform';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -281,7 +282,6 @@ export class CollectionView extends Touchable<FieldViewProps> {
     set _facetWidth(value) { this.props.Document._facetWidth = value; }
 
     bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth();
-    getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0);
     facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
 
     @computed get dataDoc() {
@@ -389,7 +389,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
 
     onPointerDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
-            this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
+            this._facetWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
             return false;
         }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0));
     }
@@ -415,27 +415,44 @@ export class CollectionView extends Touchable<FieldViewProps> {
                 <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
                     <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
                         <div className="collectionTimeView-button">
-                            <span className="collectionTimeView-span">Facet Filters</span>
                             <FontAwesomeIcon icon={faEdit} size={"lg"} />
+                            <span className="collectionTimeView-span">Facet Filters</span>
                         </div>
                     </Flyout>
                 </div>
                 <div className="collectionTimeView-tree" key="tree">
-                    <CollectionTreeView {...this.props}
+                    <CollectionTreeView
+                        Document={facetCollection}
+                        DataDoc={facetCollection}
+                        fieldKey={`${this.props.fieldKey}-filter`}
                         CollectionView={this}
-                        treeViewHideTitle={true}
+                        ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+                        ContainingCollectionView={this.props.ContainingCollectionView}
+                        PanelWidth={this.facetWidth}
+                        PanelHeight={this.props.PanelHeight}
                         NativeHeight={returnZero}
                         NativeWidth={returnZero}
+                        LibraryPath={emptyPath}
+                        rootSelected={this.props.rootSelected}
+                        renderDepth={1}
+                        dropAction={this.props.dropAction}
+                        ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                        addDocTab={returnFalse}
+                        pinToPres={returnFalse}
+                        isSelected={returnFalse}
+                        select={returnFalse}
+                        bringToFront={emptyFunction}
+                        active={this.props.active}
+                        whenActiveChanged={returnFalse}
+                        treeViewHideTitle={true}
+                        ContentScaling={returnOne}
+                        focus={returnFalse}
                         treeViewHideHeaderFields={true}
                         onCheckedClick={this.scriptField!}
                         ignoreFields={this.ignoreFields}
                         annotationsKey={""}
                         dontRegisterView={true}
-                        PanelWidth={this.facetWidth}
-                        DataDoc={facetCollection}
-                        Document={facetCollection}
                         backgroundColor={this.filterBackground}
-                        fieldKey={`${this.props.fieldKey}-filter`}
                         moveDocument={returnFalse}
                         removeDocument={returnFalse}
                         addDocument={returnFalse} />
@@ -461,7 +478,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
             }}
             onContextMenu={this.onContextMenu}>
             {this.showIsTagged()}
-            <div style={{ width: `calc(100% - ${this.facetWidth()}px)`, marginLeft: `${this.facetWidth()}px` }}>
+            <div style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
                 {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
             </div>
             {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
@@ -471,9 +488,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
                     :
                     ""))}
             {!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) :
-                <div className="collectionTimeView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this.facetWidth()}px, 0px)` }} >
-                    <span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} />
-                </div>
+                <div className="collectionTimeView-dragger" title="library View Dragger" onPointerDown={this.onPointerDown} style={{ right: this.facetWidth() - 10 }} />
             }
             {this.filterView}
         </div>);
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index 9529ef525..5203eb55f 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -61,7 +61,8 @@
                 pointer-events: all;
                 // margin-top: 10px;
             }
-            .collectionViewBaseChrome-template {
+            .collectionViewBaseChrome-template,
+            .collectionViewBaseChrome-viewModes {
                 display: grid;
                 background: rgb(238, 238, 238);
                 color:grey;
@@ -69,9 +70,12 @@
                 margin-bottom:auto;
                 margin-left: 5px;
             }
+            .collectionViewBaseChrome-viewModes {
+                margin-left: 25px;
+            }
 
             .collectionViewBaseChrome-viewSpecs {
-                margin-left: 25px;
+                margin-left: 5px;
                 display: grid;
                 
                 .collectionViewBaseChrome-filterIcon {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index cef85e148..7315d2c4e 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -276,12 +276,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
                             <FontAwesomeIcon icon="caret-up" size="2x" />
                         </button>
-                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
-                            <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.toggleViewSpecs} >
-                                <FontAwesomeIcon icon="filter" size="2x" />
-                            </div>
-                        </div>
-                        <div className="collectionViewBaseChrome-template" style={{ display: collapsed ? "none" : undefined }}>
+                        <div className="collectionViewBaseChrome-viewModes" style={{ display: collapsed ? "none" : undefined }}>
                             <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}>
                                 <div className="commandEntry-drop">
                                     <FontAwesomeIcon icon="bullseye" size="2x"></FontAwesomeIcon>
@@ -303,6 +298,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                                 </select>
                             </div>
                         </div>
+                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
+                            <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.toggleViewSpecs} >
+                                <FontAwesomeIcon icon="filter" size="2x" />
+                            </div>
+                        </div>
                         <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{ display: collapsed ? "none" : undefined }}>
                             <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
                                 <div className="commandEntry-drop">
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a77f09163..d98fe190c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -907,6 +907,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
 
     onViewDefDivClick = (e: React.MouseEvent, payload: any) => {
         (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload });
+        e.stopPropagation();
     }
     private viewDefToJSX(viewDef: ViewDefBounds): Opt<ViewDefResult> {
         const { x, y, z } = viewDef;
@@ -991,6 +992,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
                     {...this.getChildDocumentViewProps(pair.layout, pair.data)}
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
+                    pointerEvents={this.props.layoutEngine?.() !== undefined ? "none" : undefined}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
                     fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)}
                     FreezeDimensions={BoolCast(this.props.freezeChildDimensions)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e7cb2c015..05ad98c43 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -22,6 +22,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     width?: number;
     height?: number;
     jitterRotation: number;
+    pointerEvents?: "none";
     transition?: string;
     fitToBox?: boolean;
 }
@@ -92,7 +93,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 height: this.height,
                 zIndex: this.ZInd,
                 display: this.ZInd === -99 ? "none" : undefined,
-                pointerEvents: this.props.Document.isBackground ? "none" : undefined
+                pointerEvents: this.props.Document.isBackground ? "none" : this.props.pointerEvents
             }} >
 
             {!this.props.fitToBox ?
-- 
cgit v1.2.3-70-g09d2

