diff options
author | Mohammad Amoush <mohammad_amoush@brown.edu> | 2019-07-16 18:03:12 -0400 |
---|---|---|
committer | Mohammad Amoush <mohammad_amoush@brown.edu> | 2019-07-16 18:03:12 -0400 |
commit | 1cedadbdf01c392ca9910e3ca18f3875d9a86fed (patch) | |
tree | 602608ba06b997cd3144395640e404a01f666291 /src/client/views/nodes/FormattedTextBox.tsx | |
parent | f70b95879e87a6bb61aaae5de29747d9474623a7 (diff) | |
parent | f18be9418b9237acd847eaf71adc034226c54695 (diff) |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into youtube-api-muhammed
Diffstat (limited to 'src/client/views/nodes/FormattedTextBox.tsx')
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 339 |
1 files changed, 227 insertions, 112 deletions
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5c635cc0c..45e7171d2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,58 +1,53 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons'; -import { action, IReactionDisposer, observable, reaction } from "mobx"; +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 { EditorView } from "prosemirror-view"; -import { Doc, Field, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; +import { Doc, Opt } 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, makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; +import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types"; import { DocServer } from "../../DocServer"; -import { DocumentManager } from "../../util/DocumentManager"; +import { Docs } from '../../documents/Documents'; +import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from "../../util/DragManager"; -import buildKeymap from "../../util/ProsemirrorKeymap"; +import buildKeymap from "../../util/ProsemirrorExampleTransfer"; import { inpRules } from "../../util/RichTextRules"; -import { ImageResizeView, schema } from "../../util/RichTextSchema"; +import { ImageResizeView, schema, SummarizedView } from "../../util/RichTextSchema"; import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { ContextMenu } from "../../views/ContextMenu"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; +import { Templates } from '../Templates'; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); -import { DocUtils } from '../../documents/Documents'; +import { DateField } from '../../../new_fields/DateField'; +import { thisExpression } from 'babel-types'; library.add(faEdit); library.add(faSmile); // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // -// HTML Markup: <FormattedTextBox Doc={Document's ID} FieldKey={Key's name} -// -// In Code, the node's HTML is specified in the document's parameterized structure as: -// document.SetField(KeyStore.Layout, "<FormattedTextBox doc={doc} fieldKey={<KEYNAME>Key} />"); -// and the node's binding to the specified document KEYNAME as: -// document.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.<KEYNAME>])); -// The Jsx parser at run time will bind: -// 'fieldKey' property to the Key stored in LayoutKeys -// and 'doc' property to the document that is being rendered -// -// When rendered() by React, this extracts the TextController from the Document stored at the -// specified Key and assigns it to an HTML input node. When changes are made to this node, -// this will edit the document and assign the new value to that field. -//] export interface FormattedTextBoxProps { isOverlay?: boolean; hideOnLeave?: boolean; + height?: string; + color?: string; + outer_div?: (domminus: HTMLElement) => void; } const richTextSchema = createSchema({ @@ -68,68 +63,138 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return FieldView.LayoutString(FormattedTextBox, fieldStr); } private _ref: React.RefObject<HTMLDivElement>; - private _proseRef: React.RefObject<HTMLDivElement>; + private _outerdiv?: (dominus: HTMLElement) => void; + private _proseRef?: HTMLDivElement; private _editorView: Opt<EditorView>; - private _gotDown: boolean = false; - private _dropDisposer?: DragManager.DragDropDisposer; + private _toolTipTextMenu: TooltipTextMenu | undefined = undefined; + private _applyingChange: boolean = false; + private _linkClicked = ""; private _reactionDisposer: Opt<IReactionDisposer>; - private _inputReactionDisposer: Opt<IReactionDisposer>; + private _textReactionDisposer: Opt<IReactionDisposer>; private _proxyReactionDisposer: Opt<IReactionDisposer>; + private dropDisposer?: DragManager.DragDropDisposer; public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } + @observable _entered = false; @observable public static InputBoxOverlay?: FormattedTextBox = undefined; public static InputBoxOverlayScroll: number = 0; + public static IsFragment(html: string) { + return html.indexOf("data-pm-slice") !== -1; + } + public static GetHref(html: string): string { + let parser = new DOMParser(); + let parsedHtml = parser.parseFromString(html, 'text/html'); + if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && + (parsedHtml.body.childNodes[0].childNodes[0] as any).href) { + return (parsedHtml.body.childNodes[0].childNodes[0] as any).href; + } + return ""; + } + public static GetDocFromUrl(url: string) { + if (url.startsWith(document.location.origin)) { + const split = new URL(url).pathname.split("doc/"); + const docid = split[split.length - 1]; + return docid; + } + return ""; + } + + @undoBatch + public setFontColor(color: string) { + let self = this; + if (this._editorView!.state.selection.from === this._editorView!.state.selection.to) return false; + if (this._editorView!.state.selection.to - this._editorView!.state.selection.from > this._editorView!.state.doc.nodeSize - 3) { + this.props.Document.color = color; + } + let colorMark = this._editorView!.state.schema.mark(this._editorView!.state.schema.marks.pFontColor, { color: color }); + this._editorView!.dispatch(this._editorView!.state.tr.addMark(this._editorView!.state.selection.from, + this._editorView!.state.selection.to, colorMark)); + return true; + } constructor(props: FieldViewProps) { super(props); + if (this.props.outer_div) { + this._outerdiv = this.props.outer_div; + } this._ref = React.createRef(); - this._proseRef = React.createRef(); if (this.props.isOverlay) { DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined); } } - _applyingChange: boolean = false; + @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); } - _lastState: any = undefined; dispatchTransaction = (tx: Transaction) => { if (this._editorView) { - const state = this._lastState = this._editorView.state.apply(tx); + const state = this._editorView.state.apply(tx); this._editorView.updateState(state); this._applyingChange = true; - Doc.SetOnPrototype(this.props.Document, this.props.fieldKey, new RichTextField(JSON.stringify(state.toJSON()))); - Doc.SetOnPrototype(this.props.Document, "documentText", state.doc.textBetween(0, state.doc.content.size, "\n\n")); + if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"); + if (this.extensionDoc) this.extensionDoc.lastModified = new DateField(new Date(Date.now())); + this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON())); this._applyingChange = false; - let title = StrCast(this.props.Document.title); + let title = StrCast(this.dataDoc.title); if (title && title.startsWith("-") && this._editorView) { let str = this._editorView.state.doc.textContent; let titlestr = str.substr(0, Math.min(40, str.length)); - let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; - target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); + this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : ""); } } } + protected createDropTarget = (ele: HTMLDivElement) => { + this._proseRef = ele; + if (this.dropDisposer) { + this.dropDisposer(); + } + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); + } + } + @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { - if (de.data instanceof DragManager.LinkDragData) { - let sourceDoc = de.data.linkSourceDocument; - let destDoc = this.props.Document; - - DocUtils.MakeLink(sourceDoc, destDoc); - de.data.droppedDocuments.push(destDoc); + // We're dealing with a link to a document + if (de.data instanceof DragManager.EmbedDragData && de.data.urlField) { + // We're dealing with an internal document drop + let url = de.data.urlField.url.href; + let model: NodeType = (url.includes(".mov") || url.includes(".mp4")) ? schema.nodes.video : schema.nodes.image; + this._editorView!.dispatch(this._editorView!.state.tr.insert(0, model.create({ src: url }))); e.stopPropagation(); + } else { + if (de.data instanceof DragManager.DocumentDragData) { + this.props.Document.layout = de.data.draggedDocuments[0]; + de.data.draggedDocuments[0].isTemplate = true; + e.stopPropagation(); + // let ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc)); + // if (!ldocs) { + // this.dataDoc.subBulletDocs = new List<Doc>([]); + // } + // ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc)); + // if (!ldocs) return; + // if (!ldocs || !ldocs[0] || ldocs[0] instanceof Promise || StrCast((ldocs[0] as Doc).layout).indexOf("CollectionView") === -1) { + // ldocs.splice(0, 0, Docs.StackingDocument([], { title: StrCast(this.dataDoc.title) + "-subBullets", x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document.height), width: 300, height: 300 })); + // this.props.addDocument && this.props.addDocument(ldocs[0] as Doc); + // this.props.Document.templates = new List<string>([Templates.Bullet.Layout]); + // this.props.Document.isBullet = true; + // } + // let stackDoc = (ldocs[0] as Doc); + // if (de.data.moveDocument) { + // de.data.moveDocument(de.data.draggedDocuments[0], stackDoc, (doc) => { + // Cast(stackDoc.data, listSpec(Doc))!.push(doc); + // return true; + // }); + // } + } } } componentDidMount() { - if (this._ref.current) { - this._dropDisposer = DragManager.MakeDropTarget(this._ref.current, { - handlers: { drop: this.drop.bind(this) } - }); - } const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful @@ -151,97 +216,118 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ] }; - if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => FormattedTextBox.InputBoxOverlay, - () => { - if (this._editorView) { - this._editorView.destroy(); - } - this.setupEditor(config, this.props.Document);// MainOverlayTextBox.Instance.TextDoc); // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox - } - ); - } else { + if (!this.props.isOverlay) { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), () => { if (this.props.isSelected()) { FormattedTextBox.InputBoxOverlay = this; FormattedTextBox.InputBoxOverlayScroll = this._ref.current!.scrollTop; } - }); + }, { fireImmediately: true }); } - this._reactionDisposer = reaction( () => { - const field = this.props.Document ? Cast(this.props.Document[this.props.fieldKey], RichTextField) : undefined; - return field ? field.Data : undefined; + const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined; + return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`; }, - field => field && this._editorView && !this._applyingChange && - this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))) + field2 => { + if (StrCast(this.props.Document.layout).indexOf("\"" + this.props.fieldKey + "\"") !== -1) { // bcz: UGH! why is this needed... something is happening out of order. test with making a collection, then adding a text note and converting that to a template field. + this._editorView && !this._applyingChange && + this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2))); + } + } ); - this.setupEditor(config, this.props.Document); + + 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(config, this.dataDoc, this.props.fieldKey); } - private setupEditor(config: any, doc?: Doc) { - let field = doc ? Cast(doc[this.props.fieldKey], RichTextField) : undefined; - if (this._proseRef.current) { - this._editorView = new EditorView(this._proseRef.current, { + private setupEditor(config: any, doc: Doc, fieldKey: string) { + let field = doc ? Cast(doc[fieldKey], RichTextField) : undefined; + let startup = StrCast(doc.documentText); + startup = startup.startsWith("@@@") ? startup.replace("@@@", "") : ""; + if (!field && doc) { + let text = StrCast(doc[fieldKey]); + if (text) { + startup = text; + } else if (Cast(doc[fieldKey], "number")) { + startup = NumCast(doc[fieldKey], 99).toString(); + } + } + if (this._proseRef) { + this._editorView = new EditorView(this._proseRef, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, nodeViews: { - image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } + image(node, view, getPos) { return new ImageResizeView(node, view, getPos); }, + star(node, view, getPos) { return new SummarizedView(node, view, getPos); } } }); - let text = StrCast(this.props.Document.documentText); - if (text.startsWith("@@@")) { - this.props.Document.proto!.documentText = undefined; - this._editorView.dispatch(this._editorView.state.tr.insertText(text.replace("@@@", ""))); + if (startup) { + Doc.GetProto(doc).documentText = undefined; + this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); } } if (this.props.selectOnLoad) { - this.props.select(false); - this._editorView!.focus(); + if (!this.props.isOverlay) this.props.select(false); + else this._editorView!.focus(); + this.tryUpdateHeight(); } } componentWillUnmount() { - if (this._editorView) { - this._editorView.destroy(); - } - if (this._reactionDisposer) { - this._reactionDisposer(); - } - if (this._inputReactionDisposer) { - this._inputReactionDisposer(); - } - if (this._proxyReactionDisposer) { - this._proxyReactionDisposer(); - } - if (this._dropDisposer) { - this._dropDisposer(); - } + this._editorView && this._editorView.destroy(); + this._reactionDisposer && this._reactionDisposer(); + this._proxyReactionDisposer && this._proxyReactionDisposer(); + this._textReactionDisposer && this._textReactionDisposer(); } onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { - this._toolTipTextMenu.tooltip.style.opacity = "0"; + //this._toolTipTextMenu.tooltip.style.opacity = "0"; } } let ctrlKey = e.ctrlKey; 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 = (e.target as any).attributes.location.value; for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) { - href = parent.childNodes[0].href; + href = parent.childNodes[0].href ? parent.childNodes[0].href : parent.href; } if (href) { + `` if (href.indexOf(DocServer.prepend("/doc/")) === 0) { - let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; - DocServer.GetRefField(docid).then(f => { - (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")) - }); + this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; + if (this._linkClicked) { + DocServer.GetRefField(this._linkClicked).then(async linkDoc => { + if (linkDoc instanceof Doc) { + let proto = Doc.GetProto(linkDoc); + let targetContext = await Cast(proto.targetContext, Doc); + if (targetContext) { + DocumentManager.Instance.jumpToDocument(targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); + } + } + }); + e.stopPropagation(); + e.preventDefault(); + } + } 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); + this._linkClicked = webDoc[Id]; } e.stopPropagation(); e.preventDefault(); @@ -249,13 +335,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { - this._gotDown = true; e.preventDefault(); } } onPointerUp = (e: React.PointerEvent): void => { if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { - this._toolTipTextMenu.tooltip.style.opacity = "1"; + //this._toolTipTextMenu.tooltip.style.opacity = "1"; } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); @@ -273,13 +358,19 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } onPointerWheel = (e: React.WheelEvent): void => { - if (this.props.isSelected()) { + // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time + if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { e.stopPropagation(); } } onClick = (e: React.MouseEvent): void => { - this._proseRef.current!.focus(); + this._proseRef!.focus(); + if (this._linkClicked) { + this._linkClicked = ""; + e.preventDefault(); + e.stopPropagation(); + } } onMouseDown = (e: React.MouseEvent): void => { if (!this.props.isSelected()) { // preventing default allows the onClick to be generated instead of being swallowed by the text box itself @@ -295,9 +386,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return self._toolTipTextMenu = new TooltipTextMenu(_editorView, myprops); } }); + //this.props.Document.tooltip = self._toolTipTextMenu; } - _toolTipTextMenu: TooltipTextMenu | undefined = undefined; tooltipLinkingMenuPlugin() { let myprops = this.props; return new Plugin({ @@ -322,19 +413,31 @@ 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.props.Document.title).startsWith("-") && this._editorView) { + if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView) { let str = this._editorView.state.doc.textContent; let titlestr = str.substr(0, Math.min(40, str.length)); - let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; - target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); + this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : ""); } if (!this._undoTyping) { this._undoTyping = UndoManager.StartBatch("undoTyping"); } + this.tryUpdateHeight(); + } + + @action + tryUpdateHeight() { + if (this.props.isOverlay && this.props.Document.autoHeight) { + let self = this; + let xf = this._ref.current!.getBoundingClientRect(); + let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height); + 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; + this.dataDoc.nativeHeight = nh ? sh : undefined; + } } - @observable - _entered = false; @action onPointerEnter = (e: React.PointerEvent) => { this._entered = true; @@ -343,33 +446,45 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerLeave = (e: React.PointerEvent) => { this._entered = false; } + + 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" + }); + ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems }); + } render() { + let self = this; let style = this.props.isOverlay ? "scroll" : "hidden"; - let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : ""; + let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : ""; let interactive = InkingControl.Instance.selectedTool ? "" : "interactive"; + Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); return ( <div className={`formattedTextBox-cont-${style}`} ref={this._ref} style={{ + height: this.props.height ? this.props.height : undefined, background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined, opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || this.props.Document.libraryBrush ? 1 : 0.1) : 1, - color: this.props.hideOnLeave ? "white" : "initial", + color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit", pointerEvents: interactive ? "all" : "none", + fontSize: "13px" }} - // onKeyDown={this.onKeyPress} - onKeyPress={this.onKeyPress} + onKeyDown={this.onKeyPress} onFocus={this.onFocused} onClick={this.onClick} + onContextMenu={this.specificContextMenu} onBlur={this.onBlur} onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseDown={this.onMouseDown} - onContextMenu={this.specificContextMenu} // tfs: do we need this event handler onWheel={this.onPointerWheel} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} > - <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: this.props.Document.isButton && !this.props.isSelected() ? "none" : "all" }} ref={this._proseRef} /> + <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget} style={{ whiteSpace: "pre-wrap", pointerEvents: this.props.Document.isButton && !this.props.isSelected() ? "none" : "all" }} /> </div> ); } |