From 85c24ec4dcc39551e8c7de83d3482ec15472c030 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 31 Mar 2022 12:01:37 -0400
Subject: added autoLinks to formattedTextBoxes.  Set auto link target by
 titling documents with a prefix '@'.

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

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

diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 2e29c0656..46736aa4e 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -83,7 +83,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 const anchorDoc = href.replace(Doc.localServerPath(), "").split("?")[0];
                 anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => {
                     if (anchor instanceof Doc && DocListCast(anchor.links).length) {
-                        this._linkDoc = DocListCast(anchor.links)[0];
+                        this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0];
                         this._linkSrc = anchor;
                         const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
                         this._targetDoc = linkTarget?.type === DocumentType.MARKER && linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
-- 
cgit v1.2.3-70-g09d2


From 1ca9e485ea99db7db35fe52b0e15d6defa7568d3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 4 Apr 2022 11:39:17 -0400
Subject: cleaned up warnings.  fixed ink to work better with it's label boxes
 by not letting textbox ComponentView override inkinstroke.  made ink text
 boxes go away unless they have text or are selected.   fixed up brushing code
 and made it work for ink and ink w/ text labels

---
 src/client/views/InkingStroke.tsx                  | 23 ++++++++++++++-----
 .../collections/CollectionStackedTimeline.tsx      |  6 ++---
 .../collectionLinear/CollectionLinearView.tsx      |  2 +-
 src/client/views/nodes/AudioBox.tsx                | 20 ++++++++---------
 src/client/views/nodes/ComparisonBox.tsx           |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  1 +
 src/client/views/nodes/VideoBox.tsx                | 26 +++++++++++-----------
 src/client/views/nodes/button/FontIconBox.scss     | 15 +++++++++++++
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/fields/Doc.ts                                  | 12 +++++++---
 src/fields/Types.ts                                |  5 +++++
 11 files changed, 76 insertions(+), 38 deletions(-)

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

diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 23bdf8406..06671961d 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -25,16 +25,16 @@ import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, WidthSym } from "../../fields/Doc";
 import { InkData, InkField, InkTool } from "../../fields/InkField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
+import { BoolCast, Cast, NumCast, RTFCast, StrCast } from "../../fields/Types";
 import { TraceMobx } from "../../fields/util";
-import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils";
 import { CognitiveServices } from "../cognitive_services/CognitiveServices";
 import { InteractionUtils } from "../util/InteractionUtils";
 import { SnappingManager } from "../util/SnappingManager";
 import { Transform } from "../util/Transform";
 import { UndoManager } from "../util/UndoManager";
 import { ContextMenu } from "./ContextMenu";
-import { ViewBoxBaseComponent } from "./DocComponent";
+import { DocComponent, ViewBoxBaseComponent } from "./DocComponent";
 import { Colors } from "./global/globalEnums";
 import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles";
 import "./InkStroke.scss";
@@ -43,6 +43,7 @@ import { InkTangentHandles } from "./InkTangentHandles";
 import { FieldView, FieldViewProps } from "./nodes/FieldView";
 import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox";
 import Color = require("color");
+import { DocComponentView } from "./nodes/DocumentView";
 
 @observer
 export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -69,8 +70,16 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
 
     // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke
     // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc)
-    screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1)
+    screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1);
 
+    getAnchor = () => {
+        console.log(document.activeElement);
+        return this._subContentView?.getAnchor?.() || this.rootDoc;
+    }
+
+    scrollFocus = (textAnchor: Doc, smooth: boolean) => {
+        return this._subContentView?.scrollFocus?.(textAnchor, smooth);
+    }
     /**
     * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); 
     * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since
@@ -296,6 +305,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>;
     }
 
+    _subContentView: DocComponentView | undefined;
+    setSubContentView = (doc: DocComponentView) => this._subContentView = doc;
     render() {
         TraceMobx();
         const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
@@ -323,7 +334,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker,
             markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0,
             false, downHdlr);
-
         return <div className="inkStroke-wrapper">
             <svg className="inkStroke"
                 style={{
@@ -344,7 +354,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                 {clickableLine(this.onPointerDown)}
                 {inkLine}
             </svg>
-            {!closed ? (null) :
+            {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) :
                 <div className="inkStroke-text" style={{
                     color: StrCast(this.layoutDoc.textColor, "black"),
                     pointerEvents: this.props.isDocumentActive?.() ? "all" : undefined,
@@ -352,6 +362,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                 }}>
                     <FormattedTextBox
                         {...OmitKeys(this.props, ['children']).omit}
+                        setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
                         yPadding={10}
                         xPadding={10}
                         fieldKey={"text"}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index e0b947211..de307416f 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -89,7 +89,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     @observable _scroll: number = 0;
 
     // ensures that clip doesn't get trimmed so small that controls cannot be adjusted anymore 
-    get minTrimLength() { return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5) }
+    get minTrimLength() { return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5); }
 
     @computed get trimStart() { return this.IsTrimming !== TrimScope.None ? this._trimStart : this.clipStart; }
     @computed get trimDuration() { return this.trimEnd - this.trimStart; }
@@ -101,7 +101,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
 
     @computed get currentTime() { return NumCast(this.layoutDoc._currentTimecode); }
 
-    @computed get zoomFactor() { return this._zoomFactor }
+    @computed get zoomFactor() { return this._zoomFactor; }
 
 
     constructor(props: any) {
@@ -548,7 +548,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     dictationHeight = () => (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100;
 
     @computed get timelineContentHeight() { return this.props.PanelHeight() * this.dictationHeightPercent / 100; }
-    @computed get timelineContentWidth() { return this.props.PanelWidth() * this.zoomFactor - 4 };  // subtract size of container border
+    @computed get timelineContentWidth() { return this.props.PanelWidth() * this.zoomFactor - 4; }  // subtract size of container border
 
     dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight);
 
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 1d142d595..e3d4f86c1 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -232,7 +232,7 @@ export class CollectionLinearView extends CollectionSubView() {
                             Currently playing:
                             {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) =>
                                 <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true)}>
-                                    {clip.title + (i == CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")}
+                                    {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")}
                                 </span>)}
                         </span>
                     </span>}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 968dbc54d..e28e5b453 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -81,7 +81,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // mehek: not 100% sure but i think due to the order in which things are loaded this is necessary ^^
     // if you get rid of it and set the value to 0 the timeline and waveform will set their bounds incorrectly
 
-    @computed get miniPlayer() { return this.props.PanelHeight() < 50 } // used to collapse timeline when node is shrunk
+    @computed get miniPlayer() { return this.props.PanelHeight() < 50; } // used to collapse timeline when node is shrunk
     @computed get links() { return DocListCast(this.dataDoc.links); }
     @computed get pauseTime() { return this._pauseEnd - this._pauseStart; } // total time paused to update the correct recording time
     @computed get mediaState() { return this.layoutDoc.mediaState as media_state; }
@@ -212,7 +212,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         if (!CollectionStackedTimeline.CurrentlyPlaying) {
             CollectionStackedTimeline.CurrentlyPlaying = [];
         }
-        if (CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc) == -1) {
+        if (CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc) === -1) {
             CollectionStackedTimeline.CurrentlyPlaying.push(this.layoutDoc);
         }
     }
@@ -364,7 +364,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // sets <audio> ref for updating time
     setRef = (e: HTMLAudioElement | null) => {
         e?.addEventListener("timeupdate", this.timecodeChanged);
-        e?.addEventListener("ended", () => { this._finished = true; this.Pause() });
+        e?.addEventListener("ended", () => { this._finished = true; this.Pause(); });
         this._ele = e;
     }
 
@@ -417,10 +417,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     @action
     timelineWhenChildContentsActiveChanged = (isActive: boolean) =>
-        this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive);
+        this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)
 
     timelineScreenToLocal = () =>
-        this.props.ScreenToLocalTransform().translate(0, -AudioBox.bottomControlsHeight);
+        this.props.ScreenToLocalTransform().translate(0, -AudioBox.bottomControlsHeight)
 
     setPlayheadTime = (time: number) => this._ele!.currentTime = this.layoutDoc._currentTimecode = time;
 
@@ -430,7 +430,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // timeline dimensions
     timelineWidth = () => this.props.PanelWidth();
-    timelineHeight = () => (this.props.PanelHeight() - (AudioBox.topControlsHeight + AudioBox.bottomControlsHeight))
+    timelineHeight = () => (this.props.PanelHeight() - (AudioBox.topControlsHeight + AudioBox.bottomControlsHeight));
 
     // ends trim, hides trim controls and displays new clip
     @undoBatch
@@ -493,7 +493,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this._dropDisposer = DragManager.MakeDropTarget(r,
                 (e, de) => {
                     const [xp, yp] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-                    de.complete.docDragData && this.timeline!.internalDocDrop(e, de, de.complete.docDragData, xp);
+                    de.complete.docDragData && this.timeline.internalDocDrop(e, de, de.complete.docDragData, xp);
                 },
                 this.layoutDoc, undefined);
         }
@@ -529,7 +529,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     <FontAwesomeIcon icon="microphone" />
                     RECORD
                 </div>}
-        </div>
+        </div>;
     }
 
     // UI for playback, displayed for imported or recorded clips, hides timeline and collapses controls when node is shrunk vertically
@@ -563,7 +563,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     <input type="range" step="0.1" min="0" max="1" value={this._muted ? 0 : this._volume}
                         className="toolbar-slider volume"
                         onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }}
-                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.setVolume(Number(e.target.value)) }}
+                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setVolume(Number(e.target.value))}
                     />
                 </div>
             </div>
@@ -596,7 +596,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             </div>
 
 
-        </div>
+        </div>;
     }
 
     // gets CollectionStackedTimeline
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index cbc61ffdb..78608b681 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -81,7 +81,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             </div>;
         };
         const displayDoc = (which: string) => {
-            var whichDoc = Cast(this.dataDoc[which], Doc, null);
+            const whichDoc = Cast(this.dataDoc[which], Doc, null);
             // if (whichDoc?.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null);
             const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc;
             return whichDoc ? <>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 46736aa4e..7637d39be 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -182,6 +182,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             PanelHeight={this.height}
                             focus={DocUtils.DefaultFocus}
                             whenChildContentsActiveChanged={returnFalse}
+                            ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size.
                             bringToFront={returnFalse}
                             NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined}
                             NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 02ef346fb..ca8dc8515 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -202,7 +202,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // toggles video full screen
     @action public FullScreen = () => {
-        if (document.fullscreenElement == this._contentRef) {
+        if (document.fullscreenElement === this._contentRef) {
             this._fullScreen = false;
             this.player && this._contentRef && document.exitFullscreen();
         }
@@ -299,7 +299,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         if (Number.isFinite(this.player!.duration)) {
             this.rawDuration = this.player!.duration;
         }
-    })
+    });
 
 
     // updates video time
@@ -333,7 +333,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     setContentRef = (cref: HTMLDivElement | null) => {
         this._contentRef = cref;
         if (cref) {
-            cref.onfullscreenchange = action((e) => this._fullScreen = (document.fullscreenElement == cref));
+            cref.onfullscreenchange = action((e) => this._fullScreen = (document.fullscreenElement === cref));
         }
     }
 
@@ -496,7 +496,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         if (!CollectionStackedTimeline.CurrentlyPlaying) {
             CollectionStackedTimeline.CurrentlyPlaying = [];
         }
-        if (CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc) == -1) {
+        if (CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc) === -1) {
             CollectionStackedTimeline.CurrentlyPlaying.push(this.layoutDoc);
         }
     }
@@ -613,10 +613,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // stretches vertically or horizontally depending on video orientation so video fits full screen
     fullScreenSize() {
         if (this._videoRef && this._videoRef.videoHeight / this._videoRef.videoWidth > 1) {
-            return { height: "100%" }
+            return { height: "100%" };
         }
         else {
-            return { width: "100%" }
+            return { width: "100%" };
         }
     }
 
@@ -687,7 +687,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // renders video controls
     @computed get uIButtons() {
         const curTime = NumCast(this.layoutDoc._currentTimecode) - (this.timeline?.clipStart || 0);
-        return <div className="videoBox-ui" style={this._fullScreen || this.heightPercent == 100 ? { fontSize: "40px", minWidth: "80%" } : {}}>
+        return <div className="videoBox-ui" style={this._fullScreen || this.heightPercent === 100 ? { fontSize: "40px", minWidth: "80%" } : {}}>
             <div className="videobox-button"
                 title={this._playing ? "play" : "pause"}
                 onPointerDown={this.onPlayDown}>
@@ -699,12 +699,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     {formatTime(curTime)}
                 </div>
 
-                {this._fullScreen || this.heightPercent == 100 ?
+                {this._fullScreen || this.heightPercent === 100 ?
                     <div className="timeline-slider">
                         <input type="range" step="0.1" min={this.timeline.clipStart} max={this.timeline.clipEnd} value={curTime}
                             className="toolbar-slider time-progress"
                             onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }}
-                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.setPlayheadTime(Number(e.target.value)) }}
+                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setPlayheadTime(Number(e.target.value))}
                         />
                     </div>
                     :
@@ -740,11 +740,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             </div>
             <input type="range" step="0.1" min="0" max="1" value={this._muted ? 0 : this._volume}
                 className="toolbar-slider volume"
-                onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }}
-                onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.setVolume(Number(e.target.value)) }}
+                onPointerDown={(e: React.PointerEvent) => e.stopPropagation()}
+                onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setVolume(Number(e.target.value))}
             />
 
-            {!this._fullScreen && this.heightPercent != 100 &&
+            {!this._fullScreen && this.heightPercent !== 100 &&
                 <>
                     <div className="videobox-button" title="zoom">
                         <FontAwesomeIcon icon="search-plus" />
@@ -755,7 +755,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.zoom(Number(e.target.value)); }}
                     />
                 </>}
-        </div>
+        </div>;
     }
 
     // renders CollectionStackedTimeline
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
index 079c767b9..e3e2be515 100644
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ b/src/client/views/nodes/button/FontIconBox.scss
@@ -278,6 +278,21 @@
                 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;
+                    height: 10px;
+                    width: 10px;
+                    border-radius: 5px;
+                    background: #FFFFFF;
+                    cursor: pointer;
+                    -webkit-appearance: none;
+                    margin-top: -4px;
+                }
             }
         }
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6c4ca2d90..75f0978a8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -354,7 +354,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const f = this._editorView.state.selection.from;
             const t = this._editorView.state.selection.to;
             var tr = this._editorView.state.tr as any;
-            const autoAnch = this._editorView.state.schema.marks.autoLinkAnchor
+            const autoAnch = this._editorView.state.schema.marks.autoLinkAnchor;
             tr = tr.removeMark(0, tr.doc.content.size, autoAnch);
             DocListCast(Doc.UserDoc().myPublishedDocs).forEach(term => tr = this.hyperlinkTerm(tr, term, newAutoLinks));
             tr = tr.setSelection(new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t)));
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index c932259de..1edab16be 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -935,7 +935,7 @@ export namespace Doc {
     }
 
     export function isBrushedHighlightedDegree(doc: Doc) {
-        return Doc.IsHighlighted(doc) ? 6 : Doc.IsBrushedDegree(doc);
+        return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc);
     }
 
     export class DocBrush {
@@ -1009,10 +1009,16 @@ export namespace Doc {
     const isBrushedCache = computedFn(function IsBrushed(doc: Doc) { return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc)); });
     export function IsBrushed(doc: Doc) { return isBrushedCache(doc); }
 
+    export enum DocBrushStatus {
+        unbrushed = 0,
+        protoBrushed = 1,
+        selfBrushed = 2,
+        highlighted = 3
+    }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
     export function IsBrushedDegreeUnmemoized(doc: Doc) {
-        if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return 0;
-        return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0;
+        if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return DocBrushStatus.unbrushed;
+        return brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
     }
     export function IsBrushedDegree(doc: Doc) {
         return computedFn(function IsBrushDegree(doc: Doc) {
diff --git a/src/fields/Types.ts b/src/fields/Types.ts
index c90f3b6b3..7e2aa5681 100644
--- a/src/fields/Types.ts
+++ b/src/fields/Types.ts
@@ -4,6 +4,8 @@ import { RefField } from "./RefField";
 import { DateField } from "./DateField";
 import { ScriptField } from "./ScriptField";
 import { URLField, WebField, ImageField } from "./URLField";
+import { TextField } from "@material-ui/core";
+import { RichTextField } from "./RichTextField";
 
 export type ToType<T extends InterfaceValue> =
     T extends "string" ? string :
@@ -88,6 +90,9 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
 export function DateCast(field: FieldResult) {
     return Cast(field, DateField, null);
 }
+export function RTFCast(field: FieldResult) {
+    return Cast(field, RichTextField, null);
+}
 
 export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) {
     return Cast(field, ScriptField, defaultVal);
-- 
cgit v1.2.3-70-g09d2

