aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-08-21 05:29:07 -0400
committerSam Wilkins <samwilkins333@gmail.com>2019-08-21 05:29:07 -0400
commitd260d9abc13ae60c3206c3110f2d7f23ceeb2449 (patch)
treeb0db3d59f0e43e848ecac28067fd046817135b00 /src
parent8fa3c03f1fae853e3c626e748aef76f9b7bbc875 (diff)
prosemirror bulleted list dictation integration
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DictationManager.ts48
-rw-r--r--src/client/views/DocumentDecorations.tsx3
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx76
3 files changed, 93 insertions, 34 deletions
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 758482eae..781e5e465 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -45,7 +45,7 @@ export namespace DictationManager {
export namespace Controls {
- const infringe = "unable to process: dictation manager still involved in previous session";
+ export const Infringed = "unable to process: dictation manager still involved in previous session";
const intraSession = ". ";
const interSession = " ... ";
@@ -69,30 +69,32 @@ export namespace DictationManager {
delimiters: DelimiterArgs;
interimHandler: InterimResultHandler;
tryExecute: boolean;
+ terminators: string[];
}
export const listen = async (options?: Partial<ListeningOptions>) => {
let results: string | undefined;
- let main = MainView.Instance;
+ // let main = MainView.Instance;
- main.dictationOverlayVisible = true;
- main.isListening = { interim: false };
+ // main.dictationOverlayVisible = true;
+ // main.isListening = { interim: false };
try {
results = await listenImpl(options);
if (results) {
Utils.CopyText(results);
- main.isListening = false;
- let execute = options && options.tryExecute;
- main.dictatedPhrase = execute ? results.toLowerCase() : results;
- main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+ // main.isListening = false;
+ // let execute = options && options.tryExecute;
+ // main.dictatedPhrase = execute ? results.toLowerCase() : results;
+ // main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+ options && options.tryExecute && await DictationManager.Commands.execute(results);
}
} catch (e) {
- main.isListening = false;
- main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
- main.dictationSuccess = false;
+ // main.isListening = false;
+ // main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
+ // main.dictationSuccess = false;
} finally {
- main.initiateDictationFade();
+ // main.initiateDictationFade();
}
return results;
@@ -100,7 +102,7 @@ export namespace DictationManager {
const listenImpl = (options?: Partial<ListeningOptions>) => {
if (isListening) {
- return infringe;
+ return Infringed;
}
isListening = true;
@@ -128,6 +130,12 @@ export namespace DictationManager {
recognizer.onresult = (e: SpeechRecognitionEvent) => {
current = synthesize(e, intra);
+ let matchedTerminator: string | undefined;
+ if (options && options.terminators && (matchedTerminator = options.terminators.find(end => current ? current.trim().toLowerCase().endsWith(end.toLowerCase()) : false))) {
+ current = matchedTerminator;
+ recognizer.abort();
+ return complete();
+ }
handler && handler(current);
isManuallyStopped && complete();
};
@@ -163,13 +171,13 @@ export namespace DictationManager {
}
isManuallyStopped = true;
salvageSession ? recognizer.stop() : recognizer.abort();
- let main = MainView.Instance;
- if (main.dictationOverlayVisible) {
- main.cancelDictationFade();
- main.dictationOverlayVisible = false;
- main.dictationSuccess = undefined;
- setTimeout(() => main.dictatedPhrase = placeholder, 500);
- }
+ // let main = MainView.Instance;
+ // if (main.dictationOverlayVisible) {
+ // main.cancelDictationFade();
+ // main.dictationOverlayVisible = false;
+ // main.dictationSuccess = undefined;
+ // setTimeout(() => main.dictatedPhrase = placeholder, 500);
+ // }
};
const synthesize = (e: SpeechRecognitionEvent, delimiter?: string) => {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 891fd7847..cc8e57af9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -730,7 +730,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
onPointerEnter={e => e.ctrlKey && runInAction(() => this.openHover = true)}
onPointerLeave={() => runInAction(() => this.openHover = false)}
onClick={e => {
- if (e.ctrlKey) {
+ if (e.altKey) {
+ e.preventDefault();
window.open(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`);
} else {
this.clearPullColor();
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e460e3e50..222ebed8f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -6,7 +6,7 @@ import { baseKeymap } from "prosemirror-commands";
import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
-import { EditorState, Plugin, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../new_fields/DateField';
import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
@@ -36,6 +36,7 @@ import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/Goog
import { DocumentDecorations } from '../DocumentDecorations';
import { MainOverlayTextBox } from '../MainOverlayTextBox';
import { DictationManager } from '../../util/DictationManager';
+import { ReplaceStep } from 'prosemirror-transform';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -181,6 +182,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
const marks = tx.storedMarks;
if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
}
+
this._applyingChange = true;
const fieldkey = "preview";
if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
@@ -268,23 +270,70 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
setCurrentBulletContent = (value: string) => {
if (this._editorView) {
- this._editorView.state;
+ // let next = value.endsWith("bullet");
+ // if (next) {
+ // value = value.split("bullet")[0];
+ // }
+ let state = this._editorView.state;
+ let from = state.selection.from;
+ let to = state.selection.to;
+ this._editorView.dispatch(state.tr.insertText(value, from, to));
+ state = this._editorView.state;
+ let updated = TextSelection.create(state.doc, from, from + value.length);
+ this._editorView.dispatch(state.tr.setSelection(updated));
+ // if (next) {
+ // this.nextBullet(this._editorView.state.selection.to);
+ // }
}
}
- considerRecordingSession = (e: KeyboardEvent) => {
- if (e.which === 82 && e.altKey) {
- let continuous = { indefinite: true };
- DictationManager.Controls.listen({
- interimHandler: this.setCurrentBulletContent,
- continuous
- });
+ nextBullet = (pos: number) => {
+ if (this._editorView) {
+ // DictationManager.Controls.stop(false);
+ let frag = Fragment.fromArray(this.newListItems(2));
+ let slice = new Slice(frag, 2, 2);
+ let state = this._editorView.state;
+ this._editorView.dispatch(state.tr.step(new ReplaceStep(pos, pos, slice)));
+ pos += 4;
+ state = this._editorView.state;
+ this._editorView.dispatch(state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos, pos)));
+ // this.recordSession();
+ }
+ }
+
+ private newListItems = (count: number) => {
+ let listItems: any[] = [];
+ for (let i = 0; i < count; i++) {
+ listItems.push(schema.nodes.list_item.create(null, schema.nodes.paragraph.create(null)));
}
+ return listItems;
+ }
+
+ recordSession = async () => {
+ let completedCue = "end session";
+ let results = await DictationManager.Controls.listen({
+ interimHandler: this.setCurrentBulletContent,
+ continuous: { indefinite: false },
+ terminators: [completedCue, "bullet", "next"]
+ });
+ if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
+ DictationManager.Controls.stop();
+ return;
+ }
+ this.nextBullet(this._editorView!.state.selection.to);
+ setTimeout(this.recordSession, 2000);
+ }
+
+ recordKeyHandler = (e: KeyboardEvent) => {
+ if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
+ return;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ e.which === 174 && e.altKey && this.recordSession();
}
componentDidMount() {
- document.removeEventListener("keypress", this.considerRecordingSession);
- document.addEventListener("keypress", this.considerRecordingSession);
const config = {
schema,
inpRules, //these currently don't do anything, but could eventually be helpful
@@ -335,7 +384,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
updatedState.selection = { type: "text", anchor: end, head: end };
this._editorView.updateState(EditorState.fromJSON(config, updatedState));
}
- this.tryUpdateHeight();
}
}
);
@@ -595,7 +643,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
componentWillUnmount() {
- document.removeEventListener("keypress", this.considerRecordingSession);
this._editorView && this._editorView.destroy();
this._reactionDisposer && this._reactionDisposer();
this._proxyReactionDisposer && this._proxyReactionDisposer();
@@ -678,6 +725,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
@action
onFocused = (e: React.FocusEvent): void => {
+ document.removeEventListener("keypress", this.recordKeyHandler);
+ document.addEventListener("keypress", this.recordKeyHandler);
if (!this.props.isOverlay) {
FormattedTextBox.InputBoxOverlay = this;
} else {
@@ -727,6 +776,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
});
}
onBlur = (e: any) => {
+ document.removeEventListener("keypress", this.recordKeyHandler);
if (this._undoTyping) {
this._undoTyping.end();
this._undoTyping = undefined;