aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/FormattedTextBox.tsx
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-07-30 03:49:18 -0400
committerSam Wilkins <samwilkins333@gmail.com>2019-07-30 03:49:18 -0400
commit79f47098381fef8e247ddb45ce56993669f218cb (patch)
treec7fb7e88586c2eba65ad0b5e8e2bf11a2c1b29cd /src/client/views/nodes/FormattedTextBox.tsx
parent3152e69dfafe1c393bed38f3aad1e55881e62a33 (diff)
parente041988b84553797699a5a232e26e72252460e01 (diff)
successful implementation of different approach
Diffstat (limited to 'src/client/views/nodes/FormattedTextBox.tsx')
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx148
1 files changed, 134 insertions, 14 deletions
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0a79677e2..fc0cc98aa 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,21 +1,21 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons';
+import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons';
import { action, IReactionDisposer, observable, reaction, runInAction, computed, trace } from "mobx";
import { observer } from "mobx-react";
import { baseKeymap } from "prosemirror-commands";
import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
-import { NodeType } from 'prosemirror-model';
-import { EditorState, Plugin, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
+import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
import { EditorView } from "prosemirror-view";
-import { Doc, Opt } from "../../../new_fields/Doc";
+import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
import { Id, Copy } from '../../../new_fields/FieldSymbols';
import { List } from '../../../new_fields/List';
import { RichTextField } from "../../../new_fields/RichTextField";
import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
import { DocServer } from "../../DocServer";
-import { Docs } from '../../documents/Documents';
+import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from "../../util/DragManager";
import buildKeymap from "../../util/ProsemirrorExampleTransfer";
@@ -34,11 +34,11 @@ import { FieldView, FieldViewProps } from "./FieldView";
import "./FormattedTextBox.scss";
import React = require("react");
import { DateField } from '../../../new_fields/DateField';
-import { thisExpression } from 'babel-types';
import { Utils } from '../../../Utils';
+import { MainOverlayTextBox } from '../MainOverlayTextBox';
library.add(faEdit);
-library.add(faSmile);
+library.add(faSmile, faTextHeight);
// FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
//
@@ -123,12 +123,40 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
if (this.props.isOverlay) {
DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
}
+
+ document.addEventListener("paste", this.paste);
}
@computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
@computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
+ paste = (e: ClipboardEvent) => {
+ if (e.clipboardData && this._editorView) {
+ let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
+ for (let i = 0; i < e.clipboardData.items.length; i++) {
+ let item = e.clipboardData.items.item(i);
+ if (item.type === "text/plain") {
+ item.getAsString((text) => {
+ let pdfPasteIndex = text.indexOf(pdfPasteText);
+ if (pdfPasteIndex > -1) {
+ let insertText = text.substr(0, pdfPasteIndex);
+ const tx = this._editorView!.state.tr.insertText(insertText);
+ // tx.setSelection(new Selection(tx.))
+ const state = this._editorView!.state;
+ this._editorView!.dispatch(tx);
+ if (this._toolTipTextMenu) {
+ // this._toolTipTextMenu.makeLinkWithState(state)
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ });
+ }
+ }
+ }
+ }
+
dispatchTransaction = (tx: Transaction) => {
if (this._editorView) {
const state = this._editorView.state.apply(tx);
@@ -139,7 +167,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
this._applyingChange = false;
let title = StrCast(this.dataDoc.title);
- if (title && title.startsWith("-") && this._editorView) {
+ if (title && title.startsWith("-") && this._editorView && !this.Document.customTitle) {
let str = this._editorView.state.doc.textContent;
let titlestr = str.substr(0, Math.min(40, str.length));
this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
@@ -251,6 +279,92 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this.setupEditor(config, this.dataDoc, this.props.fieldKey);
}
+ clipboardTextSerializer = (slice: Slice): string => {
+ let text = "", separated = true;
+ const from = 0, to = slice.content.size;
+ slice.content.nodesBetween(from, to, (node, pos) => {
+ if (node.isText) {
+ text += node.text!.slice(Math.max(from, pos) - pos, to - pos);
+ separated = false;
+ } else if (!separated && node.isBlock) {
+ text += "\n";
+ separated = true;
+ } else if (node.type.name === "hard_break") {
+ text += "\n";
+ }
+ }, 0);
+ return text;
+ }
+
+ sliceSingleNode(slice: Slice) {
+ return slice.openStart === 0 && slice.openEnd === 0 && slice.content.childCount === 1 ? slice.content.firstChild : null;
+ }
+
+ handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
+ let cbe = event as ClipboardEvent;
+ let docId: string;
+ let regionId: string;
+ if (!cbe.clipboardData) {
+ return false;
+ }
+ let linkId: string;
+ docId = cbe.clipboardData.getData("dash/pdfOrigin");
+ regionId = cbe.clipboardData.getData("dash/pdfRegion");
+ if (!docId || !regionId) {
+ return false;
+ }
+
+ DocServer.GetRefField(docId).then(doc => {
+ DocServer.GetRefField(regionId).then(region => {
+ if (!(doc instanceof Doc) || !(region instanceof Doc)) {
+ return;
+ }
+
+ let annotations = DocListCast(region.annotations);
+ annotations.forEach(anno => anno.target = this.props.Document);
+ let fieldExtDoc = Doc.resolvedFieldDataDoc(doc, "data", "true");
+ let targetAnnotations = DocListCast(fieldExtDoc.annotations);
+ if (targetAnnotations) {
+ targetAnnotations.push(region);
+ fieldExtDoc.annotations = new List<Doc>(targetAnnotations);
+ }
+
+ let link = DocUtils.MakeLink(this.props.Document, region, doc);
+ if (link) {
+ cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
+ linkId = link[Id];
+ let frag = addMarkToFrag(slice.content);
+ slice = new Slice(frag, slice.openStart, slice.openEnd);
+ var tr = view.state.tr.replaceSelection(slice);
+ view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+ }
+ });
+ });
+
+ return true;
+
+ function addMarkToFrag(frag: Fragment) {
+ const nodes: Node[] = [];
+ frag.forEach(node => nodes.push(addLinkMark(node)));
+ return Fragment.fromArray(nodes);
+ }
+ function addLinkMark(node: Node) {
+ if (!node.isText) {
+ const content = addMarkToFrag(node.content);
+ return node.copy(content);
+ }
+ const marks = [...node.marks];
+ const linkIndex = marks.findIndex(mark => mark.type.name === "link");
+ const link = view.state.schema.mark(view.state.schema.marks.link, { href: `http://localhost:1050/doc/${linkId}`, location: "onRight" });
+ if (linkIndex !== -1) {
+ marks.splice(linkIndex, 1, link);
+ } else {
+ marks.push(link);
+ }
+ return node.mark(marks);
+ }
+ }
+
private setupEditor(config: any, doc: Doc, fieldKey: string) {
let field = doc ? Cast(doc[fieldKey], RichTextField) : undefined;
let startup = StrCast(doc.documentText);
@@ -270,7 +384,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
nodeViews: {
image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
star(node, view, getPos) { return new SummarizedView(node, view, getPos); }
- }
+ },
+ clipboardTextSerializer: this.clipboardTextSerializer,
+ handlePaste: this.handlePaste,
});
if (startup) {
Doc.GetProto(doc).documentText = undefined;
@@ -327,6 +443,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
if (targetContext) {
DocumentManager.Instance.jumpToDocument(targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab"));
+ } else if (jumpToDoc) {
+ DocumentManager.Instance.jumpToDocument(jumpToDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab"));
+
}
}
});
@@ -422,7 +541,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
// stop propagation doesn't seem to stop propagation of native keyboard events.
// so we set a flag on the native event that marks that the event's been handled.
(e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
- if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView) {
+ if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.Document.customTitle) {
let str = this._editorView.state.doc.textContent;
let titlestr = str.substr(0, Math.min(40, str.length));
this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
@@ -442,7 +561,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let nh = NumCast(this.dataDoc.nativeHeight, 0);
let dh = NumCast(this.props.Document.height, 0);
let sh = scrBounds.height;
- this.props.Document.height = nh ? dh / nh * sh : sh;
+ const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
+ this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0);
this.dataDoc.nativeHeight = nh ? sh : undefined;
}
}
@@ -459,10 +579,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
specificContextMenu = (e: React.MouseEvent): void => {
let subitems: ContextMenuProps[] = [];
subitems.push({
- description: BoolCast(this.props.Document.autoHeight, false) ? "Manual Height" : "Auto Height",
- event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight, false)), icon: "expand-arrows-alt"
+ description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
+ event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
});
- ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems });
+ ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
}
render() {
let self = this;