diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 2 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.scss | 1 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 113 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 124 |
4 files changed, 172 insertions, 68 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 88f470576..402f3e82c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -628,7 +628,7 @@ export namespace Docs { } export function AudioDocument(url: string, options: DocumentOptions = {}) { - const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), { ...options }); // hideLinkButton: false, useLinkSmallAnchor: false, + const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), { useLinkSmallAnchor: true, ...options }); // hideLinkButton: false, useLinkSmallAnchor: false, Doc.GetProto(instance).backgroundColor = ComputedField.MakeFunction("this._audioState === 'playing' ? 'green':'gray'"); return instance; } diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 35ab5da8b..0ea4b37cb 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -148,6 +148,7 @@ width: 100%; height: 100%; overflow: hidden; + z-index: 0; } .audiobox-linker, diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 3d1932883..7c90547ef 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -75,6 +75,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD _markers: Array<any> = []; _first: boolean = false; _buckets: Array<number> = new Array(); + _count: Array<any> = []; private _isPointerDown = false; private _currMarker: any; @@ -516,53 +517,74 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD return false; } + markers = () => { + const increment = NumCast(this.layoutDoc.duration) / 500; + this._count = []; + for (let i = 0; i < 500; i++) { + this._count.push([increment * i, 0]) + } + + } + // Probably need a better way to format - isOverlap = (m: any, i: number) => { - console.log("called"); - let counter = 0; + // isOverlap = (m: any, i: number) => { + // console.log("called"); + // let counter = 0; + // if (this._first) { + // this._markers = []; + // this._first = false; + // } + // for (let i = 0; i < this._markers.length; i++) { + // if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) { + // counter++; + // console.log(counter); + // } + // } + + // if (this.dataDoc.markerAmount < counter) { + // this.dataDoc.markerAmount = counter; + // } + + // this._markers.push(m); + + // return counter; + // } + + isOverlap = (m: any) => { if (this._first) { - this._markers = []; this._first = false; - } - for (let i = 0; i < this._markers.length; i++) { - if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) { - counter++; - console.log(counter); - } + this.markers(); + console.log(this._count); } - if (this.dataDoc.markerAmount < counter) { - this.dataDoc.markerAmount = counter; - } - this._markers.push(m); + let max = 0 - return counter; - } + for (let i = 0; i < 500; i++) { + if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) { + this._count[i][1]++; - // isOverlap = (m: any) => { - // if (this._markers.length < 1) { - // this._markers = new Array(Math.round(this.dataDoc.duration)).fill(0); - // } - // console.log(this._markers); - // let max = 0 + if (this._count[i][1] > max) { + max = this._count[i][1]; + } + } - // for (let i = Math.round(m.audioStart); i <= Math.round(m.audioEnd); i++) { - // this._markers[i] = this._markers[i] + 1; - // console.log(this._markers[i]); - // if (this._markers[i] > max) { - // max = this._markers[i]; - // } - // } + } - // console.log(max); - // if (this.dataDoc.markerAmount < max) { - // this.dataDoc.markerAmount = max; - // } - // return max - // } + for (let i = 0; i < 500; i++) { + if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) { + this._count[i][1] = max; + } + + } + + if (this.dataDoc.markerAmount < max) { + this.dataDoc.markerAmount = max; + } + return max - 1 + } formatTime = (time: number) => { const hours = Math.floor(time / 60 / 60); @@ -609,6 +631,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD this._first = true; } + @computed get height() { + console.log(this.layoutDoc._height); + if (this.layoutDoc._height) { + return 0.8 * this.layoutDoc._height + } + } + render() { //trace(); const interactive = this.active() ? "-interactive" : ""; @@ -673,14 +702,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime); } }}> - <div className="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}> + <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}> {console.log(this.peaks)} <Waveform color={"#000000"} - height={20} + height={this.height} barWidth={0.1} pos={this.layoutDoc.currentTimecode} - duration={this.layoutDoc.duration} + duration={this.dataDoc.duration} peaks={this._buckets.length === 100 ? this._buckets : undefined} progressColor={"#0000ff"} /> </div> @@ -690,7 +719,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={`${this.formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${this.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 + 2) * 100}%`, top: `${this.isOverlap(m, i) * 1 / (this.dataDoc.markerAmount + 2) * 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={`${this.formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${this.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="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div> <DocumentView {...this.props} Document={m} @@ -700,7 +729,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD rootSelected={returnFalse} LayoutTemplate={undefined} ContainingCollectionDoc={this.props.Document} - removeDocument={undefined} + removeDocument={this.removeDocument} parentActive={returnTrue} onClick={this.layoutDoc.playOnClick ? this.rangeScript : undefined} ignoreAutoHeight={false} @@ -722,7 +751,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD rootSelected={returnFalse} LayoutTemplate={undefined} ContainingCollectionDoc={this.props.Document} - removeDocument={undefined} + removeDocument={this.removeDocument} parentActive={returnTrue} onClick={this.layoutDoc.playOnClick ? this.labelScript : undefined} ignoreAutoHeight={false} @@ -776,7 +805,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD {this.formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))} </div> <div className="total-time"> - {this.formatTime(Math.round(NumCast(this.layoutDoc.duration)))} + {this.formatTime(Math.round(NumCast(this.dataDoc.duration)))} </div> </div> </div> diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b1d9be73b..91940466f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { isEqual } from "lodash"; -import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap, selectAll } from "prosemirror-commands"; import { history } from "prosemirror-history"; @@ -93,6 +93,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _undoTyping?: UndoManager.Batch; private _disposers: { [name: string]: IReactionDisposer } = {}; private _dropDisposer?: DragManager.DragDropDisposer; + private _first: Boolean = true; + private _recordingStart: number = 0; + private _currentTime: number = 0; + private _linkTime: number | null = null; + private _pause: boolean = false; @computed get _recording() { return this.dataDoc.audioState === "recording"; } set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; } @@ -140,6 +145,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp super(props); FormattedTextBox.Instance = this; this.updateHighlights(); + this._recordingStart = Date.now(); + this.layoutDoc._timeStampOnEnter = true; } public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } @@ -197,9 +204,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } dispatchTransaction = (tx: Transaction) => { + let timeStamp; + clearTimeout(timeStamp); + console.log("hi"); if (this._editorView) { + const metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata); if (metadata) { + const range = tx.selection.$from.blockRange(tx.selection.$to); let text = range ? tx.doc.textBetween(range.start, range.end) : ""; let textEndSelection = tx.selection.to; @@ -221,6 +233,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.dataDoc[key] = value; } } + const state = this._editorView.state.apply(tx); this._editorView.updateState(state); (tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks); @@ -234,19 +247,33 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const json = JSON.stringify(state.toJSON()); let unchanged = true; const effectiveAcl = GetEffectiveAcl(this.dataDoc); + + if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) { this._applyingChange = true; (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))); if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) if (json.replace(/"selection":.*/, "") !== curLayout?.Data.replace(/"selection":.*/, "")) { + console.log("type"); + if (!this._pause && !this.layoutDoc._timeStampOnEnter) { + console.log("started"); + timeStamp = setTimeout(() => this.pause(), 10 * 1000); + } + + if (this._pause) { + this._pause = false; + this.insertTime(); + } !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize)); !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily)); this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText }); unchanged = false; + } + } else { // if we've deleted all the text in a note driven by a template, then restore the template data this.dataDoc[this.props.fieldKey] = undefined; this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data))); @@ -260,6 +287,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } } else { + const json = JSON.parse(Cast(this.dataDoc[this.fieldKey], RichTextField)?.Data!); json.selection = state.toJSON().selection; this._editorView.updateState(EditorState.fromJSON(this.config, json)); @@ -267,6 +295,66 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } + pause = () => this._pause = true; + + formatTime = (time: number) => { + const hours = Math.floor(time / 60 / 60); + const minutes = Math.floor(time / 60) - (hours * 60); + const seconds = time % 60; + + return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0'); + } + + insertTime = () => { + let linkTime; + if (this._first) { + this._first = false; + DocListCast(this.dataDoc.links).map((l, i) => { + let la1 = l.anchor1 as Doc; + let la2 = l.anchor2 as Doc; + this._linkTime = NumCast(l.anchor2_timecode); + if (Doc.AreProtosEqual(la2, this.dataDoc)) { + la1 = l.anchor2 as Doc; + la2 = l.anchor1 as Doc; + this._linkTime = NumCast(l.anchor1_timecode); + } + + }) + + + + } + this._currentTime = Date.now(); + let time; + console.log(this._linkTime); + this._linkTime ? time = this.formatTime(Math.round(this._linkTime + this._currentTime / 1000 - this._recordingStart / 1000)) : time = null; + + if (this._editorView) { + const state = this._editorView.state; + const now = Date.now(); + let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) }); + if (!this._break && state.selection.to !== state.selection.from) { + for (let i = state.selection.from; i <= state.selection.to; i++) { + const pos = state.doc.resolve(i); + const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark); + if (um) { + mark = um; + break; + } + } + } + if (time) { + let value = ""; + this._break = false; + value = this.layoutDoc._timeStampOnEnter ? "[" + time + "] " : "\n" + "[" + time + "] "; + console.log(value); + const from = state.selection.from; + const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark); + this._editorView.dispatch(this._editorView.state.tr.insertText(value)); + } + } + } + updateTitle = () => { if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) { @@ -501,6 +589,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp uicontrols.push({ description: `${this.layoutDoc._showSidebar ? "Hide" : "Show"} Sidebar`, event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" }); + uicontrols.push({ description: `Create TimeStamp When ${this.layoutDoc._timeStampOnEnter ? "Pause" : "Enter"}`, event: () => this.layoutDoc._timeStampOnEnter = !this.layoutDoc._timeStampOnEnter, icon: "expand-arrows-alt" }); !Doc.UserDoc().noviceMode && uicontrols.push({ description: "Broadcast Message", event: () => DocServer.GetRefField("rtfProto").then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt" @@ -594,6 +683,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime(); this._break = false; value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000 + value; + console.log(value); const from = state.selection.from; const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark); this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1))); @@ -1295,30 +1385,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } e.stopPropagation(); if (e.key === "Tab" || e.key === "Enter") { - // console.log(this._recording); - // if (this._editorView) { - // const state = this._editorView.state; - // const now = Date.now(); - // let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) }); - // if (!this._break && state.selection.to !== state.selection.from) { - // for (let i = state.selection.from; i <= state.selection.to; i++) { - // const pos = state.doc.resolve(i); - // const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark); - // if (um) { - // mark = um; - // break; - // } - // } - // } - // const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime(); - // this._break = false; - // let value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000; - // //let value = "[0:02]"; - // const from = state.selection.from; - // const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark); - - // this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1))); - // } + if (e.key === "Enter" && this.layoutDoc._timeStampOnEnter) { + this.insertTime(); + } e.preventDefault(); } if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) { @@ -1371,6 +1440,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } render() { TraceMobx(); + trace(); + // if (this.props.Document.recordingStart) { + // console.log(DateCast(this.props.Document.recordingStart).date.getTime()); + // } + const scale = this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground; |