From e24584cc674f763aec5d0e8f55f95a1d4c14522f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 27 Jan 2021 17:30:36 -0500
Subject: fixed undo for timeline region creation.  fixed inking tools display
 after deleting an active text. box

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 +
 1 file changed, 1 insertion(+)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e06a324d2..f3ac837d9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1302,6 +1302,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.endUndoTypingBatch();
         this.unhighlightSearchTerms();
         this._editorView?.destroy();
+        RichTextMenu.Instance.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
     }
 
-- 
cgit v1.2.3-70-g09d2


From 17bd18fd01d8b1f7fbef11d42651932d251cacc7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 27 Jan 2021 18:00:09 -0500
Subject: fixed focusing on nested documents in a text document.

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +-
 src/client/views/nodes/formattedText/RichTextSchema.tsx   | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f3ac837d9..36d268fe9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1302,7 +1302,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.endUndoTypingBatch();
         this.unhighlightSearchTerms();
         this._editorView?.destroy();
-        RichTextMenu.Instance.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
+        RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
     }
 
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index d272b6b8c..abbb89780 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -136,6 +136,8 @@ export class DashDocView {
                     addDocument={returnFalse}
                     rootSelected={this._textBox.props.isSelected}
                     removeDocument={removeDoc}
+                    layerProvider={this._textBox.props.layerProvider}
+                    styleProvider={this._textBox.props.styleProvider}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
@@ -143,7 +145,6 @@ export class DashDocView {
                     PanelWidth={finalLayout[WidthSym]}
                     PanelHeight={finalLayout[HeightSym]}
                     focus={this.outerFocus}
-                    styleProvider={DefaultStyleProvider}
                     parentActive={returnFalse}
                     whenActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From bc4cabf751097e847f0c64cc5acc25bc1ee09243 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Jan 2021 14:28:27 -0500
Subject: more cleanup for switching back to parameterized audioTag/videoTag
 instead of anchorStartTag

---
 src/client/views/StyleProvider.tsx                         | 2 +-
 src/client/views/collections/CollectionStackedTimeline.tsx | 8 ++++----
 src/client/views/nodes/AudioBox.tsx                        | 8 ++++----
 src/client/views/nodes/PresBox.tsx                         | 6 +++---
 src/client/views/nodes/VideoBox.tsx                        | 4 ++--
 src/client/views/nodes/formattedText/FormattedTextBox.tsx  | 2 +-
 src/fields/documentSchemas.ts                              | 2 --
 7 files changed, 15 insertions(+), 17 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 803390055..3956b8c5b 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -141,7 +141,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
                             `${darkScheme() ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`);
 
                 case DocumentType.LABEL:
-                    if (doc?.anchorStartTime !== undefined) return "black 2px 2px 1px";
+                    if (doc?.annotationOn !== undefined) return "black 2px 2px 1px";
                 default:
                     return doc.z ? `#9c9396  ${StrCast(doc?.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
                         props?.ContainingCollectionDoc?._useClusters && doc.type !== DocumentType.INK ? (`${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground() ? 100 : 50) / (docProps?.ContentScaling?.() || 1)}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 893f2c53b..1d7e40e96 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -88,7 +88,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
     }
 
     anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]));
-    anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this.props.endTag]));
+    anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this.props.endTag], val));
 
     getLinkData(l: Doc) {
         let la1 = l.anchor1 as Doc;
@@ -111,7 +111,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
     changeAnchor = (anchor: Opt<Doc>, time: number) => {
         if (anchor) {
             const timelineOnly = Cast(anchor[this.props.startTag], "number", null) !== undefined;
-            if (timelineOnly) this._left ? anchor[this.props.startTag] = time : anchor[this.props.endTag] = time;
+            if (timelineOnly) Doc.SetInPlace(anchor, this._left ? this.props.startTag : this.props.endTag, time, true);
             else this._left ? anchor._timecodeToShow = time : anchor._timecodeToHide = time;
         }
     }
@@ -177,8 +177,8 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
             hideLinkButton: true,
             annotationOn: this.props.Document
         });
-        anchor[this.props.startTag] = anchorStartTime;
-        anchor[this.props.endTag] = anchorEndTime;
+        Doc.GetProto(anchor)[this.props.startTag] = anchorStartTime;
+        Doc.GetProto(anchor)[this.props.endTag] = anchorEndTime;
         if (Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), null) !== undefined) {
             Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), []).push(anchor);
         } else {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 9d7c9bffc..741a03900 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -81,7 +81,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     getLinkData(l: Doc) {
         let la1 = l.anchor1 as Doc;
         let la2 = l.anchor2 as Doc;
-        const linkTime = NumCast(la2.anchorStartTime, NumCast(la1.anchorStartTime));
+        const linkTime = this._stackedTimeline.current?.anchorStart(la2) || this._stackedTimeline.current?.anchorStart(la1);
         if (Doc.AreProtosEqual(la1, this.dataDoc)) {
             la1 = l.anchor2 as Doc;
             la2 = l.anchor1 as Doc;
@@ -334,8 +334,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         else {
             this.links.filter(l => l.anchor1 === link || l.anchor2 === link).forEach(l => {
                 const { la1, la2 } = this.getLinkData(l);
-                const startTime = NumCast(la1.anchorStartTime, NumCast(la2.anchorStartTime, null));
-                const endTime = NumCast(la1.anchorEndTime, NumCast(la2.anchorEndTime, null));
+                const startTime = this._stackedTimeline.current?.anchorStart(la1) || this._stackedTimeline.current?.anchorStart(la2);
+                const endTime = this._stackedTimeline.current?.anchorEnd(la1) || this._stackedTimeline.current?.anchorEnd(la2);
                 if (startTime !== undefined) {
                     if (this.layoutDoc.playOnSelect) endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime);
                     else this._ele!.currentTime = this.layoutDoc._currentTimecode = startTime;
@@ -351,7 +351,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             renderDepth={this.props.renderDepth + 1}
             parentActive={this.props.parentActive}
             startTag={"audioStart"}
-            endTag={"auidioEnd"}
+            endTag={"audioEnd"}
             focus={emptyFunction}
             styleProvider={this.props.styleProvider}
             docFilters={this.props.docFilters}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 8d0283a12..b6feace12 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -715,9 +715,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 if (audio) {
                     audio.mediaStart = "manual";
                     audio.mediaStop = "manual";
-                    audio.presStartTime = NumCast(doc.anchorStartTime);
-                    audio.presEndTime = NumCast(doc.anchorEndTime);
-                    audio.presDuration = NumCast(doc.anchorEndTime) - NumCast(doc.anchorStartTime);
+                    audio.presStartTime = NumCast(doc.audioStart, NumCast(doc.videoStart));
+                    audio.presEndTime = NumCast(doc.audioEnd, NumCast(doc.videoEnd));
+                    audio.presDuration = audio.presStartTime - audio.presEndTime;
                     TabDocView.PinDoc(audio, { audioRange: true });
                     setTimeout(() => this.removeDocument(doc), 0);
                     return false;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index c1cf858c0..ee5fffcc6 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -480,8 +480,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     }
 
     playLink = (doc: Doc) => {
-        const startTime = NumCast(doc.anchorStartTime, NumCast(doc._timecodeToShow));
-        const endTime = NumCast(doc.anchorEndTime, NumCast(doc._timecodeToHide, null));
+        const startTime = this._stackedTimeline.current?.anchorStart(doc) || 0;
+        const endTime = this._stackedTimeline.current?.anchorEnd(doc);
         if (startTime !== undefined) {
             if (this.layoutDoc.playOnSelect) endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime);
             else this.Seek(startTime);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 36d268fe9..96c34860b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -361,7 +361,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             DocListCast(this.dataDoc.links).map((l, i) => {
                 let la1 = l.anchor1 as Doc;
                 let la2 = l.anchor2 as Doc;
-                this._linkTime = NumCast(la1.anchorStartTime, NumCast(la2.anchorStartTime));
+                this._linkTime = NumCast(la1.audioStart, NumCast(la2.audioStart));
                 audioState = la2.audioState;
                 if (Doc.AreProtosEqual(la2, this.dataDoc)) {
                     la1 = l.anchor2 as Doc;
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index d52f3a928..b10c2b015 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -21,8 +21,6 @@ export const documentSchema = createSchema({
     _currentTimecode: "number", // current play back time of a temporal document (video / audio)
     _timecodeToShow: "number",  // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
     isLabel: "boolean",         // whether the document is a label or not (video / audio)
-    anchorStartTime: "number",    // the time code where a document activates (eg in Audio or video timelines)
-    anchorEndTime: "number",      // the time code where a document deactivates
     markers: listSpec(Doc),     // list of markers for audio / video
     x: "number",                // x coordinate when in a freeform view 
     y: "number",                // y coordinate when in a freeform view 
-- 
cgit v1.2.3-70-g09d2


From 42d8bd5f673341682452c7c1f59b6b4b3a33d346 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Jan 2021 00:00:20 -0500
Subject: fixed automatic linking to audio recordings.  now it creates anchors
 and it inserts carriage returns properly when adding timestamps and
 suppressing timestamps for code blocks.

---
 src/client/documents/Documents.ts                  |  2 --
 .../collections/CollectionStackedTimeline.tsx      | 18 +++++-----
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 src/client/views/nodes/VideoBox.tsx                |  3 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 39 ++++++++--------------
 5 files changed, 24 insertions(+), 40 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 142e14ff8..1a4aae17e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -720,8 +720,6 @@ export namespace Docs {
             linkDocProto.treeViewOpen = true;// setting this in the instance creator would set it on the view document. 
             linkDocProto.anchor1 = source.doc;
             linkDocProto.anchor2 = target.doc;
-            linkDocProto.anchor1_timecode = source.doc._currentTimecode || source.doc._timecodeToShow;
-            linkDocProto.anchor2_timecode = target.doc._currentTimecode || target.doc._timecodeToShow;
 
             if (linkDocProto.linkBoxExcludedKeys === undefined) {
                 Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "aliases", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"]);
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 1ccf474f2..02e88d939 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -148,20 +148,20 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
 
     @undoBatch
     @action
-    createAnchor(anchorStartTime?: number, anchorEndTime?: number) {
-        if (anchorStartTime === undefined) return this.props.Document;
+    static createAnchor(rootDoc: Doc, dataDoc: Doc, fieldKey: string, startTag: string, endTag: string, anchorStartTime?: number, anchorEndTime?: number) {
+        if (anchorStartTime === undefined) return rootDoc;
         const anchor = Docs.Create.LabelDocument({
-            title: ComputedField.MakeFunction(`"#" + formatToTime(self["${this.props.startTag}"]) + "-" + formatToTime(self["${this.props.endTag}"])`) as any,
+            title: ComputedField.MakeFunction(`"#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"])`) as any,
             useLinkSmallAnchor: true,
             hideLinkButton: true,
-            annotationOn: this.props.Document
+            annotationOn: rootDoc
         });
-        Doc.GetProto(anchor)[this.props.startTag] = anchorStartTime;
-        Doc.GetProto(anchor)[this.props.endTag] = anchorEndTime;
-        if (Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), null) !== undefined) {
-            Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), []).push(anchor);
+        Doc.GetProto(anchor)[startTag] = anchorStartTime;
+        Doc.GetProto(anchor)[endTag] = anchorEndTime;
+        if (Cast(dataDoc[fieldKey], listSpec(Doc), null) !== undefined) {
+            Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
         } else {
-            this.dataDoc[this.props.fieldKey] = new List<Doc>([anchor]);
+            dataDoc[fieldKey] = new List<Doc>([anchor]);
         }
         return anchor;
     }
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 9f343e904..6b9d12ac0 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -90,7 +90,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     }
 
     getAnchor = () => {
-        return this._stackedTimeline.current?.createAnchor(this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)) || this.rootDoc;
+        return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "audioStart", "audioEnd", this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)) || this.rootDoc;
     }
 
     componentWillUnmount() {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 57077d113..79d584a1d 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -60,7 +60,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     @computed get links() { return DocListCast(this.dataDoc.links); }
     @computed get heightPercent() { return NumCast(this.layoutDoc._timelineHeightPercent, 100); }
     @computed get duration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); }
-    @computed get anchorDocs() { return DocListCast(this.dataDoc[this.annotationKey + "-timeline"]).concat(DocListCast(this.dataDoc[this.annotationKey])); }
 
     private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; }
     public get player(): HTMLVideoElement | null { return this._videoRef; }
@@ -71,7 +70,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     }
 
     getAnchor = () => {
-        return this._stackedTimeline.current?.createAnchor(Cast(this.layoutDoc._currentTimecode, "number", null)) || this.rootDoc;
+        return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "videoStart", "videoEnd", Cast(this.layoutDoc._currentTimecode, "number", null)) || this.rootDoc;
     }
 
     choosePath(url: string) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 96c34860b..6914c20b4 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -99,10 +99,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     private _undoTyping?: UndoManager.Batch;
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _dropDisposer?: DragManager.DragDropDisposer;
-    private _first: Boolean = true;
     private _recordingStart: number = 0;
-    private _currentTime: number = 0;
-    private _linkTime: number | null = null;
     private _pause: boolean = false;
     private _animatingScroll: number = 0; // hack to prevent scroll values from being written to document when scroll is animating
 
@@ -356,24 +353,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     // for inserting timestamps 
     insertTime = () => {
-        let audioState;
-        if (this._first) {
-            DocListCast(this.dataDoc.links).map((l, i) => {
-                let la1 = l.anchor1 as Doc;
-                let la2 = l.anchor2 as Doc;
-                this._linkTime = NumCast(la1.audioStart, NumCast(la2.audioStart));
-                audioState = la2.audioState;
-                if (Doc.AreProtosEqual(la2, this.dataDoc)) {
-                    la1 = l.anchor2 as Doc;
-                    la2 = l.anchor1 as Doc;
-                    audioState = la1.audioState;
-                }
-            });
-        }
-        this._currentTime = Date.now();
-        let time;
-        this._linkTime ? time = this.formatTime(Math.round(this._linkTime + this._currentTime / 1000 - this._recordingStart / 1000)) : time = null;
-
+        let linkTime;
+        DocListCast(this.dataDoc.links).forEach((l, i) => {
+            const anchor = (l.anchor1 as Doc).annotationOn ? l.anchor1 as Doc : (l.anchor2 as Doc).annotationOn ? (l.anchor2 as Doc) : undefined;
+            if (anchor && (anchor.annotationOn as Doc).audioState === "recording") linkTime = NumCast(anchor.audioStart);
+        });
         if (this._editorView) {
             const state = this._editorView.state;
             const now = Date.now();
@@ -388,13 +372,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     }
                 }
             }
-            if (time && audioState === "recording") {
-                let value = "";
+
+            const path = (this._editorView.state.selection.$from as any).path;
+            if (linkTime && path[path.length - 3].type !== this._editorView.state.schema.nodes.code_block) {
+                const time = this.formatTime(Math.round(linkTime + Date.now() / 1000 - this._recordingStart / 1000));
                 this._break = false;
-                value = this.layoutDoc._timeStampOnEnter ? "[" + time + "] " : "\n" + "[" + time + "] ";
+                const value = (this.layoutDoc._timeStampOnEnter ? "" : "\n") + "[" + time + "]";
                 const from = state.selection.from;
-                const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
-                this._editorView.dispatch(this._editorView.state.tr.insertText(value));
+                const para = this._editorView.state.schema.nodes.paragraph.create();
+                const replaced = this._editorView.state.tr.insertText(value).addMark(from, from + value.length + 1, mark).insert(from + value.length, para);
+                this._editorView.dispatch(replaced.setSelection(new TextSelection(replaced.doc.resolve(from + value.length + 1))));
             }
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 80362228b691fd55b569f0f507c4ee9667644559 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Jan 2021 13:47:31 -0500
Subject: changed how auto linking to audio is implemented.  added audiotag
 html tags to click to play audio.

---
 src/client/views/nodes/AudioBox.tsx                | 11 +++----
 .../nodes/formattedText/FormattedTextBox.scss      | 11 +++++++
 .../views/nodes/formattedText/FormattedTextBox.tsx | 37 ++++++++++++---------
 src/client/views/nodes/formattedText/nodes_rts.ts  | 38 +++++++++++++++++++++-
 4 files changed, 75 insertions(+), 22 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 6b9d12ac0..57b5f3ec7 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -43,7 +43,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     _disposers: { [name: string]: IReactionDisposer } = {};
     _ele: HTMLAudioElement | null = null;
-    _audioRef = React.createRef<HTMLDivElement>();
     _stackedTimeline = React.createRef<CollectionStackedTimeline>();
     _recorder: any;
     _recordStart = 0;
@@ -105,26 +104,26 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
         this.audioState = this.path ? "paused" : undefined;
 
-        this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+        //this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
 
         this._disposers.triggerAudio = reaction(
             () => !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && this.props.renderDepth !== -1 ? NumCast(this.Document._triggerAudio, null) : undefined,
             start => start !== undefined && setTimeout(() => {
-                this._audioRef.current && this.playFrom(start);
+                this.playFrom(start);
                 setTimeout(() => {
                     this.Document._currentTimecode = start;
                     this.Document._triggerAudio = undefined;
                 }, 10);
-            }, this._audioRef.current ? 0 : 250), // wait for mainCont and try again to play
+            }), // wait for mainCont and try again to play
             { fireImmediately: true }
         );
 
         this._disposers.audioStop = reaction(
             () => this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc ? Cast(this.Document._audioStop, "number", null) : undefined,
             audioStop => audioStop !== undefined && setTimeout(() => {
-                this._audioRef.current && this.Pause();
+                this.Pause();
                 setTimeout(() => this.Document._audioStop = undefined, 10);
-            }, this._audioRef.current ? 0 : 250), // wait for mainCont and try again to play
+            }), // wait for mainCont and try again to play
             { fireImmediately: true }
         );
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index b04f60500..866f556ff 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -10,6 +10,17 @@
     outline: none !important;
 }
 
+audiotag {
+    left: 0; 
+    position: absolute; 
+    cursor: pointer; 
+    border-radius: 10px; 
+    width: 10px; 
+    margin-top: -2px; 
+    font-size: 4px; 
+    background: lightblue;
+}
+
 .formattedTextBox-cont {
     touch-action: none;
     background: inherit;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6914c20b4..d73fd9208 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -343,20 +343,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     pause = () => this._pause = true;
 
-    formatTime = (time: number) => {
-        const hours = Math.floor(time / 60 / 60);
-        const minutes = Math.floor(time / 60) - (hours * 60);
-        const seconds = time % 60;
-
-        return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
-    }
-
     // for inserting timestamps 
     insertTime = () => {
         let linkTime;
+        let linkAnchor;
         DocListCast(this.dataDoc.links).forEach((l, i) => {
             const anchor = (l.anchor1 as Doc).annotationOn ? l.anchor1 as Doc : (l.anchor2 as Doc).annotationOn ? (l.anchor2 as Doc) : undefined;
-            if (anchor && (anchor.annotationOn as Doc).audioState === "recording") linkTime = NumCast(anchor.audioStart);
+            if (anchor && (anchor.annotationOn as Doc).audioState === "recording") {
+                linkTime = NumCast(anchor.audioStart);
+                linkAnchor = anchor;
+            }
         });
         if (this._editorView) {
             const state = this._editorView.state;
@@ -374,14 +370,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }
 
             const path = (this._editorView.state.selection.$from as any).path;
-            if (linkTime && path[path.length - 3].type !== this._editorView.state.schema.nodes.code_block) {
-                const time = this.formatTime(Math.round(linkTime + Date.now() / 1000 - this._recordingStart / 1000));
+            if (linkAnchor && linkTime && path[path.length - 3].type !== this._editorView.state.schema.nodes.code_block) {
+                const time = linkTime + Date.now() / 1000 - this._recordingStart / 1000;
                 this._break = false;
-                const value = (this.layoutDoc._timeStampOnEnter ? "" : "\n") + "[" + time + "]";
                 const from = state.selection.from;
-                const para = this._editorView.state.schema.nodes.paragraph.create();
-                const replaced = this._editorView.state.tr.insertText(value).addMark(from, from + value.length + 1, mark).insert(from + value.length, para);
-                this._editorView.dispatch(replaced.setSelection(new TextSelection(replaced.doc.resolve(from + value.length + 1))));
+                const value = this._editorView.state.schema.nodes.audiotag.create({ timeCode: time, audioId: linkAnchor[Id] });
+                const replaced = this._editorView.state.tr.insert(from - 1, value);
+                this._editorView.dispatch(replaced.setSelection(new TextSelection(replaced.doc.resolve(from + 1))));
             }
         }
     }
@@ -1299,6 +1294,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     _break = false;
     _collapsed = false;
     onPointerDown = (e: React.PointerEvent): void => {
+        if ((e.target as any).tagName === "AUDIOTAG") {
+            e.preventDefault();
+            e.stopPropagation();
+            const time = (e.target as any)?.dataset?.timecode || 0;
+            const audioid = (e.target as any)?.dataset?.audioid || 0;
+            DocServer.GetRefField(audioid).then(anchor => {
+                if (anchor instanceof Doc) {
+                    const audiodoc = anchor.annotationOn as Doc;
+                    audiodoc._triggerAudio = Number(time);
+                }
+            });
+        }
         if (this._recording && !e.ctrlKey && e.button === 0) {
             this.stopDictation(true);
             this._break = true;
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 64f7d27e5..f5bc05a2d 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -6,6 +6,14 @@ import { ParagraphNodeSpec, toParagraphDOM, getParagraphNodeAttrs } from "./Para
 const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
 
+function formatAudioTime(time: number) {
+    time = Math.round(time);
+    const hours = Math.floor(time / 60 / 60);
+    const minutes = Math.floor(time / 60) - (hours * 60);
+    const seconds = time % 60;
+
+    return minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
+}
 // :: Object
 // [Specs](#model.NodeSpec) for the nodes defined in this schema.
 export const nodes: { [index: string]: NodeSpec } = {
@@ -14,6 +22,34 @@ export const nodes: { [index: string]: NodeSpec } = {
         content: "block+"
     },
 
+    audiotag: {
+        group: "block",
+        attrs: {
+            timeCode: { default: 0 },
+            audioId: { default: "" }
+        },
+        toDOM(node) {
+            return ['audiotag',
+                {
+                    // style: see FormattedTextBox.scss
+                    "data-timecode": node.attrs.timeCode,
+                    "data-audioid": node.attrs.audioId,
+                },
+                formatAudioTime(node.attrs.timeCode.toString())
+            ]
+        },
+        parseDOM: [
+            {
+                tag: "audiotag", getAttrs(dom: any) {
+                    return {
+                        timeCode: dom.getAttribute("data-timecode"),
+                        audioId: dom.getAttribute("data-audioid")
+                    };
+                }
+            },
+        ]
+    },
+
     footnote: {
         group: "inline",
         content: "inline*",
@@ -315,7 +351,7 @@ export const nodes: { [index: string]: NodeSpec } = {
             mapStyle: { default: "decimal" }, // "decimal", "multi", "bullet"
             visibility: { default: true }
         },
-        content: 'paragraph+ | (paragraph ordered_list)',
+        content: '(paragraph|audiotag)+ | ((paragraph|audiotag)+ ordered_list)',
         parseDOM: [{
             tag: "li", getAttrs(dom: any) {
                 return { mapStyle: dom.getAttribute("data-mapStyle"), bulletStyle: dom.getAttribute("data-bulletStyle") };
-- 
cgit v1.2.3-70-g09d2


From 8709e3617aa44f7b374aff4346227a4400ff6faf Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Jan 2021 15:50:08 -0500
Subject: added flag to turn off audio anchors.  made audio doc appear when
 clicking on audiotag.

---
 src/Utils.ts                                              |  4 ++--
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 12 +++++++++---
 2 files changed, 11 insertions(+), 5 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 39fc3dae4..c7074c3da 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -500,9 +500,9 @@ export function addStyleSheet(styleType: string = "text/css") {
     const sheets = document.head.appendChild(style);
     return (sheets as any).sheet;
 }
-export function addStyleSheetRule(sheet: any, selector: any, css: any) {
+export function addStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = ".") {
     const propText = typeof css === "string" ? css : Object.keys(css).map(p => p + ":" + (p === "content" ? "'" + css[p] + "'" : css[p])).join(";");
-    return sheet.insertRule("." + selector + "{" + propText + "}", sheet.cssRules.length);
+    return sheet.insertRule(selectorPrefix + selector + "{" + propText + "}", sheet.cssRules.length);
 }
 export function removeStyleSheetRule(sheet: any, rule: number) {
     if (sheet.rules.length) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d73fd9208..d24ccd9ad 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -66,6 +66,7 @@ import { SubCollectionViewProps } from '../../collections/CollectionSubView';
 import { StyleProp } from '../../StyleProvider';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
 import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
+import { DocumentManager } from '../../../util/DocumentManager';
 
 export interface FormattedTextBoxProps {
     makeLink?: () => Opt<Doc>;  // bcz: hack: notifies the text document when the container has made a link.  allows the text doc to react and setup a hyeprlink for any selected text
@@ -338,6 +339,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     this._editorView.updateState(EditorState.fromJSON(this.config, json));
                 }
             }
+            if (window.getSelection()?.isCollapsed) AnchorMenu.Instance.fadeOut(true);
         }
     }
 
@@ -550,10 +552,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
         return ret;
     }
-    static _highlights: string[] = ["Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
+    static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
 
     updateHighlights = () => {
         clearStyleSheetRules(FormattedTextBox._userStyleSheet);
+        if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) {
+            addStyleSheetRule(FormattedTextBox._userStyleSheet, "audiotag", { display: "none" }, "");
+        }
         if (FormattedTextBox._highlights.indexOf("Text from Others") !== -1) {
             addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-remote", { background: "yellow" });
         }
@@ -625,8 +630,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         });
         !Doc.UserDoc().noviceMode && changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" });
         const highlighting: ContextMenuProps[] = [];
-        const noviceHighlighting = ["My Text", "Text from Others"];
-        const expertHighlighting = ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"];
+        const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others"];
+        const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"];
         (Doc.UserDoc().noviceMode ? noviceHighlighting : expertHighlighting).forEach(option =>
             highlighting.push({
                 description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
@@ -1303,6 +1308,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 if (anchor instanceof Doc) {
                     const audiodoc = anchor.annotationOn as Doc;
                     audiodoc._triggerAudio = Number(time);
+                    !DocumentManager.Instance.getDocumentView(audiodoc) && this.props.addDocTab(audiodoc, "add:bottom");
                 }
             });
         }
-- 
cgit v1.2.3-70-g09d2

