diff options
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 202 |
1 files changed, 149 insertions, 53 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 263bb31d7..7a43c34d0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,29 +1,23 @@ -import { action, computed } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { Field, FieldWaiting, Opt } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; +import { TextField } from "../../../fields/TextField"; +import { Documents } from "../../documents/Documents"; +import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"; -import { CollectionSchemaView } from "../collections/CollectionSchemaView"; import { CollectionView, CollectionViewType } from "../collections/CollectionView"; -import { CollectionPDFView } from "../collections/CollectionPDFView"; import { ContextMenu } from "../ContextMenu"; -import { FormattedTextBox } from "../nodes/FormattedTextBox"; -import { ImageBox } from "../nodes/ImageBox"; -import { VideoBox } from "../nodes/VideoBox"; -import { AudioBox } from "../nodes/AudioBox"; -import { Documents } from "../../documents/Documents" -import { KeyValueBox } from "./KeyValueBox" -import { WebBox } from "../nodes/WebBox"; -import { PDFBox } from "../nodes/PDFBox"; import "./DocumentView.scss"; import React = require("react"); +import { DocumentContentsView } from "./DocumentContentsView"; +import { Utils } from "../../../Utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -85,9 +79,9 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { @observer export class DocumentView extends React.Component<DocumentViewProps> { private _mainCont = React.createRef<HTMLDivElement>(); - private _documentBindings: any = null; private _downX: number = 0; private _downY: number = 0; + private _reactionDisposer: Opt<IReactionDisposer>; @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); } @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; } @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); } @@ -97,15 +91,15 @@ export class DocumentView extends React.Component<DocumentViewProps> { onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; - if (e.shiftKey && e.buttons === 1) { - CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e); + if (e.shiftKey && e.buttons === 2) { + if (this.props.isTopMost) { + this.startDragging(e.pageX, e.pageY); + } + else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e); e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { e.stopPropagation(); - if (e.buttons === 2) { - e.preventDefault(); - } document.removeEventListener("pointermove", this.onPointerMove) document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp) @@ -113,25 +107,74 @@ export class DocumentView extends React.Component<DocumentViewProps> { } } } + + private dropDisposer?: DragManager.DragDropDisposer; + protected createDropTarget = (ele: HTMLDivElement) => { + + } + + componentDidMount() { + if (this._mainCont.current) { + this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); + } + runInAction(() => { + DocumentManager.Instance.DocumentViews.push(this); + }) + this._reactionDisposer = reaction( + () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(), + () => { + if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.indexOf(this.props.Document.Id) != -1) + SelectionManager.SelectDoc(this, true); + }); + } + + componentDidUpdate() { + if (this.dropDisposer) { + this.dropDisposer(); + } + if (this._mainCont.current) { + this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); + } + } + + componentWillUnmount() { + if (this.dropDisposer) { + this.dropDisposer(); + } + runInAction(() => { + DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); + + }) + if (this._reactionDisposer) { + this._reactionDisposer(); + } + } + + startDragging(x: number, y: number) { + if (this._mainCont.current) { + const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + let dragData: { [id: string]: any } = {}; + dragData["documentView"] = this; + dragData["xOffset"] = x - left; + dragData["yOffset"] = y - top; + DragManager.StartDrag(this._mainCont.current, dragData, { + handlers: { + dragComplete: action(() => { }), + }, + hideSource: true + }) + } + } + onPointerMove = (e: PointerEvent): void => { if (e.cancelBubble) { return; } if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { document.removeEventListener("pointermove", this.onPointerMove) - document.removeEventListener("pointerup", this.onPointerUp) - if (this._mainCont.current != null && !this.topMost) { - const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - let dragData: { [id: string]: any } = {}; - dragData["documentView"] = this; - dragData["xOffset"] = e.x - left; - dragData["yOffset"] = e.y - top; - DragManager.StartDrag(this._mainCont.current, dragData, { - handlers: { - dragComplete: action(() => { }), - }, - hideSource: true - }) + document.removeEventListener("pointerup", this.onPointerUp); + if (!this.topMost || e.buttons == 2 || e.altKey) { + this.startDragging(e.x, e.y); } } e.stopPropagation(); @@ -145,6 +188,9 @@ export class DocumentView extends React.Component<DocumentViewProps> { SelectionManager.SelectDoc(this, e.ctrlKey); } } + stopPropogation = (e: React.SyntheticEvent) => { + e.stopPropagation(); + } deleteClicked = (): void => { if (this.props.RemoveDocument) { @@ -172,6 +218,46 @@ export class DocumentView extends React.Component<DocumentViewProps> { } @action + drop = (e: Event, de: DragManager.DropEvent) => { + console.log("drop"); + const sourceDocView: DocumentView = de.data["linkSourceDoc"]; + if (!sourceDocView) { + return; + } + let sourceDoc: Document = sourceDocView.props.Document; + let destDoc: Document = this.props.Document; + if (this.props.isTopMost) { + return; + } + let linkDoc: Document = new Document(); + + linkDoc.Set(KeyStore.Title, new TextField("New Link")); + linkDoc.Set(KeyStore.LinkDescription, new TextField("")); + linkDoc.Set(KeyStore.LinkTags, new TextField("Default")); + + sourceDoc.GetOrCreateAsync(KeyStore.LinkedToDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) }); + linkDoc.Set(KeyStore.LinkedToDocs, destDoc); + destDoc.GetOrCreateAsync(KeyStore.LinkedFromDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) }); + linkDoc.Set(KeyStore.LinkedFromDocs, sourceDoc); + + e.stopPropagation(); + } + + onDrop = (e: React.DragEvent) => { + if (e.isDefaultPrevented()) { + return; + } + let text = e.dataTransfer.getData("text/plain"); + if (text && text.startsWith("<div")) { + let oldLayout = this.props.Document.GetText(KeyStore.Layout, ""); + let layout = text.replace("{layout}", oldLayout); + this.props.Document.SetText(KeyStore.Layout, layout); + e.stopPropagation(); + e.preventDefault(); + } + } + + @action onContextMenu = (e: React.MouseEvent): void => { e.stopPropagation(); let moved = Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3; @@ -185,6 +271,12 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }) ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }) ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) + ContextMenu.Instance.addItem({ + description: "Copy ID", + event: () => { + Utils.CopyText(this.props.Document.Id); + } + }); //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) if (!this.topMost) { @@ -196,15 +288,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) SelectionManager.SelectDoc(this, e.ctrlKey); } - @computed get mainContent() { - return <JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, WebBox, KeyValueBox, VideoBox, AudioBox, PDFBox }} - bindings={this._documentBindings} - jsx={this.layout} - showWarnings={true} - onError={(test: any) => { console.log(test) }} - /> - } + isSelected = () => { return SelectionManager.IsSelected(this); @@ -214,40 +298,52 @@ export class DocumentView extends React.Component<DocumentViewProps> { SelectionManager.SelectDoc(this, ctrlPressed) } - render() { - if (!this.props.Document) return <div></div> - let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); - if (!lkeys || lkeys === "<Waiting>") { - return <p>Error loading layout keys</p>; - } - this._documentBindings = { + @computed + get getProps() { + let bindings: any = { ...this.props, isSelected: this.isSelected, select: this.select, - focus: this.props.focus + layout: this.layout }; for (const key of this.layoutKeys) { - this._documentBindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data + bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } for (const key of this.layoutFields) { let field = this.props.Document.Get(key); - this._documentBindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; + bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; + } + bindings.bindings = bindings; + + return bindings + } + + render() { + if (!this.props.Document) { + return (null); + } + let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); + if (!lkeys || lkeys === "<Waiting>") { + return <p>Error loading layout keys</p>; } - this._documentBindings.bindings = this._documentBindings; var scaling = this.props.ContentScaling(); var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + var backgroundcolor = this.props.Document.GetText(KeyStore.BackgroundColor, ""); return ( <div className="documentView-node" ref={this._mainCont} style={{ + background: backgroundcolor, width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%", height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%", transformOrigin: "left top", transform: `scale(${scaling} , ${scaling})` }} + onDrop={this.onDrop} onContextMenu={this.onContextMenu} - onPointerDown={this.onPointerDown} > - {this.mainContent} + onPointerDown={this.onPointerDown} + onPointerUp={this.stopPropogation} > + <DocumentContentsView {...this.getProps} /> </div> ) } |