From c360dc0adb468ae3aaa1c2d943606993d01a5a52 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 27 Jul 2019 11:08:44 -0400 Subject: fixed handling of keyboard events to avoid triggering global key events. made BoolCast default to false. fixed templating to deal with conflict between field fields and template fields --- src/client/views/pdf/Page.tsx | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/client/views/pdf/Page.tsx') diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index c9d442fe5..a6864e0f3 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -1,22 +1,18 @@ +import { action, IReactionDisposer, observable } from "mobx"; import { observer } from "mobx-react"; -import React = require("react"); -import { observable, action, runInAction, IReactionDisposer, reaction } from "mobx"; import * as Pdfjs from "pdfjs-dist"; -import { Opt, Doc, FieldResult, Field, DocListCast, WidthSym, HeightSym, DocListCastAsync } from "../../../new_fields/Doc"; -import "./PDFViewer.scss"; import "pdfjs-dist/web/pdf_viewer.css"; -import { PDFBox } from "../nodes/PDFBox"; -import { DragManager } from "../../util/DragManager"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; -import { emptyFunction } from "../../../Utils"; -import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { menuBar } from "prosemirror-menu"; -import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Docs, DocUtils } from "../../documents/Documents"; +import { DragManager } from "../../util/DragManager"; +import { PDFBox } from "../nodes/PDFBox"; import PDFMenu from "./PDFMenu"; -import { UndoManager } from "../../util/UndoManager"; -import { copy } from "typescript-collections/dist/lib/arrays"; +import { scale } from "./PDFViewer"; +import "./PDFViewer.scss"; +import React = require("react"); interface IPageProps { -- cgit v1.2.3-70-g09d2 From d53ad748d90ca1c863a7ef52d0835573ce967a54 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Sat, 27 Jul 2019 16:49:07 -0400 Subject: init --- src/client/util/TooltipTextMenu.tsx | 6 +++++- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 30 ++++++++++++++++++++++++++++- src/client/views/nodes/PDFBox.tsx | 14 ++++++++++++++ src/client/views/pdf/Page.tsx | 11 ++++++++--- 5 files changed, 57 insertions(+), 6 deletions(-) (limited to 'src/client/views/pdf/Page.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a4c053de2..6214b568c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,6 +1,6 @@ import { action } from "mobx"; import { Dropdown, MenuItem, icons, } from "prosemirror-menu"; //no import css -import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; +import { EditorState, NodeSelection, TextSelection, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; import { Schema, NodeType, MarkType, Mark, ResolvedPos } from "prosemirror-model"; @@ -321,6 +321,10 @@ export class TooltipTextMenu { } } + makeLinkWithState = (state: EditorState, target: string, location: string) => { + let link = state.schema.mark(state.schema.marks.link, { href: target, location: location }); + } + makeLink = (target: string, location: string) => { let node = this.view.state.selection.$from.nodeAfter; let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location }); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 7477c5b4f..6c80c7645 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -151,9 +151,9 @@ export default class KeyManager { stopPropagation = false; break; case "a": - case "c": case "v": case "x": + case "c": stopPropagation = false; preventDefault = false; break; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0a79677e2..cf913a4c7 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 { NodeType } from 'prosemirror-model'; -import { EditorState, Plugin, Transaction } from "prosemirror-state"; +import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { Doc, Opt } from "../../../new_fields/Doc"; import { Id, Copy } from '../../../new_fields/FieldSymbols'; @@ -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); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5a5e6e6dd..282312dca 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -24,6 +24,8 @@ import { Flyout, anchorPoints } from '../DocumentDecorations'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ScriptField } from '../../../new_fields/ScriptField'; import { KeyCodes } from '../../northstar/utils/KeyCodes'; +import { Utils } from '../../../Utils'; +import { Id } from '../../../new_fields/FieldSymbols'; type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const PdfDocument = makeInterface(positionSchema, pageSchema); @@ -32,6 +34,7 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K @observer export class PDFBox extends DocComponent(PdfDocument) { public static LayoutString() { return FieldView.LayoutString(PDFBox); } + public selectionText: string = ""; @observable private _alt = false; @observable private _scrollY: number = 0; @@ -63,6 +66,8 @@ export class PDFBox extends DocComponent(PdfDocumen this._keyRef = React.createRef(); this._valueRef = React.createRef(); this._scriptRef = React.createRef(); + + document.addEventListener("keydown", this.onKeyDown); } componentDidMount() { @@ -73,6 +78,14 @@ export class PDFBox extends DocComponent(PdfDocumen this._reactionDisposer && this._reactionDisposer(); } + onKeyDown = (e: KeyboardEvent) => { + if (e.ctrlKey && e.keyCode === KeyCodes.C) { + let text = this.selectionText; + text += `${Utils.GenerateDeterministicGuid("pdf paste")}/${this.props.Document[Id]}`; + navigator.clipboard.writeText(text); + } + } + public GetPage() { return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1; } @@ -241,6 +254,7 @@ export class PDFBox extends DocComponent(PdfDocumen let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return (
{ else { let sel = window.getSelection(); if (sel && sel.type === "Range") { - this.createTextAnnotation(sel); + let selRange = sel.getRangeAt(0); + this.createTextAnnotation(sel, selRange); PDFMenu.Instance.jumpTo(e.clientX, e.clientY); } } @@ -375,8 +376,8 @@ export default class Page extends React.Component { } @action - createTextAnnotation = (sel: Selection) => { - let clientRects = sel.getRangeAt(0).getClientRects(); + createTextAnnotation = (sel: Selection, selRange: Range) => { + let clientRects = selRange.getClientRects(); if (this._textLayer.current) { let boundingRect = this._textLayer.current.getBoundingClientRect(); for (let i = 0; i < clientRects.length; i++) { @@ -393,6 +394,10 @@ export default class Page extends React.Component { } } } + let text = selRange.extractContents().textContent; + if (text) { + this.props.parent.selectionText = text; + } // clear selection if (sel.empty) { // Chrome sel.empty(); -- cgit v1.2.3-70-g09d2 From 160ca6c2673b96b8cfe9dfd5bd887a3637a1a45f Mon Sep 17 00:00:00 2001 From: yipstanley Date: Sat, 27 Jul 2019 22:58:01 -0400 Subject: finisheddd --- src/client/views/nodes/FormattedTextBox.tsx | 42 +++++++++++++++++++---------- src/client/views/nodes/PDFBox.tsx | 2 -- src/client/views/pdf/PDFViewer.tsx | 30 ++++++++++++++++++--- src/client/views/pdf/Page.tsx | 3 ++- 4 files changed, 56 insertions(+), 21 deletions(-) (limited to 'src/client/views/pdf/Page.tsx') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 364dc1c83..f019868aa 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -8,7 +8,7 @@ import { keymap } from "prosemirror-keymap"; 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"; @@ -302,28 +302,42 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe 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"); - if (!docId) { + regionId = cbe.clipboardData.getData("dash/pdfRegion"); + if (!docId || !regionId) { return false; } DocServer.GetRefField(docId).then(doc => { - if (!(doc instanceof Doc)) { - return; - } - let link = DocUtils.MakeLink(this.props.Document, 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")); - } + 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(targetAnnotations); + } + + let link = DocUtils.MakeLink(this.props.Document, region); + 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; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 72d835fce..f527c0595 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -34,7 +34,6 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K @observer export class PDFBox extends DocComponent(PdfDocument) { public static LayoutString() { return FieldView.LayoutString(PDFBox); } - public selectionText: string = ""; @observable private _alt = false; @observable private _scrollY: number = 0; @@ -82,7 +81,6 @@ export class PDFBox extends DocComponent(PdfDocumen private copy = (e: ClipboardEvent) => { if (this.props.active()) { - let text = this.selectionText; if (e.clipboardData) { e.clipboardData.setData("text/plain", text); e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index db2d49f0f..6fef8a4de 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -92,6 +92,7 @@ export class Viewer extends React.Component { // private _textContent: Pdfjs.TextContent[] = []; private _pdfFindController: any; private _searchString: string = ""; + private _selectionText: string = ""; constructor(props: IViewerProps) { super(props); @@ -102,6 +103,10 @@ export class Viewer extends React.Component { this._mainCont = React.createRef(); } + setSelectionText = (text: string) => { + this._selectionText = text; + } + componentDidUpdate = (prevProps: IViewerProps) => { if (this.scrollY !== prevProps.scrollY) { this.renderPages(); @@ -158,8 +163,8 @@ export class Viewer extends React.Component { this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); } - document.removeEventListener("paste", this.paste); - document.addEventListener("paste", this.paste); + document.removeEventListener("copy", this.copy); + document.addEventListener("copy", this.copy); } componentWillUnmount = () => { @@ -167,7 +172,24 @@ export class Viewer extends React.Component { this._annotationReactionDisposer && this._annotationReactionDisposer(); this._filterReactionDisposer && this._filterReactionDisposer(); this._dropDisposer && this._dropDisposer(); - document.removeEventListener("paste", this.paste); + document.removeEventListener("copy", this.copy); + } + + private copy = (e: ClipboardEvent) => { + if (this.props.parent.props.active()) { + let text = this._selectionText; + if (e.clipboardData) { + e.clipboardData.setData("text/plain", text); + e.clipboardData.setData("dash/pdfOrigin", this.props.parent.props.Document[Id]); + let annoDoc = this.makeAnnotationDocument(undefined, 0, "#0390fc"); + e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]); + e.preventDefault(); + } + } + // let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations); + // if (targetAnnotations) { + // targetAnnotations.push(destDoc); + // } } paste = (e: ClipboardEvent) => { @@ -281,7 +303,6 @@ export class Viewer extends React.Component { let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations); if (targetAnnotations) { targetAnnotations.push(destDoc); - this.props.parent.fieldExtensionDoc.annotations = new List(targetAnnotations); } else { this.props.parent.fieldExtensionDoc.annotations = new List([destDoc]); @@ -315,6 +336,7 @@ export class Viewer extends React.Component { this._isPage[page] = "page"; this._visibleElements[page] = ( void; makeAnnotationDocuments: (doc: Doc | undefined, scale: number, color: string, linkTo: boolean) => Doc; getScrollFromPage: (page: number) => number; + setSelectionText: (text: string) => void; } @observer @@ -392,7 +393,7 @@ export default class Page extends React.Component { } let text = selRange.extractContents().textContent; if (text) { - this.props.parent.selectionText = text; + this.props.setSelectionText(text); } // clear selection if (sel.empty) { // Chrome -- cgit v1.2.3-70-g09d2