aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/FormattedTextBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/FormattedTextBox.tsx')
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx346
1 files changed, 200 insertions, 146 deletions
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index b05d0046c..31919f192 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,7 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
import _ 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 } from "prosemirror-commands";
import { history } from "prosemirror-history";
@@ -17,14 +17,13 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols';
import { RichTextField } from "../../../new_fields/RichTextField";
import { RichTextUtils } from '../../../new_fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../new_fields/Schema";
-import { Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types";
-import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules } from '../../../Utils';
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnOne } from '../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
import { DocServer } from "../../DocServer";
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DictationManager } from '../../util/DictationManager';
-import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from "../../util/DragManager";
import buildKeymap from "../../util/ProsemirrorExampleTransfer";
import { inpRules } from "../../util/RichTextRules";
@@ -33,7 +32,7 @@ import { SelectionManager } from "../../util/SelectionManager";
import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
import { TooltipTextMenu } from "../../util/TooltipTextMenu";
import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { DocComponent } from "../DocComponent";
+import { DocAnnotatableComponent } from "../DocComponent";
import { DocumentButtonBar } from '../DocumentButtonBar';
import { DocumentDecorations } from '../DocumentDecorations';
import { InkingControl } from "../InkingControl";
@@ -43,7 +42,11 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format
import React = require("react");
import { ContextMenuProps } from '../ContextMenuItem';
import { ContextMenu } from '../ContextMenu';
-import { TextShadowProperty } from 'csstype';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+import { AudioBox } from './AudioBox';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
+import { InkTool } from '../../../new_fields/InkField';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -62,19 +65,17 @@ const richTextSchema = createSchema({
export const GoogleRef = "googleDocId";
-type RichTextDocument = makeInterface<[typeof richTextSchema]>;
-const RichTextDocument = makeInterface(richTextSchema);
+type RichTextDocument = makeInterface<[typeof richTextSchema, typeof documentSchema]>;
+const RichTextDocument = makeInterface(richTextSchema, documentSchema);
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@observer
-export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
- public static LayoutString(fieldStr: string = "data") {
- return FieldView.LayoutString(FormattedTextBox, fieldStr);
- }
+export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
+ public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
public static Instance: FormattedTextBox;
- private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
+ public static ToolTipTextMenu: TooltipTextMenu | undefined = undefined;
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _proseRef?: HTMLDivElement;
private _editorView: Opt<EditorView>;
@@ -85,7 +86,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
private _searchReactionDisposer?: Lambda;
private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>;
private _reactionDisposer: Opt<IReactionDisposer>;
- private _textReactionDisposer: Opt<IReactionDisposer>;
private _heightReactionDisposer: Opt<IReactionDisposer>;
private _rulesReactionDisposer: Opt<IReactionDisposer>;
private _proxyReactionDisposer: Opt<IReactionDisposer>;
@@ -93,8 +93,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
private _pushReactionDisposer: Opt<IReactionDisposer>;
private dropDisposer?: DragManager.DragDropDisposer;
- @observable private _fontSize = 13;
- @observable private _fontFamily = "Arial";
+ @observable private _ruleFontSize = 0;
+ @observable private _ruleFontFamily = "Arial";
@observable private _fontAlign = "";
@observable private _entered = false;
public static SelectOnLoad = "";
@@ -120,7 +120,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
public static getToolTip(ev: EditorView) {
- return this._toolTipTextMenu ? this._toolTipTextMenu : this._toolTipTextMenu = new TooltipTextMenu(ev);
+ return this.ToolTipTextMenu ? this.ToolTipTextMenu : this.ToolTipTextMenu = new TooltipTextMenu(ev);
}
@undoBatch
@@ -128,24 +128,20 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let view = this._editorView!;
if (view.state.selection.from === view.state.selection.to) return false;
if (view.state.selection.to - view.state.selection.from > view.state.doc.nodeSize - 3) {
- this.props.Document.color = color;
+ this.layoutDoc.color = color;
}
let colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color: color });
view.dispatch(view.state.tr.addMark(view.state.selection.from, view.state.selection.to, colorMark));
return true;
}
- constructor(props: FieldViewProps) {
+ constructor(props: any) {
super(props);
FormattedTextBox.Instance = this;
}
public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
- @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); }
-
- @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
-
linkOnDeselect: Map<string, string> = new Map();
doLinkOnDeselect() {
@@ -191,14 +187,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- if (state.selection.empty && FormattedTextBox._toolTipTextMenu && tx.storedMarks) {
- FormattedTextBox._toolTipTextMenu.mark_key_pressed(tx.storedMarks);
- }
+ let 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)));
this._applyingChange = true;
- this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"));
this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now())));
- this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
+ this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), state.doc.textBetween(0, state.doc.content.size, "\n\n"));
this._applyingChange = false;
this.updateTitle();
this.tryUpdateHeight();
@@ -250,42 +244,42 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
@undoBatch
@action
drop = async (e: Event, de: DragManager.DropEvent) => {
- // We're dealing with a link to a document
- if (de.data instanceof DragManager.EmbedDragData) {
- let target = de.data.embeddableSourceDoc;
- // We're dealing with an internal document drop
- const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "ImgRef:" + target.title);
- let alias = Doc.MakeAlias(target);
- alias.fitToBox = true;
- let node = schema.nodes.dashDoc.create({
- width: target[WidthSym](), height: target[HeightSym](),
- title: "dashDoc", docid: alias[Id],
- float: "right"
- });
- let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y });
- link && this._editorView!.dispatch(this._editorView!.state.tr.insert(pos!.pos, node));
- this.tryUpdateHeight();
- e.stopPropagation();
- } else if (de.data instanceof DragManager.DocumentDragData) {
+ if (de.data instanceof DragManager.DocumentDragData) {
const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0];
- if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) {
- if (de.mods === "AltKey") {
- if (draggedDoc.data instanceof RichTextField) {
- Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data);
- e.stopPropagation();
- }
- } else if (de.mods === "CtrlKey") {
- draggedDoc.isTemplate = true;
- if (typeof (draggedDoc.layout) === "string") {
- let layoutDelegateToOverrideFieldKey = Doc.MakeDelegate(draggedDoc);
- layoutDelegateToOverrideFieldKey.layout = StrCast(layoutDelegateToOverrideFieldKey.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${this.props.fieldKey}"}`);
- this.props.Document.layout = layoutDelegateToOverrideFieldKey;
- } else {
- this.props.Document.layout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc;
- }
+ // replace text contents whend dragging with Alt
+ if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "AltKey") {
+ if (draggedDoc.data instanceof RichTextField) {
+ Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
+ e.stopPropagation();
+ }
+ // apply as template when dragging with Meta
+ } else if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "MetaKey") {
+ draggedDoc.isTemplateDoc = true;
+ let newLayout = Doc.Layout(draggedDoc);
+ if (typeof (draggedDoc.layout) === "string") {
+ newLayout = Doc.MakeDelegate(draggedDoc);
+ newLayout.layout = StrCast(newLayout.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${this.props.fieldKey}"}`);
}
+ this.Document.layoutCustom = newLayout;
+ this.Document.layoutKey = "layoutCustom";
e.stopPropagation();
- }
+ // embed document when dragging with a userDropAction or an embedDoc flag set
+ } else if (de.data.userDropAction || de.data.embedDoc) {
+ let target = de.data.droppedDocuments[0];
+ const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "Embedded Doc:" + target.title);
+ if (link) {
+ target.fitToBox = true;
+ let node = schema.nodes.dashDoc.create({
+ width: target[WidthSym](), height: target[HeightSym](),
+ title: "dashDoc", docid: target[Id],
+ float: "right"
+ });
+ let view = this._editorView!;
+ view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
+ this.tryUpdateHeight();
+ e.stopPropagation();
+ }
+ } // otherwise, fall through to outer collection to handle drop
}
}
@@ -295,6 +289,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
if (context === node) return { from: offset, to: offset + node.nodeSize };
if (node.isBlock) {
+ // tslint:disable-next-line: prefer-for-of
for (let i = 0; i < (context.content as any).content.length; i++) {
let result = this.getNodeEndpoints((context.content as any).content[i], node);
if (result) {
@@ -365,7 +360,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
specificContextMenu = (e: React.MouseEvent): void => {
let funcs: ContextMenuProps[] = [];
- funcs.push({ description: "Dictate", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"; }, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, 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({
description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
@@ -382,6 +378,27 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
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 },
+ }).then(results => {
+ if (results && [DictationManager.Controls.Infringed].includes(results)) {
+ DictationManager.Controls.stop();
+ }
+ this._editorView!.focus();
+ });
+ }
+ stopDictation = (abort: boolean) => {
+ runInAction(() => this._recording = false);
+ DictationManager.Controls.stop(!abort);
+ }
+
recordBullet = async () => {
let completedCue = "end session";
let results = await DictationManager.Controls.listen({
@@ -490,26 +507,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
);
this._heightReactionDisposer = reaction(
- () => this.props.Document[WidthSym](),
+ () => [this.layoutDoc[WidthSym](), this.layoutDoc.autoHeight],
() => this.tryUpdateHeight()
);
- this._textReactionDisposer = reaction(
- () => this.extensionDoc,
- () => {
- if (this.dataDoc.text || this.dataDoc.lastModified) {
- this.extensionDoc.text = this.dataDoc.text;
- this.extensionDoc.lastModified = DateCast(this.dataDoc.lastModified)[Copy]();
- this.dataDoc.text = undefined;
- this.dataDoc.lastModified = undefined;
- }
- }, { fireImmediately: true });
-
this.setupEditor(this.config, this.dataDoc, this.props.fieldKey);
this._searchReactionDisposer = reaction(() => {
- return StrCast(this.props.Document.search_string);
+ return StrCast(this.layoutDoc.search_string);
}, searchString => {
if (searchString) {
this.highlightSearchTerms([searchString]);
@@ -522,7 +528,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._rulesReactionDisposer = reaction(() => {
let ruleProvider = this.props.ruleProvider;
- let heading = NumCast(this.props.Document.heading);
+ let heading = NumCast(this.layoutDoc.heading);
if (ruleProvider instanceof Doc) {
return {
align: StrCast(ruleProvider["ruleAlign_" + heading], ""),
@@ -533,8 +539,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
return undefined;
},
action((rules: any) => {
- this._fontFamily = rules ? rules.font : "Arial";
- this._fontSize = rules ? rules.size : NumCast(this.props.Document.fontSize, 13);
+ this._ruleFontFamily = rules ? rules.font : "Arial";
+ this._ruleFontSize = rules ? rules.size : 0;
rules && setTimeout(() => {
const view = this._editorView!;
if (this._proseRef) {
@@ -551,7 +557,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}), { fireImmediately: true }
);
this._scrollToRegionReactionDisposer = reaction(
- () => StrCast(this.props.Document.scrollToLinkID),
+ () => StrCast(this.layoutDoc.scrollToLinkID),
async (scrollToLinkID) => {
let findLinkFrag = (frag: Fragment, editor: EditorView) => {
const nodes: Node[] = [];
@@ -589,7 +595,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0);
setTimeout(() => this.unhighlightSearchTerms(), 2000);
}
- this.props.Document.scrollToLinkID = undefined;
+ Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
}
},
@@ -706,8 +712,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
DocServer.GetRefField(pdfRegionId).then(pdfRegion => {
if ((pdfDoc instanceof Doc) && (pdfRegion instanceof Doc)) {
setTimeout(async () => {
- let targetAnnotations = await DocListCastAsync(Doc.fieldExtensionDoc(pdfDoc, "data").annotations);// bcz: NO... this assumes the pdf is using its 'data' field. need to have the PDF's view handle updating its own annotations
- targetAnnotations && targetAnnotations.push(pdfRegion);
+ const extension = Doc.fieldExtensionDoc(pdfDoc, "data");
+ if (extension) {
+ let targetAnnotations = await DocListCastAsync(extension.annotations);// bcz: NO... this assumes the pdf is using its 'data' field. need to have the PDF's view handle updating its own annotations
+ targetAnnotations && targetAnnotations.push(pdfRegion);
+ }
});
let link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "note on " + pdfDoc.title, "pasted PDF link");
@@ -768,7 +777,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement;
let r1 = refNode && refNode.getBoundingClientRect();
let r3 = self._ref.current!.getBoundingClientRect();
- r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale);
+ if (r1.top < r3.top || r1.top > r3.bottom) {
+ r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale);
+ }
return true;
},
dispatchTransaction: this.dispatchTransaction,
@@ -815,7 +826,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._rulesReactionDisposer && this._rulesReactionDisposer();
this._reactionDisposer && this._reactionDisposer();
this._proxyReactionDisposer && this._proxyReactionDisposer();
- this._textReactionDisposer && this._textReactionDisposer();
this._pushReactionDisposer && this._pushReactionDisposer();
this._pullReactionDisposer && this._pullReactionDisposer();
this._heightReactionDisposer && this._heightReactionDisposer();
@@ -823,6 +833,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._editorView && this._editorView.destroy();
}
onPointerDown = (e: React.PointerEvent): void => {
+ FormattedTextBoxComment.textBox = this;
let pos = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
pos && (this._nodeClicked = this._editorView!.state.doc.nodeAt(pos.pos));
if (this.props.onClick && e.button === 0) {
@@ -837,7 +848,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
onPointerUp = (e: React.PointerEvent): void => {
- if (!(e.nativeEvent as any).formattedHandled) { FormattedTextBoxComment.textBox = this; }
+ if (!(e.nativeEvent as any).formattedHandled) {
+ FormattedTextBoxComment.textBox = this;
+ FormattedTextBoxComment.update(this._editorView!);
+ }
(e.nativeEvent as any).formattedHandled = true;
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
@@ -864,40 +878,41 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
onClick = (e: React.MouseEvent): void => {
if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; }
(e.nativeEvent as any).formattedHandled = true;
- if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
- let href = (e.target as any).href;
- let location: string;
- if ((e.target as any).attributes.location) {
- location = (e.target as any).attributes.location.value;
- }
- let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
- let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
- if (node) {
- let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
- if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above).
- href = link && link.attrs.href;
- location = link && link.attrs.location;
- }
- }
- if (href) {
- if (href.indexOf(Utils.prepend("/doc/")) === 0) {
- let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
- if (linkClicked) {
- DocServer.GetRefField(linkClicked).then(async linkDoc => {
- (linkDoc instanceof Doc) &&
- DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
- });
- }
- } else {
- let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.props.Document.x, 0) + NumCast(this.props.Document.width, 0), y: NumCast(this.props.Document.y) });
- this.props.addDocument && this.props.addDocument(webDoc);
- }
- e.stopPropagation();
- e.preventDefault();
- }
- }
+ // if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
+ // let href = (e.target as any).href;
+ // let location: string;
+ // if ((e.target as any).attributes.location) {
+ // location = (e.target as any).attributes.location.value;
+ // }
+ // let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
+ // let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
+ // if (node) {
+ // let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
+ // if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above).
+ // href = link && link.attrs.href;
+ // location = link && link.attrs.location;
+ // }
+ // }
+ // if (href) {
+ // if (href.indexOf(Utils.prepend("/doc/")) === 0) {
+ // let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
+ // if (linkClicked) {
+ // DocServer.GetRefField(linkClicked).then(async linkDoc => {
+ // (linkDoc instanceof Doc) &&
+ // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
+ // });
+ // }
+ // } else {
+ // let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) });
+ // this.props.addDocument && this.props.addDocument(webDoc);
+ // }
+ // e.stopPropagation();
+ // e.preventDefault();
+ // }
+ // }
this.hitBulletTargets(e.clientX, e.clientY, e.nativeEvent.offsetX, e.shiftKey);
+ 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.
@@ -928,16 +943,18 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
onMouseUp = (e: React.MouseEvent): void => {
e.stopPropagation();
- // this interposes on prosemirror's upHandler to prevent prosemirror's up from invoked multiple times when there are nested prosemirrors. We only want the lowest level prosemirror to be invoked.
- if ((this._editorView as any).mouseDown) {
- let originalUpHandler = (this._editorView as any).mouseDown.up;
- (this._editorView as any).root.removeEventListener("mouseup", originalUpHandler);
- (this._editorView as any).mouseDown.up = (e: MouseEvent) => {
+ let view = this._editorView as any;
+ // this interposes on prosemirror's upHandler to prevent prosemirror's up from invoked multiple times when there
+ // are nested prosemirrors. We only want the lowest level prosemirror to be invoked.
+ if (view.mouseDown) {
+ let originalUpHandler = view.mouseDown.up;
+ view.root.removeEventListener("mouseup", originalUpHandler);
+ view.mouseDown.up = (e: MouseEvent) => {
!(e as any).formattedHandled && originalUpHandler(e);
- e.stopPropagation();
+ // e.stopPropagation();
(e as any).formattedHandled = true;
};
- (this._editorView as any).root.addEventListener("mouseup", (this._editorView as any).mouseDown.up);
+ view.root.addEventListener("mouseup", view.mouseDown.up);
}
}
@@ -945,7 +962,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let self = FormattedTextBox;
return new Plugin({
view(newView) {
- return self._toolTipTextMenu = FormattedTextBox.getToolTip(newView);
+ return self.ToolTipTextMenu = FormattedTextBox.getToolTip(newView);
}
});
}
@@ -959,7 +976,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
});
}
onBlur = (e: any) => {
- DictationManager.Controls.stop(false);
+ //DictationManager.Controls.stop(false);
if (this._undoTyping) {
this._undoTyping.end();
this._undoTyping = undefined;
@@ -980,40 +997,43 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
if (!this._undoTyping) {
this._undoTyping = UndoManager.StartBatch("undoTyping");
}
+ if (this._recording) { this.stopDictation(true); setTimeout(() => this.recordDictation(), 250); }
}
@action
tryUpdateHeight() {
- const ChromeHeight = this.props.ChromeHeight;
- let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
- if (!this.props.Document.isAnimating && this.props.Document.autoHeight && sh !== 0 && getComputedStyle(this._ref.current!.parentElement!).top === "0px") {
- let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
- let dh = NumCast(this.props.Document.height, 0);
- this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
- this.dataDoc.nativeHeight = nh ? sh : undefined;
+ let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0;
+ if (!this.layoutDoc.isAnimating && this.layoutDoc.autoHeight && scrollHeight !== 0 &&
+ getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ let nh = this.Document.isTemplateField ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
+ let dh = NumCast(this.layoutDoc.height, 0);
+ this.layoutDoc.height = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0));
+ this.dataDoc.nativeHeight = nh ? scrollHeight : undefined;
}
}
+ @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); }
+ @computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
+ @computed get annotationsKey() { return "annotations"; }
render() {
- let style = "hidden";
- let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : "";
- let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.props.Document.isBackground
- ? "none" : "all";
- Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey);
+ trace();
+ let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
+ let interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground;
if (this.props.isSelected()) {
- FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props);
+ FormattedTextBox.ToolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props);
+ } else if (FormattedTextBoxComment.textBox === this) {
+ FormattedTextBoxComment.Hide();
}
return (
- <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
+ <div className={`formattedTextBox-cont`} ref={this._ref}
style={{
- overflowY: this.props.Document.autoHeight ? "hidden" : "auto",
- height: this.props.Document.autoHeight ? "max-content" : this.props.height ? this.props.height : undefined,
+ height: this.layoutDoc.autoHeight ? "max-content" : this.props.height ? this.props.height : undefined,
background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
- pointerEvents: interactive,
- fontSize: this._fontSize,
- fontFamily: this._fontFamily,
+ pointerEvents: interactive ? "none" : "all",
+ fontSize: this._ruleFontSize ? this._ruleFontSize : NumCast(this.layoutDoc.fontSize, 13),
+ fontFamily: this._ruleFontFamily ? this._ruleFontFamily : StrCast(this.layoutDoc.fontFamily, "Crimson Text"),
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyPress}
@@ -1027,7 +1047,41 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
onPointerEnter={action(() => this._entered = true)}
onPointerLeave={action(() => this._entered = false)}
>
- <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.props.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} />
+ <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }}>
+ <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} />
+ </div>
+ {this.sidebarWidthPercent === "0%" ? (null) : <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}` }}>
+ <CollectionFreeFormView {...this.props}
+ PanelHeight={() => this.props.PanelHeight()}
+ PanelWidth={() => this.sidebarWidth}
+ annotationsKey={this.annotationsKey}
+ isAnnotationOverlay={true}
+ focus={this.props.focus}
+ isSelected={this.props.isSelected}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ ContentScaling={returnOne}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
+ ruleProvider={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ chromeCollapsed={true}>
+ </CollectionFreeFormView>
+ </div>}
+ <div className="formattedTextBox-dictation"
+ onClick={e => {
+ this._recording ? this.stopDictation(true) : this.recordDictation();
+ setTimeout(() => this._editorView!.focus(), 500);
+ e.stopPropagation();
+ }} >
+ <FontAwesomeIcon className="formattedTExtBox-audioFont"
+ style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.2 }} icon={"microphone"} size="sm" />
+ </div>
</div>
);
}