aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/FormattedTextBox.tsx
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-03-05 22:20:52 -0500
committerBob Zeleznik <zzzman@gmail.com>2020-03-05 22:20:52 -0500
commitb667ac18c58cd022219bec091e59977107b5bd7d (patch)
treebf79b3ad5fa5c3ebd89383b1c7cc50e846697900 /src/client/views/nodes/FormattedTextBox.tsx
parent45643918180f32f070f8d9f770c446b70c08548d (diff)
parent288e4d24b61d281819b7f0b5bb697edbcc9ed173 (diff)
Merge branch 'master' into audio_refactor
Diffstat (limited to 'src/client/views/nodes/FormattedTextBox.tsx')
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx93
1 files changed, 62 insertions, 31 deletions
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ad804209b..f18183600 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -20,7 +20,7 @@ import { InkTool } from '../../../new_fields/InkField';
import { RichTextField } from "../../../new_fields/RichTextField";
import { RichTextUtils } from '../../../new_fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
import { TraceMobx } from '../../../new_fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils } from '../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
@@ -82,6 +82,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
private _lastY = 0;
private _undoTyping?: UndoManager.Batch;
private _searchReactionDisposer?: Lambda;
+ private _recordReactionDisposer: Opt<IReactionDisposer>;
private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>;
private _reactionDisposer: Opt<IReactionDisposer>;
private _heightReactionDisposer: Opt<IReactionDisposer>;
@@ -92,6 +93,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
private _scrollDisposer: Opt<IReactionDisposer>;
private dropDisposer?: DragManager.DragDropDisposer;
+ @computed get _recording() { return this.dataDoc.audioState === "recording"; }
+ set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
+
@observable private _entered = false;
public static FocusedBox: FormattedTextBox | undefined;
@@ -150,7 +154,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500 }, value);
DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument);
if (linkDoc) { (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc; }
- else DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: this.dataDoc[key] as Doc }, "Ref:" + value, "link to named target", id);
+ else DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: this.dataDoc[key] as Doc }, "link to named target", id);
});
});
});
@@ -186,7 +190,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
(tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks);
const tsel = this._editorView.state.selection.$from;
- tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000)));
+ tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000)));
const curText = state.doc.textBetween(0, state.doc.content.size, "\n\n");
const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField);
if (!this._applyingChange) {
@@ -207,7 +211,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
updateTitle = () => {
- if ((this.props.Document.isTemplateForField === "data" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
+ 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.Document.customTitle) {
const str = this._editorView.state.doc.textContent;
const titlestr = str.substr(0, Math.min(40, str.length));
@@ -387,7 +391,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
!this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, icon: "eye" });
funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
- funcs.push({ description: "Record Bullet", event: () => this.recordBullet(), icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" });
["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
funcs.push({
@@ -405,12 +409,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: funcs, icon: "asterisk" });
}
- @observable _recording = false;
-
recordDictation = () => {
- //this._editorView!.focus();
- if (this._recording) return;
- runInAction(() => this._recording = true);
DictationManager.Controls.listen({
interimHandler: this.setCurrentBulletContent,
continuous: { indefinite: false },
@@ -418,13 +417,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (results && [DictationManager.Controls.Infringed].includes(results)) {
DictationManager.Controls.stop();
}
- this._editorView!.focus();
+ //this._editorView!.focus();
});
}
- stopDictation = (abort: boolean) => {
- runInAction(() => this._recording = false);
- DictationManager.Controls.stop(!abort);
- }
+ stopDictation = (abort: boolean) => { DictationManager.Controls.stop(!abort); }
@action
toggleMenubar = () => {
@@ -449,12 +445,28 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
setCurrentBulletContent = (value: string) => {
if (this._editorView) {
let state = this._editorView.state;
+ let now = Date.now();
+ if (NumCast(this.props.Document.recordingStart, -1) === 0) {
+ this.props.Document.recordingStart = now = AudioBox.START;
+ }
+ console.log("NOW = " + (now - AudioBox.START) / 1000);
+ 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;
+ }
+ }
+ }
+ this._break = false;
+ console.log("start = " + (mark.attrs.modified * 1000 - AudioBox.START) / 1000);
+ value = "" + (mark.attrs.modified * 1000 - AudioBox.START) / 1000 + value;
const from = state.selection.from;
- const to = state.selection.to;
- this._editorView.dispatch(state.tr.insertText(value, from, to));
- state = this._editorView.state;
- const updated = TextSelection.create(state.doc, from, from + value.length);
- this._editorView.dispatch(state.tr.setSelection(updated));
+ 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)));
}
}
@@ -558,6 +570,17 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
{ fireImmediately: true });
+ this._recordReactionDisposer = reaction(() => this._recording,
+ () => {
+ if (this._recording) {
+ setTimeout(action(() => {
+ this.stopDictation(true);
+ setTimeout(() => this.recordDictation(), 500);
+ }), 500);
+ } else setTimeout(() => this.stopDictation(true), 0);
+ }
+ );
+
this._scrollToRegionReactionDisposer = reaction(
() => StrCast(this.layoutDoc.scrollToLinkID),
async (scrollToLinkID) => {
@@ -723,7 +746,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
targetAnnotations?.push(pdfRegion);
});
- const link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "note on " + pdfDoc.title, "pasted PDF link");
+ const link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "PDF pasted");
if (link) {
cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
const linkId = link[Id];
@@ -807,7 +830,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
(selectOnLoad /* || !rtfField?.Text*/) && this._editorView!.focus();
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
- this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.round(Date.now() / 1000 / 5) })];
+ this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
}
getFont(font: string) {
switch (font) {
@@ -831,6 +854,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this._pullReactionDisposer?.();
this._heightReactionDisposer?.();
this._searchReactionDisposer?.();
+ this._recordReactionDisposer?.();
this._buttonBarReactionDisposer?.();
this._editorView?.destroy();
}
@@ -838,7 +862,19 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
static _downEvent: any;
_downX = 0;
_downY = 0;
+ _break = false;
onPointerDown = (e: React.PointerEvent): void => {
+ if (this._recording && !e.ctrlKey && e.button === 0) {
+ this.stopDictation(true);
+ this._break = true;
+ let state = this._editorView!.state;
+ const to = state.selection.to;
+ const updated = TextSelection.create(state.doc, to, to);
+ this._editorView!.dispatch(this._editorView!.state.tr.setSelection(updated).insertText("\n", to));
+ e.preventDefault();
+ e.stopPropagation();
+ if (this._recording) setTimeout(() => this.recordDictation(), 500);
+ }
this._downX = e.clientX;
this._downY = e.clientY;
this.doLinkOnDeselect();
@@ -955,7 +991,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.props.select(e.ctrlKey);
this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false);
}
- if (this._recording) setTimeout(() => { this.stopDictation(true); setTimeout(() => this.recordDictation(), 500); }, 500);
}
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
@@ -1016,7 +1051,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
richTextMenuPlugin() {
return new Plugin({
view(newView) {
- RichTextMenu.Instance.changeView(newView);
+ RichTextMenu.Instance && RichTextMenu.Instance.changeView(newView);
return RichTextMenu.Instance;
}
});
@@ -1062,17 +1097,13 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (e.key === "Tab" || e.key === "Enter") {
e.preventDefault();
}
- const mark = e.key !== " " && this._lastTimedMark ? this._lastTimedMark : schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.round(Date.now() / 1000 / 5) });
+ const mark = e.key !== " " && this._lastTimedMark ? this._lastTimedMark : schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
this._lastTimedMark = mark;
this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark));
if (!this._undoTyping) {
this._undoTyping = UndoManager.StartBatch("undoTyping");
}
- if (this._recording) {
- this.stopDictation(true);
- setTimeout(() => this.recordDictation(), 250);
- }
}
onscrolled = (ev: React.UIEvent) => {
@@ -1169,8 +1200,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
</div>}
{!this.props.Document._showAudio ? (null) :
<div className="formattedTextBox-dictation"
- onClick={e => {
- this._recording ? this.stopDictation(true) : this.recordDictation();
+ onPointerDown={e => {
+ runInAction(() => this._recording = !this._recording);
setTimeout(() => this._editorView!.focus(), 500);
e.stopPropagation();
}} >