From 9e18edc6c2b178d9d0960aa95d2b2a9f198ab6d1 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 13 Jan 2020 16:48:45 -0500
Subject: fixed onChildClick handlers to work for freeform views. added padding
 for fitTocontents views.  fixed performance with templates.  added
 openOnRight script func.  switched filter to ||,

---
 src/client/views/collections/CollectionDockingView.tsx | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 151b84c50..6c50ea0f2 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -34,6 +34,7 @@ import { DocumentType } from '../../documents/DocumentTypes';
 import { ComputedField } from '../../../new_fields/ScriptField';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { TraceMobx } from '../../../new_fields/util';
+import { Scripting } from '../../util/Scripting';
 library.add(faFile);
 const _global = (window /* browser */ || global /* node */) as any;
 
@@ -177,7 +178,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     //
     @undoBatch
     @action
-    public static AddRightSplit(document: Doc, dataDoc: Doc | undefined, minimize: boolean = false, libraryPath?: Doc[]) {
+    public static AddRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]) {
         if (!CollectionDockingView.Instance) return false;
         const instance = CollectionDockingView.Instance;
         const newItemStackConfig = {
@@ -202,11 +203,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             collayout.config.width = 50;
             newContentItem.config.width = 50;
         }
-        if (minimize) {
-            // bcz: this makes the drag image show up better, but it also messes with fixed layout sizes
-            // newContentItem.config.width = 10;
-            // newContentItem.config.height = 10;
-        }
         newContentItem.callDownwards('_$init');
         instance.layoutChanged();
         return true;
@@ -674,7 +670,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         if (doc.dockingConfig) {
             return MainView.Instance.openWorkspace(doc);
         } else if (location === "onRight") {
-            return CollectionDockingView.AddRightSplit(doc, dataDoc, undefined, libraryPath);
+            return CollectionDockingView.AddRightSplit(doc, dataDoc, libraryPath);
         } else if (location === "close") {
             return CollectionDockingView.CloseRightSplit(doc);
         } else {
@@ -724,3 +720,4 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             </div >);
     }
 }
+Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); });
-- 
cgit v1.2.3-70-g09d2


From e183f40509edec426b6519fe77590792c1f3f346 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 16 Jan 2020 16:15:26 -0500
Subject: pivot viewer improvements.

---
 .../tmp/start_8210707001248201939.properties       |  11 ++
 src/client/documents/Documents.ts                  |   5 +
 .../views/collections/CollectionDockingView.tsx    |  33 ++++++
 .../views/collections/CollectionPivotView.scss     |  57 ++++++++++
 .../views/collections/CollectionPivotView.tsx      | 119 +++++++++++++++++++++
 .../views/collections/CollectionTreeView.tsx       |  23 ++--
 src/client/views/collections/CollectionView.tsx    |   3 +-
 7 files changed, 239 insertions(+), 12 deletions(-)
 create mode 100644 solr-8.3.1/server/tmp/start_8210707001248201939.properties
 create mode 100644 src/client/views/collections/CollectionPivotView.scss
 create mode 100644 src/client/views/collections/CollectionPivotView.tsx

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

diff --git a/solr-8.3.1/server/tmp/start_8210707001248201939.properties b/solr-8.3.1/server/tmp/start_8210707001248201939.properties
new file mode 100644
index 000000000..aebc17bdc
--- /dev/null
+++ b/solr-8.3.1/server/tmp/start_8210707001248201939.properties
@@ -0,0 +1,11 @@
+#start.jar properties
+#Thu Jan 16 20:33:22 UTC 2020
+java.version.platform=8
+java.version=1.8.0_211
+java.version.micro=0
+jetty.home=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
+java.version.minor=8
+jetty.home.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
+jetty.base=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
+java.version.major=1
+jetty.base.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index be678d765..eacdd8214 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -69,6 +69,8 @@ export interface DocumentOptions {
     page?: number;
     scale?: number;
     fitWidth?: boolean;
+    fitToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents
+    isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents
     forceActive?: boolean;
     preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view
     layout?: string | Doc;
@@ -114,6 +116,9 @@ export interface DocumentOptions {
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     strokeWidth?: number;
     color?: string;
+    treeViewHideTitle?: boolean; // whether to hide the title of a tree view
+    treeViewOpen?: boolean; // whether this document is expanded in a tree view
+    isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
     // [key: string]: Opt<Field>;
 }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 6c50ea0f2..a7a124825 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -207,6 +207,38 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         instance.layoutChanged();
         return true;
     }
+    //
+    //  Creates a vertical split on the right side of the docking view, and then adds the Document to that split
+    //
+    @undoBatch
+    @action
+    public static UseRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]) {
+        if (!CollectionDockingView.Instance) return false;
+        const instance = CollectionDockingView.Instance;
+        if (instance._goldenLayout.root.contentItems[0].isRow) {
+            let found: DocumentView | undefined;
+            Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
+                if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" &&
+                    DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.props.Document.isDisplayPanel) {
+                    found = DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)!;
+                } else {
+                    Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => {
+                        if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.props.Document.isDisplayPanel) {
+                            found = DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!;
+                            return true;
+                        }
+                        return false;
+                    });
+                }
+            });
+            if (found) {
+                Doc.GetProto(found.props.Document).data = new List<Doc>([document]);
+            } else {
+                const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" })
+                CollectionDockingView.AddRightSplit(stackView, undefined, []);
+            }
+        }
+    }
 
     @undoBatch
     @action
@@ -721,3 +753,4 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
 }
 Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); });
+Scripting.addGlobal(function useRightSplit(doc: any) { CollectionDockingView.UseRightSplit(doc, undefined); });
diff --git a/src/client/views/collections/CollectionPivotView.scss b/src/client/views/collections/CollectionPivotView.scss
new file mode 100644
index 000000000..bd3d6c77b
--- /dev/null
+++ b/src/client/views/collections/CollectionPivotView.scss
@@ -0,0 +1,57 @@
+.collectionPivotView {
+    display: flex;
+    flex-direction: row;
+    position: absolute;
+    height:100%;
+    width:100%;
+    .collectionPivotView-flyout {
+        width: 400px;
+        height: 300px;
+        display: inline-block;
+        .collectionPivotView-flyout-item {
+            background-color: lightgray;
+            text-align: left;
+            display: inline-block;
+            position: relative;
+            width: 100%;
+        }
+    }
+
+    .collectionPivotView-treeView {
+        display:flex;
+        flex-direction: column;
+        width: 200px;
+        height: 100%;
+        .collectionPivotView-addfacet {
+            display:inline-block;
+            width: 200px;
+            height: 30px;
+            background: darkGray;
+            text-align: center;
+            .collectionPivotView-button {
+                align-items: center;
+                display: flex;
+                width: 100%;
+                height: 100%;
+                .collectionPivotView-span {
+                    margin: auto;
+                }
+            }
+            > div, > div > div {
+                width: 100%;
+                height: 100%;
+                text-align: center;
+            }
+        }
+        .collectionPivotView-tree {
+            display:inline-block;
+            width: 200px;
+            height: calc(100% - 30px);
+        }
+    }
+    .collectionPivotView-pivot {
+        display:inline-block;
+        width: calc(100% - 200px);
+        height: 100%;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
new file mode 100644
index 000000000..d56052ed5
--- /dev/null
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -0,0 +1,119 @@
+import { CollectionSubView } from "./CollectionSubView";
+import React = require("react");
+import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx";
+import { faEdit, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
+import "./CollectionPivotView.scss";
+import { observer } from "mobx-react";
+import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
+import { CollectionTreeView } from "./CollectionTreeView";
+import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { Docs } from "../../documents/Documents";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { CompileScript } from "../../util/Scripting";
+import { anchorPoints, Flyout } from "../TemplateMenu";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { List } from "../../../new_fields/List";
+import { Set } from "typescript-collections";
+
+@observer
+export class CollectionPivotView extends CollectionSubView(doc => doc) {
+    componentDidMount = () => {
+        this.props.Document.freeformLayoutEngine = "pivot";
+        if (!this.props.Document.facetCollection) {
+            const facetCollection = Docs.Create.FreeformDocument([], { title: "facetFilters", yMargin: 0, treeViewHideTitle: true });
+            facetCollection.target = this.props.Document;
+
+            const scriptText = "setDocFilter(context.target, heading, this.title, checked)";
+            const script = CompileScript(scriptText, {
+                params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name },
+                typecheck: false,
+                editable: true,
+            });
+            if (script.compiled) {
+                facetCollection.onCheckedClick = new ScriptField(script);
+            }
+
+            const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layoutCustom'; useRightSplit(alias); ";
+            const openDocScript = CompileScript(openDocText, {
+                params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name },
+                typecheck: false,
+                editable: true,
+            });
+            if (openDocScript.compiled) {
+                this.props.Document.onChildClick = new ScriptField(openDocScript);
+            }
+
+            this.props.Document.facetCollection = facetCollection;
+            this.props.Document.fitToBox = true;
+        }
+    }
+
+    @computed get fieldExtensionDoc() {
+        return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey);
+    }
+
+    bodyPanelWidth = () => this.props.PanelWidth() - 200;
+    getTransform = () => this.props.ScreenToLocalTransform().translate(-200, 0);
+
+    @computed get _allFacets() {
+        const facets = new Set<string>();
+        this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
+        return facets.toArray();
+    }
+
+    facetClick = (facet: string) => {
+        const facetCollection = this.props.Document.facetCollection;
+        if (facetCollection instanceof Doc) {
+            let found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet);
+            if (found !== -1) {
+                //Doc.RemoveDocFromList(facetCollection, "data", DocListCast(facetCollection.data)[found]);
+                (facetCollection.data as List<Doc>).splice(found, 1);
+            } else {
+                const facetValues = new Set<string>();
+                this.childDocs.forEach(child => {
+                    Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facet]?.toString() || "(null)"));
+                    facetValues.add(child[facet]?.toString() || "(null)");
+                });
+                this.childDocs
+
+                const newFacetVals = facetValues.toArray().map(val => Docs.Create.TextDocument({ title: val.toString() }));
+                const newFacet = Docs.Create.FreeformDocument(newFacetVals, { title: facet, treeViewOpen: true, isFacetFilter: true });
+                Doc.AddDocToList(facetCollection, "data", newFacet);
+            }
+        }
+    }
+
+    render() {
+        const facetCollection = Cast(this.props.Document?.facetCollection, Doc, null);
+        const flyout = (
+            <div className="collectionPivotView-flyout" title=" ">
+                {this._allFacets.map(facet => <label className="collectionPivotView-flyout-item" onClick={e => this.facetClick(facet)}>
+                    <input type="checkbox" checked={this.props.Document.facetCollection instanceof Doc && DocListCast(this.props.Document.facetCollection.data).some(d => {
+                        return d.title === facet;
+                    })} />
+                    <span className="checkmark" />
+                    {facet}
+                </label>)}
+            </div>
+        );
+        return !facetCollection ? (null) : <div className="collectionPivotView">
+            <div className="collectionPivotView-treeView">
+                <div className="collectionPivotView-addFacet" onPointerDown={e => e.stopPropagation()}>
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
+                        <div className="collectionPivotView-button">
+                            <span className="collectionPivotView-span">Facet Filters</span>
+                            <FontAwesomeIcon icon={faEdit} size={"lg"} />
+                        </div>
+                    </Flyout>
+                </div>
+                <div className="collectionPivotView-tree">
+                    <CollectionTreeView {...this.props} Document={facetCollection} />
+                </div>
+            </div>
+            <div className="collectionPivotView-pivot">
+                <CollectionFreeFormView  {...this.props} ScreenToLocalTransform={this.getTransform} PanelWidth={this.bodyPanelWidth} />
+            </div>
+        </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3356aed68..70860b6bd 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -52,7 +52,7 @@ export interface TreeViewProps {
     outdentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
     outerXf: () => { translateX: number, translateY: number };
-    treeViewId: string;
+    treeViewId: Doc;
     parentKey: string;
     active: (outsideReaction?: boolean) => boolean;
     hideHeaderFields: () => boolean;
@@ -234,8 +234,8 @@ class TreeView extends React.Component<TreeViewProps> {
             if (inside) {
                 addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc);
             }
-            const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments);
-            return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId)) || de.complete.docDragData.userDropAction) ?
+            const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments);
+            return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ?
                 de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d) || added, false)
                 : de.complete.docDragData.moveDocument ?
                     movedDocs.reduce((added, d) => de.complete.docDragData?.moveDocument?.(d, undefined, addDoc) || added, false)
@@ -368,12 +368,13 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @action
     bulletClick = (e: React.MouseEvent) => {
-        if (this.props.onCheckedClick) {
+        if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) {
             this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
             ScriptCast(this.props.onCheckedClick).script.run({
                 this: this.props.document.isTemplateField && this.props.dataDoc ? this.props.dataDoc : this.props.document,
                 heading: this.props.containingCollection.title,
-                checked: this.props.document.treeViewChecked === "check" ? false : this.props.document.treeViewChecked === "x" ? "x" : "none"
+                checked: this.props.document.treeViewChecked === "check" ? false : this.props.document.treeViewChecked === "x" ? "x" : "none",
+                context: this.props.treeViewId
             }, console.log);
         } else {
             this.treeViewOpen = !this.treeViewOpen;
@@ -383,7 +384,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @computed
     get renderBullet() {
-        const checked = this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
+        const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
         return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "black"), opacity: 0.4 }}>
             {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
         </div>;
@@ -394,7 +395,7 @@ class TreeView extends React.Component<TreeViewProps> {
     @computed
     get renderTitle() {
         const reference = React.createRef<HTMLDivElement>();
-        const onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
+        const onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
 
         const headerElements = (
             <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
@@ -444,7 +445,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
     public static GetChildElements(
         childDocs: Doc[],
-        treeViewId: string,
+        treeViewId: Doc,
         containingCollection: Doc,
         dataDoc: Doc | undefined,
         key: string,
@@ -655,7 +656,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                 onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
                 onDrop={this.onTreeDrop}
                 ref={this.createTreeDropTarget}>
-                <EditableView
+                {(this.props.Document.treeViewHideTitle ? (null) : <EditableView
                     contents={this.dataDoc.title}
                     display={"block"}
                     maxHeight={72}
@@ -668,11 +669,11 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         const doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
                         TreeView.loadId = doc[Id];
                         Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false);
-                    })} />
+                    })} />)}
                 {this.props.Document.allowClear ? this.renderClearButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
-                        TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
+                        TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
                             moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
                             this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.hideHeaderFields),
                             BoolCast(this.props.Document.preventTreeViewOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 21371dd39..022fc8f48 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -36,6 +36,7 @@ import { TraceMobx } from '../../../new_fields/util';
 import { Utils } from '../../../Utils';
 import { ScriptBox } from '../ScriptBox';
 import CollectionMulticolumnView from '../CollectionMulticolumnView';
+import { CollectionPivotView } from './CollectionPivotView';
 const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
 
@@ -180,7 +181,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
             case CollectionViewType.Linear: { return (<CollectionLinearView key="collview" {...props} />); }
             case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); }
             case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); }
-            case CollectionViewType.Pivot: { this.props.Document.freeformLayoutEngine = "pivot"; return (<CollectionFreeFormView key="collview" {...props} />); }
+            case CollectionViewType.Pivot: { return (<CollectionPivotView key="collview" {...props} />); }
             case CollectionViewType.Freeform:
             default: { this.props.Document.freeformLayoutEngine = undefined; return (<CollectionFreeFormView key="collview" {...props} />); }
         }
-- 
cgit v1.2.3-70-g09d2


From 05eb320bef0395fef704f583d69673bfa5abaa77 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 17 Jan 2020 00:39:03 -0500
Subject: visual displays for widths

---
 src/client/views/CollectionMulticolumnView.scss    | 12 ++-
 src/client/views/CollectionMulticolumnView.tsx     | 91 ++++++++++++----------
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionPivotView.tsx      |  2 +-
 4 files changed, 65 insertions(+), 42 deletions(-)

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

diff --git a/src/client/views/CollectionMulticolumnView.scss b/src/client/views/CollectionMulticolumnView.scss
index 1c2389809..8c4410f01 100644
--- a/src/client/views/CollectionMulticolumnView.scss
+++ b/src/client/views/CollectionMulticolumnView.scss
@@ -4,8 +4,18 @@
     height: 100%;
     overflow: hidden;
 
+    .fish {
+        display: flex;
+        flex-direction: column;
+
+        .display {
+            text-align: center;
+            height: 20px;
+        }
+
+    }
+
     .spacer {
-        width: 2px;
         background: black;
         cursor: ew-resize;
         opacity: 0.2;
diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx
index 61ce8d99c..20923d8e6 100644
--- a/src/client/views/CollectionMulticolumnView.tsx
+++ b/src/client/views/CollectionMulticolumnView.tsx
@@ -1,15 +1,14 @@
 import { observer } from 'mobx-react';
-import { makeInterface, listSpec } from '../../new_fields/Schema';
+import { makeInterface } from '../../new_fields/Schema';
 import { documentSchema } from '../../new_fields/documentSchemas';
 import { CollectionSubView } from './collections/CollectionSubView';
 import { DragManager } from '../util/DragManager';
 import * as React from "react";
 import { Doc, DocListCast } from '../../new_fields/Doc';
-import { NumCast, Cast, StrCast } from '../../new_fields/Types';
+import { NumCast, StrCast } from '../../new_fields/Types';
 import { List } from '../../new_fields/List';
 import { ContentFittingDocumentView } from './nodes/ContentFittingDocumentView';
 import { Utils } from '../../Utils';
-import { Transform } from '../util/Transform';
 import "./collectionMulticolumnView.scss";
 import { computed } from 'mobx';
 
@@ -29,7 +28,15 @@ interface Resolved {
     pixels: number;
 }
 
+interface LayoutData {
+    unresolved: Unresolved[];
+    numFixed: number;
+    numRatio: number;
+    starSum: number;
+}
+
 const resolvedUnits = ["*", "px"];
+const resizerWidth = 2;
 
 @observer
 export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) {
@@ -50,23 +57,20 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
     }
 
     @computed
-    private get resolvedLayoutInformation() {
+    private get resolvedLayoutInformation(): LayoutData {
         const unresolved: Unresolved[] = [];
-        let ratioSum = 0, numFixed = 0, numRatio = 0;
+        let starSum = 0, numFixed = 0, numRatio = 0;
         for (const config of this.configuration) {
             const { target, widthMagnitude, widthUnit } = config;
             if (target instanceof Doc) {
                 const unit = StrCast(widthUnit);
                 const magnitude = NumCast(widthMagnitude);
                 if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
-                    switch (unit) {
-                        case "*":
-                            ratioSum += magnitude;
-                            numRatio++;
-                            break;
-                        case "px":
-                            numFixed++;
-                            break;
+                    if (unit === "*") {
+                        starSum += magnitude;
+                        numRatio++;
+                    } else {
+                        numFixed++;
                     }
                     unresolved.push({ config, target, magnitude, unit });
                 }
@@ -74,7 +78,7 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
                 // space is allocated as if the document were absent from the configuration list
             }
         }
-        return { unresolved, numRatio, numFixed, ratioSum };
+        return { unresolved, numRatio, numFixed, starSum };
     }
 
     /**
@@ -112,17 +116,21 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
     @computed
     private get totalRatioAllocation(): number | undefined {
         const { totalFixedAllocation } = this;
-        return totalFixedAllocation !== undefined ? this.props.PanelWidth() - totalFixedAllocation : undefined;
+        const layout = this.resolvedLayoutInformation;
+        if (!layout) {
+            return undefined;
+        }
+        return totalFixedAllocation !== undefined ? this.props.PanelWidth() - (totalFixedAllocation + resizerWidth * (layout.unresolved.length - 1)) : undefined;
     }
 
     /**
      * This returns the total quantity, in pixels, that
      * 1* (relative / star unit) is worth. For example,
-     * if the configuration had three documents, with, respectively,
-     * widths of 2*, 2* and 1*, and the panel width was 1000px,
-     * this value would return 1000 / (2 + 2 + 1), or 200px.
-     * This is then multiplied by each relative-width
-     * document's * factor to compute its actual width (400px, 400px and 200px).
+     * if the configuration has three documents, with, respectively,
+     * widths of 2*, 2* and 1*, and the panel width returns 1000px,
+     * this accessor returns 1000 / (2 + 2 + 1), or 200px.
+     * Elsewhere, this is then multiplied by each relative-width
+     * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px).
      * 
      * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined
      * because we're waiting indirectly on promises to resolve, this value will be undefined as well.
@@ -131,11 +139,10 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
     private get columnUnitLength(): number | undefined {
         const layout = this.resolvedLayoutInformation;
         const { totalRatioAllocation } = this;
-        if (layout !== null && totalRatioAllocation !== undefined) {
-            const { ratioSum, unresolved } = layout;
-            return (totalRatioAllocation - 2 * (unresolved.length - 1)) / ratioSum;
+        if (layout === null || totalRatioAllocation === undefined) {
+            return undefined;
         }
-        return undefined;
+        return totalRatioAllocation / layout.starSum;
     }
 
     @computed
@@ -146,27 +153,31 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
             return (null); // we're still waiting on promises to resolve
         }
         const resolved: Resolved[] = [];
-        layout.unresolved.forEach(value => {
-            const { unit, magnitude, ...remaining } = value;
+        layout.unresolved.forEach(item => {
+            const { unit, magnitude, ...remaining } = item;
             let width = magnitude;
             if (unit === "*") {
                 width = magnitude * columnUnitLength;
             }
-            resolved.push({ pixels: width, ...remaining, });
+            resolved.push({ pixels: width, ...remaining });
         });
         const collector: JSX.Element[] = [];
         for (let i = 0; i < resolved.length; i++) {
             const { target, pixels, config } = resolved[i];
-            collector.push(<ContentFittingDocumentView
-                {...this.props}
-                key={Utils.GenerateGuid()}
-                Document={target}
-                DataDocument={undefined}
-                PanelWidth={() => pixels}
-                getTransform={this.props.ScreenToLocalTransform}
-            />);
             collector.push(
-                <MulticolumnSpacer
+                <div className={"fish"}>
+                    <ContentFittingDocumentView
+                        {...this.props}
+                        key={Utils.GenerateGuid()}
+                        Document={target}
+                        DataDocument={undefined}
+                        PanelWidth={() => pixels}
+                        getTransform={this.props.ScreenToLocalTransform}
+                    />
+                    <span className={"display"}>{NumCast(config.widthMagnitude).toFixed(3)} {StrCast(config.widthUnit)}</span>
+                </div>,
+                <ResizeBar
+                    width={resizerWidth}
                     key={Utils.GenerateGuid()}
                     columnUnitLength={columnUnitLength}
                     toLeft={config}
@@ -174,11 +185,11 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
                 />
             );
         }
-        collector.pop(); // not the cleanest, but simply removes the final extraneous spacer
+        collector.pop(); // removes the final extraneous resize bar
         return collector;
     }
 
-    render() {
+    render(): JSX.Element {
         return (
             <div className={"collectionMulticolumnView_contents"}>
                 {this.contents}
@@ -189,12 +200,13 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico
 }
 
 interface SpacerProps {
+    width: number;
     columnUnitLength: number;
     toLeft?: Doc;
     toRight?: Doc;
 }
 
-class MulticolumnSpacer extends React.Component<SpacerProps> {
+class ResizeBar extends React.Component<SpacerProps> {
 
     private registerResizing = (e: React.PointerEvent<HTMLDivElement>) => {
         e.stopPropagation();
@@ -225,6 +237,7 @@ class MulticolumnSpacer extends React.Component<SpacerProps> {
         return (
             <div
                 className={"spacer"}
+                style={{ width: this.props.width }}
                 onPointerDown={this.registerResizing}
             />
         );
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a7a124825..022eccc13 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -234,7 +234,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             if (found) {
                 Doc.GetProto(found.props.Document).data = new List<Doc>([document]);
             } else {
-                const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" })
+                const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" });
                 CollectionDockingView.AddRightSplit(stackView, undefined, []);
             }
         }
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
index d56052ed5..d6261c7ee 100644
--- a/src/client/views/collections/CollectionPivotView.tsx
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -65,7 +65,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
     facetClick = (facet: string) => {
         const facetCollection = this.props.Document.facetCollection;
         if (facetCollection instanceof Doc) {
-            let found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet);
+            const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet);
             if (found !== -1) {
                 //Doc.RemoveDocFromList(facetCollection, "data", DocListCast(facetCollection.data)[found]);
                 (facetCollection.data as List<Doc>).splice(found, 1);
-- 
cgit v1.2.3-70-g09d2

