From 7b08cb4fd86a7e7048e14c05ab980f5b008d18d8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Apr 2022 13:57:42 -0400
Subject: cleaned up creation of icon templates.  fixed labelBox to support
 padding and to work with multiple lines and min font sizes.

---
 src/client/views/nodes/LabelBox.tsx | 46 ++++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 13 deletions(-)

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

diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index d539ca9b8..dfff59005 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -27,14 +27,19 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
         return `<${fieldType.name} fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
     }
     private dropDisposer?: DragManager.DragDropDisposer;
-
+    private _timeout: any;
     componentDidMount() {
         this.props.setContentView?.(this);
     }
+    componentWillUnMount() {
+        this._timeout && clearTimeout(this._timeout);
+    }
 
     getTitle() {
-        return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label :
-            typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title);
+        return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) :
+            this.props.label ? this.props.label :
+                typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) :
+                    StrCast(this.rootDoc.title);
     }
 
     protected createDropTarget = (ele: HTMLDivElement) => {
@@ -73,8 +78,8 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
     @observable _mouseOver = false;
     @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; }
 
-    fitTextToBox = (r: any) => {
-        BigText(r, {
+    fitTextToBox = (r: any): any => {
+        const params = {
             rotateText: null,
             fontSizeFactor: 1,
             minimumFontSize: NumCast(this.layoutDoc._minFontSize),
@@ -83,11 +88,25 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
             horizontalAlign: "center",
             verticalAlign: "center",
             textAlign: "center",
-            whiteSpace: "nowrap"
-        });
+            whiteSpace: this.layoutDoc._singleLine ? "nowrap" : "pre-wrap"
+        };
+        this._timeout = undefined;
+        if (!r) return params;
+        if (!r.offsetHeight || !r.offsetWidth) return this._timeout = setTimeout(() => this.fitTextToBox(r));
+        const parent = r.parentNode;
+        const parentStyle = parent.style;
+        parentStyle.display = "";
+        parentStyle.alignItems = "";
+        r.setAttribute("style", "");
+        r.style.width = this.layoutDoc._singleLine ? "" : "100%";
+
+        r.style.textOverflow = "ellipsis";
+        r.style.overflow = "hidden";
+        BigText(r, params);
     }
     // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
     render() {
+        this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes
         const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
         const missingParams = params?.filter(p => !this.paramsDoc[p]);
         params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
@@ -104,16 +123,17 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
                     letterSpacing: StrCast(this.layoutDoc.letterSpacing),
                     textTransform: StrCast(this.layoutDoc.textTransform) as any,
+                    paddingLeft: NumCast(this.rootDoc._xPadding),
+                    paddingRight: NumCast(this.rootDoc._xPadding),
+                    paddingTop: NumCast(this.rootDoc._yPadding),
+                    paddingBottom: NumCast(this.rootDoc._yPadding),
                     width: this.props.PanelWidth(),
                     height: this.props.PanelHeight(),
                     whiteSpace: this.layoutDoc._singleLine ? "pre" : "pre-wrap"
                 }} >
-                    <span ref={r => {
-                        if (r) {
-                            if (!r.offsetWidth || !r.offsetHeight) setTimeout(() => this.fitTextToBox(r));
-                            else this.fitTextToBox(r);
-                        }
-                    }}>{label.startsWith("#") ? (null) : label}</span>
+                    <span ref={action((r: any) => this.fitTextToBox(r))}>
+                        {label.startsWith("#") ? (null) : label}
+                    </span>
                 </div>
                 <div className="labelBox-fieldKeyParams" >
                     {!missingParams?.length ? (null) : missingParams.map(m => <div key={m} className="labelBox-missingParam">{m}</div>)}
-- 
cgit v1.2.3-70-g09d2


From a6aec8759298fba41b486a973796662056f47da0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Apr 2022 17:05:10 -0400
Subject: changed the way labelBox splits words to allow .&- added icon for
 webBox

---
 src/client/util/CurrentUserUtils.ts                                 | 1 +
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +-
 src/client/views/nodes/DocumentView.scss                            | 6 ++++--
 src/client/views/nodes/LabelBox.tsx                                 | 2 +-
 src/client/views/nodes/PDFBox.tsx                                   | 2 +-
 src/client/views/nodes/WebBoxRenderer.js                            | 2 +-
 6 files changed, 9 insertions(+), 6 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 03c63e737..9720343e1 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -315,6 +315,7 @@ export class CurrentUserUtils {
             makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })),
             makeIconTemplate(DocumentType.AUDIO, "title", () => labelBox({ _backgroundColor: "lightgreen" })),
             makeIconTemplate(DocumentType.PDF, "title", () => labelBox({ _backgroundColor: "pink" })),
+            makeIconTemplate(DocumentType.WEB, "title", () => labelBox({ _backgroundColor: "brown" })),
             makeIconTemplate(DocumentType.RTF, "text", () => labelBox({ _showTitle: "creationDate" })),
             makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })),
             makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})),
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 452a6bfcf..5d1e1892c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1454,7 +1454,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         CreateImage(
             "",
             document.styleSheets,
-            htmlString?.replace(/docView-hack/g, 'documentView-hack'),
+            htmlString,
             nativeWidth,
             nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
             NumCast(this.layoutDoc._scrollTop)
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 5c5d2df10..6a1bfa406 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -3,12 +3,14 @@
 .documentView-effectsWrapper {
     border-radius: inherit;
 }
+
+// documentViews have a docView-hack tag which is replaced by this tag when capturing bitmaps (when the dom is converted to an html string)
 .documentView-hack {
-    display: inline;
+    display: inline; //  this swap is needed because for some reason when capturing bitmaps, things don't appear unless dispay:inline is explicitly set.
 }
 
 .documentView-customBorder {
-    width:100%;
+    width: 100%;
     height: 100%;
     position: absolute;
     top: 0;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index dfff59005..1a28fc318 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -132,7 +132,7 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     whiteSpace: this.layoutDoc._singleLine ? "pre" : "pre-wrap"
                 }} >
                     <span ref={action((r: any) => this.fitTextToBox(r))}>
-                        {label.startsWith("#") ? (null) : label}
+                        {label.startsWith("#") ? (null) : label.replace(/([\.\-&])/g, "$1 ")}
                     </span>
                 </div>
                 <div className="labelBox-fieldKeyParams" >
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index f386c7bbd..69662d53a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -87,7 +87,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         CreateImage(
             "",
             document.styleSheets,
-            htmlString?.replace(/docView-hack/g, 'documentView-hack'),
+            htmlString,
             nativeWidth,
             nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
             NumCast(this.layoutDoc._scrollTop) * this.props.PanelHeight() / NumCast(this.rootDoc[this.fieldKey + "-nativeHeight"])
diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js
index 08a5746d1..d2b701cf9 100644
--- a/src/client/views/nodes/WebBoxRenderer.js
+++ b/src/client/views/nodes/WebBoxRenderer.js
@@ -312,7 +312,7 @@ var ForeignHtmlRenderer = function (styleSheets) {
 
 
 export function CreateImage(webUrl, styleSheets, html, width, height, scroll) {
-    const val = (new ForeignHtmlRenderer(styleSheets)).renderToBase64Png(webUrl, html.replace(/\n/g, "").replace(/<script((?!\/script).)*<\/script>/g, ""), width, height, scroll);
+    const val = (new ForeignHtmlRenderer(styleSheets)).renderToBase64Png(webUrl, html.replace(/docView-hack/g, 'documentView-hack').replace(/\n/g, "").replace(/<script((?!\/script).)*<\/script>/g, ""), width, height, scroll);
     return val;
 }
 
-- 
cgit v1.2.3-70-g09d2


From 10dda7683987a7d0735478374af1a256bca8e7f1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Apr 2022 20:37:22 -0400
Subject: another fix for Label's BigText to make multiline work better.  fixed
 server bug for 'write after end' when servering web pages.

---
 src/client/views/nodes/LabelBigText.js | 46 +++++++++++++++++++++-------------
 src/client/views/nodes/LabelBox.tsx    | 15 +++++------
 src/server/server_Initialization.ts    | 25 ++++++++++++------
 3 files changed, 55 insertions(+), 31 deletions(-)

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

diff --git a/src/client/views/nodes/LabelBigText.js b/src/client/views/nodes/LabelBigText.js
index 6a212d9ea..290152cd0 100644
--- a/src/client/views/nodes/LabelBigText.js
+++ b/src/client/views/nodes/LabelBigText.js
@@ -100,7 +100,8 @@ export default function BigText(element, options) {
         horizontalAlign: "center",
         verticalAlign: "center",
         textAlign: "center",
-        whiteSpace: "nowrap"
+        whiteSpace: "nowrap",
+        singleLine: true
     };
 
     //Merge provided options and default options
@@ -111,20 +112,29 @@ export default function BigText(element, options) {
 
     //Get variables which we will reference frequently
     var style = element.style;
-    var computedStyle = document.defaultView.getComputedStyle(element);
     var parent = element.parentNode;
     var parentStyle = parent.style;
     var parentComputedStyle = document.defaultView.getComputedStyle(parent);
 
     //hides the element to prevent "flashing"
     style.visibility = "hidden";
-
     //Set some properties
     style.display = "inline-block";
     style.clear = "both";
     style.float = "left";
-    style.fontSize = (1000 * options.fontSizeFactor) + "px";
-    style.lineHeight = "1000px";
+    var fontSize = options.maximumFontSize;
+    if (options.singleLine) {
+        style.fontSize = (fontSize * options.fontSizeFactor) + "px";
+        style.lineHeight = fontSize + "px";
+    } else {
+        for (; fontSize > options.minimumFontSize; fontSize = fontSize - Math.min(fontSize / 2, Math.max(0, fontSize - 48) + 2)) {
+            style.fontSize = (fontSize * options.fontSizeFactor) + "px";
+            style.lineHeight = "1";
+            if (element.offsetHeight <= +parentComputedStyle.height.replace("px", "")) {
+                break;
+            }
+        }
+    }
     style.whiteSpace = options.whiteSpace;
     style.textAlign = options.textAlign;
     style.position = "relative";
@@ -132,6 +142,7 @@ export default function BigText(element, options) {
     style.margin = 0;
     style.left = "50%";
     style.top = "50%";
+    var computedStyle = document.defaultView.getComputedStyle(element);
 
     //Get properties of parent to allow easier referencing later.
     var parentPadding = {
@@ -175,19 +186,20 @@ export default function BigText(element, options) {
         box.height = element.offsetWidth * sine + element.offsetHeight * cosine;
     }
 
-    var widthFactor = (parentInnerWidth - parentPadding.left - parentPadding.right) / box.width;
-    var heightFactor = (parentInnerHeight - parentPadding.top - parentPadding.bottom) / box.height;
+    var parentWidth = (parentInnerWidth - parentPadding.left - parentPadding.right);
+    var parentHeight = (parentInnerHeight - parentPadding.top - parentPadding.bottom);
+    var widthFactor = parentWidth / box.width;
+    var heightFactor = parentHeight / box.height;
     var lineHeight;
 
     if (options.limitingDimension.toLowerCase() === "width") {
-        lineHeight = Math.floor(widthFactor * 1000);
-        parentStyle.height = lineHeight + "px";
+        lineHeight = Math.floor(widthFactor * fontSize);
     } else if (options.limitingDimension.toLowerCase() === "height") {
-        lineHeight = Math.floor(heightFactor * 1000);
+        lineHeight = Math.floor(heightFactor * fontSize);
     } else if (widthFactor < heightFactor)
-        lineHeight = Math.floor(widthFactor * 1000);
+        lineHeight = Math.floor(widthFactor * fontSize);
     else if (widthFactor >= heightFactor)
-        lineHeight = Math.floor(heightFactor * 1000);
+        lineHeight = Math.floor(heightFactor * fontSize);
 
     var fontSize = lineHeight * options.fontSizeFactor;
     if (fontSize < options.minimumFontSize) {
@@ -214,11 +226,11 @@ export default function BigText(element, options) {
     style.marginBottom = "0px";
     style.marginRight = "0px";
 
-    if (options.limitingDimension.toLowerCase() === "height") {
-        //this option needs the font-size to be set already so computedStyle.getPropertyValue("width") returns the right size
-        //this +4 is to compensate the rounding erros that can occur due to the calls to Math.floor in the centering code
-        parentStyle.width = (parseInt(computedStyle.getPropertyValue("width")) + 4) + "px";
-    }
+    // if (options.limitingDimension.toLowerCase() === "height") {
+    //     //this option needs the font-size to be set already so computedStyle.getPropertyValue("width") returns the right size
+    //     //this +4 is to compensate the rounding erros that can occur due to the calls to Math.floor in the centering code
+    //     parentStyle.width = (parseInt(computedStyle.getPropertyValue("width")) + 4) + "px";
+    // }
 
     //Calculate the inner width and height
     var innerDimensions = _calculateInnerDimensions(computedStyle);
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 1a28fc318..2ff2adafa 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, DocListCast } from '../../../fields/Doc';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
-import { Cast, StrCast, NumCast } from '../../../fields/Types';
+import { Cast, StrCast, NumCast, BoolCast } from '../../../fields/Types';
 import { DragManager } from '../../util/DragManager';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
@@ -82,13 +82,14 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.layoutDoc._minFontSize),
-            maximumFontSize: NumCast(this.layoutDoc._maxFontSize),
+            minimumFontSize: NumCast(this.rootDoc._minFontSize, 2),
+            maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
             limitingDimension: "both",
             horizontalAlign: "center",
             verticalAlign: "center",
             textAlign: "center",
-            whiteSpace: this.layoutDoc._singleLine ? "nowrap" : "pre-wrap"
+            singleLine: BoolCast(this.rootDoc._singleLine),
+            whiteSpace: this.rootDoc._singleLine ? "nowrap" : "pre-wrap"
         };
         this._timeout = undefined;
         if (!r) return params;
@@ -98,7 +99,7 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
         parentStyle.display = "";
         parentStyle.alignItems = "";
         r.setAttribute("style", "");
-        r.style.width = this.layoutDoc._singleLine ? "" : "100%";
+        r.style.width = this.rootDoc._singleLine ? "" : "100%";
 
         r.style.textOverflow = "ellipsis";
         r.style.overflow = "hidden";
@@ -129,9 +130,9 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     paddingBottom: NumCast(this.rootDoc._yPadding),
                     width: this.props.PanelWidth(),
                     height: this.props.PanelHeight(),
-                    whiteSpace: this.layoutDoc._singleLine ? "pre" : "pre-wrap"
+                    whiteSpace: this.rootDoc._singleLine ? "pre" : "pre-wrap"
                 }} >
-                    <span ref={action((r: any) => this.fitTextToBox(r))}>
+                    <span style={{ width: this.layoutDoc._singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
                         {label.startsWith("#") ? (null) : label.replace(/([\.\-&])/g, "$1 ")}
                     </span>
                 </div>
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 24cc3b796..81ed0d2a1 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -193,11 +193,11 @@ function proxyServe(req: any, requrl: string, response: any) {
                                     return `href="${resolvedServerUrl + "/corsProxy/http" + href}"`;
                                 };
                                 const zipToStringDecoder = new (require('string_decoder').StringDecoder)('utf8');
-                                // const htmlText = zipToStringDecoder.write(zlib.gunzipSync(htmlBodyMemoryStream.read()).toString('utf8')
-                                //     .replace('<head>', '<head> <style>[id ^= "google"] { display: none; } </style>')
-                                //     .replace(/href="http([^"]*)"/g, replacer)
-                                //     .replace(/target="_blank"/g, ""));
-                                // rewrittenHtmlBody = zlib.gzipSync(htmlText);
+                                const htmlText = zipToStringDecoder.write(zlib.gunzipSync(htmlBodyMemoryStream.read()).toString('utf8')
+                                    .replace('<head>', '<head> <style>[id ^= "google"] { display: none; } </style>')
+                                    .replace(/href="http([^"]*)"/g, replacer)
+                                    .replace(/target="_blank"/g, ""));
+                                rewrittenHtmlBody = zlib.gzipSync(htmlText);
                                 const bodyStream = htmlBodyMemoryStream.read();
                                 if (bodyStream) {
                                     const htmlText = zipToStringDecoder.write(zlib.gunzipSync(bodyStream).toString('utf8')
@@ -208,14 +208,25 @@ function proxyServe(req: any, requrl: string, response: any) {
                                 } else {
                                     console.log("EMPTY body: href");
                                 }
-                            } catch (e) { console.log(e); }
+                            } catch (e) {
+                                console.log("EROR?: ", e);
+                            }
                         }
                     });
                 })
                 .on('data', (e: any) => {
-                    rewrittenHtmlBody && response.send(rewrittenHtmlBody);
+                    try {
+                        if (!response.connection.writable) {
+                            rewrittenHtmlBody && response.send(rewrittenHtmlBody);
+                        }
+                    } catch (e) {
+                        console.log("ERROR data : ", e);
+                    }
                     rewrittenHtmlBody = undefined;
                 })
+                .on('error', (e: any) => {
+                    console.log("ERROR ON SERVER: ", e);
+                })
                 .pipe(response);
         })
         .pipe(htmlBodyMemoryStream);
-- 
cgit v1.2.3-70-g09d2


From 41d4b4bc754466d06100dc321d5556ac4d24330e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Apr 2022 20:45:33 -0400
Subject: another labelBox fix using zerowidth spaces!

---
 src/client/views/nodes/LabelBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 2ff2adafa..d0d61fd79 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -133,7 +133,7 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     whiteSpace: this.rootDoc._singleLine ? "pre" : "pre-wrap"
                 }} >
                     <span style={{ width: this.layoutDoc._singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
-                        {label.startsWith("#") ? (null) : label.replace(/([\.\-&])/g, "$1 ")}
+                        {label.startsWith("#") ? (null) : label.replace(/([^a-zA-Z])/g, "$1\u200b")}
                     </span>
                 </div>
                 <div className="labelBox-fieldKeyParams" >
-- 
cgit v1.2.3-70-g09d2


From 58114c03252463b7386d16fc2aef61c361038bfa Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Jun 2022 15:44:23 -0400
Subject: fixed previously introduced bug where pin doc added pres to first tab
 collection.  Highlight pres targets when following.  fixed videoBox to play
 regions properly.  adjusted labelBox for stackedTimeline views.  fixed
 stacked timelines to not stop keyboard events which was preventing text notes
 from being created on video boxes.

---
 src/Utils.ts                                         |  2 +-
 .../views/collections/CollectionStackedTimeline.tsx  |  9 +++++++--
 src/client/views/collections/TabDocView.tsx          |  4 +---
 src/client/views/nodes/LabelBox.tsx                  | 20 +++++++++++---------
 src/client/views/nodes/VideoBox.tsx                  |  2 ++
 src/client/views/nodes/trails/PresBox.tsx            |  1 +
 src/fields/Doc.ts                                    |  4 ++--
 src/fields/List.ts                                   |  1 +
 8 files changed, 26 insertions(+), 17 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index dbae0aa8c..e6aa0ad8b 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -209,7 +209,7 @@ export namespace Utils {
         if (scrollTop + contextHgt < Math.min(scrollHeight, targetY + minSpacing + targetHgt)) {
             return Math.ceil(targetY + minSpacing + targetHgt - contextHgt);
         }
-        if (scrollTop > Math.max(0, targetY - minSpacing - targetHgt)) {
+        if (scrollTop >= Math.max(0, targetY - minSpacing - targetHgt)) {
             return Math.max(0, Math.floor(targetY - minSpacing - targetHgt));
         }
     }
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 02b2248fb..5a1cc4ded 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -22,6 +22,7 @@ import {
     returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent
 } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager } from "../../util/DragManager";
 import { LinkManager } from "../../util/LinkManager";
@@ -182,7 +183,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         ) {
             // if shift pressed scrub 1 second otherwise 1/10th
             const jump = e.shiftKey ? 1 : 0.1;
-            e.stopPropagation();
             switch (e.key) {
                 case " ":
                     if (!CollectionStackedTimeline.SelectingRegion) {
@@ -202,18 +202,22 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                         this._markerEnd = undefined;
                         CollectionStackedTimeline.SelectingRegion = undefined;
                     }
+                    e.stopPropagation();
                     break;
                 case "Escape":
                     // abandons current trim
                     this._trimStart = this.clipStart;
                     this._trimStart = this.clipEnd;
                     this._trimming = TrimScope.None;
+                    e.stopPropagation();
                     break;
                 case "ArrowLeft":
                     this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime - jump), this.clipEnd));
+                    e.stopPropagation();
                     break;
                 case "ArrowRight":
                     this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime + jump), this.clipEnd));
+                    e.stopPropagation();
                     break;
             }
         }
@@ -788,6 +792,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
 
     // updates marker document title to reflect correct timecodes
     computeTitle = () => {
+        if (this.props.mark.type !== DocumentType.LABEL) return undefined;
         const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart;
         const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart;
         return `#${formatTime(start)}-${formatTime(end)}`;
@@ -921,7 +926,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     DataDoc={undefined}
                     renderDepth={this.props.renderDepth + 1}
                     LayoutTemplate={undefined}
-                    LayoutTemplateString={LabelBox.LayoutStringWithTitle(LabelBox, "data", this.computeTitle())}
+                    LayoutTemplateString={LabelBox.LayoutStringWithTitle("data", this.computeTitle())}
                     isDocumentActive={this.props.isDocumentActive}
                     PanelWidth={width}
                     PanelHeight={height}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2b78b20ea..be68e1001 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -236,9 +236,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             const dview = CollectionDockingView.Instance.props.Document;
             const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const sublists = DocListCast(dview[fieldKey]);
-            const tabs = Cast(sublists[0], Doc, null);
-            const tabdocs = await DocListCastAsync(tabs?.data);
+            const tabdocs = await DocListCastAsync(dview[fieldKey]);
             runInAction(() => {
                 if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
                     tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index d0d61fd79..b0b050cea 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -23,8 +23,8 @@ export interface LabelBoxProps {
 @observer
 export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); }
-    public static LayoutStringWithTitle(fieldType: { name: string }, fieldStr: string, label: string) {
-        return `<${fieldType.name} fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
+    public static LayoutStringWithTitle(fieldStr: string, label?: string) {
+        return !label ? LabelBox.LayoutString(fieldStr) : `<LabelBox fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
     }
     private dropDisposer?: DragManager.DragDropDisposer;
     private _timeout: any;
@@ -79,17 +79,18 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
     @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; }
 
     fitTextToBox = (r: any): any => {
+        const singleLine = BoolCast(this.rootDoc._singleLine, true);
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.rootDoc._minFontSize, 2),
+            minimumFontSize: NumCast(this.rootDoc._minFontSize, 8),
             maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
             limitingDimension: "both",
             horizontalAlign: "center",
             verticalAlign: "center",
             textAlign: "center",
-            singleLine: BoolCast(this.rootDoc._singleLine),
-            whiteSpace: this.rootDoc._singleLine ? "nowrap" : "pre-wrap"
+            singleLine,
+            whiteSpace: singleLine ? "nowrap" : "pre-wrap"
         };
         this._timeout = undefined;
         if (!r) return params;
@@ -99,15 +100,16 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
         parentStyle.display = "";
         parentStyle.alignItems = "";
         r.setAttribute("style", "");
-        r.style.width = this.rootDoc._singleLine ? "" : "100%";
+        r.style.width = singleLine ? "" : "100%";
 
         r.style.textOverflow = "ellipsis";
         r.style.overflow = "hidden";
         BigText(r, params);
+        return params;
     }
     // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
     render() {
-        this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes
+        const boxParams = this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes
         const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
         const missingParams = params?.filter(p => !this.paramsDoc[p]);
         params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
@@ -130,9 +132,9 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     paddingBottom: NumCast(this.rootDoc._yPadding),
                     width: this.props.PanelWidth(),
                     height: this.props.PanelHeight(),
-                    whiteSpace: this.rootDoc._singleLine ? "pre" : "pre-wrap"
+                    whiteSpace: boxParams.singleLine ? "pre" : "pre-wrap"
                 }} >
-                    <span style={{ width: this.layoutDoc._singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
+                    <span style={{ width: boxParams.singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
                         {label.startsWith("#") ? (null) : label.replace(/([^a-zA-Z])/g, "$1\u200b")}
                     </span>
                 </div>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index c350e3139..ac848fc2a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -147,6 +147,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // plays video
     @action public Play = (update: boolean = true) => {
+        if (this._playRegionTimer) return;
         this._playing = true;
         const eleTime = this.player?.currentTime || 0;
         if (this.timeline) {
@@ -558,6 +559,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         // removes from currently playing if playback has reached end of range marker
                         else this.removeCurrentlyPlaying();
                         this.Pause();
+                        this._playRegionTimer = undefined;
                     }, playRegionDuration * 1000);
             } else {
                 this.Pause();
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 9641b403f..077db9077 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -297,6 +297,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 this.startTempMedia(targetDoc, activeItem);
             }
             if (targetDoc) {
+                Doc.linkFollowHighlight((targetDoc.annotationOn instanceof Doc) ? [targetDoc, targetDoc.annotationOn] : targetDoc);
                 targetDoc && runInAction(() => {
                     if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
                     else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b0a45091e..6abc27b23 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1073,9 +1073,9 @@ export namespace Doc {
     }
 
     let _lastDate = 0;
-    export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) {
+    export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true) {
         linkFollowUnhighlight();
-        Doc.HighlightDoc(destDoc, dataAndDisplayDocs);
+        (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs));
         document.removeEventListener("pointerdown", linkFollowUnhighlight);
         document.addEventListener("pointerdown", linkFollowUnhighlight);
         const lastDate = _lastDate = Date.now();
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 60bf442d4..b15548327 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -32,6 +32,7 @@ const listHandlers: any = {
     },
     push: action(function (this: any, ...items: any[]) {
         items = items.map(toObjectField);
+
         const list = this[Self];
         const length = list.__fields.length;
         for (let i = 0; i < items.length; i++) {
-- 
cgit v1.2.3-70-g09d2

