From cc806ebbe8d48d1c5a4c3c49231a5d38d6f39943 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 27 Jul 2019 04:12:07 -0400
Subject: fixed a bunch of template and stacking view issues among others.

---
 .../views/collections/CollectionDockingView.tsx    | 39 ++++++++--------------
 1 file changed, 13 insertions(+), 26 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 ba7903419..0865058be 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -539,17 +539,17 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         }
     }
 
+    panelWidth = () => Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth()));
+    panelHeight = () => Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), NumCast(this._document!.nativeHeight, this._panelHeight)));
+
+    nativeWidth = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeWidth, this._panelWidth) : 0;
+    nativeHeight = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeHeight, this._panelHeight) : 0;
 
-    nativeWidth = () => NumCast(this._document!.nativeWidth, this._panelWidth);
-    nativeHeight = () => {
-        let nh = NumCast(this._document!.nativeHeight, this._panelHeight);
-        let res = BoolCast(this._document!.ignoreAspect) ? this._panelHeight : nh;
-        return res;
-    }
     contentScaling = () => {
         const nativeH = this.nativeHeight();
         const nativeW = this.nativeWidth();
-        let wscale = this._panelWidth / nativeW;
+        if (!nativeW || !nativeH) return 1;
+        let wscale = this.panelWidth() / nativeW;
         return wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
     }
 
@@ -561,18 +561,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         }
         return Transform.Identity();
     }
-    get scaleToFitMultiplier() {
-        let docWidth = NumCast(this._document!.width);
-        let docHeight = NumCast(this._document!.height);
-        if (NumCast(this._document!.nativeWidth) || !docWidth || !this._panelWidth || !this._panelHeight) return 1;
-        if (StrCast(this._document!.layout).indexOf("Collection") === -1 ||
-            !BoolCast(this._document!.fitToContents, false) ||
-            NumCast(this._document!.viewType) !== CollectionViewType.Freeform) return 1;
-        let scaling = Math.max(1, this._panelWidth / docWidth * docHeight > this._panelHeight ?
-            this._panelHeight / docHeight : this._panelWidth / docWidth);
-        return scaling;
-    }
-    get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; }
+    get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
 
     addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
         if (doc.dockingConfig) {
@@ -588,6 +577,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             return (null);
         }
         let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc;
+        console.log("pw = " + this.panelWidth() + "," + this.panelHeight() + " " + this.contentScaling());
         return <DocumentView key={this._document[Id]}
             Document={this._document}
             DataDoc={resolvedDataDoc}
@@ -595,8 +585,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             addDocument={undefined}
             removeDocument={undefined}
             ContentScaling={this.contentScaling}
-            PanelWidth={this.nativeWidth}
-            PanelHeight={this.nativeHeight}
+            PanelWidth={this.panelWidth}
+            PanelHeight={this.panelHeight}
             ScreenToLocalTransform={this.ScreenToLocalTransform}
             renderDepth={0}
             selectOnLoad={false}
@@ -610,18 +600,15 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
 
     @computed get content() {
-        if (!this._document) {
-            return (null);
-        }
         return (
             <div className="collectionDockingView-content" ref={this._mainCont}
-                style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px) scale(${this.scaleToFitMultiplier})` }}>
+                style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}>
                 {this.docView}
             </div >);
     }
 
     render() {
-        if (!this._isActive) return null;
+        if (!this._isActive || !this._document) return null;
         let theContent = this.content;
         return !this._document ? (null) :
             <Measure offset onResize={action((r: any) => { this._panelWidth = r.offset.width; this._panelHeight = r.offset.height; })}>
-- 
cgit v1.2.3-70-g09d2


From be1e6e967a60f49eec1cb1d404912b0736812323 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sun, 28 Jul 2019 17:59:00 -0400
Subject: Added ability to capture documents in button scripts

---
 src/client/views/ScriptBox.tsx                     | 23 +++++++-
 src/client/views/ScriptingRepl.tsx                 | 31 +----------
 .../views/collections/CollectionDockingView.tsx    |  1 -
 src/client/views/nodes/ButtonBox.tsx               |  6 +-
 src/client/views/nodes/DocumentIcon.tsx            | 65 ++++++++++++++++++++++
 5 files changed, 94 insertions(+), 32 deletions(-)
 create mode 100644 src/client/views/nodes/DocumentIcon.tsx

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

diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index fa236c2da..d073945e5 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -3,11 +3,15 @@ import { observer } from "mobx-react";
 import { observable, action } from "mobx";
 
 import "./ScriptBox.scss";
+import { OverlayView } from "./OverlayView";
+import { DocumentIconContainer } from "./nodes/DocumentIcon";
+import { Opt } from "../../new_fields/Doc";
 
 export interface ScriptBoxProps {
     onSave: (text: string, onError: (error: string) => void) => void;
     onCancel?: () => void;
     initialText?: string;
+    showDocumentIcons?: boolean;
 }
 
 @observer
@@ -30,14 +34,31 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
         console.log(error);
     }
 
+    overlayDisposer?: () => void;
+    onFocus = () => {
+        if (this.overlayDisposer) {
+            this.overlayDisposer();
+        }
+        this.overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+    }
+
+    onBlur = () => {
+        this.overlayDisposer && this.overlayDisposer();
+    }
+
     render() {
+        let onFocus: Opt<() => void> = undefined, onBlur: Opt<() => void> = undefined;
+        if (this.props.showDocumentIcons) {
+            onFocus = this.onFocus;
+            onBlur = this.onBlur;
+        }
         return (
             <div className="scriptBox-outerDiv">
                 <div className="scriptBox-toolbar">
                     <button onClick={e => { this.props.onSave(this._scriptText, this.onError); e.stopPropagation(); }}>Save</button>
                     <button onClick={e => { this.props.onCancel && this.props.onCancel(); e.stopPropagation(); }}>Cancel</button>
                 </div>
-                <textarea className="scriptBox-textarea" onChange={this.onChange} value={this._scriptText}></textarea>
+                <textarea className="scriptBox-textarea" onChange={this.onChange} value={this._scriptText} onFocus={onFocus} onBlur={onBlur}></textarea>
             </div>
         );
     }
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 0cff145b6..e05195ca0 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -4,40 +4,15 @@ import { observable, action } from 'mobx';
 import './ScriptingRepl.scss';
 import { Scripting, CompileScript, ts, Transformer } from '../util/Scripting';
 import { DocumentManager } from '../util/DocumentManager';
-import { DocumentView } from './nodes/DocumentView';
 import { OverlayView } from './OverlayView';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
+import { DocumentIconContainer } from './nodes/DocumentIcon';
 
 library.add(faCaretDown);
 library.add(faCaretRight);
 
-@observer
-export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> {
-    render() {
-        const view = this.props.view;
-        const transform = view.props.ScreenToLocalTransform().scale(view.props.ContentScaling()).inverse();
-        const { x, y, width, height } = transform.transformBounds(0, 0, view.props.PanelWidth(), view.props.PanelHeight());
-
-        return (
-            <div className="documentIcon-outerDiv" style={{
-                position: "absolute",
-                transform: `translate(${x + width / 2}px, ${y}px)`,
-            }}>
-                <p>${this.props.index}</p>
-            </div>
-        );
-    }
-}
-
-@observer
-export class DocumentIconContainer extends React.Component {
-    render() {
-        return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
-    }
-}
-
 @observer
 export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void, value: { [key: string]: any }, name?: string }> {
     @observable collapsed = true;
@@ -129,7 +104,7 @@ export class ScriptingRepl extends React.Component {
                             if (ts.isParameter(node.parent)) {
                                 // delete knownVars[node.text];
                             } else if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) {
-                                const match = node.text.match(/\$([0-9]+)/);
+                                const match = node.text.match(/\d([0-9]+)/);
                                 if (match) {
                                     const m = parseInt(match[1]);
                                     usedDocuments.push(m);
@@ -153,7 +128,7 @@ export class ScriptingRepl extends React.Component {
         switch (e.key) {
             case "Enter": {
                 const docGlobals: { [name: string]: any } = {};
-                DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`$${i}`] = dv.props.Document);
+                DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document);
                 const globals = Scripting.makeMutableGlobalsCopy(docGlobals);
                 const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals });
                 if (!script.compiled) {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 0865058be..1859ebee7 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -577,7 +577,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             return (null);
         }
         let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc;
-        console.log("pw = " + this.panelWidth() + "," + this.panelHeight() + " " + this.contentScaling());
         return <DocumentView key={this._document[Id]}
             Document={this._document}
             DataDoc={resolvedDataDoc}
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index 744611661..d2c23fdab 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -14,6 +14,7 @@ import { Doc } from '../../../new_fields/Doc';
 
 import './ButtonBox.scss';
 import { observer } from 'mobx-react';
+import { DocumentIconContainer } from './DocumentIcon';
 
 library.add(faEdit);
 
@@ -51,7 +52,8 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
                     const script = CompileScript(text, {
                         params: { this: Doc.name },
                         typecheck: false,
-                        editable: true
+                        editable: true,
+                        transformer: DocumentIconContainer.getTransformer()
                     });
                     if (!script.compiled) {
                         onError(script.errors.map(error => error.messageText).join("\n"));
@@ -59,7 +61,7 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
                     }
                     this.Document.onClick = new ScriptField(script);
                     overlayDisposer();
-                }} />;
+                }} showDocumentIcons />;
                 overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` });
             }
         });
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
new file mode 100644
index 000000000..f56f5e829
--- /dev/null
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -0,0 +1,65 @@
+import { observer } from "mobx-react";
+import * as React from "react";
+import { DocumentView } from "./DocumentView";
+import { DocumentManager } from "../../util/DocumentManager";
+import { Transformer, Scripting, ts } from "../../util/Scripting";
+import { Field } from "../../../new_fields/Doc";
+
+@observer
+export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> {
+    render() {
+        const view = this.props.view;
+        const transform = view.props.ScreenToLocalTransform().scale(view.props.ContentScaling()).inverse();
+        const { x, y, width, height } = transform.transformBounds(0, 0, view.props.PanelWidth(), view.props.PanelHeight());
+
+        return (
+            <div className="documentIcon-outerDiv" style={{
+                position: "absolute",
+                transform: `translate(${x + width / 2}px, ${y}px)`,
+            }}>
+                <p>d{this.props.index}</p>
+            </div>
+        );
+    }
+}
+
+@observer
+export class DocumentIconContainer extends React.Component {
+    public static getTransformer(): Transformer {
+        const usedDocuments = new Set<number>();
+        return {
+            transformer: context => {
+                return root => {
+                    function visit(node: ts.Node) {
+                        node = ts.visitEachChild(node, visit, context);
+
+                        if (ts.isIdentifier(node)) {
+                            const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
+                            const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
+                            const isntParameter = !ts.isParameter(node.parent);
+                            if (isntPropAccess && isntPropAssign && isntParameter && !(node.text in globalThis)) {
+                                const match = node.text.match(/d([0-9]+)/);
+                                if (match) {
+                                    const m = parseInt(match[1]);
+                                    usedDocuments.add(m);
+                                }
+                            }
+                        }
+
+                        return node;
+                    }
+                    return ts.visitNode(root, visit);
+                };
+            },
+            getVars() {
+                const docs = DocumentManager.Instance.DocumentViews;
+                const capturedVariables: { [name: string]: Field } = {};
+                usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document);
+                return { capturedVariables };
+            }
+        };
+    }
+    render() {
+        return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 06dfb537826e8b1642783a9c4ab2514fd7da2fe3 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 29 Jul 2019 16:53:52 -0400
Subject: More fixes

---
 src/client/views/collections/CollectionDockingView.tsx             | 2 +-
 src/client/views/collections/CollectionStackingView.scss           | 1 +
 src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 4 ++--
 src/client/views/nodes/ImageBox.tsx                                | 2 +-
 4 files changed, 5 insertions(+), 4 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 1859ebee7..d7b5262b1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -561,7 +561,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         }
         return Transform.Identity();
     }
-    get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth()) / 2 : 0; }
 
     addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
         if (doc.dockingConfig) {
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 004b57eff..2bb36c825 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -74,6 +74,7 @@
         transform-origin: top left;
         grid-column-end: span 1;
         height: 100%;
+        margin: auto;
     }
 
     .collectionStackingView-sectionHeader {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 71c4d9f0c..b5dbc1a22 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -239,7 +239,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         };
         let headingView = this.props.headingObject ?
             <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef}
-                style={{ width: (style.columnWidth) / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) }}>
+                style={{ width: (style.columnWidth) / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1) }}>
                 {/* the default bucket (no key value) has a tooltip that describes what it is.
                     Further, it does not have a color and cannot be deleted. */}
                 <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
@@ -261,7 +261,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             </div> : (null);
         for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `;
         return (
-            <div key={heading} style={{ width: `${100 / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0))}%`, background: this._background }}
+            <div key={heading} style={{ width: `${100 / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1)}%`, background: this._background }}
                 ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
                 {headingView}
                 <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 82af4b4ca..d4e0eaf98 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -291,7 +291,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                 let aspect = size.height / size.width;
                 let rotation = NumCast(this.dataDoc.rotation) % 180;
                 if (rotation === 90 || rotation === 270) aspect = 1 / aspect;
-                if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) {
+                if (Math.abs(NumCast(layoutdoc.height) - size.height) > 1 || Math.abs(NumCast(layoutdoc.width) - size.width) > 1) {
                     setTimeout(action(() => {
                         layoutdoc.height = layoutdoc[WidthSym]() * aspect;
                         layoutdoc.nativeHeight = size.height;
-- 
cgit v1.2.3-70-g09d2


From d7af2cae3ec66ca9a8c9abbc0a221ee1dbb6d101 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 29 Jul 2019 19:17:29 -0400
Subject: Made AddTab be able to accept no stack

---
 src/client/views/collections/CollectionDockingView.tsx | 15 ++++++++++++++-
 src/new_fields/SchemaHeaderField.ts                    |  1 -
 2 files changed, 14 insertions(+), 2 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 d7b5262b1..ab4d1aa62 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -211,7 +211,20 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         }
         let docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument);
         var newContentItem = stack.layoutManager.createContentItem(docContentConfig, this._goldenLayout);
-        stack.addChild(newContentItem.contentItems[0], undefined);
+        if (stack === undefined) {
+            if (this._goldenLayout.root.contentItems.length === 0) {
+                this._goldenLayout.root.addChild(newContentItem);
+            } else {
+                const rowOrCol = this._goldenLayout.root.contentItems[0];
+                if (rowOrCol.contentItems.length) {
+                    rowOrCol.contentItems[0].addChild(newContentItem);
+                } else {
+                    rowOrCol.addChild(newContentItem);
+                }
+            }
+        } else {
+            stack.addChild(newContentItem.contentItems[0], undefined);
+        }
         this.layoutChanged();
     }
 
diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts
index d124a3907..d5da56b10 100644
--- a/src/new_fields/SchemaHeaderField.ts
+++ b/src/new_fields/SchemaHeaderField.ts
@@ -49,7 +49,6 @@ export class SchemaHeaderField extends ObjectField {
     type: number;
 
     constructor(heading: string = "", color?: string, type?: ColumnType) {
-        console.log("CREATING SCHEMA HEADER FIELD");
         super();
 
         this.heading = heading;
-- 
cgit v1.2.3-70-g09d2

