From 0737a14e2c436ab9613c638bcebdc5480df1d4d4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 13 Apr 2019 00:23:44 -0400
Subject: repairs to keyvaluebox

---
 src/client/views/nodes/KeyValueBox.tsx | 53 ++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 12 deletions(-)

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

diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index bcac113f0..29e4af160 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -1,23 +1,25 @@
 
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
 import { Document } from '../../../fields/Document';
-import { FieldWaiting, Field } from '../../../fields/Field';
+import { Field, FieldWaiting } from '../../../fields/Field';
+import { Key } from '../../../fields/Key';
 import { KeyStore } from '../../../fields/KeyStore';
+import { CompileScript, ToField } from "../../util/Scripting";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./KeyValueBox.scss";
 import { KeyValuePair } from "./KeyValuePair";
 import React = require("react");
-import { CompileScript, ToField } from "../../util/Scripting";
-import { Key } from '../../../fields/Key';
-import { observable, action } from "mobx";
 
 @observer
 export class KeyValueBox extends React.Component<FieldViewProps> {
+    private _mainCont = React.createRef<HTMLDivElement>();
 
     public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); }
     @observable private _keyInput: string = "";
     @observable private _valueInput: string = "";
+    @computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 50); }
 
 
     constructor(props: FieldViewProps) {
@@ -90,7 +92,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         let rows: JSX.Element[] = [];
         let i = 0;
         for (let key in ids) {
-            rows.push(<KeyValuePair doc={realDoc} rowStyle={"keyValueBox-" + (i++ % 2 ? "oddRow" : "evenRow")} fieldId={key} key={key} />);
+            rows.push(<KeyValuePair doc={realDoc} keyWidth={100 - this.splitPercentage} rowStyle={"keyValueBox-" + (i++ % 2 ? "oddRow" : "evenRow")} fieldId={key} key={key} />);
         }
         return rows;
     }
@@ -107,24 +109,51 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
 
     newKeyValue = () =>
         (
-            <tr>
-                <td><input type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} /></td>
-                <td><input type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyPress={this.onEnterKey} /></td>
+            <tr className="keyValueBox-valueRow">
+                <td className="keyValueBox-td-key" style={{ width: `${100 - this.splitPercentage}%` }}>
+                    <input style={{ width: "100%" }} type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} />
+                </td>
+                <td className="keyValueBox-td-value" style={{ width: `${this.splitPercentage}%` }}>
+                    <input style={{ width: "100%" }} type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyPress={this.onEnterKey} />
+                </td>
             </tr>
         )
 
+    @action
+    onDividerMove = (e: PointerEvent): void => {
+        let nativeWidth = this._mainCont.current!.getBoundingClientRect();
+        this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, Math.max(0, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100)));
+    }
+    @action
+    onDividerUp = (e: PointerEvent): void => {
+        document.removeEventListener("pointermove", this.onDividerMove);
+        document.removeEventListener('pointerup', this.onDividerUp);
+    }
+    onDividerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+        document.addEventListener("pointermove", this.onDividerMove);
+        document.addEventListener('pointerup', this.onDividerUp);
+    }
+
     render() {
-        return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel}>
+        let dividerDragger = this.splitPercentage === 0 ? (null) :
+            <div className="keyValueBox-dividerDragger" style={{ transform: `translate(calc(${100 - this.splitPercentage}% - 5px), 0px)` }}>
+                <div className="keyValueBox-dividerDraggerThumb" onPointerDown={this.onDividerDown} />
+            </div>;
+
+        return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel} ref={this._mainCont}>
             <table className="keyValueBox-table">
-                <tbody>
+                <tbody className="keyValueBox-tbody">
                     <tr className="keyValueBox-header">
-                        <th>Key</th>
-                        <th>Fields</th>
+                        <th className="keyValueBox-key" style={{ width: `${100 - this.splitPercentage}%` }}>Key</th>
+                        <th className="keyValueBox-fields" style={{ width: `${this.splitPercentage}%` }}>Fields</th>
                     </tr>
                     {this.createTable()}
                     {this.newKeyValue()}
                 </tbody>
             </table>
+            {dividerDragger}
         </div>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 166c37942ba536f024cbeba6f151da0ed6a3f671 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Apr 2019 16:04:16 -0400
Subject: fixing up small interaction issues with web pages, collections, etc.

---
 src/client/views/EditableView.scss                 |  1 -
 src/client/views/Main.tsx                          |  6 +-
 .../views/collections/CollectionBaseView.tsx       |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 89 +++++++++++++---------
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/DocumentView.scss           |  5 +-
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  1 -
 src/client/views/nodes/KeyValueBox.tsx             |  6 --
 src/client/views/nodes/WebBox.scss                 |  6 ++
 src/client/views/nodes/WebBox.tsx                  | 35 +++++++--
 11 files changed, 99 insertions(+), 57 deletions(-)

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

diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
index be3c5069a..ea401eaf9 100644
--- a/src/client/views/EditableView.scss
+++ b/src/client/views/EditableView.scss
@@ -2,5 +2,4 @@
     overflow-wrap: break-word;
     word-wrap: break-word;
     hyphens: auto;
-    max-width: 300px;
 }
\ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 98ef329c7..6c18e9ad5 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -84,7 +84,11 @@ export class Main extends React.Component {
         this.initEventListeners();
         this.initAuthenticationRouters();
 
-        this.initializeNorthstar();
+        try {
+            this.initializeNorthstar();
+        } catch (e) {
+
+        }
     }
 
     componentDidMount() { window.onpopstate = this.onHistory; }
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index bff56e8c3..444f6fc26 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -88,7 +88,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
         doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
         if (this.isAnnotationOverlay) {
-            doc.SetOnPrototype(KeyStore.Zoom, new NumberField(this.props.Document.GetNumber(KeyStore.Scale, 1)));
+            doc.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1));
         }
         if (curPage >= 0) {
             doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4db3bf81b..03426cb27 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -111,7 +111,11 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || e.button === 0) && this.props.active()) {
+        let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+            var dv = DocumentManager.Instance.getDocumentView(doc);
+            return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+        }, false);
+        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
@@ -130,38 +134,36 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerMove = (e: PointerEvent): void => {
-        if (!e.cancelBubble && this.props.active()) {
-            if ((!this.isAnnotationOverlay || this.zoomScaling !== 1) && !e.shiftKey) {
-                let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
-                let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
-                let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
-                let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
-                if (!this.isAnnotationOverlay) {
-                    let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
-                    let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
-                    let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
-                    let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
-                    let ranges = docs.filter(doc => doc).reduce((range, doc) => {
-                        let x = doc.GetNumber(KeyStore.X, 0);
-                        let xe = x + doc.GetNumber(KeyStore.Width, 0);
-                        let y = doc.GetNumber(KeyStore.Y, 0);
-                        let ye = y + doc.GetNumber(KeyStore.Height, 0);
-                        return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
-                        [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
-                    }, [[minx, maxx], [miny, maxy]]);
-                    let panelwidth = this._pwidth / this.scale / 2;
-                    let panelheight = this._pheight / this.scale / 2;
-                    if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
-                    if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
-                    if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
-                    if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
-                }
-                this.SetPan(x - dx, y - dy);
-                this._lastX = e.pageX;
-                this._lastY = e.pageY;
-                e.stopPropagation();
-                e.preventDefault();
+        if (!e.cancelBubble) {
+            let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
+            let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
+            let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+            let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
+            if (!this.isAnnotationOverlay) {
+                let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
+                let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
+                let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
+                let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
+                let ranges = docs.filter(doc => doc).reduce((range, doc) => {
+                    let x = doc.GetNumber(KeyStore.X, 0);
+                    let xe = x + doc.GetNumber(KeyStore.Width, 0);
+                    let y = doc.GetNumber(KeyStore.Y, 0);
+                    let ye = y + doc.GetNumber(KeyStore.Height, 0);
+                    return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
+                    [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
+                }, [[minx, maxx], [miny, maxy]]);
+                let panelwidth = this._pwidth / this.scale / 2;
+                let panelheight = this._pheight / this.scale / 2;
+                if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
+                if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
+                if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
+                if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
             }
+            this.SetPan(x - dx, y - dy);
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
+            e.stopPropagation();
+            e.preventDefault();
         }
     }
 
@@ -170,6 +172,13 @@ export class CollectionFreeFormView extends CollectionSubView {
         // if (!this.props.active()) {
         //     return;
         // }
+        let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+            var dv = DocumentManager.Instance.getDocumentView(doc);
+            return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+        }, false);
+        if (!this.props.isSelected() && !childSelected && !this.props.isTopMost) {
+            return;
+        }
         e.stopPropagation();
         let coefficient = 1000;
 
@@ -281,13 +290,23 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
+        let pw = this.props.CollectionView.props
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
             var zoom = doc.GetNumber(KeyStore.Zoom, 1);
-            var dv = DocumentManager.Instance.getDocumentView(doc);
-            let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 :
-                Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale));
+            let zoomFade = 1;
+            var documentView = DocumentManager.Instance.getDocumentView(doc);
+            if (documentView) {
+                let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
+                var [sptX, sptY] = transform.transformPoint(0, 0);
+                let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
+                let w = bptX - sptX;
+                //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
+                let fadeUp = .75 * 1800;
+                let fadeDown = .075 * 1800;
+                zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+            }
             if (page === curPage || page === -1) {
                 prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
             }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index dbab790d4..783470286 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -160,7 +160,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 pany: 0,
                 width: bounds.width,
                 height: bounds.height,
-                backgroundColor: "Transparent",
                 ink: inkData ? this.marqueeInkSelect(inkData) : undefined,
                 title: "a nested collection"
             });
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a946ac1a8..5071c9440 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,6 +1,6 @@
 @import "../globalCssVariables";
 
-.documentView-node {
+.documentView-node .documentView-node-topMost {
   position: inherit;
   top: 0;
   left:0;
@@ -28,6 +28,9 @@
     height: calc(100% - 20px);
   }
 }
+.documentView-node-topMost {
+    background: white;
+}
 
 .minimized-box {
   height: 10px;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bcd746024..20592894f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -212,7 +212,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
     }
     fullScreenClicked = (e: React.MouseEvent): void => {
-        CollectionDockingView.Instance.OpenFullScreen(this.props.Document);
+        CollectionDockingView.Instance.OpenFullScreen((this.props.Document.GetPrototype() as Document).MakeDelegate());
         ContextMenu.Instance.clearItems();
         ContextMenu.Instance.addItem({
             description: "Close Full Screen",
@@ -425,7 +425,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             );
             return (
                 <div
-                    className="documentView-node"
+                    className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
                     ref={this._mainCont}
                     style={{
                         background: backgroundcolor,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ad1ed5df0..8963484b6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -42,7 +42,6 @@ export interface FormattedTextBoxOverlay {
     isOverlay?: boolean;
 }
 
-@observer
 export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> {
     public static LayoutString(fieldStr: string = "DataKey") {
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 29e4af160..ddbec014b 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -26,12 +26,6 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         super(props);
     }
 
-
-
-    shouldComponentUpdate() {
-        return false;
-    }
-
     @action
     onEnterKey = (e: React.KeyboardEvent): void => {
         if (e.key === 'Enter') {
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index c73bc0c47..2ad1129a4 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -9,6 +9,12 @@
     overflow: scroll;
 }
 
+#webBox-htmlSpan {
+    position: absolute;
+    top:0;
+    left:0;
+}
+
 .webBox-button {
     padding : 0vw;
     border: none;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 90ce72c41..1edb4d826 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -18,21 +18,40 @@ export class WebBox extends React.Component<FieldViewProps> {
 
     @computed get html(): string { return this.props.Document.GetHtml(KeyStore.Data, ""); }
 
+    _ignore = 0;
+    onPreWheel = (e: React.WheelEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPrePointer = (e: React.PointerEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPostPointer = (e: React.PointerEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
+    onPostWheel = (e: React.WheelEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
     render() {
         let field = this.props.Document.Get(this.props.fieldKey);
         let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
             field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu";
 
-        let content = this.html ?
-            <span dangerouslySetInnerHTML={{ __html: this.html }}></span> :
-            <div style={{ width: "100%", height: "100%", position: "absolute" }}>
-                <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }}></iframe>
-                {this.props.isSelected() ? (null) : <div style={{ width: "100%", height: "100%", position: "absolute" }} />}
+        let content =
+            <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
+                {this.html ? <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: this.html }} /> :
+                    <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }} />}
             </div>;
 
         return (
-            <div className="webBox-cont"  >
-                {content}
-            </div>);
+            <>
+                <div className="webBox-cont"  >
+                    {content}
+                </div>
+                {this.props.isSelected() ? (null) : <div onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} style={{ width: "100%", height: "100%", position: "absolute" }} />}
+            </>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

