From a2df645d2ffe83be24c20997c26eaf7257e847c0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 2 May 2022 18:09:22 -0400
Subject: fixed scaling  ink label in lightbox,etc views. changed ink strokes
 so that clicking on label of closed stroke is lower preceden than clicking on
 line.  fixed fontsize UI for setting ink label sizes.  can no longer slide
 ink pts that are cusps along curve.

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

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

diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index ca13590de..d3ff2586b 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -656,7 +656,7 @@ ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boo
 ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: boolean) {
     const editorView = RichTextMenu.Instance?.TextView?.EditorView;
     if (checkResult) {
-        return (editorView ? RichTextMenu.Instance.fontSize : StrCast(Doc.UserDoc().fontSize, "10px")).replace("px", "");
+        return RichTextMenu.Instance.fontSize.replace("px", "");
     }
     if (typeof size === "number") size = size.toString();
     if (size && Number(size).toString() === size) size += "px";
-- 
cgit v1.2.3-70-g09d2


From 5dd7905530dbfbac3318e55fc625fe46427e23c4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 20 May 2022 13:45:21 -0400
Subject: adjusted placement of fonticonbox labels

---
 src/client/util/CurrentUserUtils.ts            | 64 ++++++++++++--------------
 src/client/views/MainView.tsx                  |  2 +-
 src/client/views/nodes/button/FontIconBox.scss |  8 ++--
 src/client/views/nodes/button/FontIconBox.tsx  | 23 +++++----
 4 files changed, 51 insertions(+), 46 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index e0580d3c4..b9d2d63ba 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -181,21 +181,22 @@ export class CurrentUserUtils {
             "icon-nativeWidth": 360 / 4, "icon-nativeHeight": 270 / 4, _width: 360 / 4, _height: 270 / 4,
             _showTitle: "title", system: true, onClick: deiconifyScript(), ...extra
         });
-        const newIconsList = [
-            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", {})),
-            makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})),
-            makeIconTemplate(DocumentType.BUTTON, "data", () => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() })),
-            // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {}))
-        ].filter(d => d).map(d => d!);
         if (!templateIconsDoc) {
+            const newIconsList = [
+                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", {})),
+                makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})),
+                makeIconTemplate(DocumentType.BUTTON, "data", () => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() })),
+                // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {}))
+            ].filter(d => d).map(d => d!);
+
             doc["template-icons"] = Docs.Create.TreeDocument(newIconsList, { title: "icon templates", _height: 75, system: true });
-            newIconsList.map(d => (doc["template-icons"] as Doc)[StrCast(d.title)] = new PrefetchProxy(d));
+            newIconsList.forEach(d => (doc["template-icons"] as Doc)[StrCast(d.title)] = new PrefetchProxy(d));
         }
     }
 
@@ -224,7 +225,6 @@ export class CurrentUserUtils {
                 backgroundColor: "white", system: true, cloneFieldFilter: new List<string>(["system"])
             });
             Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text');
-            FormattedTextBox.SelectOnLoad = textDoc[Id];
             doc.emptySlide = textDoc;
         }
         if ((doc.emptyHeader as Doc)?.version !== headerViewVersion) {
@@ -287,11 +287,7 @@ export class CurrentUserUtils {
             ((doc.emptyAudio as Doc).proto as Doc)["dragFactory-count"] = 0;
         }
         if (doc.emptyNote === undefined) {
-            doc.emptyNote = Docs.Create.TextDocument("", {
-                _width: 200, title: "text note", _autoHeight: true, system: true,
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-                cloneFieldFilter: new List<string>(["system"])
-            });
+            doc.emptyNote = Docs.Create.TextDocument("", { _width: 200, title: "text note", _autoHeight: true, system: true, cloneFieldFilter: new List<string>(["system"]) });
             ((doc.emptyNote as Doc).proto as Doc)["dragFactory-count"] = 0;
         }
         if (doc.emptyImage === undefined) {
@@ -790,20 +786,20 @@ export class CurrentUserUtils {
                         "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"],
                     script: 'setFont(value, _readOnly_)'
                 },
-                { title: "Font size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, script: 'setFontSize(value, _readOnly_)' },
-                { title: "Font color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, script: 'setFontColor(value, _readOnly_)' },
+                { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, script: 'setFontSize(value, _readOnly_)' },
+                { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, script: 'setFontColor(value, _readOnly_)' },
                 { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", click: 'toggleBold(_readOnly_)' },
                 { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", click: 'toggleItalic(_readOnly_)' },
-                { title: "Underline", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", click: 'toggleUnderline(_readOnly_)' },
-                { title: "Bullet List", toolTip: "Bullet", btnType: ButtonType.ToggleButton, icon: "list", click: 'setBulletList("bullet", _readOnly_)' },
-                { title: "Number List", toolTip: "Number", btnType: ButtonType.ToggleButton, icon: "list-ol", click: 'setBulletList("decimal", _readOnly_)' },
+                { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", click: 'toggleUnderline(_readOnly_)' },
+                { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", click: 'setBulletList("bullet", _readOnly_)' },
+                { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", click: 'setBulletList("decimal", _readOnly_)' },
 
                 // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", click: 'toggleStrikethrough()'},
                 // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", click: 'toggleSuperscript()'},
                 // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", click: 'toggleSubscript()'},
-                { title: "Left align", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' },
-                { title: "Center align", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' },
-                { title: "Right align", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' },
+                { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' },
+                { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' },
+                { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' },
             ];
         return tools;
     }
@@ -816,9 +812,9 @@ export class CurrentUserUtils {
             { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' },
             // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveInkTool("square")' },
             { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", click: 'setActiveInkTool("line", _readOnly_)' },
-            { title: "Fill color", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setFillColor(value, _readOnly_)" },
-            { title: "Stroke width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, script: 'setStrokeWidth(value, _readOnly_)' },
-            { title: "Stroke color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, script: 'setStrokeColor(value, _readOnly_)' },
+            { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setFillColor(value, _readOnly_)" },
+            { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, script: 'setStrokeWidth(value, _readOnly_)' },
+            { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, script: 'setStrokeColor(value, _readOnly_)' },
         ];
         return tools;
     }
@@ -862,19 +858,19 @@ export class CurrentUserUtils {
                 script: 'setView(value, _readOnly_)',
             }, // Always show
             {
-                title: "back", toolTip: "prev", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame()', icon: "chevron-left",
+                title: "Back", toolTip: "Prev AnimationFrame", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame()', icon: "chevron-left",
                 hidden: 'IsNoviceMode()'
             },
             {
-                title: "Forward", toolTip: "next", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame()', icon: "chevron-right",
+                title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame()', icon: "chevron-right",
                 hidden: 'IsNoviceMode()'
             },
             {
-                title: "Background Color", toolTip: "Background Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip",
+                title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip",
                 script: "setBackgroundColor(value, _readOnly_)", hidden: 'selectedDocumentType()'
             }, // Only when a document is selected
             {
-                title: "Header Color", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading",
+                title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading",
                 script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()',
             }, // Only when a document is selected
             { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", backgroundColor: 'toggleOverlay(true)', click: 'toggleOverlay()', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 9be00fa9e..45dd84e31 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -173,7 +173,7 @@ export class MainView extends React.Component {
         fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt,
         fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
         fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote, fa.faArrowsAltV,
-        fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes,
+        fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes, fa.faFlag,
         fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
         fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
         fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any,
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
index e3e2be515..df9046f12 100644
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ b/src/client/views/nodes/button/FontIconBox.scss
@@ -64,7 +64,7 @@
         justify-items: center;
 
         &:hover {
-            filter:brightness(0.85) !important;
+            filter: brightness(0.85) !important;
         }
     }
 
@@ -166,8 +166,8 @@
             width: 45% !important;
             height: 45%;
         }
-        
-        &:hover{
+
+        &:hover {
             filter: brightness(0.85);
         }
     }
@@ -278,10 +278,12 @@
                 background-color: #e3e3e3;
                 box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
                 border-radius: $standard-border-radius;
+
                 input[type=range]::-webkit-slider-runnable-track {
                     background: gray;
                     height: 3px;
                 }
+
                 input[type=range]::-webkit-slider-thumb {
                     box-shadow: 1px 1px 1px #000000;
                     border: 1px solid #000000;
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index d3ff2586b..20b2be216 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -107,6 +107,11 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         // Script for checking the outcome of the toggle
         const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0;
 
+        const label = !Doc.UserDoc()._showLabel ? (null) :
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, position: "absolute" }}>
+                {this.label}
+            </div>;
+
         if (numBtnType === NumButtonType.Slider) {
             const dropdown =
                 <div
@@ -126,6 +131,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                     onClick={action(() => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen)}
                 >
                     {checkResult}
+                    {label}
                     {this.rootDoc.dropDownOpen ? dropdown : null}
                 </div>
             );
@@ -206,7 +212,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
                 onClick={action(() => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen)}>
                 <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
-                {!this.label || !Doc.UserDoc()._showLabel ? (null) : <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
+                {!this.label || !Doc.UserDoc()._showLabel ? (null) : <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
                 <div
                     className="menuButton-dropdown"
                     style={{ borderBottomRightRadius: this.dropdown ? 0 : undefined }}>
@@ -277,7 +283,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         });
 
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color: color, backgroundColor: backgroundColor, position: "absolute" }}>
                 {this.label}
             </div>;
 
@@ -331,7 +337,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const curColor = this.colorScript?.script.run({ value: undefined, _readOnly_: true }).result ?? "transparent";
 
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
                 {this.label}
             </div>;
 
@@ -375,7 +381,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
         // Button label
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
                 {this.label}
             </div>;
 
@@ -387,7 +393,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                         <input type="checkbox"
                             checked={backgroundColor === Colors.MEDIUM_BLUE}
                         />
-                        <span className="slider round"></span>
+                        <span className="slider round" />
                     </label>
                 </div>
             );
@@ -416,7 +422,8 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 style={{ backgroundColor: "transparent", borderBottomLeftRadius: this.dropdown ? 0 : undefined }}>
                 <div className="menuButton-wrap">
                     <FontAwesomeIcon className={`menuButton-icon-${this.type}`} icon={this.icon} color={"black"} size={"sm"} />
-                    {!this.label || !Doc.UserDoc()._showLabel ? (null) : <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
+                    {!this.label || !Doc.UserDoc()._showLabel ? (null) :
+                        <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
                 </div>
             </div>
         );
@@ -443,12 +450,12 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
         const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
                 {this.label}
             </div>;
 
         const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) :
-            <div className="fontIconBox-label" style={{ color, backgroundColor: "transparent" }}>
+            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color, backgroundColor: "transparent" }}>
                 {this.label}
             </div>;
 
-- 
cgit v1.2.3-70-g09d2


From 366cd5f3799a78c297c9a0dc31eb0bd8c0e4c4bd Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 20 May 2022 16:35:24 -0400
Subject: some cleanup of currentUserUtils.  css fixes for fonticon boxes with
 labels

---
 src/client/util/CurrentUserUtils.ts                | 288 +++++++--------------
 .../collectionLinear/CollectionLinearView.tsx      |   2 +-
 src/client/views/nodes/button/FontIconBox.scss     |  44 +++-
 src/client/views/nodes/button/FontIconBox.tsx      |  44 ++--
 4 files changed, 146 insertions(+), 232 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b9d2d63ba..b9789ab7f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -6,7 +6,6 @@ import { InkTool } from "../../fields/InkField";
 import { List } from "../../fields/List";
 import { PrefetchProxy } from "../../fields/Proxy";
 import { RichTextField } from "../../fields/RichTextField";
-import { listSpec } from "../../fields/Schema";
 import { ComputedField, ScriptField } from "../../fields/ScriptField";
 import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
 import { nullAudio } from "../../fields/URLField";
@@ -23,7 +22,6 @@ import { Colors } from "../views/global/globalEnums";
 import { MainView } from "../views/MainView";
 import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox";
 import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView";
-import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
 import { OverlayView } from "../views/OverlayView";
 import { DocumentManager } from "./DocumentManager";
 import { DragManager } from "./DragManager";
@@ -53,6 +51,7 @@ interface Button {
     list?: string[];
     ignoreClick?: boolean;
     buttonText?: string;
+    hidden?: string;
 }
 
 export let resolvedPorts: { server: number, socket: number };
@@ -62,7 +61,6 @@ export class CurrentUserUtils {
     //TODO tfs: these should be temporary...
     private static mainDocId: string | undefined;
 
-    public static searchBtn: Doc;
     public static get id() { return this.curr_id; }
     public static get MainDocId() { return this.mainDocId; }
     public static set MainDocId(id: string | undefined) { this.mainDocId = id; }
@@ -196,7 +194,6 @@ export class CurrentUserUtils {
             ].filter(d => d).map(d => d!);
 
             doc["template-icons"] = Docs.Create.TreeDocument(newIconsList, { title: "icon templates", _height: 75, system: true });
-            newIconsList.forEach(d => (doc["template-icons"] as Doc)[StrCast(d.title)] = new PrefetchProxy(d));
         }
     }
 
@@ -329,15 +326,11 @@ export class CurrentUserUtils {
     }
 
     // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
-    static async setupCreatorButtons(doc: Doc) {
+    static setupCreatorButtons(doc: Doc) {
         let alreadyCreatedButtons: string[] = [];
         const dragCreatorSet = Cast(doc.myItemCreators, Doc, null);
         if (dragCreatorSet) {
-            const dragCreators = Cast(dragCreatorSet.data, listSpec(Doc));
-            if (dragCreators) {
-                const dragDocs = await Promise.all(Array.from(dragCreators));
-                alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title));
-            }
+            alreadyCreatedButtons = DocListCast(dragCreatorSet.data).map(d => StrCast(d.title));
         }
         const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title));
         const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({
@@ -373,7 +366,7 @@ export class CurrentUserUtils {
         return doc.myItemCreators as Doc;
     }
 
-    static async menuBtnDescriptions(doc: Doc) {
+    static menuBtnDescriptions(doc: Doc) {
         return [
             { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' },
             { title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' },
@@ -390,7 +383,7 @@ export class CurrentUserUtils {
     static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
         if (doc.menuStack === undefined) {
             await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId);  // sets up the right sidebar collection for mobile upload documents and sharing
-            const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments, hidden }) =>
+            const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, watchedDocuments, hidden }) =>
                 Docs.Create.FontIconDocument({
                     icon,
                     btnType: ButtonType.MenuButton,
@@ -411,17 +404,7 @@ export class CurrentUserUtils {
                 })
             );
 
-            menuBtns.forEach(menuBtn => {
-                if (menuBtn.title === "Search") {
-                    this.searchBtn = menuBtn;
-                }
-            });
-
-            menuBtns.forEach(menuBtn => {
-                if (menuBtn.title === "Search") {
-                    doc.searchBtn = menuBtn;
-                }
-            });
+            doc.searchBtn = menuBtns.find(btn => btn.title === "Search");
 
             doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, {
                 title: "menuItemPanel",
@@ -436,19 +419,6 @@ export class CurrentUserUtils {
                 _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true
             }));
         }
-        // this resets all sidebar buttons to being deactivated
-        PromiseValue(Cast(doc.menuStack, Doc)).then(stack => {
-            stack && PromiseValue(stack.data).then(btns => {
-                DocListCastAsync(btns).then(bts => bts?.forEach(btn => {
-                    btn.dontUndo = true;
-                    btn.system = true;
-                    if (btn.title === "Catalog" || btn.title === "My Files") { // migration from Catalog to My Files
-                        btn.target = Doc.UserDoc().myFilesystem;
-                        btn.title = "My Files";
-                    }
-                }));
-            });
-        });
         return doc.menuStack as Doc;
     }
 
@@ -578,35 +548,26 @@ export class CurrentUserUtils {
 
     // setup the Creator button which will display the creator panel.  This panel will include the drag creators and the color picker.
     // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
-    static async setupToolsBtnPanel(doc: Doc) {
+    static setupToolsBtnPanel(doc: Doc) {
         // setup a masonry view of all he creators
-        const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
+        const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc);
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc);
 
-        doc["tabs-button-tools"] = undefined;
-
-        if (doc.myCreators === undefined) {
-            doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
-                title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, _fitWidth: true,
-                _width: 500, _height: 300, ignoreClick: true, _lockedPosition: true, system: true, _chromeHidden: true,
-            }));
-        }
-        // setup a color picker
-        if (doc.myColorPicker === undefined) {
-            const color = Docs.Create.ColorDocument({
-                title: "color picker", _width: 220, _dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, _forceActive: true, _removeDropProperties: new List<string>(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true
-            });
-            doc.myColorPicker = new PrefetchProxy(color);
-        }
+        doc.myCreators = doc.myCreators ?? new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
+            title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, _fitWidth: true,
+            _width: 500, _height: 300, ignoreClick: true, _lockedPosition: true, system: true, _chromeHidden: true,
+        }));
+        if (!DocListCast(doc.myCreators).includes(creatorBtns as Doc) || !DocListCast(doc.myCreators).includes(templateBtns as Doc)) Doc.GetProto(doc.myCreators as Doc).data = new List<Doc>([creatorBtns, templateBtns]);
 
-        if (doc.myTools === undefined) {
-            const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc], {
-                title: "My Tools", _showTitle: "title", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true,
-                system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0",
-            })) as any as Doc;
+        doc.myColorPicker = doc.myColorPicker ?? new PrefetchProxy(Docs.Create.ColorDocument({
+            title: "color picker", _width: 220, _dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, _forceActive: true, _removeDropProperties: new List<string>(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true
+        }));
 
-            doc.myTools = toolsStack;
-        }
+        doc.myTools = doc.myTools ?? new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc], {
+            title: "My Tools", _showTitle: "title", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true,
+            system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0",
+        })) as any as Doc;
+        if (!DocListCast(doc.myTools).includes(doc.myCreators as Doc)) Doc.GetProto(doc.myTools as Doc).data = new List<Doc>([doc.myCreators as Doc]);
     }
 
     static async setupDashboards(doc: Doc) {
@@ -639,8 +600,7 @@ export class CurrentUserUtils {
         return doc.myDashboards as any as Doc;
     }
 
-    static async setupPresentations(doc: Doc) {
-        await doc.myTrails;
+    static setupPresentations(doc: Doc) {
         if (doc.myTrails === undefined) {
             const newTrail = ScriptField.MakeScript(`createNewPresentation()`);
             const newTrailButton: Doc = Docs.Create.FontIconDocument({ onClick: newTrail, _forceActive: true, toolTip: "Create new trail", _stayInCollection: true, _hideContextMenu: true, title: "New trail", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true });
@@ -743,7 +703,7 @@ export class CurrentUserUtils {
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
     static async setupSidebarButtons(doc: Doc) {
         CurrentUserUtils.setupSidebarContainer(doc);
-        await CurrentUserUtils.setupToolsBtnPanel(doc);
+        CurrentUserUtils.setupToolsBtnPanel(doc);
         CurrentUserUtils.setupImportSidebar(doc);
         CurrentUserUtils.setupDashboards(doc);
         CurrentUserUtils.setupPresentations(doc);
@@ -764,17 +724,26 @@ export class CurrentUserUtils {
 
     /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
     static setupDockedButtons(doc: Doc) {
-        if (doc["dockedBtn-undo"] === undefined) {
-            doc["dockedBtn-undo"] = CurrentUserUtils.createToolButton({ onClick: ScriptField.MakeScript("undo()"), _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo", title: "undo", icon: "undo-alt", system: true });
-        }
-        if (doc["dockedBtn-redo"] === undefined) {
-            doc["dockedBtn-redo"] = CurrentUserUtils.createToolButton({ onClick: ScriptField.MakeScript("redo()"), _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo", title: "redo", icon: "redo-alt", system: true });
-        }
         if (doc.dockedBtns === undefined) {
-            doc.dockedBtns = CurrentUserUtils.linearButtonList({ title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
+            if (doc["dockedBtn-undo"] === undefined) {
+                doc["dockedBtn-undo"] = CurrentUserUtils.createToolButton({
+                    title: "undo", icon: "undo-alt", _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, system: true,
+                    onClick: ScriptField.MakeScript("undo()"), btnType: ButtonType.ToolButton, _dropAction: "alias",
+                    _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo"
+                });
+            }
+            if (doc["dockedBtn-redo"] === undefined) {
+                doc["dockedBtn-redo"] = CurrentUserUtils.createToolButton({
+                    title: "redo", icon: "redo-alt", _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, system: true,
+                    onClick: ScriptField.MakeScript("redo()"), btnType: ButtonType.ToolButton, _dropAction: "alias",
+                    _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo",
+                });
+            }
+            doc.dockedBtns = CurrentUserUtils.linearButtonList({
+                title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true,
+                linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
+            }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
         }
-        (doc["dockedBtn-undo"] as Doc).dontUndo = true;
-        (doc["dockedBtn-redo"] as Doc).dontUndo = true;
     }
 
     static textTools(doc: Doc) {
@@ -821,16 +790,7 @@ export class CurrentUserUtils {
 
     static schemaTools(doc: Doc) {
         const tools: Button[] =
-            [
-                {
-                    title: "Show preview",
-                    toolTip: "Show preview of selected document",
-                    btnType: ButtonType.ToggleButton,
-                    buttonText: "Show Preview",
-                    icon: "eye",
-                    click: 'toggleSchemaPreview(_readOnly_)',
-                },
-            ];
+            [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", click: 'toggleSchemaPreview(_readOnly_)', }];
         return tools;
     }
 
@@ -846,7 +806,7 @@ export class CurrentUserUtils {
         return tools;
     }
 
-    static async contextMenuTools(doc: Doc) {
+    static contextMenuTools(doc: Doc) {
         return [
             {
                 title: "Perspective", toolTip: "View", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true,
@@ -857,128 +817,52 @@ export class CurrentUserUtils {
                 CollectionViewType.Grid],
                 script: 'setView(value, _readOnly_)',
             }, // Always show
-            {
-                title: "Back", toolTip: "Prev AnimationFrame", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame()', icon: "chevron-left",
-                hidden: 'IsNoviceMode()'
-            },
-            {
-                title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame()', icon: "chevron-right",
-                hidden: 'IsNoviceMode()'
-            },
-            {
-                title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip",
-                script: "setBackgroundColor(value, _readOnly_)", hidden: 'selectedDocumentType()'
-            }, // Only when a document is selected
-            {
-                title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading",
-                script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()',
-            }, // Only when a document is selected
-            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", backgroundColor: 'toggleOverlay(true)', click: 'toggleOverlay()', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform
+            { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame(_readOnly_)', icon: "chevron-left", hidden: 'IsNoviceMode()' },
+            { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame(_readOnly_)', icon: "chevron-right", hidden: 'IsNoviceMode()' },
+            { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setBackgroundColor(value, _readOnly_)", hidden: 'selectedDocumentType()' }, // Only when a document is selected
+            { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()', },
+            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay(_readOnly_)', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform
             // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected 
-            { title: "Text", type: "textTools", subMenu: true, expanded: 'selectedDocumentType("rtf")' }, // Always available
-            { title: "Ink", type: "inkTools", subMenu: true, expanded: 'selectedDocumentType("ink")' }, // Always available
-            { title: "Web", type: "webTools", subMenu: true, hidden: 'selectedDocumentType("web")' }, // Only when Web is selected
-            { title: "Schema", type: "schemaTools", subMenu: true, hidden: 'selectedDocumentType(undefined, "schema")' } // Only when Schema is selected
+            { title: "Text", type: "textTools", subMenu: CurrentUserUtils.textTools(doc), expanded: 'selectedDocumentType("rtf")' }, // Always available
+            { title: "Ink", type: "inkTools", subMenu: CurrentUserUtils.inkTools(doc), expanded: 'selectedDocumentType("ink")' }, // Always available
+            { title: "Web", type: "webTools", subMenu: CurrentUserUtils.webTools(doc), hidden: 'selectedDocumentType("web")' }, // Only when Web is selected
+            { title: "Schema", type: "schemaTools", subMenu: CurrentUserUtils.schemaTools(doc), hidden: 'selectedDocumentType(undefined, "schema")' } // Only when Schema is selected
         ];
     }
 
     // Sets up the default context menu buttons
-    static async setupContextMenuButtons(doc: Doc) {
+    static setupContextMenuButtons(doc: Doc) {
+        const btnFunc = (params: Button) => Docs.Create.FontIconDocument({
+            title: params.title, icon: params.icon, toolTip: params.toolTip, color: Colors.WHITE, system: true, dontUndo: true, ignoreClick: params.ignoreClick,
+            _nativeWidth: params.width ? params.width : 30,
+            _nativeHeight: 30,
+            _width: params.width ? params.width : 30,
+            _height: 30,
+            btnType: params.btnType,
+            numBtnType: params.numBtnType, numBtnMin: params.numBtnMin, numBtnMax: params.numBtnMax,
+            btnList: new List<string>(params.list),
+            _stayInCollection: true,
+            _hideContextMenu: true,
+            _lockedPosition: true,
+            _dropAction: "alias",
+            _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
+            script: params.script ? ScriptField.MakeScript(params.script, { value: "any" }) : undefined,
+            backgroundColor: params.click ? ComputedField.MakeFunction(params.click) as any : "transparent",
+            onClick: params.click ? ScriptField.MakeScript(params.click, { scriptContext: "any" }, { _readOnly_: false }) : undefined,
+            hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined,
+        });
         if (doc.contextMenuBtns === undefined) {
-            const docList: Doc[] = [];
-
-            (await CurrentUserUtils.contextMenuTools(doc)).map(({ title, width, list, toolTip, backgroundColor, ignoreClick, icon, type, btnType, click, script, subMenu, hidden, expanded }) => {
-                const menuDocList: Doc[] = [];
-                if (subMenu) {
-                    // default is textTools
-                    let tools: Button[];
-                    switch (type) {
-                        case "inkTools":
-                            tools = CurrentUserUtils.inkTools(doc);
-                            break;
-                        case "schemaTools":
-                            tools = CurrentUserUtils.schemaTools(doc);
-                            break;
-                        case "webTools":
-                            tools = CurrentUserUtils.webTools(doc);
-                            break;
-                        case "textTools":
-                            tools = CurrentUserUtils.textTools(doc);
-                            break;
-                        default:
-                            tools = CurrentUserUtils.textTools(doc);
-                            break;
-                    }
-                    tools.map(({ title, toolTip, icon, btnType, numBtnType, numBtnMax, numBtnMin, click, script, width, list, ignoreClick, switchToggle }) => {
-                        const backgroundColor = click ? ComputedField.MakeFunction(click) as any : "transparent";
-                        menuDocList.push(Docs.Create.FontIconDocument({
-                            _nativeWidth: width ? width : 25,
-                            _nativeHeight: 25,
-                            _width: width ? width : 25,
-                            _height: 25,
-                            icon,
-                            toolTip,
-                            numBtnType,
-                            numBtnMin,
-                            numBtnMax,
-                            script: script ? ScriptField.MakeScript(script, { value: "any" }) : undefined,
-                            btnType: btnType,
-                            btnList: new List<string>(list),
-                            ignoreClick: ignoreClick,
-                            _stayInCollection: true,
-                            _hideContextMenu: true,
-                            _lockedPosition: true,
-                            system: true,
-                            dontUndo: true,
-                            title,
-                            switchToggle,
-                            color: Colors.WHITE,
-                            backgroundColor,
-                            _dropAction: "alias",
-                            _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
-                            onClick: click ? ScriptField.MakeScript(click) : undefined
-                        }));
-                    });
-                    docList.push(CurrentUserUtils.linearButtonList({
-                        linearViewSubMenu: true,
-                        flexGap: 0,
-                        ignoreClick: true,
-                        linearViewExpandable: true,
-                        icon: title,
-                        _height: 30,
-                        // backgroundColor: hidden ? ComputedField.MakeFunction(hidden, {  }, { _readOnly_: true }) as any : "transparent",
-                        linearViewIsExpanded: expanded ? !(ComputedField.MakeFunction(expanded) as any) : undefined,
-                        hidden: hidden ? ComputedField.MakeFunction(hidden) as any : undefined,
-                    }, menuDocList));
-                } else {
-                    docList.push(Docs.Create.FontIconDocument({
-                        _nativeWidth: width ? width : 25,
-                        _nativeHeight: 25,
-                        _width: width ? width : 25,
-                        _height: 25,
-                        icon,
-                        toolTip,
-                        script: script ? ScriptField.MakeScript(script, { value: "any" }) : undefined,
-                        btnType,
-                        btnList: new List<string>(list),
-                        ignoreClick,
-                        _stayInCollection: true,
-                        _hideContextMenu: true,
-                        _lockedPosition: true,
-                        system: true,
-                        dontUndo: true,
-                        title,
-                        color: Colors.WHITE,
-                        backgroundColor: backgroundColor ? ComputedField.MakeFunction(backgroundColor) as any : "transparent",
-                        _dropAction: "alias",
-                        hidden: hidden ? ComputedField.MakeFunction(hidden) as any : undefined,
-                        _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
-                        onClick: click ? ScriptField.MakeScript(click, { scriptContext: "any" }, { _readOnly_: false }) : undefined
-                    }));
-                }
-            });
-
-            doc.contextMenuBtns = CurrentUserUtils.linearButtonList({ title: "menu buttons", flexGap: 0, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }, docList);
+            doc.contextMenuBtns = CurrentUserUtils.linearButtonList(
+                { title: "menu buttons", flexGap: 0, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 },
+                CurrentUserUtils.contextMenuTools(doc).map(params =>
+                    !params.subMenu ?
+                        btnFunc(params) :
+                        CurrentUserUtils.linearButtonList({
+                            linearViewSubMenu: true, flexGap: 0, ignoreClick: true,
+                            linearViewExpandable: true, icon: params.title, _height: 30,
+                            linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined,
+                            hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined,
+                        }, params.subMenu.map(subParams => btnFunc(subParams)))));
         }
     }
 
@@ -1463,7 +1347,8 @@ ScriptingGlobals.add(function makeTopLevelFolder() {
 ScriptingGlobals.add(function toggleComicMode() {
     Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic";
 });
-ScriptingGlobals.add(function nextKeyFrame() {
+ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) {
+    if (readOnly) return;
     const sel = SelectionManager.Views()[0];
     const col = (sel.ComponentView as CollectionFreeFormView);
     const currentFrame = Cast(sel.props.Document._currentFrame, "number", null);
@@ -1476,7 +1361,8 @@ ScriptingGlobals.add(function nextKeyFrame() {
     sel.rootDoc.lastFrame = Math.max(NumCast(sel.rootDoc._currentFrame), NumCast(sel.rootDoc.lastFrame));
 }
 );
-ScriptingGlobals.add(function prevKeyFrame() {
+ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) {
+    if (readOnly) return;
     const sel = SelectionManager.Views()[0];
     const col = (sel.ComponentView as CollectionFreeFormView);
     const currentFrame = Cast(sel.props.Document._currentFrame, "number", null);
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index bec582dcd..c0a33a5e0 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -151,7 +151,7 @@ export class CollectionLinearView extends CollectionSubView() {
                 removeDocument={this.props.removeDocument}
                 ScreenToLocalTransform={docXf}
                 PanelWidth={nested ? doc[WidthSym] : this.dimension}
-                PanelHeight={nested ? doc[HeightSym] : this.dimension}
+                PanelHeight={nested || doc._height ? doc[HeightSym] : this.dimension}
                 renderDepth={this.props.renderDepth + 1}
                 focus={emptyFunction}
                 styleProvider={this.props.styleProvider}
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
index df9046f12..6cd56f84e 100644
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ b/src/client/views/nodes/button/FontIconBox.scss
@@ -18,12 +18,12 @@
 
     .fontIconBox-label {
         color: $white;
-        position: relative;
+        bottom: 0;
+        position: absolute;
         text-align: center;
         font-size: 7px;
         letter-spacing: normal;
         background-color: inherit;
-        margin-top: 5px;
         border-radius: 8px;
         padding: 0;
         width: 100%;
@@ -40,8 +40,10 @@
         height: 80%;
     }
 
-    &.clickBtn {
+    &.clickBtn,
+    &.clickBtnLabel {
         cursor: pointer;
+        flex-direction: column;
 
         &:hover {
             background-color: rgba(0, 0, 0, 0.3) !important;
@@ -53,6 +55,12 @@
         }
     }
 
+    &.clickBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
     &.textBtn {
         display: grid;
         /* grid-row: auto; */
@@ -68,8 +76,10 @@
         }
     }
 
-    &.tglBtn {
+    &.tglBtn,
+    &.tglBtnLabel {
         cursor: pointer;
+        flex-direction: column;
 
         &.switch {
             //TOGGLE
@@ -146,10 +156,19 @@
         }
     }
 
-    &.toolBtn {
+    &.tglBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
+    &.toolBtn,
+    &.toolBtnLabel {
         cursor: pointer;
         width: 100%;
         border-radius: 100%;
+        flex-direction: column;
+        margin-top: -4px;
 
         svg {
             width: 60% !important;
@@ -157,6 +176,12 @@
         }
     }
 
+    &.toolBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
     &.menuBtn {
         cursor: pointer !important;
         border-radius: 0px;
@@ -174,7 +199,8 @@
 
 
 
-    &.colorBtn {
+    &.colorBtn,
+    &.colorBtnLabel {
         color: black;
         cursor: pointer;
         flex-direction: column;
@@ -204,6 +230,12 @@
         }
     }
 
+    &.colorBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
     &.drpdownList {
         width: 100%;
         display: grid;
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 20b2be216..e6d8fe88d 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -108,23 +108,19 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0;
 
         const label = !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, position: "absolute" }}>
+            <div className="fontIconBox-label">
                 {this.label}
             </div>;
 
         if (numBtnType === NumButtonType.Slider) {
-            const dropdown =
-                <div
-                    className="menuButton-dropdownBox"
-                    onPointerDown={e => e.stopPropagation()}
-                >
-                    <input type="range" step="1" min={NumCast(this.rootDoc.numBtnMin, 0)} max={NumCast(this.rootDoc.numBtnMax, 100)} value={checkResult}
-                        className={"menu-slider"} id="slider"
-                        onPointerDown={() => this._batch = UndoManager.StartBatch("presDuration")}
-                        onPointerUp={() => this._batch?.end()}
-                        onChange={e => { e.stopPropagation(); setValue(Number(e.target.value)); }}
-                    />
-                </div>;
+            const dropdown = <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()} >
+                <input type="range" step="1" min={NumCast(this.rootDoc.numBtnMin, 0)} max={NumCast(this.rootDoc.numBtnMax, 100)} value={checkResult}
+                    className={"menu-slider"} id="slider"
+                    onPointerDown={() => this._batch = UndoManager.StartBatch("presDuration")}
+                    onPointerUp={() => this._batch?.end()}
+                    onChange={e => { e.stopPropagation(); setValue(Number(e.target.value)); }}
+                />
+            </div>;
             return (
                 <div
                     className={`menuButton ${this.type} ${numBtnType}`}
@@ -212,7 +208,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
                 onClick={action(() => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen)}>
                 <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
-                {!this.label || !Doc.UserDoc()._showLabel ? (null) : <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
+                {!this.label || !Doc.UserDoc()._showLabel ? (null) : <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
                 <div
                     className="menuButton-dropdown"
                     style={{ borderBottomRightRadius: this.dropdown ? 0 : undefined }}>
@@ -283,7 +279,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         });
 
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color: color, backgroundColor: backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ bottom: 0, position: "absolute", color: color, backgroundColor: backgroundColor }}>
                 {this.label}
             </div>;
 
@@ -337,7 +333,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const curColor = this.colorScript?.script.run({ value: undefined, _readOnly_: true }).result ?? "transparent";
 
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ color, backgroundColor }}>
                 {this.label}
             </div>;
 
@@ -348,7 +344,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         </div>;
         setTimeout(() => this.colorPicker(curColor)); // cause an update to the color picker rendered in MainView
         return (
-            <div className={`menuButton ${this.type} ${this.colorPickerClosed}`}
+            <div className={`menuButton ${this.type + (Doc.UserDoc()._showLabel ? "Label" : "")} ${this.colorPickerClosed}`}
                 style={{ color: color, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
                 onClick={action(() => this.colorPickerClosed = !this.colorPickerClosed)}
                 onPointerDown={e => e.stopPropagation()}>
@@ -381,7 +377,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
         // Button label
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ color, backgroundColor }}>
                 {this.label}
             </div>;
 
@@ -399,7 +395,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
             );
         } else {
             return (
-                <div className={`menuButton ${this.type}`}
+                <div className={`menuButton ${this.type + (Doc.UserDoc()._showLabel ? "Label" : "")}`}
                     style={{ opacity: 1, backgroundColor, color }}>
                     <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
                     {label}
@@ -423,7 +419,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 <div className="menuButton-wrap">
                     <FontAwesomeIcon className={`menuButton-icon-${this.type}`} icon={this.icon} color={"black"} size={"sm"} />
                     {!this.label || !Doc.UserDoc()._showLabel ? (null) :
-                        <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 37 ? -4 : 0, color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
+                        <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {this.label} </div>}
                 </div>
             </div>
         );
@@ -450,12 +446,12 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
         const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
         const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color, backgroundColor, position: "absolute" }}>
+            <div className="fontIconBox-label" style={{ color, backgroundColor }}>
                 {this.label}
             </div>;
 
         const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) :
-            <div className="fontIconBox-label" style={{ bottom: this.props.PanelHeight() < 20 ? -4 : 0, color, backgroundColor: "transparent" }}>
+            <div className="fontIconBox-label" style={{ color, backgroundColor: "transparent" }}>
                 {this.label}
             </div>;
 
@@ -496,7 +492,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 break;
             case ButtonType.ToolButton:
                 button = (
-                    <div className={`menuButton ${this.type}`} style={{ opacity: 1, backgroundColor, color }}>
+                    <div className={`menuButton ${this.type + (Doc.UserDoc()._showLabel ? "Label" : "")}`} style={{ opacity: 1, backgroundColor, color }}>
                         <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
                         {label}
                     </div>
@@ -508,7 +504,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                 break;
             case ButtonType.ClickButton:
                 button = (
-                    <div className={`menuButton ${this.type}`} style={{ color, backgroundColor, opacity: 1 }}>
+                    <div className={`menuButton ${this.type + (Doc.UserDoc()._showLabel ? "Label" : "")}`} style={{ color, backgroundColor, opacity: 1 }}>
                         <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
                         {label}
                     </div>
-- 
cgit v1.2.3-70-g09d2


From 53cae5e2ab9267295a824ff721c119ada5e5dc20 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 31 May 2022 13:03:19 -0400
Subject: added a pop up menu for viewing dashField view collection.  added a
 menu button for turning off autoLinking to text selection.  added ability to
 add button to top contextMenu buttons without blowing away db.

---
 src/client/util/CurrentUserUtils.ts                | 34 +++++++++
 src/client/views/MainView.tsx                      |  2 +
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/button/FontIconBox.tsx      |  8 +++
 .../views/nodes/formattedText/DashFieldView.tsx    | 81 +++++++++++++++++-----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 12 ++--
 .../formattedText/ProsemirrorExampleTransfer.ts    |  2 +
 .../views/nodes/formattedText/RichTextMenu.tsx     | 14 +++-
 .../views/nodes/formattedText/RichTextRules.ts     |  2 +-
 src/client/views/nodes/formattedText/marks_rts.ts  | 14 ++++
 10 files changed, 144 insertions(+), 27 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 083530ce7..c4e2afd08 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -745,6 +745,7 @@ export class CurrentUserUtils {
                 { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' },
                 { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' },
                 { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' },
+                { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", click: 'toggleNoAutoLinkAnchor(_readOnly_)' },
             ];
         return tools;
     }
@@ -834,11 +835,44 @@ export class CurrentUserUtils {
                     !params.subMenu ?
                         btnFunc(params) :
                         CurrentUserUtils.linearButtonList({
+                            title: params.title,
                             linearViewSubMenu: true, flexGap: 0, ignoreClick: true,
                             linearViewExpandable: true, icon: params.title, _height: 30,
                             linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined,
                             hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined,
                         }, params.subMenu.map(btnFunc))));
+        } else {
+            const menuBtnList = DocListCast((doc.contextMenuBtns as Doc).data);
+            let prev = "";
+            CurrentUserUtils.contextMenuTools(doc).forEach(params => {
+                const menuBtnDoc = menuBtnList.find(doc => doc.title === params.title);
+                if (!menuBtnDoc) {
+                    const newMenuBtnDoc = !params.subMenu ?
+                        btnFunc(params) :
+                        CurrentUserUtils.linearButtonList({
+                            title: params.title,
+                            linearViewSubMenu: true, flexGap: 0, ignoreClick: true,
+                            linearViewExpandable: true, icon: params.title, _height: 30,
+                            linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined,
+                            hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined,
+                        }, params.subMenu.map(btnFunc));
+                    const after = menuBtnList.find(doc => doc.title === prev);
+                    Doc.AddDocToList(doc.contextMenuBtns as Doc, "data", newMenuBtnDoc, after, false, !after);
+                }
+                const subMenuBtnList = menuBtnDoc?.data ? DocListCast(menuBtnDoc.data) : undefined;
+                if (menuBtnDoc && subMenuBtnList && params.subMenu && DocListCast(doc.data).length !== subMenuBtnList.length) {
+                    let prevSub = "";
+                    params.subMenu.forEach(sub => {
+                        if (!subMenuBtnList.find(doc => doc.title === sub.title)) {
+                            const newSubMenuBtnDoc = btnFunc(sub);
+                            const after = subMenuBtnList.find(doc => doc.title === prevSub);
+                            Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub);
+                        }
+                        prevSub = params.title;
+                    })
+                }
+                prev = params.title;
+            });
         }
     }
 
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ff2857739..55190001b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -50,6 +50,7 @@ import { AudioBox } from './nodes/AudioBox';
 import { ButtonType } from './nodes/button/FontIconBox';
 import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
+import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from './nodes/formattedText/RichTextMenu';
 import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
@@ -686,6 +687,7 @@ export class MainView extends React.Component {
             <ContextMenu />
             <RadialMenu />
             <AnchorMenu />
+            <DashFieldViewMenu />
             <MarqueeOptionsMenu />
             <OverlayView />
             <TimelineMenu />
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f4cb08f8f..259cc1ee5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1166,7 +1166,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         const docView = fieldProps.DocumentView?.();
-        if (docView && (e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) {
+        if (docView && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) {
             e.stopPropagation?.();
             const below = !e.altKey && e.key !== "Tab";
             const layoutKey = StrCast(docView.LayoutFieldKey);
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index e6d8fe88d..625f5d14a 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -666,6 +666,14 @@ ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: b
     if (editorView) RichTextMenu.Instance.setFontSize(size);
     else Doc.UserDoc()._fontSize = size;
 });
+ScriptingGlobals.add(function toggleNoAutoLinkAnchor(checkResult?: boolean) {
+    const editorView = RichTextMenu.Instance?.TextView?.EditorView;
+    if (checkResult) {
+        return (editorView ? RichTextMenu.Instance.noAutoLink : Doc.UserDoc().noAutoLink) ? Colors.MEDIUM_BLUE : "transparent";
+    }
+    if (editorView) RichTextMenu.Instance?.toggleNoAutoLinkAnchor();
+    else Doc.UserDoc().noAutoLink = Doc.UserDoc().noAutoLink ? true : false;
+});
 
 ScriptingGlobals.add(function toggleBold(checkResult?: boolean) {
     const editorView = RichTextMenu.Instance?.TextView?.EditorView;
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 1a8352b72..6a3f9ed00 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -8,35 +8,41 @@ import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
 import { ComputedField } from "../../../../fields/ScriptField";
 import { Cast, StrCast } from "../../../../fields/Types";
 import { DocServer } from "../../../DocServer";
-import { DocUtils } from "../../../documents/Documents";
 import { CollectionViewType } from "../../collections/CollectionView";
 import "./DashFieldView.scss";
 import { FormattedTextBox } from "./FormattedTextBox";
 import React = require("react");
+import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../../Utils";
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
+import { Tooltip } from "@material-ui/core";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 
 export class DashFieldView {
     _fieldWrapper: HTMLDivElement; // container for label and value
 
     constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
+        const { boolVal, strVal } = DashFieldViewInternal.fieldContent(tbox.props.Document, tbox.rootDoc, node.attrs.fieldKey);
+
         this._fieldWrapper = document.createElement("div");
         this._fieldWrapper.style.width = node.attrs.width;
         this._fieldWrapper.style.height = node.attrs.height;
         this._fieldWrapper.style.fontWeight = "bold";
         this._fieldWrapper.style.position = "relative";
         this._fieldWrapper.style.display = "inline-block";
+        this._fieldWrapper.textContent = node.attrs.fieldKey.startsWith("#") ? node.attrs.fieldKey : node.attrs.fieldKey + " " + strVal;
         this._fieldWrapper.onkeypress = function (e: any) { e.stopPropagation(); };
         this._fieldWrapper.onkeydown = function (e: any) { e.stopPropagation(); };
         this._fieldWrapper.onkeyup = function (e: any) { e.stopPropagation(); };
         this._fieldWrapper.onmousedown = function (e: any) { e.stopPropagation(); };
 
-        ReactDOM.render(<DashFieldViewInternal
+        setTimeout(() => ReactDOM.render(<DashFieldViewInternal
             fieldKey={node.attrs.fieldKey}
             docid={node.attrs.docid}
             width={node.attrs.width}
             height={node.attrs.height}
             hideKey={node.attrs.hideKey}
             tbox={tbox}
-        />, this._fieldWrapper);
+        />, this._fieldWrapper));
         (this as any).dom = this._fieldWrapper;
     }
     destroy() { ReactDOM.unmountComponentAtNode(this._fieldWrapper); }
@@ -76,16 +82,17 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         this._reactionDisposer?.();
     }
 
-    multiValueDelimeter = ";";
+    public static multiValueDelimeter = ";";
+    public static fieldContent(textBoxDoc: Doc, dashDoc: Doc, fieldKey: string) {
+        const dashVal = dashDoc[fieldKey] ?? dashDoc[DataSym][fieldKey] ?? (fieldKey === "PARAMS" ? textBoxDoc[fieldKey] : "");
+        const fval = dashVal instanceof List ? dashVal.join(DashFieldViewInternal.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(textBoxDoc)[fieldKey] : dashVal;
+        return { boolVal: Cast(fval, "boolean", null), strVal: Field.toString(fval as Field) || "" }
+    }
 
     // set the display of the field's value (checkbox for booleans, span of text for strings)
     @computed get fieldValueContent() {
         if (this._dashDoc) {
-            const dashVal = this._dashDoc[this._fieldKey] ?? this._dashDoc[DataSym][this._fieldKey] ?? (this._fieldKey === "PARAMS" ? this._textBoxDoc[this._fieldKey] : "");
-            const fval = dashVal instanceof List ? dashVal.join(this.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(this._textBoxDoc)[this._fieldKey] : dashVal;
-            const boolVal = Cast(fval, "boolean", null);
-            const strVal = Field.toString(fval as Field) || "";
-
+            const { boolVal, strVal } = DashFieldViewInternal.fieldContent(this._textBoxDoc, this._dashDoc, this._fieldKey);
             // field value is a boolean, so use a checkbox or similar widget to display it
             if (boolVal === true || boolVal === false) {
                 return <input
@@ -108,9 +115,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                     ref={r => {
                         r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r));
                         r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false));
-                        r?.addEventListener("pointerdown", action((e) => {
-                            e.stopPropagation();
-                        }));
+                        r?.addEventListener("pointerdown", action(e => e.stopPropagation()));
                     }} >
                     {strVal}
                 </span>;
@@ -161,7 +166,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                         if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = Number(newText);
                         Doc.SetInPlace(this._dashDoc!, this._fieldKey, newText, true);
                     } else {
-                        const splits = newText.split(this.multiValueDelimeter);
+                        const splits = newText.split(DashFieldViewInternal.multiValueDelimeter);
                         if (this._fieldKey !== "PARAMS" || !this._textBoxDoc[this._fieldKey] || this._dashDoc?.PARAMS) {
                             const strVal = splits.length > 1 ? new List<string>(splits) : newText;
                             if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = strVal;
@@ -173,11 +178,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         }
     }
 
-
-    // clicking on the label creates a pivot view collection of all documents
-    // in the same collection.  The pivot field is the fieldKey of this label
-    onPointerDownLabelSpan = (e: any) => {
-        e.stopPropagation();
+    createPivotForField = (e: React.MouseEvent) => {
         let container = this.props.tbox.props.ContainingCollectionView;
         while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) {
             container = container.props.ContainingCollectionView;
@@ -196,6 +197,16 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         }
     }
 
+
+    // clicking on the label creates a pivot view collection of all documents
+    // in the same collection.  The pivot field is the fieldKey of this label
+    onPointerDownLabelSpan = (e: any) => {
+        setupMoveUpEvents(this, e, returnFalse, returnFalse, (e) => {
+            DashFieldViewMenu.createFieldView = this.createPivotForField;
+            DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16);
+        });
+    }
+
     render() {
         return <div className="dashFieldView" style={{
             width: this.props.width,
@@ -210,4 +221,38 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
 
         </div >;
     }
+}
+@observer
+export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> {
+    static Instance: DashFieldViewMenu;
+    static createFieldView: (e: React.MouseEvent) => void = emptyFunction;
+    constructor(props: any) {
+        super(props);
+        DashFieldViewMenu.Instance = this;
+    }
+    @action
+    showFields = (e: React.MouseEvent) => {
+        DashFieldViewMenu.createFieldView(e);
+        DashFieldViewMenu.Instance.fadeOut(true);
+    }
+
+    public show = (x: number, y: number) => {
+        this.jumpTo(x, y, true);
+        const hideMenu = () => {
+            this.fadeOut(true);
+            document.removeEventListener("pointerdown", hideMenu);
+        }
+        document.addEventListener("pointerdown", hideMenu)
+    }
+    render() {
+        const buttons = [
+            <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
+                <button className="antimodeMenu-button" onPointerDown={this.showFields}>
+                    <FontAwesomeIcon icon="eye" size="lg" />
+                </button>
+            </Tooltip>,
+        ];
+
+        return this.getElement(buttons);
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d468822c0..ce82821b6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -391,16 +391,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             flattened1.forEach((flat, i) => {
                 const flattened = this.findInNode(this._editorView!, this._editorView!.state.doc, autoLinkTerm);
                 this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
-                alink = alink ?? (DocListCast(this.Document.links).find(link =>
-                    Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) &&
-                    Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target },
-                        LinkManager.AutoKeywords)!);
-                newAutoLinks.add(alink);
                 const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
                 const sel = flattened[i];
                 tr = tr.addMark(sel.from, sel.to, splitter);
                 tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
-                    if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
+                    if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
+                        alink = alink ?? (DocListCast(this.Document.links).find(link =>
+                            Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) &&
+                            Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target },
+                                LinkManager.AutoKeywords)!);
+                        newAutoLinks.add(alink);
                         const allAnchors = [{ href: Doc.localServerPath(target), title: "a link", anchorId: this.props.Document[Id] }];
                         allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
                         const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: "auto term", location: "add:right" });
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index e979ae59e..fb49b0698 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -82,6 +82,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
 
     bind("Ctrl-Tab", () => props.onKey?.(event, props) ? true : true);
     bind("Alt-Tab", () => props.onKey?.(event, props) ? true : true);
+    bind("Meta-Tab", () => props.onKey?.(event, props) ? true : true);
+    bind("Meta-Enter", () => props.onKey?.(event, props) ? true : true);
     bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         if (props.onKey?.(event, props)) return true;
         if (!canEdit(state)) return true;
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index c5f76cc8d..3df1e45a5 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -35,6 +35,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     public _brushMap: Map<string, Set<Mark>> = new Map();
 
     @observable private collapsed: boolean = false;
+    @observable private _noLinkActive: boolean = false;
     @observable private _boldActive: boolean = false;
     @observable private _italicsActive: boolean = false;
     @observable private _underlineActive: boolean = false;
@@ -79,6 +80,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         this._reaction?.();
     }
 
+    @computed get noAutoLink() { return this._noLinkActive; }
     @computed get bold() { return this._boldActive; }
     @computed get underline() { return this._underlineActive; }
     @computed get italics() { return this._italicsActive; }
@@ -220,7 +222,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         let activeMarks: MarkType[] = [];
         if (!this.view || !this.TextView.props.isSelected(true)) return activeMarks;
 
-        const markGroup = [schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript];
+        const markGroup = [schema.marks.noAutoLinkAnchor, schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript];
         if (this.view.state.storedMarks) return this.view.state.storedMarks.map(mark => mark.type);
         //current selection
         const { empty, ranges, $to } = this.view.state.selection as TextSelection;
@@ -264,6 +266,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     setActiveMarkButtons(activeMarks: MarkType[] | undefined) {
         if (!activeMarks) return;
 
+        this._noLinkActive = false;
         this._boldActive = false;
         this._italicsActive = false;
         this._underlineActive = false;
@@ -273,6 +276,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
 
         activeMarks.forEach(mark => {
             switch (mark.name) {
+                case "noAutoLinkAnchor": this._noLinkActive = true; break;
                 case "strong": this._boldActive = true; break;
                 case "em": this._italicsActive = true; break;
                 case "underline": this._underlineActive = true; break;
@@ -283,6 +287,14 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         });
     }
 
+    toggleNoAutoLinkAnchor = () => {
+        if (this.view) {
+            const mark = this.view.state.schema.mark(this.view.state.schema.marks.noAutoLinkAnchor);
+            this.setMark(mark, this.view.state, this.view.dispatch, false);
+            this.TextView.autoLink();
+            this.view.focus();
+        }
+    }
     toggleBold = () => {
         if (this.view) {
             const mark = this.view.state.schema.mark(this.view.state.schema.marks.strong);
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 427e05edb..8851d52e4 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -348,7 +348,7 @@ export class RichTextRules {
                         this.Document[DataSym].tags = `${tags + "#" + tag + ':'}`;
                     }
                     const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" + tag });
-                    return state.tr.deleteRange(start, end).insert(start, fieldView);
+                    return state.tr.deleteRange(start, end).insert(start, fieldView).insertText(" ");
                 }),
 
 
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 1f6ce014f..2fde5c7ba 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -48,6 +48,20 @@ export const marks: { [index: string]: MarkSpec } = {
             return ["a", { class: anchorids, "data-targethrefs": targethrefs, "data-linkdoc": node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0];
         }
     },
+    noAutoLinkAnchor: {
+        attrs: {},
+        inclusive: false,
+        parseDOM: [{
+            tag: "div", getAttrs(dom: any) {
+                return {
+                    noAutoLink: dom.getAttribute("data-noAutoLink"),
+                };
+            }
+        }],
+        toDOM(node: any) {
+            return ["span", { "data-noAutoLink": "true" }, 0];
+        }
+    },
     // :: MarkSpec A linkAnchor. The anchor can have multiple links, where each linkAnchor specifies an href to the URL of the source selection Marker text,
     // and a title for use in menus and hover. `title`
     // defaults to the empty string. Rendered and parsed as an `<a>`
-- 
cgit v1.2.3-70-g09d2

