diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/DragManager.ts | 12 | ||||
-rw-r--r-- | src/client/util/SelectionManager.ts | 12 | ||||
-rw-r--r-- | src/client/util/Transform.ts | 73 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 43 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 11 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 20 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 70 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 16 | ||||
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 167 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 267 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 4 |
14 files changed, 353 insertions, 358 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f4dcce7c8..337ec855a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -78,9 +78,13 @@ export namespace DragManager { dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; + // It seems like the above code should be able to just be this: + // dragElement.style.transform = `translate(${x}px, ${y}px)`; + // dragElement.style.width = `${rect.width}px`; + // dragElement.style.height = `${rect.height}px`; dragDiv.appendChild(dragElement); - _lastPointerX = dragData["xOffset"] + rect.left; - _lastPointerY = dragData["yOffset"] + rect.top; let hideSource = false; if (typeof options.hideSource === "boolean") { @@ -96,8 +100,8 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - x += e.clientX - _lastPointerX; _lastPointerX = e.clientX; - y += e.clientY - _lastPointerY; _lastPointerY = e.clientY; + x += e.movementX; + y += e.movementY; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; }; const upHandler = (e: PointerEvent) => { diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 0759ae110..1a711ae64 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,13 +1,13 @@ -import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { observable, action } from "mobx"; +import { DocumentView } from "../views/nodes/DocumentView"; export namespace SelectionManager { class Manager { @observable - SelectedDocuments: Array<CollectionFreeFormDocumentView> = []; + SelectedDocuments: Array<DocumentView> = []; @action - SelectDoc(doc: CollectionFreeFormDocumentView, ctrlPressed: boolean): void { + SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { // if doc is not in SelectedDocuments, add it if (!ctrlPressed) { manager.SelectedDocuments = []; @@ -21,11 +21,11 @@ export namespace SelectionManager { const manager = new Manager; - export function SelectDoc(doc: CollectionFreeFormDocumentView, ctrlPressed: boolean): void { + export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { manager.SelectDoc(doc, ctrlPressed) } - export function IsSelected(doc: CollectionFreeFormDocumentView): boolean { + export function IsSelected(doc: DocumentView): boolean { return manager.SelectedDocuments.indexOf(doc) !== -1; } @@ -33,7 +33,7 @@ export namespace SelectionManager { manager.SelectedDocuments = [] } - export function SelectedDocuments(): Array<CollectionFreeFormDocumentView> { + export function SelectedDocuments(): Array<DocumentView> { return manager.SelectedDocuments; } }
\ No newline at end of file diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 7861ed308..9fd4f7bef 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -7,6 +7,10 @@ export class Transform { return new Transform(0, 0, 1); } + get TranslateX(): number { return this._translateX; } + get TranslateY(): number { return this._translateY; } + get Scale(): number { return this._scale; } + constructor(x: number, y: number, scale: number) { this._translateX = x; this._translateY = y; @@ -19,56 +23,67 @@ export class Transform { return this; } - translated = (x: number, y: number): Transform => { - return this.copy().translate(x, y); - } - - preTranslate = (x: number, y: number): Transform => { - this._translateX += x * this._scale; - this._translateY += y * this._scale; + scale = (scale: number): Transform => { + this._scale *= scale; + this._translateX *= scale; + this._translateY *= scale; return this; } - preTranslated = (x: number, y: number): Transform => { - return this.copy().preTranslate(x, y); + scaleAbout = (scale: number, x: number, y: number): Transform => { + this._translateX += x * this._scale - x * this._scale * scale; + this._translateY += y * this._scale - y * this._scale * scale; + this._scale *= scale; + return this; } - scale = (scale: number): Transform => { - this._scale *= scale; + transform = (transform: Transform): Transform => { + this._translateX = transform._translateX + transform._scale * this._translateX; + this._translateY = transform._translateY + transform._scale * this._translateY; + this._scale *= transform._scale; return this; } - scaled = (scale: number): Transform => { - return this.copy().scale(scale); + preTranslate = (x: number, y: number): Transform => { + this._translateX += this._scale * x; + this._translateY += this._scale * y; + return this; } preScale = (scale: number): Transform => { this._scale *= scale; - this._translateX *= scale; - this._translateY *= scale; return this; } - preScaled = (scale: number): Transform => { - return this.copy().preScale(scale); - } - - transform = (transform: Transform): Transform => { + preTransform = (transform: Transform): Transform => { this._translateX += transform._translateX * this._scale; this._translateY += transform._translateY * this._scale; this._scale *= transform._scale; return this; } - transformed = (transform: Transform): Transform => { - return this.copy().transform(transform); + translated = (x: number, y: number): Transform => { + return this.copy().translate(x, y); } - preTransform = (transform: Transform): Transform => { - this._translateX = transform._translateX + this._translateX * transform._scale; - this._translateY = transform._translateY + this._translateY * transform._scale; - this._scale *= transform._scale; - return this; + preTranslated = (x: number, y: number): Transform => { + return this.copy().preTranslate(x, y); + } + + scaled = (scale: number): Transform => { + return this.copy().scale(scale); + } + + scaledAbout = (scale: number, x: number, y: number): Transform => { + return this.copy().scaleAbout(scale, x, y); + } + + preScaled = (scale: number): Transform => { + return this.copy().preScale(scale); + } + + transformed = (transform: Transform): Transform => { + return this.copy().transform(transform); } preTransformed = (transform: Transform): Transform => { @@ -83,6 +98,10 @@ export class Transform { return [x, y]; } + transformDirection = (x: number, y: number): [number, number] => { + return [x * this._scale, y * this._scale]; + } + inverse = () => { return new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1224495f6..d385bcdef 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,6 +5,7 @@ import { observer } from "mobx-react"; import './DocumentDecorations.scss' import { CollectionFreeFormView } from "./collections/CollectionFreeFormView"; import { KeyStore } from '../../fields/Key' +import { NumberField } from "../../fields/NumberField"; @observer export class DocumentDecorations extends React.Component { @@ -26,11 +27,15 @@ export class DocumentDecorations extends React.Component { !(element.props.ContainingCollectionView instanceof CollectionFreeFormView)) { return bounds; } - var spt = element.TransformToScreenPoint(0, 0); - var bpt = element.TransformToScreenPoint(element.width, element.height); + let transform = element.props.ScreenToLocalTransform().inverse(); + var [sptX, sptY] = transform.transformPoint(0, 0); + // var [bptX, bptY] = transform.transformDirection(element.width, element.height); + let doc = element.props.Document; + let [bptX, bptY] = [doc.GetNumber(KeyStore.Width, 0), doc.GetNumber(KeyStore.Height, 0)]; + [bptX, bptY] = transform.transformPoint(bptX, bptY); return { - x: Math.min(spt.ScreenX, bounds.x), y: Math.min(spt.ScreenY, bounds.y), - r: Math.max(bpt.ScreenX, bounds.r), b: Math.max(bpt.ScreenY, bounds.b) + x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), + r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) } }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); } @@ -106,16 +111,32 @@ export class DocumentDecorations extends React.Component { SelectionManager.SelectedDocuments().forEach(element => { const rect = element.screenRect; + // if (rect.width !== 0) { + // let scale = element.width / rect.width; + // let actualdW = Math.max(element.width + (dW * scale), 20); + // let actualdH = Math.max(element.height + (dH * scale), 20); + // element.x += dX * (actualdW - element.width); + // element.y += dY * (actualdH - element.height); + // if (Math.abs(dW) > Math.abs(dH)) + // element.width = actualdW; + // else + // element.height = actualdH; + // } if (rect.width !== 0) { - let scale = element.width / rect.width; - let actualdW = Math.max(element.width + (dW * scale), 20); - let actualdH = Math.max(element.height + (dH * scale), 20); - element.props.Document.SetNumber(KeyStore.X, element.props.Document.GetNumber(KeyStore.X, 0) + dX * (actualdW - element.width)); - element.props.Document.SetNumber(KeyStore.Y, element.props.Document.GetNumber(KeyStore.Y, 0) + dY * (actualdH - element.height)); + let doc = element.props.Document; + let width = doc.GetOrCreate(KeyStore.Width, NumberField); + let height = doc.GetOrCreate(KeyStore.Height, NumberField); + let x = doc.GetOrCreate(KeyStore.X, NumberField); + let y = doc.GetOrCreate(KeyStore.X, NumberField); + let scale = width.Data / rect.width; + let actualdW = Math.max(width.Data + (dW * scale), 20); + let actualdH = Math.max(height.Data + (dH * scale), 20); + x.Data += dX * (actualdW - width.Data); + y.Data += dY * (actualdH - height.Data); if (Math.abs(dW) > Math.abs(dH)) - element.width = actualdW; + width.Data = actualdW; else - element.height = actualdH; + height.Data = actualdH; } }) } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index aec9618ae..1eeec7ff5 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -67,10 +67,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { let doc6 = Documents.CollectionDocument(docset2, { x: 350, y: 100, width: 600, height: 600, title: "docking collection" }); - let mainNodes = null;// mainContainer.GetFieldT(KeyStore.Data, ListField); - if (!mainNodes) { - mainNodes = new ListField<Document>(); - } + let mainNodes = mainContainer.GetOrCreate<ListField<Document>>(KeyStore.Data, ListField); // mainNodes.Data.push(doc6); // mainNodes.Data.push(doc2); mainNodes.Data.push(doc4); @@ -79,7 +76,6 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // mainNodes.Data.push(doc1); // mainNodes.Data.push(doc2); mainNodes.Data.push(doc6); - mainContainer.Set(KeyStore.Data, mainNodes); } //} //); @@ -87,8 +83,9 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { ReactDOM.render(( <div style={{ position: "absolute", width: "100%", height: "100%" }}> <DocumentView Document={mainContainer} - AddDocument={undefined} RemoveDocument={undefined} GetTransform={() => Transform.Identity} - ParentScaling={1} + AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity} + Scaling={1} + isTopMost={true} ContainingCollectionView={undefined} DocumentView={undefined} /> <DocumentDecorations /> <ContextMenu /> diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1653994cf..1c1f6f8b4 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -15,6 +15,7 @@ import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from import React = require("react"); import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; +import { Utils } from "../../../Utils"; @observer export class CollectionDockingView extends CollectionViewBase { @@ -97,8 +98,9 @@ export class CollectionDockingView extends CollectionViewBase { if (value[i].Id === component) { return (<DocumentView key={value[i].Id} Document={value[i]} AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={() => Transform.Identity} - ParentScaling={1} + ScreenToLocalTransform={() => Transform.Identity} + isTopMost={true} + Scaling={1} ContainingCollectionView={this} DocumentView={undefined} />); } } @@ -238,14 +240,14 @@ export class CollectionDockingView extends CollectionViewBase { var containingDiv = "component_" + me.nextId(); container.getElement().html("<div id='" + containingDiv + "'></div>"); setTimeout(function () { - let divContainer = document.getElementById(containingDiv); + let divContainer = document.getElementById(containingDiv) as HTMLDivElement; if (divContainer) { let props: DockingProps = { ContainingDiv: containingDiv, Document: state.doc, Container: container, CollectionDockingView: me, - HtmlElement: divContainer + HtmlElement: divContainer, } ReactDOM.render((<RenderClass {...props} />), divContainer); if (CollectionDockingView.myLayout._maxstack) { @@ -292,7 +294,7 @@ interface DockingProps { Document: Document, Container: any, HtmlElement: HTMLElement, - CollectionDockingView: CollectionDockingView + CollectionDockingView: CollectionDockingView, } @observer export class RenderClass extends React.Component<DockingProps> { @@ -306,8 +308,12 @@ export class RenderClass extends React.Component<DockingProps> { <DocumentView key={this.props.Document.Id} Document={this.props.Document} AddDocument={this.props.CollectionDockingView.addDocument} RemoveDocument={this.props.CollectionDockingView.removeDocument} - GetTransform={() => Transform.Identity} - ParentScaling={this._parentScaling} + Scaling={this._parentScaling} + ScreenToLocalTransform={() => { + let { scale, translateX, translateY } = Utils.GetScreenTransform(this.props.HtmlElement); + return this.props.CollectionDockingView.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale) + }} + isTopMost={true} ContainingCollectionView={this.props.CollectionDockingView} DocumentView={undefined} /> if (nativeWidth > 0 && (layout.indexOf("CollectionFreeForm") == -1 || layout.indexOf("AnnotationsKey") != -1)) { diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 04373df12..eca8a0adf 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -14,6 +14,7 @@ import { NumberField } from "../../../fields/NumberField"; import { Documents } from "../../documents/Documents"; import { FieldWaiting } from "../../../fields/Field"; import { Transform } from "../../util/Transform"; +import { DocumentView } from "../nodes/DocumentView"; @observer export class CollectionFreeFormView extends CollectionViewBase { @@ -45,23 +46,22 @@ export class CollectionFreeFormView extends CollectionViewBase { @action drop = (e: Event, de: DragManager.DropEvent) => { - const doc = de.data["document"]; + const doc: DocumentView = de.data["document"]; var me = this; - if (doc instanceof CollectionFreeFormDocumentView) { - if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) { - doc.props.ContainingCollectionView.removeDocument(doc.props.Document); - this.addDocument(doc.props.Document); - } - const xOffset = de.data["xOffset"] as number || 0; - const yOffset = de.data["yOffset"] as number || 0; - const { translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); - const currScale = this.resizeScaling * this.zoomScaling * this.props.ContainingDocumentView!.ScalingToScreenSpace; - const screenX = de.x - xOffset; - const screenY = de.y - yOffset; - doc.props.Document.SetNumber(KeyStore.X, (screenX - translateX) / currScale); - doc.props.Document.SetNumber(KeyStore.Y, (screenY - translateY) / currScale); - this.bringToFront(doc); + if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) { + doc.props.ContainingCollectionView.removeDocument(doc.props.Document); + this.addDocument(doc.props.Document); } + const xOffset = de.data["xOffset"] as number || 0; + const yOffset = de.data["yOffset"] as number || 0; + //this should be able to use translate and scale methods on an Identity transform, no? + const transform = me.getTransform(); + const screenX = de.x - xOffset; + const screenY = de.y - yOffset; + const [x, y] = transform.transformPoint(screenX, screenY); + doc.props.Document.SetNumber(KeyStore.X, x); + doc.props.Document.SetNumber(KeyStore.Y, y); + this.bringToFront(doc); e.stopPropagation(); } @@ -94,8 +94,8 @@ export class CollectionFreeFormView extends CollectionViewBase { document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); if (Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) { - if (!SelectionManager.IsSelected(this.props.ContainingDocumentView as CollectionFreeFormDocumentView)) { - SelectionManager.SelectDoc(this.props.ContainingDocumentView as CollectionFreeFormDocumentView, false); + if (!this.props.isSelected()) { + this.props.select(false); } } } @@ -105,11 +105,11 @@ export class CollectionFreeFormView extends CollectionViewBase { if (!e.cancelBubble && this.active) { e.preventDefault(); e.stopPropagation(); - let currScale: number = this.props.ContainingDocumentView!.ScalingToScreenSpace; let x = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0); let y = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0); + let [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - this.SetPan(x + (e.pageX - this._lastX) / currScale, y + (e.pageY - this._lastY) / currScale); + this.SetPan(x + dx, y + dy); } this._lastX = e.pageX; this._lastY = e.pageY; @@ -123,15 +123,16 @@ export class CollectionFreeFormView extends CollectionViewBase { let coefficient = 1000; // if (modes[e.deltaMode] == 'pixels') coefficient = 50; // else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height?? + let transform = this.getTransform(); + + let deltaScale = (1 - (e.deltaY / coefficient)); + let [x, y] = transform.transformPoint(e.clientX, e.clientY); - let { LocalX, LocalY, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY); - var Xx = this.props.ContainingDocumentView!.LeftCorner(); - var Yy = this.props.ContainingDocumentView!.TopCorner(); - var deltaScale = (1 - (e.deltaY / coefficient)) * this.props.ContainingDocumentView!.props.Document.GetNumber(KeyStore.Scale, 1); - var newDeltaScale = this.isAnnotationOverlay ? Math.max(1, deltaScale) : deltaScale; + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) - this.props.DocumentForCollection.SetNumber(KeyStore.Scale, newDeltaScale); - this.SetPan(ContainerX - (LocalX * newDeltaScale + Xx), ContainerY - (LocalY * newDeltaScale + Yy)); + this.props.DocumentForCollection.SetNumber(KeyStore.Scale, localTransform.Scale); + this.SetPan(localTransform.TranslateX, localTransform.TranslateY); } @action @@ -180,7 +181,7 @@ export class CollectionFreeFormView extends CollectionViewBase { } @action - bringToFront(doc: CollectionFreeFormDocumentView) { + bringToFront(doc: DocumentView) { const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; const value: Document[] = Document.GetList<Document>(fieldKey, []); @@ -210,8 +211,12 @@ export class CollectionFreeFormView extends CollectionViewBase { } getTransform = (): Transform => { + return this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform()) + } + + getLocalTransform = (): Transform => { const [x, y] = this.translate; - return this.props.GetTransform().scaled(this.scale).translate(x, y); + return Transform.Identity.translate(-x, -y).scale(1 / this.scale); } render() { @@ -236,14 +241,15 @@ export class CollectionFreeFormView extends CollectionViewBase { style={{ width: "100%", transformOrigin: "left top", transform: ` translate(${panx}px, ${pany}px) scale(${this.zoomScaling}, ${this.zoomScaling})` }} ref={this._canvasRef}> - {this.props.BackgroundView} + {this.props.BackgroundView ? this.props.BackgroundView() : null} {value.map(doc => { return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc} AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={this.getTransform} - ParentScaling={1} - ContainingCollectionView={this} DocumentView={undefined} />); + ScreenToLocalTransform={this.getTransform} + isTopMost={false} + Scaling={1} + ContainingCollectionView={this} DocumentView={this.props.ContainingDocumentView} />); })} </div> </div> diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 76706f520..9a0ce0782 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -28,7 +28,8 @@ export class CollectionSchemaView extends CollectionViewBase { let props: FieldViewProps = { doc: rowProps.value[0], fieldKey: rowProps.value[1], - DocumentViewForField: undefined, + isSelected: () => false, + isTopMost: false } let contents = ( <FieldView {...props} /> @@ -122,8 +123,9 @@ export class CollectionSchemaView extends CollectionViewBase { <div ref={measureRef}> <DocumentView Document={children[this.selectedIndex]} AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={() => Transform.Identity}//TODO This should probably be an actual transform - ParentScaling={this._parentScaling} + ScreenToLocalTransform={() => Transform.Identity}//TODO This should probably be an actual transform + Scaling={this._parentScaling} + isTopMost={false} DocumentView={undefined} ContainingCollectionView={me} /> </div> } diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 1cf07ce05..4cbafe950 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -17,8 +17,11 @@ export interface CollectionViewProps { CollectionFieldKey: Key; DocumentForCollection: Document; ContainingDocumentView: Opt<DocumentView>; - GetTransform: () => Transform; - BackgroundView: Opt<DocumentView>; + ScreenToLocalTransform: () => Transform; + isSelected: () => boolean; + isTopMost: boolean; + select: (ctrlPressed: boolean) => void; + BackgroundView?: () => JSX.Element; ParentScaling: number; } @@ -28,15 +31,16 @@ export const COLLECTION_BORDER_WIDTH = 2; export class CollectionViewBase extends React.Component<CollectionViewProps> { public static LayoutString(collectionType: string, fieldKey: string = "DataKey") { - return `<${collectionType} ParentScaling={ParentScaling} DocumentForCollection={Document} CollectionFieldKey={${fieldKey}} ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`; + return `<${collectionType} Scaling={Scaling} DocumentForCollection={Document} + ScreenToLocalTransform={ScreenToLocalTransform} CollectionFieldKey={${fieldKey}} isSelected={isSelected} select={select} + isTopMost={isTopMost} + ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`; } @computed public get active(): boolean { var isSelected = (this.props.ContainingDocumentView instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView)); var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this); - var topMost = this.props.ContainingDocumentView != undefined && ( - this.props.ContainingDocumentView.props.ContainingCollectionView == undefined || - this.props.ContainingDocumentView.props.ContainingCollectionView instanceof CollectionDockingView); + var topMost = this.props.isTopMost; return isSelected || childSelected || topMost; } @action diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a2fbe96d2..57527076b 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -14,11 +14,8 @@ import { Transform } from "../../util/Transform"; @observer -export class CollectionFreeFormDocumentView extends DocumentView { - private _contextMenuCanOpen = false; - private _downX: number = 0; - private _downY: number = 0; - // private _mainCont = React.createRef<HTMLDivElement>(); +export class CollectionFreeFormDocumentView extends React.Component<DocumentViewProps> { + private _mainCont = React.createRef<HTMLDivElement>(); constructor(props: DocumentViewProps) { super(props); @@ -30,17 +27,9 @@ export class CollectionFreeFormDocumentView extends DocumentView { return new DOMRect(); } - public LeftCorner(): number { - return this.props.Document.GetNumber(KeyStore.X, 0) + super.LeftCorner(); - } - - public TopCorner(): number { - return this.props.Document.GetNumber(KeyStore.Y, 0) + super.TopCorner(); - } - @computed get transform(): string { - return `scale(${this.props.ParentScaling}, ${this.props.ParentScaling}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`; + return `scale(${this.props.Scaling}, ${this.props.Scaling}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`; } @computed @@ -85,151 +74,25 @@ export class CollectionFreeFormDocumentView extends DocumentView { this.props.Document.SetData(KeyStore.ZIndex, h, NumberField) } - @action - dragComplete = (e: DragManager.DragCompleteEvent) => { - } - - @computed - get active(): boolean { - return SelectionManager.IsSelected(this) || this.props.ContainingCollectionView === undefined || - this.props.ContainingCollectionView.active; - } - - @computed - get topMost(): boolean { - return this.props.ContainingCollectionView == undefined || this.props.ContainingCollectionView instanceof CollectionDockingView; - } - - onPointerDown = (e: React.PointerEvent): void => { - this._downX = e.clientX; - this._downY = e.clientY; - var me = this; - if (e.shiftKey && e.buttons === 1) { - CollectionDockingView.StartOtherDrag(this._mainCont.current!, this.props.Document); - e.stopPropagation(); - return; - } - this._contextMenuCanOpen = e.button == 2; - 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) - document.addEventListener("pointerup", this.onPointerUp); - } - } - - onPointerMove = (e: PointerEvent): void => { - if (e.cancelBubble) { - this._contextMenuCanOpen = false; - return; - } - if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { - this._contextMenuCanOpen = false; - if (this._mainCont.current != null && !this.topMost) { - this._contextMenuCanOpen = false; - const rect = this.screenRect; - let dragData: { [id: string]: any } = {}; - dragData["document"] = this; - dragData["xOffset"] = e.x - rect.left; - dragData["yOffset"] = e.y - rect.top; - DragManager.StartDrag(this._mainCont.current, dragData, { - handlers: { - dragComplete: this.dragComplete, - }, - hideSource: true - }) - } - } - e.stopPropagation(); - e.preventDefault(); - } - - onPointerUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onPointerMove) - document.removeEventListener("pointerup", this.onPointerUp) - e.stopPropagation(); - if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { - SelectionManager.SelectDoc(this, e.ctrlKey); - } - } - - openRight = (e: React.MouseEvent): void => { - CollectionDockingView.AddRightSplit(this.props.Document); - } - - deleteClicked = (e: React.MouseEvent): void => { - if (this.props.ContainingCollectionView instanceof CollectionFreeFormView) { - this.props.ContainingCollectionView.removeDocument(this.props.Document) - } - } - @action - fullScreenClicked = (e: React.MouseEvent): void => { - CollectionDockingView.OpenFullScreen(this.props.Document); - ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked }); - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) - } - @action - closeFullScreenClicked = (e: React.MouseEvent): void => { - CollectionDockingView.CloseFullScreen(); - ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) - } - - @action - onContextMenu = (e: React.MouseEvent): void => { - if (!SelectionManager.IsSelected(this)) { - return; - } - e.preventDefault() - - if (!this._contextMenuCanOpen) { - return; - } - - if (this.topMost) { - ContextMenu.Instance.clearItems() - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) - } - else { - // DocumentViews should stop propogation of this event - e.stopPropagation(); - - ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) - ContextMenu.Instance.addItem({ description: "Open Right", event: this.openRight }) - ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked }) - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) - SelectionManager.SelectDoc(this, e.ctrlKey); - } - } getTransform = (): Transform => { - return this.props.GetTransform().translated(this.props.Document.GetNumber(KeyStore.X, 0), this.props.Document.GetNumber(KeyStore.Y, 0)); + return this.props.ScreenToLocalTransform().translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)); } render() { var parentScaling = this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; return ( - <div className="documentView-node" ref={this._mainCont} - onContextMenu={this.onContextMenu} - onPointerDown={this.onPointerDown} - style={{ - transformOrigin: "left top", - transform: this.transform, - width: this.width, - height: this.height, - position: "absolute", - zIndex: this.zIndex, - }}> - - <DocumentView {...this.props} ref={this._renderDoc} ParentScaling={parentScaling} GetTransform={this.getTransform} DocumentView={this} /> + <div ref={this._mainCont} style={{ + transformOrigin: "left top", + transform: this.transform, + width: this.width, + height: this.height, + position: "absolute", + zIndex: this.zIndex, + backgroundColor: "transparent" + }} > + + <DocumentView {...this.props} Scaling={this.width / this.nativeWidth} ScreenToLocalTransform={this.getTransform} /> </div> ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c5270e0cd..f368fdeaf 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -14,6 +14,10 @@ import { ImageBox } from "../nodes/ImageBox"; import "./DocumentView.scss"; import React = require("react"); import { Transform } from "../../util/Transform"; +import { SelectionManager } from "../../util/SelectionManager"; +import { DragManager } from "../../util/DragManager"; +import { ContextMenu } from "../ContextMenu"; +import { TextField } from "../../../fields/TextField"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? export interface DocumentViewProps { @@ -23,32 +27,35 @@ export interface DocumentViewProps { Document: Document; AddDocument?: (doc: Document) => void; RemoveDocument?: (doc: Document) => boolean; - GetTransform: () => Transform; - ParentScaling: number; + ScreenToLocalTransform: () => Transform; + isTopMost: boolean; + Scaling: number; } @observer export class DocumentView extends React.Component<DocumentViewProps> { - protected _renderDoc = React.createRef<any>(); - protected _mainCont = React.createRef<any>(); + private _mainCont = React.createRef<HTMLDivElement>(); get MainContent() { return this._mainCont; } - - @computed - get parentScaling(): number { - return this._renderDoc.current ? this._renderDoc.current.props.ParentScaling : this.props.ParentScaling > 0 ? this.props.ParentScaling : 1; + get screenRect(): ClientRect | DOMRect { + if (this._mainCont.current) { + return this._mainCont.current.getBoundingClientRect(); + } + return new DOMRect(); } - @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); } @computed - get backgroundLayout(): string { - return this.props.Document.GetText(KeyStore.BackgroundLayout, ""); + get backgroundLayout(): string | undefined { + let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField); + if (field && field !== "<Waiting>") { + return field.Data; + } } @computed @@ -61,93 +68,159 @@ export class DocumentView extends React.Component<DocumentViewProps> { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); } - // - // returns the cumulative scaling between the document and the screen - // @computed - public get ScalingToScreenSpace(): number { - if (this.props.ContainingCollectionView != undefined && - this.props.ContainingCollectionView.props.ContainingDocumentView != undefined) { - let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetNumber(KeyStore.Scale, 1); - return this.props.ContainingCollectionView.props.ContainingDocumentView.ScalingToScreenSpace * ss; + get active(): boolean { + return SelectionManager.IsSelected(this) || this.props.ContainingCollectionView === undefined || + this.props.ContainingCollectionView.active; + } + + private _contextMenuCanOpen = false; + private _downX: number = 0; + private _downY: number = 0; + onPointerDown = (e: React.PointerEvent): void => { + this._downX = e.clientX; + this._downY = e.clientY; + var me = this; + if (e.shiftKey && e.buttons === 1) { + CollectionDockingView.StartOtherDrag(this._mainCont.current!, this.props.Document); + e.stopPropagation(); + return; + } + this._contextMenuCanOpen = e.button == 2; + 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) + document.addEventListener("pointerup", this.onPointerUp); } - return 1; } + @action + dragComplete = (e: DragManager.DragCompleteEvent) => { + } + + @computed + get topMost(): boolean { + return this.props.ContainingCollectionView == undefined || this.props.ContainingCollectionView instanceof CollectionDockingView; + } - public LeftCorner(): number { - if (this.props.ContainingCollectionView) { - if (this.props.ContainingCollectionView instanceof CollectionDockingView) { - // this is a hacky way to account for the titles/pane placement/etc of a CollectionDockingView - // this only works if the collectionDockingView is the root collection, too. - // need to find a better way. - var { translateX: rx, translateY: ry } = Utils.GetScreenTransform(this.MainContent.current!); - return rx + COLLECTION_BORDER_WIDTH; + onPointerMove = (e: PointerEvent): void => { + if (e.cancelBubble) { + this._contextMenuCanOpen = false; + return; + } + if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { + this._contextMenuCanOpen = false; + if (this._mainCont.current != null && !this.topMost) { + this._contextMenuCanOpen = false; + const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + let dragData: { [id: string]: any } = {}; + dragData["document"] = this; + dragData["xOffset"] = e.x - left; + dragData["yOffset"] = e.y - top; + DragManager.StartDrag(this._mainCont.current, dragData, { + handlers: { + dragComplete: this.dragComplete, + }, + hideSource: true + }) } - return COLLECTION_BORDER_WIDTH; // assumes all collections have the same border } - return 0; + e.stopPropagation(); + e.preventDefault(); } - public TopCorner(): number { - if (this.props.ContainingCollectionView) { - if (this.props.ContainingCollectionView instanceof CollectionDockingView) { - // this is a hacky way to account for the titles/pane placement/etc of a CollectionDockingView - // this only works if the collectionDockingView is the root collection, too. - // need to find a better way. - var { translateX: rx, translateY: ry } = Utils.GetScreenTransform(this.MainContent.current!); - return ry + COLLECTION_BORDER_WIDTH; - } - return COLLECTION_BORDER_WIDTH; // assumes all collections have the same border + onPointerUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onPointerMove) + document.removeEventListener("pointerup", this.onPointerUp) + e.stopPropagation(); + if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { + SelectionManager.SelectDoc(this, e.ctrlKey); } - return 0; } - // - // Converts a coordinate in the screen space of the app to a local point in the space of the DocumentView. - // This also returns the point in the coordinate space of this document's containing CollectionView - // - public TransformToLocalPoint(screenX: number, screenY: number) { - // if this collection view is nested within another collection view, then - // first transform the screen point into the parent collection's coordinate space. - let containingCollectionViewDoc = this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; - let { LocalX: parentX, LocalY: parentY } = !containingCollectionViewDoc ? { LocalX: screenX, LocalY: screenY } : - containingCollectionViewDoc.TransformToLocalPoint(screenX, screenY); - let ContainerX: number = parentX - COLLECTION_BORDER_WIDTH; - let ContainerY: number = parentY - COLLECTION_BORDER_WIDTH; - let Ss = this.props.Document.GetNumber(KeyStore.Scale, 1); - let Panxx = this.props.Document.GetNumber(KeyStore.PanX, 0); - let Panyy = this.props.Document.GetNumber(KeyStore.PanY, 0); - let LocalX = (ContainerX - (this.LeftCorner() + Panxx)) / Ss; - let LocalY = (ContainerY - (this.TopCorner() + Panyy)) / Ss; + openRight = (e: React.MouseEvent): void => { + CollectionDockingView.AddRightSplit(this.props.Document); + } + + deleteClicked = (e: React.MouseEvent): void => { + if (this.props.RemoveDocument) { + this.props.RemoveDocument(this.props.Document); + } + } + @action + fullScreenClicked = (e: React.MouseEvent): void => { + CollectionDockingView.OpenFullScreen(this.props.Document); + ContextMenu.Instance.clearItems(); + ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked }); + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) + } + @action + closeFullScreenClicked = (e: React.MouseEvent): void => { + CollectionDockingView.CloseFullScreen(); + ContextMenu.Instance.clearItems(); + ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) + } + + @action + onContextMenu = (e: React.MouseEvent): void => { + if (!SelectionManager.IsSelected(this)) { + return; + } + e.preventDefault() + + if (!this._contextMenuCanOpen) { + return; + } + + if (this.topMost) { + ContextMenu.Instance.clearItems() + ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) + } + else { + // DocumentViews should stop propogation of this event + e.stopPropagation(); - return { LocalX, LocalY, ContainerX, ContainerY }; + ContextMenu.Instance.clearItems(); + ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) + ContextMenu.Instance.addItem({ description: "Open Right", event: this.openRight }) + ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked }) + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) + SelectionManager.SelectDoc(this, e.ctrlKey); + } } + // + // returns the cumulative scaling between the document and the screen // - // Converts a point in the coordinate space of the document to coordinate in app screen coordinates - // - public TransformToScreenPoint(localX: number, localY: number, applyViewXf: boolean = false): { ScreenX: number, ScreenY: number } { - var parentScaling = applyViewXf ? this.parentScaling : 1; - let Panxx = applyViewXf ? this.props.Document.GetNumber(KeyStore.PanX, 0) : 0; - let Panyy = applyViewXf ? this.props.Document.GetNumber(KeyStore.PanY, 0) : 0; - var Zoom = applyViewXf ? this.props.Document.GetNumber(KeyStore.Scale, 1) : 1; - - let parentX = this.LeftCorner() + (Panxx + (localX - COLLECTION_BORDER_WIDTH) * Zoom) * parentScaling; - let parentY = this.TopCorner() + (Panyy + (localY - COLLECTION_BORDER_WIDTH) * Zoom) * parentScaling; - // if this collection view is nested within another collection view, then - // first transform the local point into the parent collection's coordinate space. - let containingDocView = this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; - if (containingDocView) { - let { ScreenX, ScreenY } = containingDocView.TransformToScreenPoint(parentX + COLLECTION_BORDER_WIDTH * parentScaling, parentY + COLLECTION_BORDER_WIDTH * parentScaling, true); - parentX = ScreenX; - parentY = ScreenY; + @computed + public get ScalingToScreenSpace(): number { + if (this.props.ContainingCollectionView != undefined && + this.props.ContainingCollectionView.props.ContainingDocumentView != undefined) { + let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetNumber(KeyStore.Scale, 1); + return this.props.ContainingCollectionView.props.ContainingDocumentView.ScalingToScreenSpace * ss; } - return { ScreenX: parentX, ScreenY: parentY }; + return 1; + } + + isSelected = () => { + return SelectionManager.IsSelected(this); + } + + select = (ctrlPressed: boolean) => { + SelectionManager.SelectDoc(this, ctrlPressed) } render() { let bindings = { ...this.props } as any; + bindings.isSelected = this.isSelected; + bindings.select = this.select; for (const key of this.layoutKeys) { 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 } @@ -155,33 +228,33 @@ export class DocumentView extends React.Component<DocumentViewProps> { let field = this.props.Document.Get(key); bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; } - if (bindings.DocumentView === undefined) { - bindings.DocumentView = this; // set the DocumentView to this if it hasn't already been set by a sub-class during its render method. - } - if (this.backgroundLayout) { - var backgroundview = <JsxParser - components={{ FormattedTextBox: FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} + /* + Should this be moved to CollectionFreeformView or another component that renders + Document backgrounds (or contents based on a layout key, which could be used here as well) + that CollectionFreeformView uses? It seems like a lot for it to be here considering only one view currently uses it... + */ + let backgroundLayout = this.backgroundLayout; + if (backgroundLayout) { + let backgroundView = () => (<JsxParser + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} bindings={bindings} jsx={this.backgroundLayout} showWarnings={true} onError={(test: any) => { console.log(test) }} - />; - bindings["BackgroundView"] = backgroundview; + />); + bindings.BackgroundView = backgroundView; } - var nativewidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); - var nativeheight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); - var width = nativewidth > 0 ? nativewidth + "px" : "100%"; - var height = nativeheight > 0 ? nativeheight + "px" : "100%"; + + var width = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + var strwidth = width > 0 ? width.toString() + "px" : "100%"; + var height = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + var strheight = height > 0 ? height.toString() + "px" : "100%"; return ( - <div className="documentView-node" ref={this._mainCont} - style={{ - width: width, - height: height, - transformOrigin: "top left", - transform: `scale(${this.props.ParentScaling},${this.props.ParentScaling})` - }}> + <div className="documentView-node" ref={this._mainCont} style={{ width: strwidth, height: strheight, transformOrigin: "left top", transform: `scale(${this.props.Scaling},${this.props.Scaling})` }} + onContextMenu={this.onContextMenu} + onPointerDown={this.onPointerDown} > <JsxParser - components={{ FormattedTextBox: FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} bindings={bindings} jsx={this.layout} showWarnings={true} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 12371eb2e..08de53e1c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -10,7 +10,6 @@ import { ImageField } from "../../../fields/ImageField"; import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; -import { DocumentView } from "./DocumentView"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. @@ -20,12 +19,13 @@ import { DocumentView } from "./DocumentView"; export interface FieldViewProps { fieldKey: Key; doc: Document; - DocumentViewForField: Opt<DocumentView> + isSelected: () => boolean; + isTopMost: boolean; } @observer export class FieldView extends React.Component<FieldViewProps> { - public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} />`; } + public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} isSelected={isSelected} isTopMost={isTopMost} />`; } @computed get field(): FieldValue<Field> { const { doc, fieldKey } = this.props; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f6bd0c0f8..2e3d396c1 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -110,7 +110,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { } onPointerDown = (e: React.PointerEvent): void => { let me = this; - if (e.buttons === 1 && me.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(me.props.DocumentViewForField)) { + if (e.buttons === 1 && this.props.isSelected()) { e.stopPropagation(); } } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 2fa70734d..e1fa26e2f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -41,7 +41,7 @@ export class ImageBox extends React.Component<FieldViewProps> { onPointerDown = (e: React.PointerEvent): void => { if (Date.now() - this._lastTap < 300) { - if (e.buttons === 1 && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) { + if (e.buttons === 1 && this.props.isSelected()) { e.stopPropagation(); this._downX = e.clientX; this._downY = e.clientY; @@ -63,7 +63,7 @@ export class ImageBox extends React.Component<FieldViewProps> { lightbox = (path: string) => { const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"]; - if (this._isOpen && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) { + if (this._isOpen && this.props.isSelected()) { return (<Lightbox mainSrc={images[this._photoIndex]} nextSrc={images[(this._photoIndex + 1) % images.length]} |