aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/views/linking/LinkEditor.tsx6
-rw-r--r--src/client/views/nodes/AudioBox.scss5
-rw-r--r--src/client/views/nodes/AudioBox.tsx256
4 files changed, 140 insertions, 129 deletions
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>;
}
}