aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2019-10-22 14:20:16 -0400
committerBob Zeleznik <zzzman@gmail.com>2019-10-22 14:20:16 -0400
commit0206517bbf09c10b8f3926c7ea133fa4c0263a3a (patch)
tree278a2cdee0ce8da1369cca0ff668940291bcafc3 /src
parent79476255d05e0bd7c24e46267507769800c547f8 (diff)
using links to trigger audio playback.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/AudioBox.tsx80
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
4 files changed, 59 insertions, 29 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b1406d5e1..fd2009dd6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -334,6 +334,10 @@ export namespace Docs {
let dataDoc = MakeDataDelegate(proto, protoProps, data);
let viewDoc = Doc.MakeDelegate(dataDoc, delegId);
+ AudioBox.ActiveRecordings.map(d => {
+ DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title);
+ })
+
return Doc.assign(viewDoc, delegateProps);
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d7350fe1a..f6518a01d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -263,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
onPointerDown = (e: React.PointerEvent): void => {
if (e.nativeEvent.cancelBubble) return;
this._hitCluster = this.props.Document.useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false;
- if (e.button === 0 && !e.shiftKey && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1) && this.props.active()) {
+ if (e.button === 0 && !e.shiftKey && !e.altKey && !e.ctrlKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1) && this.props.active()) {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 5f5202f65..85607c6b8 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -9,12 +9,13 @@ import { makeInterface, createSchema } from "../../../new_fields/Schema";
import { documentSchema } from "../../../new_fields/documentSchemas";
import { Utils } from "../../../Utils";
import { RouteStore } from "../../../server/RouteStore";
-import { runInAction, observable, reaction, IReactionDisposer, computed } from "mobx";
+import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
import { DateField } from "../../../new_fields/DateField";
import { SelectionManager } from "../../util/SelectionManager";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
import { ContextMenuProps } from "../ContextMenuItem";
import { ContextMenu } from "../ContextMenu";
+import { Id } from "../../../new_fields/FieldSymbols";
interface Window {
MediaRecorder: MediaRecorder;
@@ -33,41 +34,60 @@ const AudioDocument = makeInterface(documentSchema, audioSchema);
@observer
export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocument>(AudioDocument) {
- _reactionDisposer: IReactionDisposer | undefined;
- @observable private _audioState = 0;
-
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); }
+
+ _linkPlayDisposer: IReactionDisposer | undefined;
+ _reactionDisposer: IReactionDisposer | undefined;
_ref = React.createRef<HTMLAudioElement>();
+ _recorder: any;
+
+ @observable private _audioState = 0;
+ public static ActiveRecordings: Doc[] = [];
componentDidMount() {
runInAction(() => this._audioState = this.path ? 2 : 0);
+ this._linkPlayDisposer = reaction(() => this.layoutDoc.scrollToLinkID,
+ scrollLinkId => {
+ scrollLinkId && DocListCast(this.dataDoc.links).map(l => {
+ const la1 = l.anchor1 as Doc;
+ const la2 = l.anchor2 as Doc;
+ if (l[Id] === scrollLinkId && la1 && la2) {
+ setTimeout(() => this.playFrom(Doc.AreProtosEqual(la1, this.dataDoc) ? la2 : la1), 250);
+ }
+ });
+ scrollLinkId && (this.layoutDoc.scrollLinkID = undefined);
+ }, { fireImmediately: true });
this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
selected => {
let sel = selected.length ? selected[0].props.Document : undefined;
- const extensionDoc = this.extensionDoc;
- let start = extensionDoc && DateCast(extensionDoc.recordingStart);
- let seek = sel && DateCast(sel.creationDate)
- if (this._ref.current && start && seek) {
- if (this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document)) {
- let delta = (seek.date.getTime() - start.date.getTime()) / 1000;
- if (start && seek && delta > 0 && delta < this._ref.current.duration) {
- this._ref.current.currentTime = delta;
- this._ref.current.play();
- } else {
- this._ref.current.pause();
- }
- } else {
- this._ref.current.pause();
- }
- }
+ this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(sel);
});
}
+ playFrom = (sel: Doc) => {
+ const extensionDoc = this.extensionDoc;
+ let start = extensionDoc && DateCast(extensionDoc.recordingStart);
+ let seek = sel && DateCast(sel.creationDate)
+ if (this._ref.current && start && seek) {
+ if (sel) {
+ let delta = (seek.date.getTime() - start.date.getTime()) / 1000;
+ if (start && seek && delta > 0 && delta < this._ref.current.duration) {
+ this._ref.current.currentTime = delta;
+ this._ref.current.play();
+ } else {
+ this._ref.current.pause();
+ }
+ } else {
+ this._ref.current.pause();
+ }
+ }
+ }
+
componentWillUnmount() {
this._reactionDisposer && this._reactionDisposer();
+ this._linkPlayDisposer && this._linkPlayDisposer();
}
- _recorder: any;
recordAudioAnnotation = () => {
let gumStream: any;
let self = this;
@@ -78,6 +98,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
gumStream = stream;
self._recorder = new MediaRecorder(stream);
extensionDoc.recordingStart = new DateField(new Date());
+ AudioBox.ActiveRecordings.push(self.props.Document);
self._recorder.ondataavailable = async function (e: any) {
const formData = new FormData();
formData.append("file", e.data);
@@ -93,8 +114,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
runInAction(() => self._audioState = 1);
self._recorder.start();
setTimeout(() => {
- self._recorder.stop();
- runInAction(() => self._audioState = 2);
+ self.stopRecording();
gumStream.getAudioTracks()[0].stop();
}, 60 * 60 * 1000); // stop after an hour?
});
@@ -107,11 +127,17 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
ContextMenu.Instance.addItem({ description: "Audio Funcs...", subitems: funcs, icon: "asterisk" });
}
+ stopRecording = action(() => {
+ this._recorder.stop();
+ this._audioState = 2;
+ let ind = AudioBox.ActiveRecordings.indexOf(this.props.Document);
+ ind !== -1 && (AudioBox.ActiveRecordings.splice(ind, 1));
+ })
+
recordClick = (e: React.MouseEvent) => {
- if (e.button === 0) {
+ if (e.button === 0 && !e.ctrlKey) {
if (this._recorder) {
- this._recorder.stop();
- runInAction(() => this._audioState = 2);
+ this.stopRecording();
} else {
this.recordAudioAnnotation();
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 05080b824..67c85e158 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -218,7 +218,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this._hitTemplateDrag = true;
}
}
- if ((this.active || this.Document.onDragStart || this.Document.onClick) && e.button === 0 && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag);
+ if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && e.button === 0 && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag);
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);