From da61cf1a3b9b37d43087b16be75af162cfb8b5cf Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Sat, 8 Aug 2020 15:52:16 -0700
Subject: working version of click and drag

---
 src/client/views/nodes/AudioBox.tsx | 102 ++++++++++++++++++++++++++++++++----
 1 file changed, 92 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index f01382d43..db87b15d1 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -60,20 +60,26 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _start: number = 0;
     _hold: boolean = false;
     _left: boolean = false;
-    _markers: Array<any> = [];
     _first: boolean = false;
     _dragging = false;
 
     _count: Array<any> = [];
     _timeline: Opt<HTMLDivElement>;
     _duration = 0;
+    @observable _visible: boolean = false;
+    _containerX: number = 0;
+    _containerY: number = 0;
+    @observable _currX: number = 0;
+    @observable _currY: number = 0;
+    _invertedX: boolean = false;
+    _invertedY: boolean = false;
 
     private _isPointerDown = false;
     private _currMarker: any;
 
     @observable _position: number = 0;
     @observable _buckets: Array<number> = new Array<number>();
-    @observable private _height: number = NumCast(this.layoutDoc.height);
+    @observable _waveHeight = this.layoutDoc._height;
     @observable private _paused: boolean = false;
     @observable private static _scrubTime = 0;
     @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); }
@@ -355,6 +361,74 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return (this._pauseEnd - this._pauseStart);
     }
 
+    // starting the drag event for marker resizing
+    @action
+    onPointerDownTimeline = (e: React.PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+        this._isPointerDown = true;
+        this._timeline?.setPointerCapture(e.pointerId);
+
+        this.start(this._ele!.currentTime);
+
+        const rect = (e.target as any).getBoundingClientRect();
+        this._containerX = this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+        this._containerY = this._currY = (e.clientY - rect.y) / rect.height;
+        console.log(rect.height);
+
+        document.removeEventListener("pointermove", this.onPointerMoveTimeline);
+        document.addEventListener("pointermove", this.onPointerMoveTimeline);
+        document.removeEventListener("pointerup", this.onPointerUpTimeline);
+        document.addEventListener("pointerup", this.onPointerUpTimeline);
+
+    }
+
+    // ending the drag event for marker resizing
+    @action
+    onPointerUpTimeline = (e: PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+        this._isPointerDown = false;
+
+        const rect = (e.target as any).getBoundingClientRect();
+        const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration)
+        this._visible ? this.end(time) : this._start = 0;
+        this._visible = false;
+
+        this._containerX = 0;
+        this._containerY = 0;
+        this._timeline?.releasePointerCapture(e.pointerId);
+
+        document.removeEventListener("pointermove", this.onPointerMoveTimeline);
+        document.removeEventListener("pointerup", this.onPointerUpTimeline);
+    }
+
+    // resizes the marker while dragging
+    @action
+    onPointerMoveTimeline = (e: PointerEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+
+        if (!this._isPointerDown) {
+            return;
+        }
+        this._visible = true;
+        const rect = (e.target as any).getBoundingClientRect();
+        console.log(rect.height);
+
+        this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+        this._currY = (e.clientY - rect.y) / rect.height;
+
+        (this._currX - this._containerX < 0) ? this._invertedX = true : this._invertedX = false;
+
+        this._currY - this._containerY < 0 ? this._invertedY = true : this._invertedY = false;
+        console.log(this._invertedY);
+    }
+
+    @computed get container() {
+        return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${Math.abs(this._currY - this._containerY) * 100}%`, top: !this._invertedY ? `${this._containerY * 100}%` : `${this._currY * 100}%` }}></div>
+    }
+
     // creates a new label 
     @action
     newMarker(marker: Doc) {
@@ -376,7 +450,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @action
     end(marker: number) {
         this._hold = false;
-        let newMarker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
+        const newMarker = this._invertedX ?
+            Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: marker, audioEnd: this._start, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document })
+            :
+            Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
         newMarker.data = "";
         if (this.dataDoc[this.annotationKey]) {
             this.dataDoc[this.annotationKey].push(newMarker);
@@ -498,7 +575,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @computed get waveform() {
         return <Waveform
             color={"darkblue"}
-            height={this._height}
+            height={this._waveHeight}
             barWidth={0.1}
             // pos={this.layoutDoc.currentTimecode}
             pos={this.dataDoc.duration}
@@ -560,12 +637,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @action
     update = (width: number, height: number) => {
         if (height) {
-            this._height = 0.8 * NumCast(this.layoutDoc._height);
+            const height = 0.8 * NumCast(this.layoutDoc._height);
             let canvas2 = document.getElementsByTagName("canvas")[0];
             if (canvas2) {
                 let oldWidth = canvas2.width;
                 let oldHeight = canvas2.height;
-                canvas2.style.height = `${this._height}`;
+                canvas2.style.height = `${height}`;
                 canvas2.style.width = `${width}`;
 
                 let ratio1 = oldWidth / window.innerWidth;
@@ -580,7 +657,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             if (canvas1) {
                 let oldWidth = canvas1.width;
                 let oldHeight = canvas1.height;
-                canvas1.style.height = `${this._height}`;
+                canvas1.style.height = `${height}`;
                 canvas1.style.width = `${width}`;
 
                 let ratio1 = oldWidth / window.innerWidth;
@@ -593,7 +670,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 let parent = canvas1.parentElement;
                 if (parent) {
                     parent.style.width = `${width}`;
-                    parent.style.height = `${this._height}`;
+                    parent.style.height = `${height}`;
                 }
             }
         }
@@ -642,11 +719,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 if (e.button === 0 && !e.ctrlKey) {
                                     const rect = (e.target as any).getBoundingClientRect();
 
+
                                     if (e.target as HTMLElement !== document.getElementById("current")) {
                                         const wasPaused = this.audioState === "paused";
                                         this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
                                         wasPaused && this.pause();
                                     }
+
+                                    this.onPointerDownTimeline(e);
                                 }
                                 if (e.button === 0 && e.altKey) {
                                     this.newMarker(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
@@ -658,7 +738,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                     this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
                                 }
                             }}>
-                            <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}>
+                            <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px", pointerEvents: "none" }}>
                                 {this.waveform}
                             </div>
                             {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => {
@@ -666,7 +746,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 (!m.isLabel) ?
                                     (this.layoutDoc.hideMarkers) ? (null) :
                                         rect =
-                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"} title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`} key={i} id={"audiobox-marker-container1"} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`, top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation() }} >
+                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"} title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`} key={i} id={"audiobox-marker-container1"} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation() }} >
                                             <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
                                             <DocumentView {...this.props}
                                                 Document={m}
@@ -741,6 +821,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const wasPaused = this.audioState === "paused"; this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
                                     </div>;
                             })}
+                            {this._visible ? this.container : null}
+
                             <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%`, pointerEvents: "none" }} />
                             {this.audio}
                         </div>
-- 
cgit v1.2.3-70-g09d2


From e8907b549dce6c991de92c9e8038e08c76725b18 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Sat, 8 Aug 2020 17:16:14 -0700
Subject: changed to 100% height and added minimum width dragged

---
 src/client/views/nodes/AudioBox.tsx | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index db87b15d1..9d3d157c3 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../fields/URLField";
 import { ViewBoxAnnotatableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../fields/Schema";
 import { documentSchema } from "../../../fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime, setupMoveUpEvents } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action, trace, toJS } from "mobx";
 import { DateField } from "../../../fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -25,6 +25,7 @@ import { List } from "../../../fields/List";
 import { Scripting } from "../../util/Scripting";
 import Waveform from "react-audio-waveform"
 import axios from "axios"
+import { DragManager } from "../../util/DragManager";
 const _global = (window /* browser */ || global /* node */) as any;
 
 declare class MediaRecorder {
@@ -66,17 +67,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _count: Array<any> = [];
     _timeline: Opt<HTMLDivElement>;
     _duration = 0;
-    @observable _visible: boolean = false;
     _containerX: number = 0;
-    _containerY: number = 0;
-    @observable _currX: number = 0;
-    @observable _currY: number = 0;
     _invertedX: boolean = false;
-    _invertedY: boolean = false;
-
     private _isPointerDown = false;
     private _currMarker: any;
 
+    @observable _visible: boolean = false;
+    @observable _currX: number = 0;
     @observable _position: number = 0;
     @observable _buckets: Array<number> = new Array<number>();
     @observable _waveHeight = this.layoutDoc._height;
@@ -373,14 +370,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
         const rect = (e.target as any).getBoundingClientRect();
         this._containerX = this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-        this._containerY = this._currY = (e.clientY - rect.y) / rect.height;
-        console.log(rect.height);
 
         document.removeEventListener("pointermove", this.onPointerMoveTimeline);
         document.addEventListener("pointermove", this.onPointerMoveTimeline);
         document.removeEventListener("pointerup", this.onPointerUpTimeline);
         document.addEventListener("pointerup", this.onPointerUpTimeline);
-
     }
 
     // ending the drag event for marker resizing
@@ -391,12 +385,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._isPointerDown = false;
 
         const rect = (e.target as any).getBoundingClientRect();
-        const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration)
-        this._visible ? this.end(time) : this._start = 0;
+        const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+
+        // if drag is greater than 15px (didn't use setupMoveEvent)
+        (this._visible && Math.abs(this._currX - this._containerX) * rect.width / NumCast(this.dataDoc.duration) > 15) ? this.end(time) : this._start = 0;
         this._visible = false;
 
         this._containerX = 0;
-        this._containerY = 0;
         this._timeline?.releasePointerCapture(e.pointerId);
 
         document.removeEventListener("pointermove", this.onPointerMoveTimeline);
@@ -414,19 +409,15 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
         this._visible = true;
         const rect = (e.target as any).getBoundingClientRect();
-        console.log(rect.height);
 
         this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-        this._currY = (e.clientY - rect.y) / rect.height;
 
         (this._currX - this._containerX < 0) ? this._invertedX = true : this._invertedX = false;
-
-        this._currY - this._containerY < 0 ? this._invertedY = true : this._invertedY = false;
-        console.log(this._invertedY);
     }
 
+    // returns the selection container 
     @computed get container() {
-        return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${Math.abs(this._currY - this._containerY) * 100}%`, top: !this._invertedY ? `${this._containerY * 100}%` : `${this._currY * 100}%` }}></div>
+        return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: "100%", top: "0%" }}></div>
     }
 
     // creates a new label 
-- 
cgit v1.2.3-70-g09d2


From 1032f8b421402371be4e4d62171bc837fdcb4368 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Sat, 8 Aug 2020 17:31:54 -0700
Subject: changed from alt to shift key

---
 src/client/views/nodes/AudioBox.tsx | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 9d3d157c3..9347e9b5b 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -719,15 +719,15 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
                                     this.onPointerDownTimeline(e);
                                 }
-                                if (e.button === 0 && e.altKey) {
+                                if (e.button === 0 && e.shiftKey) {
                                     this.newMarker(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
                                 }
 
-                                if (e.button === 0 && e.shiftKey) {
-                                    const rect = (e.target as any).getBoundingClientRect();
-                                    this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-                                    this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
-                                }
+                                // if (e.button === 0 && e.shiftKey) {
+                                //     const rect = (e.target as any).getBoundingClientRect();
+                                //     this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+                                //     this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
+                                // }
                             }}>
                             <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px", pointerEvents: "none" }}>
                                 {this.waveform}
-- 
cgit v1.2.3-70-g09d2


From 25fa93e7060c8f8561c294c7309c763e3b8f9313 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Sat, 8 Aug 2020 18:23:50 -0700
Subject: minor fixes

---
 src/client/views/nodes/AudioBox.tsx | 4 ++--
 src/server/index.ts                 | 1 -
 2 files changed, 2 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 59b60defa..4805b8643 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -739,8 +739,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
                                             style={{
                                                 left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`,
-                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`,
-                                                top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`
+                                                top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`,
+                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
                                             }}
                                             onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
                                             <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
diff --git a/src/server/index.ts b/src/server/index.ts
index 9185e3c5e..4ac4de847 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -105,7 +105,6 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }:
     const serve: PublicHandler = ({ req, res }) => {
         const detector = new mobileDetect(req.headers['user-agent'] || "");
         const filename = detector.mobile() !== null ? 'mobile/image.html' : 'index.html';
-        console.log(detector.is("iPhone"));
         res.sendFile(path.join(__dirname, '../../deploy/' + filename));
     };
 
-- 
cgit v1.2.3-70-g09d2


From ce3e3b1b217a02a65a3bc4eae5eccb7ca0842fac Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 10:57:25 -0400
Subject: cleaning up AudioBox

---
 src/Utils.ts                         |   4 +-
 src/client/views/nodes/AudioBox.scss |   3 +-
 src/client/views/nodes/AudioBox.tsx  | 357 +++++++++++------------------------
 3 files changed, 117 insertions(+), 247 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 0be27b25d..d9a5353e8 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -547,7 +547,7 @@ export function setupMoveUpEvents(
     target: object,
     e: React.PointerEvent,
     moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
-    upEvent: (e: PointerEvent) => void,
+    upEvent: (e: PointerEvent, movement: number[]) => void,
     clickEvent: (e: PointerEvent, doubleTap?: boolean) => void,
     stopPropagation: boolean = true,
     stopMovePropagation: boolean = true
@@ -571,7 +571,7 @@ export function setupMoveUpEvents(
     const _upEvent = (e: PointerEvent): void => {
         (target as any)._doubleTap = (Date.now() - (target as any)._lastTap < 300);
         (target as any)._lastTap = Date.now();
-        upEvent(e);
+        upEvent(e, [e.clientX - (target as any)._downX, e.clientY - (target as any)._downY]);
         if (Math.abs(e.clientX - (target as any)._downX) < 4 && Math.abs(e.clientY - (target as any)._downY) < 4) {
             clickEvent(e, (target as any)._doubleTap);
         }
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index c0743933e..973de979e 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -179,7 +179,8 @@
                     height: 100%;
                     overflow: hidden;
                     z-index: -1000;
-                    bottom: -30%;
+                    bottom: 0;
+                    pointer-events: none;
                 }
 
                 .audiobox-linker,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4805b8643..0fb191c05 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -31,9 +31,7 @@ declare class MediaRecorder {
     // whatever MediaRecorder has
     constructor(e: any);
 }
-export const audioSchema = createSchema({
-    playOnSelect: "boolean"
-});
+export const audioSchema = createSchema({ playOnSelect: "boolean" });
 
 type AudioDocument = makeInterface<[typeof documentSchema, typeof audioSchema]>;
 const AudioDocument = makeInterface(documentSchema, audioSchema);
@@ -66,13 +64,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _count: Array<any> = [];
     _timeline: Opt<HTMLDivElement>;
     _duration = 0;
-    _containerX: number = 0;
-    _invertedX: boolean = false;
-    private _isPointerDown = false;
+    _markerStart: number = 0;
     private _currMarker: any;
 
     @observable _visible: boolean = false;
-    @observable _currX: number = 0;
+    @observable _markerEnd: number = 0;
     @observable _position: number = 0;
     @observable _buckets: Array<number> = new Array<number>();
     @observable _waveHeight: number | undefined = this.layoutDoc._height;
@@ -82,6 +78,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     set audioState(value) { this.dataDoc.audioState = value; }
     public static SetScrubTime = (timeInMillisFrom1970: number) => { runInAction(() => AudioBox._scrubTime = 0); runInAction(() => AudioBox._scrubTime = timeInMillisFrom1970); };
     @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
+    @computed get audioDuration() { return NumCast(this.dataDoc.duration); }
     async slideTemplate() { return (await Cast((await Cast(Doc.UserDoc().slidesBtn, Doc) as Doc).dragFactory, Doc) as Doc); }
 
     constructor(props: Readonly<FieldViewProps>) {
@@ -137,21 +134,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 la2 = l.anchor1 as Doc;
                                 linkTime = NumCast(l.anchor1_timecode);
                             }
-                            if (la2.audioStart) {
-                                linkTime = NumCast(la2.audioStart);
-                            }
-
-                            if (la1.audioStart) {
-                                linkTime = NumCast(la1.audioStart);
-                            }
-
-                            if (la1.audioEnd) {
-                                endTime = NumCast(la1.audioEnd);
-                            }
+                            if (la2.audioStart) linkTime = NumCast(la2.audioStart);
+                            if (la1.audioStart) linkTime = NumCast(la1.audioStart);
 
-                            if (la2.audioEnd) {
-                                endTime = NumCast(la2.audioEnd);
-                            }
+                            if (la1.audioEnd) endTime = NumCast(la1.audioEnd);
+                            if (la2.audioEnd) endTime = NumCast(la2.audioEnd);
 
                             if (linkTime) {
                                 link = true;
@@ -203,7 +190,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     // play back the audio from time
     @action
-    playFrom = (seekTimeInSeconds: number, endTime: number = this.dataDoc.duration) => {
+    playFrom = (seekTimeInSeconds: number, endTime: number = this.audioDuration) => {
         let play;
         clearTimeout(play);
         this._duration = endTime - seekTimeInSeconds;
@@ -218,7 +205,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 this._ele.currentTime = seekTimeInSeconds;
                 this._ele.play();
                 runInAction(() => this.audioState = "playing");
-                if (endTime !== this.dataDoc.duration) {
+                if (endTime !== this.audioDuration) {
                     play = setTimeout(() => this.pause(), (this._duration) * 1000); // use setTimeout to play a specific duration
                 }
             } else {
@@ -230,11 +217,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // update the recording time
     updateRecordTime = () => {
         if (this.audioState === "recording") {
+            setTimeout(this.updateRecordTime, 30);
             if (this._paused) {
-                setTimeout(this.updateRecordTime, 30);
                 this._pausedTime += (new Date().getTime() - this._recordStart) / 1000;
             } else {
-                setTimeout(this.updateRecordTime, 30);
                 this.layoutDoc.currentTimecode = (new Date().getTime() - this._recordStart - this.pauseTime) / 1000;
             }
         }
@@ -353,74 +339,55 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     // return the total time paused to update the correct time
     @computed get pauseTime() {
-        return (this._pauseEnd - this._pauseStart);
+        return this._pauseEnd - this._pauseStart;
     }
 
     // starting the drag event for marker resizing
     @action
     onPointerDownTimeline = (e: React.PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = true;
-        this._timeline?.setPointerCapture(e.pointerId);
-
-        this.start(this._ele!.currentTime);
-
         const rect = (e.target as any).getBoundingClientRect();
-        this._containerX = this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
-        document.removeEventListener("pointermove", this.onPointerMoveTimeline);
-        document.addEventListener("pointermove", this.onPointerMoveTimeline);
-        document.removeEventListener("pointerup", this.onPointerUpTimeline);
-        document.addEventListener("pointerup", this.onPointerUpTimeline);
+        const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
+        this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x);
+        setupMoveUpEvents(this, e, action((e: PointerEvent) => {
+            this._visible = true;
+            this._markerEnd = toTimeline(e.clientX - rect.x);
+            if (this._markerEnd < this._markerStart) {
+                const tmp = this._markerStart;
+                this._markerStart = this._markerEnd;
+                this._markerEnd = tmp;
+            }
+            return false;
+        }),
+            action((e: PointerEvent, movement: number[]) => {
+                if (Math.abs(movement[0]) > 15) {
+                    this.createNewMarker(this._markerStart, toTimeline(e.clientX - rect.x));
+                }
+                this._visible = false;
+            }),
+            emptyFunction);
     }
-
-    // ending the drag event for marker resizing
-    @action
-    onPointerUpTimeline = (e: PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = false;
-
-        const rect = (e.target as any).getBoundingClientRect();
-        const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
-        // if drag is greater than 15px (didn't use setupMoveEvent)
-        (this._visible && Math.abs(this._currX - this._containerX) * rect.width / NumCast(this.dataDoc.duration) > 15) ? this.end(time) : this._start = 0;
-        this._visible = false;
-
-        this._containerX = 0;
-        this._timeline?.releasePointerCapture(e.pointerId);
-
-        document.removeEventListener("pointermove", this.onPointerMoveTimeline);
-        document.removeEventListener("pointerup", this.onPointerUpTimeline);
+    // returns the selection container 
+    @computed get container() {
+        return <div className="audiobox-container" style={{
+            left: `${NumCast(this._markerStart) / this.audioDuration * 100}%`,
+            width: `${Math.abs(this._markerStart - this._markerEnd) / this.audioDuration * 100}%`, height: "100%", top: "0%"
+        }}></div>
     }
 
-    // resizes the marker while dragging
+    // creates a new marker
     @action
-    onPointerMoveTimeline = (e: PointerEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-
-        if (!this._isPointerDown) {
-            return;
-        }
-        this._visible = true;
-        const rect = (e.target as any).getBoundingClientRect();
-
-        this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
-        (this._currX - this._containerX < 0) ? this._invertedX = true : this._invertedX = false;
+    createNewMarker(audioStart: number, audioEnd: number) {
+        const newMarker = Docs.Create.LabelDocument({
+            title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false,
+            useLinkSmallAnchor: true, hideLinkButton: true, audioStart, audioEnd, _showSidebar: false,
+            _autoHeight: true, annotationOn: this.props.Document
+        })
+        this.addMark(newMarker);
     }
 
-    // returns the selection container 
-    @computed get container() {
-        return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: "100%", top: "0%" }}></div>
-    }
-
-    // creates a new label 
+    // adds an annotation marker or label
     @action
-    newMarker(marker: Doc) {
+    addMark(marker: Doc) {
         marker.data = "";
         if (this.dataDoc[this.annotationKey]) {
             this.dataDoc[this.annotationKey].push(marker);
@@ -429,104 +396,39 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
-    // the starting time of the marker
-    start(startingPoint: number) {
-        this._hold = true;
-        this._start = startingPoint;
-    }
-
-    // creates a new marker
-    @action
-    end(marker: number) {
-        this._hold = false;
-        const newMarker = this._invertedX ?
-            Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: marker, audioEnd: this._start, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document })
-            :
-            Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
-        newMarker.data = "";
-        if (this.dataDoc[this.annotationKey]) {
-            this.dataDoc[this.annotationKey].push(newMarker);
-        } else {
-            this.dataDoc[this.annotationKey] = new List<Doc>([newMarker]);
-        }
-
-        this._start = 0;
-    }
-
     // starting the drag event for marker resizing
     onPointerDown = (e: React.PointerEvent, m: any, left: boolean): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = true;
         this._currMarker = m;
-        this._timeline?.setPointerCapture(e.pointerId);
         this._left = left;
-
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.addEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-        document.addEventListener("pointerup", this.onPointerUp);
-    }
-
-    // ending the drag event for marker resizing
-    @action
-    onPointerUp = (e: PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = false;
-        this._dragging = false;
-
         const rect = (e.target as any).getBoundingClientRect();
-        this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
-        this._timeline?.releasePointerCapture(e.pointerId);
-
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-    }
-
-    // resizes the marker while dragging
-    onPointerMove = async (e: PointerEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-
-        if (!this._isPointerDown) {
-            return;
-        }
-
-        const rect = await (e.target as any).getBoundingClientRect();
-
-        const newTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
-        this.changeMarker(this._currMarker, newTime);
+        const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
+        setupMoveUpEvents(this, e, () => {
+            this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x));
+            return false;
+        },
+            () => this._ele!.currentTime = this.layoutDoc.currentTimecode = toTimeline(e.clientX - rect.x),
+            emptyFunction);
     }
 
     // updates the marker with the new time
     @action
     changeMarker = (m: any, time: any) => {
-        DocListCast(this.dataDoc[this.annotationKey]).forEach((marker: Doc) => {
-            if (this.isSame(marker, m)) {
-                this._left ? marker.audioStart = time : marker.audioEnd = time;
-            }
-        });
+        DocListCast(this.dataDoc[this.annotationKey]).filter(marker => this.isSame(marker, m)).forEach(marker =>
+            this._left ? marker.audioStart = time : marker.audioEnd = time);
     }
 
     // checks if the two markers are the same with start and end time
     isSame = (m1: any, m2: any) => {
-        if (m1.audioStart === m2.audioStart && m1.audioEnd === m2.audioEnd) {
-            return true;
-        }
-        return false;
+        return m1.audioStart === m2.audioStart && m1.audioEnd === m2.audioEnd;
     }
 
     // instantiates a new array of size 500 for marker layout
     markers = () => {
-        const increment = NumCast(this.layoutDoc.duration) / 500;
+        const increment = this.audioDuration / 500;
         this._count = [];
         for (let i = 0; i < 500; i++) {
             this._count.push([increment * i, 0]);
         }
-
     }
 
     // makes sure no markers overlaps each other by setting the correct position and width
@@ -551,7 +453,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) {
                 this._count[i][1] = max;
             }
-
         }
 
         if (this.dataDoc.markerAmount < max) {
@@ -567,8 +468,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             height={this._waveHeight}
             barWidth={0.1}
             // pos={this.layoutDoc.currentTimecode} need to correctly resize parent to make this work (not very necessary for function)
-            pos={this.dataDoc.duration}
-            duration={this.dataDoc.duration}
+            pos={this.audioDuration}
+            duration={this.audioDuration}
             peaks={this._buckets.length === 100 ? this._buckets : undefined}
             progressColor={"blue"} />;
     }
@@ -612,10 +513,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // for updating the width and height of the waveform with timeline ref
     timelineRef = (timeline: HTMLDivElement) => {
         const observer = new _global.ResizeObserver(action((entries: any) => {
-            for (const entry of entries) {
-                this.update(entry.contentRect.width, entry.contentRect.height);
-                this._position = entry.contentRect.width;
-            }
+            Array.from(entries).map(e => e as any).filter(e => e.contentRect.width).forEach(e => {
+                this.update(e.contentRect.width, e.contentRect.height);
+                this._position = e.contentRect.width;
+            })
         }));
         timeline && observer.observe(timeline);
 
@@ -625,36 +526,29 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // update the width and height of the audio waveform
     @action
     update = (width: number, height: number) => {
+        const scaleCanvas = (canvas: HTMLCanvasElement) => {
+            let oldWidth = canvas.width;
+            let oldHeight = canvas.height;
+            canvas.style.height = `${height}`;
+            canvas.style.width = `${width}`;
+
+            const ratio1 = oldWidth / window.innerWidth;
+            const ratio2 = oldHeight / window.innerHeight;
+            const context = canvas.getContext('2d');
+            if (context) {
+                context.scale(ratio1, ratio2);
+            }
+        }
         if (height) {
             const height = 0.8 * NumCast(this.layoutDoc._height);
             let canvas2 = document.getElementsByTagName("canvas")[0];
             if (canvas2) {
-                let oldWidth = canvas2.width;
-                let oldHeight = canvas2.height;
-                canvas2.style.height = `${height}`;
-                canvas2.style.width = `${width}`;
-
-                const ratio1 = oldWidth / window.innerWidth;
-                const ratio2 = oldHeight / window.innerHeight;
-                const context = canvas2.getContext('2d');
-                if (context) {
-                    context.scale(ratio1, ratio2);
-                }
+                scaleCanvas(canvas2);
             }
 
             const canvas1 = document.getElementsByTagName("canvas")[1];
             if (canvas1) {
-                const oldWidth = canvas1.width;
-                const oldHeight = canvas1.height;
-                canvas1.style.height = `${height}`;
-                canvas1.style.width = `${width}`;
-
-                const ratio1 = oldWidth / window.innerWidth;
-                const ratio2 = oldHeight / window.innerHeight;
-                const context = canvas1.getContext('2d');
-                if (context) {
-                    context.scale(ratio1, ratio2);
-                }
+                scaleCanvas(canvas1);
 
                 const parent = canvas1.parentElement;
                 if (parent) {
@@ -666,16 +560,28 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     }
 
     rangeScript = () => AudioBox.RangeScript;
-
     labelScript = () => AudioBox.LabelScript;
 
-    // for indicating the first marker that is rendered
-    reset = () => this._first = true;
-
     render() {
         const interactive = this.active() ? "-interactive" : "";
-        this.reset();
+        this._first = true;  // for indicating the first marker that is rendered
         this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording
+        const markerDoc = (mark: Doc, script: undefined | (() => ScriptField)) => {
+            return <DocumentView {...this.props}
+                Document={mark}
+                pointerEvents={true}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                rootSelected={returnFalse}
+                LayoutTemplate={undefined}
+                ContainingCollectionDoc={this.props.Document}
+                removeDocument={this.removeDocument}
+                parentActive={returnTrue}
+                onClick={this.layoutDoc.playOnClick ? script : undefined}
+                ignoreAutoHeight={false}
+                bringToFront={emptyFunction}
+                scriptContext={this} />
+        }
         return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
             {!this.path ?
                 <div className="audiobox-buttons">
@@ -708,81 +614,44 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 if (e.button === 0 && !e.ctrlKey) {
                                     const rect = (e.target as any).getBoundingClientRect();
 
-
                                     if (e.target as HTMLElement !== document.getElementById("current")) {
                                         const wasPaused = this.audioState === "paused";
-                                        this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+                                        this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration;
                                         wasPaused && this.pause();
                                     }
 
                                     this.onPointerDownTimeline(e);
                                 }
                                 if (e.button === 0 && e.shiftKey) {
-                                    this.newMarker(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
+                                    this.addMark(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
                                 }
-
-                                // if (e.button === 0 && e.shiftKey) {
-                                //     const rect = (e.target as any).getBoundingClientRect();
-                                //     this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-                                //     this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
-                                // }
                             }}>
-                            <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px", pointerEvents: "none" }}>
+                            <div className="waveform">
                                 {this.waveform}
                             </div>
-                            {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => {
-                                let rect;
+                            {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) =>
                                 (!m.isLabel) ?
                                     (this.layoutDoc.hideMarkers) ? (null) :
-                                        rect =
-                                        <div key={i} id={"audiobox-marker-container1"} className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"}
+                                        <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container1`} key={i}
                                             title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
                                             style={{
-                                                left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`,
+                                                left: `${NumCast(m.audioStart) / this.audioDuration * 100}%`,
                                                 top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`,
-                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
+                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
                                             }}
                                             onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
                                             <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
-                                            <DocumentView {...this.props}
-                                                Document={m}
-                                                pointerEvents={true}
-                                                NativeHeight={returnZero}
-                                                NativeWidth={returnZero}
-                                                rootSelected={returnFalse}
-                                                LayoutTemplate={undefined}
-                                                ContainingCollectionDoc={this.props.Document}
-                                                removeDocument={this.removeDocument}
-                                                parentActive={returnTrue}
-                                                onClick={this.layoutDoc.playOnClick ? this.rangeScript : undefined}
-                                                ignoreAutoHeight={false}
-                                                bringToFront={emptyFunction}
-                                                scriptContext={this} />
+                                            {markerDoc(m, this.rangeScript)}
                                             <div className="resizer" onPointerDown={e => this.onPointerDown(e, m, false)}></div>
                                         </div>
                                     :
                                     (this.layoutDoc.hideLabels) ? (null) :
-                                        rect =
-                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={i} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
-                                            <DocumentView {...this.props}
-                                                Document={m}
-                                                pointerEvents={true}
-                                                NativeHeight={returnZero}
-                                                NativeWidth={returnZero}
-                                                rootSelected={returnFalse}
-                                                LayoutTemplate={undefined}
-                                                ContainingCollectionDoc={this.props.Document}
-                                                removeDocument={this.removeDocument}
-                                                parentActive={returnTrue}
-                                                onClick={this.layoutDoc.playOnClick ? this.labelScript : undefined}
-                                                ignoreAutoHeight={false}
-                                                bringToFront={emptyFunction}
-                                                scriptContext={this} />
-                                        </div>;
-                                return rect;
-                            })}
+                                        <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={i}
+                                            style={{ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%` }}>
+                                            {markerDoc(m, this.labelScript)}
+                                        </div>
+                            )}
                             {DocListCast(this.dataDoc.links).map((l, i) => {
-
                                 let la1 = l.anchor1 as Doc;
                                 let la2 = l.anchor2 as Doc;
                                 let linkTime = NumCast(l.anchor2_timecode);
@@ -797,7 +666,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 }
 
                                 return !linkTime ? (null) :
-                                    <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }} onClick={e => e.stopPropagation()}>
+                                    <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${linkTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}>
                                         <DocumentView {...this.props}
                                             Document={l}
                                             NativeHeight={returnZero}
@@ -814,19 +683,19 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)}
                                         />
                                         <div key={i} className={`audiobox-marker`} onPointerEnter={() => Doc.linkFollowHighlight(la1)}
-                                            onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const wasPaused = this.audioState === "paused"; this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
+                                            onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
                                     </div>;
                             })}
                             {this._visible ? this.container : null}
 
-                            <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%`, pointerEvents: "none" }} />
+                            <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
                             {this.audio}
                         </div>
                         <div className="current-time">
                             {formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
                         </div>
                         <div className="total-time">
-                            {formatTime(Math.round(NumCast(this.dataDoc.duration)))}
+                            {formatTime(Math.round(this.audioDuration))}
                         </div>
                     </div>
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 3ca9aa0d915e9000f78d528fa59639512f8c4d25 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 11:37:31 -0400
Subject: more audioBox cleanup/fixes

---
 src/client/views/nodes/AudioBox.tsx | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 0fb191c05..4c5d7fa0f 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -62,6 +62,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _dragging = false;
 
     _count: Array<any> = [];
+    _audioRef = React.createRef<HTMLDivElement>();
     _timeline: Opt<HTMLDivElement>;
     _duration = 0;
     _markerStart: number = 0;
@@ -71,12 +72,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @observable _markerEnd: number = 0;
     @observable _position: number = 0;
     @observable _buckets: Array<number> = new Array<number>();
-    @observable _waveHeight: number | undefined = this.layoutDoc._height;
+    @observable _waveHeight: Opt<number> = this.layoutDoc._height;
     @observable private _paused: boolean = false;
     @observable private static _scrubTime = 0;
     @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); }
     set audioState(value) { this.dataDoc.audioState = value; }
-    public static SetScrubTime = (timeInMillisFrom1970: number) => { runInAction(() => AudioBox._scrubTime = 0); runInAction(() => AudioBox._scrubTime = timeInMillisFrom1970); };
+    public static SetScrubTime = action((timeInMillisFrom1970: number) => { AudioBox._scrubTime = 0; AudioBox._scrubTime = timeInMillisFrom1970; });
     @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
     @computed get audioDuration() { return NumCast(this.dataDoc.duration); }
     async slideTemplate() { return (await Cast((await Cast(Doc.UserDoc().slidesBtn, Doc) as Doc).dragFactory, Doc) as Doc); }
@@ -155,6 +156,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 }
             });
         this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+        setTimeout(() => {
+            const rect = this._timeline?.getBoundingClientRect();
+            rect && this.update(rect.width, rect.height);
+        }, 1000);
     }
 
     // for updating the timecode
@@ -541,12 +546,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
         if (height) {
             const height = 0.8 * NumCast(this.layoutDoc._height);
-            let canvas2 = document.getElementsByTagName("canvas")[0];
+            let canvas2 = this._timeline?.getElementsByTagName("canvas")[0];
             if (canvas2) {
                 scaleCanvas(canvas2);
             }
 
-            const canvas1 = document.getElementsByTagName("canvas")[1];
+            const canvas1 = this._timeline?.getElementsByTagName("canvas")[1];
             if (canvas1) {
                 scaleCanvas(canvas1);
 
@@ -582,7 +587,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 bringToFront={emptyFunction}
                 scriptContext={this} />
         }
-        return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
+        return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}
+            style={{ pointerEvents: !interactive ? "none" : undefined }}>
             {!this.path ?
                 <div className="audiobox-buttons">
                     <div className="audiobox-dictation" onClick={this.onFile}>
@@ -614,7 +620,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 if (e.button === 0 && !e.ctrlKey) {
                                     const rect = (e.target as any).getBoundingClientRect();
 
-                                    if (e.target as HTMLElement !== document.getElementById("current")) {
+                                    if (e.target !== this._audioRef.current) {
                                         const wasPaused = this.audioState === "paused";
                                         this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration;
                                         wasPaused && this.pause();
@@ -688,7 +694,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                             })}
                             {this._visible ? this.container : null}
 
-                            <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
+                            <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
                             {this.audio}
                         </div>
                         <div className="current-time">
-- 
cgit v1.2.3-70-g09d2


From ab15a89319e53697a770929ed2ccd732c3d91ed2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 12:51:04 -0400
Subject: fixed audio box waveform to resize cleanly

---
 src/client/views/nodes/AudioBox.scss |  8 +++++
 src/client/views/nodes/AudioBox.tsx  | 63 +++---------------------------------
 2 files changed, 13 insertions(+), 58 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index 973de979e..0d787d9af 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -181,6 +181,14 @@
                     z-index: -1000;
                     bottom: 0;
                     pointer-events: none;
+                    div {
+                        height: 100% !important;
+                        width: 100%  !important;
+                    }
+                    canvas { 
+                        height: 100% !important;
+                        width: 100%  !important;
+                    }
                 }
 
                 .audiobox-linker,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4c5d7fa0f..bc89cb6f9 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -156,10 +156,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 }
             });
         this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
-        setTimeout(() => {
-            const rect = this._timeline?.getBoundingClientRect();
-            rect && this.update(rect.width, rect.height);
-        }, 1000);
     }
 
     // for updating the timecode
@@ -376,7 +372,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return <div className="audiobox-container" style={{
             left: `${NumCast(this._markerStart) / this.audioDuration * 100}%`,
             width: `${Math.abs(this._markerStart - this._markerEnd) / this.audioDuration * 100}%`, height: "100%", top: "0%"
-        }}></div>
+        }}></div>;
     }
 
     // creates a new marker
@@ -386,7 +382,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false,
             useLinkSmallAnchor: true, hideLinkButton: true, audioStart, audioEnd, _showSidebar: false,
             _autoHeight: true, annotationOn: this.props.Document
-        })
+        });
         this.addMark(newMarker);
     }
 
@@ -515,55 +511,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return this.buckets();
     }
 
-    // for updating the width and height of the waveform with timeline ref
-    timelineRef = (timeline: HTMLDivElement) => {
-        const observer = new _global.ResizeObserver(action((entries: any) => {
-            Array.from(entries).map(e => e as any).filter(e => e.contentRect.width).forEach(e => {
-                this.update(e.contentRect.width, e.contentRect.height);
-                this._position = e.contentRect.width;
-            })
-        }));
-        timeline && observer.observe(timeline);
-
-        this._timeline = timeline;
-    }
-
-    // update the width and height of the audio waveform
-    @action
-    update = (width: number, height: number) => {
-        const scaleCanvas = (canvas: HTMLCanvasElement) => {
-            let oldWidth = canvas.width;
-            let oldHeight = canvas.height;
-            canvas.style.height = `${height}`;
-            canvas.style.width = `${width}`;
-
-            const ratio1 = oldWidth / window.innerWidth;
-            const ratio2 = oldHeight / window.innerHeight;
-            const context = canvas.getContext('2d');
-            if (context) {
-                context.scale(ratio1, ratio2);
-            }
-        }
-        if (height) {
-            const height = 0.8 * NumCast(this.layoutDoc._height);
-            let canvas2 = this._timeline?.getElementsByTagName("canvas")[0];
-            if (canvas2) {
-                scaleCanvas(canvas2);
-            }
-
-            const canvas1 = this._timeline?.getElementsByTagName("canvas")[1];
-            if (canvas1) {
-                scaleCanvas(canvas1);
-
-                const parent = canvas1.parentElement;
-                if (parent) {
-                    parent.style.width = `${width}`;
-                    parent.style.height = `${height}`;
-                }
-            }
-        }
-    }
-
     rangeScript = () => AudioBox.RangeScript;
     labelScript = () => AudioBox.LabelScript;
 
@@ -585,8 +532,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 onClick={this.layoutDoc.playOnClick ? script : undefined}
                 ignoreAutoHeight={false}
                 bringToFront={emptyFunction}
-                scriptContext={this} />
-        }
+                scriptContext={this} />;
+        };
         return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}
             style={{ pointerEvents: !interactive ? "none" : undefined }}>
             {!this.path ?
@@ -613,7 +560,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                     <div className="audiobox-dictation"></div>
                     <div className="audiobox-player" >
                         <div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
-                        <div className="audiobox-timeline" ref={this.timelineRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }}
+                        <div className="audiobox-timeline" onClick={e => { e.stopPropagation(); e.preventDefault(); }}
                             onPointerDown={e => {
                                 e.stopPropagation();
                                 e.preventDefault();
-- 
cgit v1.2.3-70-g09d2


From 3ee0b9320fff9910c38bbef04e4866c6746316b8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 21:45:17 -0400
Subject: more audiobox cleanup.  fixed dropping links onto audio box
 regions/labels.

---
 src/client/views/nodes/AudioBox.tsx | 125 +++++++++++++++---------------------
 1 file changed, 51 insertions(+), 74 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index bc89cb6f9..709422f35 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -25,6 +25,7 @@ import { List } from "../../../fields/List";
 import { Scripting } from "../../util/Scripting";
 import Waveform from "react-audio-waveform";
 import axios from "axios";
+import { SnappingManager } from "../../util/SnappingManager";
 const _global = (window /* browser */ || global /* node */) as any;
 
 declare class MediaRecorder {
@@ -85,14 +86,21 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     constructor(props: Readonly<FieldViewProps>) {
         super(props);
 
-        // onClick play script
-        if (!AudioBox.RangeScript) {
-            AudioBox.RangeScript = ScriptField.MakeScript(`scriptContext.playFrom((this.audioStart), (this.audioEnd))`, { scriptContext: "any" })!;
-        }
+        // onClick play scripts
+        AudioBox.RangeScript = AudioBox.RangeScript || ScriptField.MakeScript(`scriptContext.playFrom((this.audioStart), (this.audioEnd))`, { scriptContext: "any" })!;
+        AudioBox.LabelScript = AudioBox.LabelScript || ScriptField.MakeScript(`scriptContext.playFrom((this.audioStart))`, { scriptContext: "any" })!;
+    }
 
-        if (!AudioBox.LabelScript) {
-            AudioBox.LabelScript = ScriptField.MakeScript(`scriptContext.playFrom((this.audioStart))`, { scriptContext: "any" })!;
+    getLinkData(l: Doc) {
+        let la1 = l.anchor1 as Doc;
+        let la2 = l.anchor2 as Doc;
+        let linkTime = NumCast(l.anchor2_timecode);
+        if (Doc.AreProtosEqual(la1, this.dataDoc)) {
+            la1 = l.anchor2 as Doc;
+            la2 = l.anchor1 as Doc;
+            linkTime = NumCast(l.anchor1_timecode);
         }
+        return { la1, la2, linkTime };
     }
 
     componentWillUnmount() {
@@ -110,7 +118,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             scrollLinkId => {
                 if (scrollLinkId) {
                     DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
-                        const linkTime = Doc.AreProtosEqual(l.anchor1 as Doc, this.dataDoc) ? NumCast(l.anchor1_timecode) : NumCast(l.anchor2_timecode);
+                        const { linkTime } = this.getLinkData(l);
                         setTimeout(() => { this.playFromTime(linkTime); Doc.linkFollowHighlight(l); }, 250);
                     });
                     Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
@@ -124,17 +132,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 let link;
                 if (sel) {
                     // for determining if the link is created after recording (since it will use linkTime rather than creation date)
-                    DocListCast(this.dataDoc.links).map((l, i) => {
-                        let la1 = l.anchor1 as Doc;
-                        let la2 = l.anchor2 as Doc;
+                    DocListCast(this.dataDoc.links).map(l => {
+                        let { la1, la2, linkTime } = this.getLinkData(l);
                         if (la1 === sel || la2 === sel) { // if the selected document is linked to this audio 
-                            let linkTime = NumCast(l.anchor2_timecode);
                             let endTime;
-                            if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-                                la1 = l.anchor2 as Doc;
-                                la2 = l.anchor1 as Doc;
-                                linkTime = NumCast(l.anchor1_timecode);
-                            }
                             if (la2.audioStart) linkTime = NumCast(la2.audioStart);
                             if (la1.audioStart) linkTime = NumCast(la1.audioStart);
 
@@ -164,12 +165,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         if (this.audioState !== "recording" && htmlEle) {
             htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
             DocListCast(this.dataDoc.links).map(l => {
-                let la1 = l.anchor1 as Doc;
-                let linkTime = NumCast(l.anchor2_timecode);
-                if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-                    linkTime = NumCast(l.anchor1_timecode);
-                    la1 = l.anchor2 as Doc;
-                }
+                const { la1, linkTime } = this.getLinkData(l);
                 if (linkTime > NumCast(this.layoutDoc.currentTimecode) && linkTime < htmlEle.currentTime) {
                     Doc.linkFollowHighlight(la1);
                 }
@@ -349,47 +345,33 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         const rect = (e.target as any).getBoundingClientRect();
         const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
         this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x);
-        setupMoveUpEvents(this, e, action((e: PointerEvent) => {
-            this._visible = true;
-            this._markerEnd = toTimeline(e.clientX - rect.x);
-            if (this._markerEnd < this._markerStart) {
-                const tmp = this._markerStart;
-                this._markerStart = this._markerEnd;
-                this._markerEnd = tmp;
-            }
-            return false;
-        }),
-            action((e: PointerEvent, movement: number[]) => {
-                if (Math.abs(movement[0]) > 15) {
-                    this.createNewMarker(this._markerStart, toTimeline(e.clientX - rect.x));
+        setupMoveUpEvents(this, e,
+            action((e: PointerEvent) => {
+                this._visible = true;
+                this._markerEnd = toTimeline(e.clientX - rect.x);
+                if (this._markerEnd < this._markerStart) {
+                    const tmp = this._markerStart;
+                    this._markerStart = this._markerEnd;
+                    this._markerEnd = tmp;
                 }
+                return false;
+            }),
+            action((e: PointerEvent, movement: number[]) => {
+                (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, toTimeline(e.clientX - rect.x));
                 this._visible = false;
             }),
-            emptyFunction);
-    }
-    // returns the selection container 
-    @computed get container() {
-        return <div className="audiobox-container" style={{
-            left: `${NumCast(this._markerStart) / this.audioDuration * 100}%`,
-            width: `${Math.abs(this._markerStart - this._markerEnd) / this.audioDuration * 100}%`, height: "100%", top: "0%"
-        }}></div>;
+            (e: PointerEvent) => e.shiftKey && this.createMarker(this._ele!.currentTime)
+        );
     }
 
-    // creates a new marker
     @action
-    createNewMarker(audioStart: number, audioEnd: number) {
-        const newMarker = Docs.Create.LabelDocument({
-            title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false,
+    createMarker(audioStart: number, audioEnd?: number) {
+        const marker = Docs.Create.LabelDocument({
+            title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: audioEnd === undefined,
             useLinkSmallAnchor: true, hideLinkButton: true, audioStart, audioEnd, _showSidebar: false,
             _autoHeight: true, annotationOn: this.props.Document
         });
-        this.addMark(newMarker);
-    }
-
-    // adds an annotation marker or label
-    @action
-    addMark(marker: Doc) {
-        marker.data = "";
+        marker.data = ""; // clears out the label's text so that only its border will display
         if (this.dataDoc[this.annotationKey]) {
             this.dataDoc[this.annotationKey].push(marker);
         } else {
@@ -403,10 +385,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._left = left;
         const rect = (e.target as any).getBoundingClientRect();
         const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
-        setupMoveUpEvents(this, e, () => {
-            this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x));
-            return false;
-        },
+        setupMoveUpEvents(this, e,
+            () => {
+                this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x));
+                return false;
+            },
             () => this._ele!.currentTime = this.layoutDoc.currentTimecode = toTimeline(e.clientX - rect.x),
             emptyFunction);
     }
@@ -462,6 +445,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return max - 1;
     }
 
+    @computed get selectionContainer() {
+        return <div className="audiobox-container" style={{
+            left: `${NumCast(this._markerStart) / this.audioDuration * 100}%`,
+            width: `${Math.abs(this._markerStart - this._markerEnd) / this.audioDuration * 100}%`, height: "100%", top: "0%"
+        }} />;
+    }
+
     // returns the audio waveform
     @computed get waveform() {
         return <Waveform
@@ -515,7 +505,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     labelScript = () => AudioBox.LabelScript;
 
     render() {
-        const interactive = this.active() ? "-interactive" : "";
+        const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : "";
         this._first = true;  // for indicating the first marker that is rendered
         this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording
         const markerDoc = (mark: Doc, script: undefined | (() => ScriptField)) => {
@@ -562,8 +552,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                         <div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
                         <div className="audiobox-timeline" onClick={e => { e.stopPropagation(); e.preventDefault(); }}
                             onPointerDown={e => {
-                                e.stopPropagation();
-                                e.preventDefault();
                                 if (e.button === 0 && !e.ctrlKey) {
                                     const rect = (e.target as any).getBoundingClientRect();
 
@@ -575,9 +563,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
                                     this.onPointerDownTimeline(e);
                                 }
-                                if (e.button === 0 && e.shiftKey) {
-                                    this.addMark(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
-                                }
                             }}>
                             <div className="waveform">
                                 {this.waveform}
@@ -605,15 +590,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                         </div>
                             )}
                             {DocListCast(this.dataDoc.links).map((l, i) => {
-                                let la1 = l.anchor1 as Doc;
-                                let la2 = l.anchor2 as Doc;
-                                let linkTime = NumCast(l.anchor2_timecode);
-                                if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-                                    la1 = l.anchor2 as Doc;
-                                    la2 = l.anchor1 as Doc;
-                                    linkTime = NumCast(l.anchor1_timecode);
-                                }
-
+                                let { la1, la2, linkTime } = this.getLinkData(l);
                                 if (la2.audioStart && !la2.audioEnd) {
                                     linkTime = NumCast(la2.audioStart);
                                 }
@@ -639,7 +616,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
                                     </div>;
                             })}
-                            {this._visible ? this.container : null}
+                            {this._visible ? this.selectionContainer : null}
 
                             <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
                             {this.audio}
-- 
cgit v1.2.3-70-g09d2


From dc0ffc050b5b11e345245927f3d8a813937e588d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 22:48:26 -0400
Subject: starting to fix link following behavior to audio regions.

---
 src/client/util/DocumentManager.ts      |   2 +-
 src/client/views/linking/LinkEditor.tsx |   6 +-
 src/client/views/nodes/AudioBox.scss    |   5 +
 src/client/views/nodes/AudioBox.tsx     | 256 ++++++++++++++++----------------
 4 files changed, 140 insertions(+), 129 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 523dbfca0..bd57e7f48 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -152,7 +152,7 @@ export class DocumentManager {
             const first = getFirstDocView(annotatedDoc);
             if (first) {
                 annotatedDoc = first.props.Document;
-                docView?.props.focus(annotatedDoc, false);
+                first.props.focus(annotatedDoc, false);
             }
         }
         if (docView) {  // we have a docView already and aren't forced to create a new one ... just focus on the document.  TODO move into view if necessary otherwise just highlight?
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 5832a2181..3ef391a5d 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -355,11 +355,11 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         this.openDropdown = !this.openDropdown;
     }
 
-    @undoBatch @action
-    changeFollowBehavior = (follow: string) => {
+    @undoBatch
+    changeFollowBehavior = action((follow: string) => {
         this.openDropdown = false;
         Doc.GetProto(this.props.linkDoc).followLinkLocation = follow;
-    }
+    })
 
     @computed
     get followingDropdown() {
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index 0d787d9af..c80e3af24 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -8,6 +8,11 @@
     position: relative;
     cursor: default;
 
+    .audiobox-inner {
+        width:100%;
+        height: 100%;
+    }
+
     .audiobox-buttons {
         display: flex;
         width: 100%;
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 709422f35..0ea624edf 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -128,37 +128,41 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         // for play when link is selected
         this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
             selected => {
-                const sel = selected.length ? selected[0].props.Document : undefined;
-                let link;
-                if (sel) {
-                    // for determining if the link is created after recording (since it will use linkTime rather than creation date)
-                    DocListCast(this.dataDoc.links).map(l => {
-                        let { la1, la2, linkTime } = this.getLinkData(l);
-                        if (la1 === sel || la2 === sel) { // if the selected document is linked to this audio 
-                            let endTime;
-                            if (la2.audioStart) linkTime = NumCast(la2.audioStart);
-                            if (la1.audioStart) linkTime = NumCast(la1.audioStart);
-
-                            if (la1.audioEnd) endTime = NumCast(la1.audioEnd);
-                            if (la2.audioEnd) endTime = NumCast(la2.audioEnd);
-
-                            if (linkTime) {
-                                link = true;
-                                this.layoutDoc.playOnSelect && this.recordingStart && sel && !Doc.AreProtosEqual(sel, this.props.Document) && (endTime ? this.playFrom(linkTime, endTime) : this.playFrom(linkTime));
-                            }
-                        }
-                    });
-                }
-
-                // for links created during recording 
-                if (!link) {
-                    this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
-                    this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
+                if (this.layoutDoc.playOnSelect) {
+                    const sel = selected.length ? selected[0].props.Document : undefined;
+                    const link = sel && DocListCast(this.dataDoc.links).forEach(l => (l.anchor1 === sel || l.anchor2 === sel) && this.playLink(l), false);
+                    // for links created during recording 
+                    if (!link) {
+                        this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
+                        this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
+                    }
                 }
             });
         this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
     }
 
+    playLink = (doc: Doc) => {
+        let link = false;
+        !Doc.AreProtosEqual(doc, this.props.Document) && DocListCast(this.props.Document.links).forEach(l => {
+            if (l.anchor1 === doc || l.anchor2 === doc) {
+                const { la1, la2, linkTime } = this.getLinkData(l);
+                let startTime = linkTime;
+                if (la2.audioStart) startTime = NumCast(la2.audioStart);
+                if (la1.audioStart) startTime = NumCast(la1.audioStart);
+
+                let endTime;
+                if (la1.audioEnd) endTime = NumCast(la1.audioEnd);
+                if (la2.audioEnd) endTime = NumCast(la2.audioEnd);
+
+                if (startTime) {
+                    link = true;
+                    this.recordingStart && (endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime));
+                }
+            }
+        });
+        return link;
+    }
+
     // for updating the timecode
     timecodeChanged = () => {
         const htmlEle = this._ele;
@@ -511,6 +515,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         const markerDoc = (mark: Doc, script: undefined | (() => ScriptField)) => {
             return <DocumentView {...this.props}
                 Document={mark}
+                focus={() => this.playLink(mark)}
                 pointerEvents={true}
                 NativeHeight={returnZero}
                 NativeWidth={returnZero}
@@ -524,112 +529,113 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 bringToFront={emptyFunction}
                 scriptContext={this} />;
         };
-        return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}
-            style={{ pointerEvents: !interactive ? "none" : undefined }}>
-            {!this.path ?
-                <div className="audiobox-buttons">
-                    <div className="audiobox-dictation" onClick={this.onFile}>
-                        <FontAwesomeIcon style={{ width: "30px", background: this.layoutDoc.playOnSelect ? "yellow" : "rgba(0,0,0,0)" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
-                    </div>
-                    {this.audioState === "recording" ?
-                        <div className="recording" onClick={e => e.stopPropagation()}>
-                            <div className="buttons" onClick={this.recordClick}>
-                                <FontAwesomeIcon style={{ width: "100%" }} icon={"stop"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
-                            </div>
-                            <div className="buttons" onClick={this._paused ? this.recordPlay : this.recordPause}>
-                                <FontAwesomeIcon style={{ width: "100%" }} icon={this._paused ? "play" : "pause"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
-                            </div>
-                            <div className="time">{formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}</div>
+        return <div className="audiobox-container" onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
+            <div className="audiobox-inner" style={{ pointerEvents: !interactive ? "none" : undefined }}>
+                {!this.path ?
+                    <div className="audiobox-buttons">
+                        <div className="audiobox-dictation" onClick={this.onFile}>
+                            <FontAwesomeIcon style={{ width: "30px", background: this.layoutDoc.playOnSelect ? "yellow" : "rgba(0,0,0,0)" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
                         </div>
-                        :
-                        <button className={`audiobox-record${interactive}`} style={{ backgroundColor: "black" }}>
-                            RECORD
+                        {this.audioState === "recording" ?
+                            <div className="recording" onClick={e => e.stopPropagation()}>
+                                <div className="buttons" onClick={this.recordClick}>
+                                    <FontAwesomeIcon style={{ width: "100%" }} icon={"stop"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+                                </div>
+                                <div className="buttons" onClick={this._paused ? this.recordPlay : this.recordPause}>
+                                    <FontAwesomeIcon style={{ width: "100%" }} icon={this._paused ? "play" : "pause"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+                                </div>
+                                <div className="time">{formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}</div>
+                            </div>
+                            :
+                            <button className={`audiobox-record${interactive}`} style={{ backgroundColor: "black" }}>
+                                RECORD
                             </button>}
-                </div> :
-                <div className="audiobox-controls" >
-                    <div className="audiobox-dictation"></div>
-                    <div className="audiobox-player" >
-                        <div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
-                        <div className="audiobox-timeline" onClick={e => { e.stopPropagation(); e.preventDefault(); }}
-                            onPointerDown={e => {
-                                if (e.button === 0 && !e.ctrlKey) {
-                                    const rect = (e.target as any).getBoundingClientRect();
-
-                                    if (e.target !== this._audioRef.current) {
-                                        const wasPaused = this.audioState === "paused";
-                                        this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration;
-                                        wasPaused && this.pause();
+                    </div> :
+                    <div className="audiobox-controls" >
+                        <div className="audiobox-dictation"></div>
+                        <div className="audiobox-player" >
+                            <div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
+                            <div className="audiobox-timeline" onClick={e => { e.stopPropagation(); e.preventDefault(); }}
+                                onPointerDown={e => {
+                                    if (e.button === 0 && !e.ctrlKey) {
+                                        const rect = (e.target as any).getBoundingClientRect();
+
+                                        if (e.target !== this._audioRef.current) {
+                                            const wasPaused = this.audioState === "paused";
+                                            this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration;
+                                            wasPaused && this.pause();
+                                        }
+
+                                        this.onPointerDownTimeline(e);
+                                    }
+                                }}>
+                                <div className="waveform">
+                                    {this.waveform}
+                                </div>
+                                {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) =>
+                                    (!m.isLabel) ?
+                                        (this.layoutDoc.hideMarkers) ? (null) :
+                                            <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container1`} key={i}
+                                                title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
+                                                style={{
+                                                    left: `${NumCast(m.audioStart) / this.audioDuration * 100}%`,
+                                                    top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`,
+                                                    width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
+                                                }}
+                                                onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
+                                                <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
+                                                {markerDoc(m, this.rangeScript)}
+                                                <div className="resizer" onPointerDown={e => this.onPointerDown(e, m, false)}></div>
+                                            </div>
+                                        :
+                                        (this.layoutDoc.hideLabels) ? (null) :
+                                            <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={i}
+                                                style={{ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%` }}>
+                                                {markerDoc(m, this.labelScript)}
+                                            </div>
+                                )}
+                                {DocListCast(this.dataDoc.links).map((l, i) => {
+                                    const { la1, la2, linkTime } = this.getLinkData(l);
+                                    let startTime = linkTime;
+                                    if (la2.audioStart && !la2.audioEnd) {
+                                        startTime = NumCast(la2.audioStart);
                                     }
 
-                                    this.onPointerDownTimeline(e);
-                                }
-                            }}>
-                            <div className="waveform">
-                                {this.waveform}
+                                    return !linkTime ? (null) :
+                                        <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${startTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}>
+                                            <DocumentView {...this.props}
+                                                Document={l}
+                                                NativeHeight={returnZero}
+                                                NativeWidth={returnZero}
+                                                rootSelected={returnFalse}
+                                                ContainingCollectionDoc={this.props.Document}
+                                                parentActive={returnTrue}
+                                                bringToFront={emptyFunction}
+                                                backgroundColor={returnTransparent}
+                                                ContentScaling={returnOne}
+                                                forcedBackgroundColor={returnTransparent}
+                                                pointerEvents={false}
+                                                LayoutTemplate={undefined}
+                                                LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)}
+                                            />
+                                            <div key={i} className={`audiobox-marker`} onPointerEnter={() => Doc.linkFollowHighlight(la1)}
+                                                onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(startTime); e.stopPropagation(); e.preventDefault(); } }} />
+                                        </div>;
+                                })}
+                                {this._visible ? this.selectionContainer : null}
+
+                                <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
+                                {this.audio}
+                            </div>
+                            <div className="current-time">
+                                {formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
+                            </div>
+                            <div className="total-time">
+                                {formatTime(Math.round(this.audioDuration))}
                             </div>
-                            {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) =>
-                                (!m.isLabel) ?
-                                    (this.layoutDoc.hideMarkers) ? (null) :
-                                        <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container1`} key={i}
-                                            title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
-                                            style={{
-                                                left: `${NumCast(m.audioStart) / this.audioDuration * 100}%`,
-                                                top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`,
-                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
-                                            }}
-                                            onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
-                                            <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
-                                            {markerDoc(m, this.rangeScript)}
-                                            <div className="resizer" onPointerDown={e => this.onPointerDown(e, m, false)}></div>
-                                        </div>
-                                    :
-                                    (this.layoutDoc.hideLabels) ? (null) :
-                                        <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={i}
-                                            style={{ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%` }}>
-                                            {markerDoc(m, this.labelScript)}
-                                        </div>
-                            )}
-                            {DocListCast(this.dataDoc.links).map((l, i) => {
-                                let { la1, la2, linkTime } = this.getLinkData(l);
-                                if (la2.audioStart && !la2.audioEnd) {
-                                    linkTime = NumCast(la2.audioStart);
-                                }
-
-                                return !linkTime ? (null) :
-                                    <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${linkTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}>
-                                        <DocumentView {...this.props}
-                                            Document={l}
-                                            NativeHeight={returnZero}
-                                            NativeWidth={returnZero}
-                                            rootSelected={returnFalse}
-                                            ContainingCollectionDoc={this.props.Document}
-                                            parentActive={returnTrue}
-                                            bringToFront={emptyFunction}
-                                            backgroundColor={returnTransparent}
-                                            ContentScaling={returnOne}
-                                            forcedBackgroundColor={returnTransparent}
-                                            pointerEvents={false}
-                                            LayoutTemplate={undefined}
-                                            LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)}
-                                        />
-                                        <div key={i} className={`audiobox-marker`} onPointerEnter={() => Doc.linkFollowHighlight(la1)}
-                                            onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
-                                    </div>;
-                            })}
-                            {this._visible ? this.selectionContainer : null}
-
-                            <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
-                            {this.audio}
-                        </div>
-                        <div className="current-time">
-                            {formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
-                        </div>
-                        <div className="total-time">
-                            {formatTime(Math.round(this.audioDuration))}
                         </div>
                     </div>
-                </div>
-            }
+                }</div>
         </div>;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From 1d2851b237fd41f8a8726244b095986699f513a5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 23:09:49 -0400
Subject: fixed playing audio on link follow when audio opens on right or in
 tab

---
 src/client/views/linking/LinkMenuItem.tsx | 9 ++++++++-
 src/client/views/nodes/AudioBox.tsx       | 4 +++-
 2 files changed, 11 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index b95fccf2a..21c666a4d 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -162,7 +162,14 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         }
 
         if (linkDoc.followLinkLocation && linkDoc.followLinkLocation !== "Default") {
-            this.props.addDocTab(this.props.destinationDoc, StrCast(linkDoc.followLinkLocation));
+            const annotationOn = this.props.destinationDoc.annotationOn as Doc;
+            this.props.addDocTab(annotationOn instanceof Doc ? annotationOn : this.props.destinationDoc, StrCast(linkDoc.followLinkLocation));
+            if (annotationOn) {
+                setTimeout(() => {
+                    const dv = DocumentManager.Instance.getFirstDocumentView(this.props.destinationDoc);
+                    dv?.props.focus(this.props.destinationDoc, false);
+                });
+            }
         } else {
             DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false);
         }
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 0ea624edf..d689aeadc 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -195,7 +195,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         let play;
         clearTimeout(play);
         this._duration = endTime - seekTimeInSeconds;
-        if (this._ele && AudioBox.Enabled) {
+        if (Number.isNaN(this._ele?.duration)) {
+            setTimeout(() => this.playFrom(seekTimeInSeconds, endTime), 500);
+        } else if (this._ele && AudioBox.Enabled) {
             if (seekTimeInSeconds < 0) {
                 if (seekTimeInSeconds > -1) {
                     setTimeout(() => this.playFrom(0), -seekTimeInSeconds * 1000);
-- 
cgit v1.2.3-70-g09d2


From b096129d54238bc4cea735cd2db8e5f3e94613b7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 9 Aug 2020 23:23:06 -0400
Subject: fixed playing audio links on select.

---
 src/client/views/nodes/AudioBox.tsx | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index d689aeadc..289388320 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -128,14 +128,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         // for play when link is selected
         this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
             selected => {
-                if (this.layoutDoc.playOnSelect) {
-                    const sel = selected.length ? selected[0].props.Document : undefined;
-                    const link = sel && DocListCast(this.dataDoc.links).forEach(l => (l.anchor1 === sel || l.anchor2 === sel) && this.playLink(l), false);
-                    // for links created during recording 
-                    if (!link) {
-                        this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
-                        this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
-                    }
+                const sel = selected.length ? selected[0].props.Document : undefined;
+                const link = sel && DocListCast(this.dataDoc.links).forEach(l => (l.anchor1 === sel || l.anchor2 === sel) && this.playLink(sel), false);
+                // for links created during recording 
+                if (!link) {
+                    this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
+                    this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
                 }
             });
         this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
-- 
cgit v1.2.3-70-g09d2

