From 11134bc5ce01d0a025d311a4f83e67ff6e63ce1c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 9 Feb 2019 19:13:24 -0500 Subject: Moved client code to client folder --- src/client/views/nodes/ImageBox.tsx | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/client/views/nodes/ImageBox.tsx (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx new file mode 100644 index 000000000..ab20f140c --- /dev/null +++ b/src/client/views/nodes/ImageBox.tsx @@ -0,0 +1,92 @@ + +import Lightbox from 'react-image-lightbox'; +import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app +import { SelectionManager } from "../../util/SelectionManager"; +import "./ImageBox.scss"; +import React = require("react") +import { ImageField } from '../../../fields/ImageField'; +import { FieldViewProps, FieldView } from './FieldView'; +import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; +import { FieldWaiting } from '../../../fields/Field'; +import { observer } from "mobx-react" +import { observable, action } from 'mobx'; + +@observer +export class ImageBox extends React.Component { + + public static LayoutString() { return FieldView.LayoutString("ImageBox"); } + private _ref: React.RefObject; + private _downX: number = 0; + private _downY: number = 0; + private _lastTap: number = 0; + @observable private _photoIndex: number = 0; + @observable private _isOpen: boolean = false; + + constructor(props: FieldViewProps) { + super(props); + + this._ref = React.createRef(); + this.state = { + photoIndex: 0, + isOpen: false, + }; + } + + componentDidMount() { + } + + componentWillUnmount() { + } + + 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)) { + e.stopPropagation(); + this._downX = e.clientX; + this._downY = e.clientY; + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + } else { + this._lastTap = Date.now(); + } + } + @action + onPointerUp = (e: PointerEvent): void => { + document.removeEventListener("pointerup", this.onPointerUp); + if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { + this._isOpen = true; + } + e.stopPropagation(); + } + + 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)) { + return ( this.setState({ isOpen: false })} + onMovePrevRequest={action(() => + this._photoIndex = (this._photoIndex + images.length - 1) % images.length + )} + onMoveNextRequest={action(() => + this._photoIndex = (this._photoIndex + 1) % images.length + )} + />) + } + } + + render() { + let field = this.props.doc.Get(this.props.fieldKey); + let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; + + return ( +
+ Image not found + {this.lightbox(path)} +
) + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9f8653ab3d7f82a5d82b925bf339bef8d6723f5c Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 11 Feb 2019 17:37:03 -0500 Subject: added framework for annotation overlays -- see ImageBox --- src/client/documents/Documents.ts | 14 +++-- src/client/views/Main.tsx | 12 ++-- .../views/collections/CollectionDockingView.tsx | 4 +- .../views/collections/CollectionFreeFormView.tsx | 69 ++++++++++++++-------- .../views/collections/CollectionSchemaView.tsx | 14 +++-- .../views/collections/CollectionViewBase.tsx | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 20 ++++++- src/client/views/nodes/ImageBox.scss | 1 + src/client/views/nodes/ImageBox.tsx | 10 +++- src/fields/Key.ts | 3 + 11 files changed, 101 insertions(+), 50 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6925234fe..12eddaec9 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -115,11 +115,13 @@ export namespace Documents { imageProto.Set(KeyStore.Title, new TextField("IMAGE PROTO")); imageProto.Set(KeyStore.X, new NumberField(0)); imageProto.Set(KeyStore.Y, new NumberField(0)); - imageProto.Set(KeyStore.Width, new NumberField(300)); - imageProto.Set(KeyStore.Height, new NumberField(300)); - imageProto.Set(KeyStore.Layout, new TextField(ImageBox.LayoutString())); + imageProto.Set(KeyStore.NativeWidth, new NumberField(606)); + imageProto.Set(KeyStore.Width, new NumberField(606)); + imageProto.Set(KeyStore.Height, new NumberField(446)); + imageProto.Set(KeyStore.Layout, new TextField("")); + imageProto.Set(KeyStore.AnnotatedLayout, new TextField(ImageBox.LayoutString())); // imageProto.SetField(KeyStore.Layout, new TextField('
')); - imageProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); + imageProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations])); Server.AddDocument(imageProto); return imageProto; } @@ -130,6 +132,10 @@ export namespace Documents { let doc = GetImagePrototype().MakeDelegate(); setupOptions(doc, options); doc.Set(KeyStore.Data, new ImageField(new URL(url))); + + let annotation = Documents.TextDocument({ title: "hello" }); + Server.AddDocument(annotation); + doc.Set(KeyStore.Annotations, new ListField([annotation])); Server.AddDocument(doc); var sdoc = Server.GetField(doc.Id) as Document; return sdoc; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 9a359e868..31a709744 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -43,11 +43,11 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { let doc2 = doc1.MakeDelegate(); doc2.Set(KS.X, new NumberField(150)); doc2.Set(KS.Y, new NumberField(20)); - let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { + let doc3 = Documents.ImageDocument("https://psmag.com/.image/t_share/MTMyNzc2NzM1MDY1MjgzMDM4/shutterstock_151341212jpg.jpg", { x: 450, y: 100, title: "cat 1" }); - doc3.Set(KeyStore.Data, new ImageField); - const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { + //doc3.Set(KeyStore.Data, new ImageField); + const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://psmag.com/.image/t_share/MTMyNzc2NzM1MDY1MjgzMDM4/shutterstock_151341212jpg.jpg", { x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v })); schemaDocs[0].SetData(KS.Author, "Tyler", TextField); @@ -61,7 +61,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { // x: 650, y: 500, width: 600, height: 600, title: "cat 2" // }); - let docset2 = new Array(doc4);//, doc1, doc3); + let docset2 = [doc4, doc1, doc3]; let doc6 = Documents.CollectionDocument(docset2, { x: 350, y: 100, width: 600, height: 600, title: "docking collection" }); @@ -76,7 +76,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // mainNodes.Data.push(doc5); // mainNodes.Data.push(doc1); //mainNodes.Data.push(doc2); - //mainNodes.Data.push(doc6); + mainNodes.Data.push(doc6); mainContainer.Set(KeyStore.Data, mainNodes); } //} @@ -84,7 +84,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { ReactDOM.render((
- +
), diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9aee9c10f..037b85712 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -95,7 +95,7 @@ export class CollectionDockingView extends CollectionViewBase { const value: Document[] = Document.GetData(fieldKey, ListField, []); for (var i: number = 0; i < value.length; i++) { if (value[i].Id === component) { - return (); + return (); } } if (component === "text") { @@ -236,7 +236,7 @@ export class CollectionDockingView extends CollectionViewBase { container.getElement().html("
"); setTimeout(function () { ReactDOM.render(( - + ), document.getElementById(containingDiv) ); diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 9cf29d000..9cf8f2e35 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -22,11 +22,25 @@ export class CollectionFreeFormView extends CollectionViewBase { private _nodeContainerRef = React.createRef(); private _lastX: number = 0; private _lastY: number = 0; + private _downX: number = 0; + private _downY: number = 0; constructor(props: CollectionViewProps) { super(props); } + @computed + get isAnnotationOverlay() { return this.props.CollectionFieldKey == KeyStore.Annotations; } + + @computed + get nativeWidth() { return this.props.DocumentForCollection.GetNumber(KeyStore.NativeWidth, 0); } + + @computed + get zoomScaling() { return this.props.DocumentForCollection.GetNumber(KeyStore.Scale, 1); } + + @computed + get resizeScaling() { return this.isAnnotationOverlay ? this.props.DocumentForCollection.GetNumber(KeyStore.Width, 0) / this.nativeWidth : 1; } + @action drop = (e: Event, de: DragManager.DropEvent) => { const doc = de.data["document"]; @@ -38,12 +52,12 @@ export class CollectionFreeFormView extends CollectionViewBase { } const xOffset = de.data["xOffset"] as number || 0; const yOffset = de.data["yOffset"] as number || 0; - const { scale, translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); - let sscale = this.props.ContainingDocumentView!.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)) + 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; - const docX = (screenX - translateX) / sscale / scale; - const docY = (screenY - translateY) / sscale / scale; + const docX = (screenX - translateX) / currScale; + const docY = (screenY - translateY) / currScale; doc.x = docX; doc.y = docY; this.bringToFront(doc); @@ -69,8 +83,8 @@ export class CollectionFreeFormView extends CollectionViewBase { document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); - this._lastX = e.pageX; - this._lastY = e.pageY; + this._downX = this._lastX = e.pageX; + this._downY = this._lastY = e.pageY; } } @@ -79,20 +93,23 @@ export class CollectionFreeFormView extends CollectionViewBase { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - SelectionManager.DeselectAll(); + 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); + } + } } @action onPointerMove = (e: PointerEvent): void => { - var me = this; if (!e.cancelBubble && this.active) { e.preventDefault(); e.stopPropagation(); let currScale: number = this.props.ContainingDocumentView!.ScalingToScreenSpace; - let x = this.props.DocumentForCollection.GetData(KeyStore.PanX, NumberField, Number(0)); - let y = this.props.DocumentForCollection.GetData(KeyStore.PanY, NumberField, Number(0)); - this.props.DocumentForCollection.SetData(KeyStore.PanX, x + (e.pageX - this._lastX) / currScale, NumberField); - this.props.DocumentForCollection.SetData(KeyStore.PanY, y + (e.pageY - this._lastY) / currScale, NumberField); + let x = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0); + let y = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0); + + this.SetPan(x + (e.pageX - this._lastX) / currScale, y + (e.pageY - this._lastY) / currScale); } this._lastX = e.pageX; this._lastY = e.pageY; @@ -105,16 +122,18 @@ export class CollectionFreeFormView extends CollectionViewBase { let { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY); var deltaScale = (1 - (e.deltaY / 1000)) * Ss; + var newDeltaScale = this.isAnnotationOverlay ? Math.max(1, deltaScale) : deltaScale; - var newContainerX = LocalX * deltaScale + Panxx + Xx; - var newContainerY = LocalY * deltaScale + Panyy + Yy; - - let dx = ContainerX - newContainerX; - let dy = ContainerY - newContainerY; + this.props.DocumentForCollection.SetNumber(KeyStore.Scale, newDeltaScale); + this.SetPan(ContainerX - (LocalX * newDeltaScale + Xx), ContainerY - (LocalY * newDeltaScale + Yy)); + } - this.props.DocumentForCollection.Set(KeyStore.Scale, new NumberField(deltaScale)); - this.props.DocumentForCollection.SetData(KeyStore.PanX, Panxx + dx, NumberField); - this.props.DocumentForCollection.SetData(KeyStore.PanY, Panyy + dy, NumberField); + @action + private SetPan(panX: number, panY: number) { + const newPanX = Math.max(-(this.resizeScaling * this.zoomScaling - this.resizeScaling) * this.nativeWidth, Math.min(0, panX)); + const newPanY = Math.min(0, panY); + this.props.DocumentForCollection.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX); + this.props.DocumentForCollection.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY); } @action @@ -173,11 +192,10 @@ export class CollectionFreeFormView extends CollectionViewBase { } render() { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; - const value: Document[] = Document.GetList(fieldKey, []); + const Document: Document = this.props.DocumentForCollection; + const value: Document[] = Document.GetList(this.props.CollectionFieldKey, []); const panx: number = Document.GetNumber(KeyStore.PanX, 0); const pany: number = Document.GetNumber(KeyStore.PanY, 0); - const currScale: number = Document.GetNumber(KeyStore.Scale, 1); return (
-
+
+ {this.props.BackgroundView} {value.map(doc => { - return (); + return (); })}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2d5bd6c99..b2ee2f5f2 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -86,10 +86,11 @@ export class CollectionSchemaView extends CollectionViewBase { if (target.tagName == "SPAN" && target.className.includes("Resizer")) { e.stopPropagation(); } - if (e.button === 2 && this.active) { - e.stopPropagation(); - e.preventDefault(); - } else { + // if (e.button === 2 && this.active) { + // e.stopPropagation(); + // e.preventDefault(); + // } else + { if (e.buttons === 1 && this.active) { e.stopPropagation(); } @@ -104,7 +105,7 @@ export class CollectionSchemaView extends CollectionViewBase { let content; if (this.selectedIndex != -1) { content = ( - + ) } else { content =
@@ -119,7 +120,8 @@ export class CollectionSchemaView extends CollectionViewBase { page={0} showPagination={false} style={{ - display: "inline-block" + display: "inline-block", + width: "100%" }} columns={columns.map(col => { return ( diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 09e8ec729..e854d3077 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -16,6 +16,7 @@ export interface CollectionViewProps { CollectionFieldKey: Key; DocumentForCollection: Document; ContainingDocumentView: Opt; + BackgroundView: Opt; } export const COLLECTION_BORDER_WIDTH = 2; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 1d53cedc4..a183db828 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -48,7 +48,7 @@ export class CollectionFreeFormDocumentView extends DocumentView { @computed get transform(): string { - return `translate(${this.x}px, ${this.y}px)`; + return `scale(${this.props.Scaling}, ${this.props.Scaling}) translate(${this.x}px, ${this.y}px)`; } @computed @@ -207,6 +207,7 @@ export class CollectionFreeFormDocumentView extends DocumentView { var freestyling = this.props.ContainingCollectionView instanceof CollectionFreeFormView; return (
// needed only to set ContainingDocumentView on CollectionViewProps when invoked from JsxParser -- is there a better way? ContainingCollectionView: Opt; + Scaling: number; } @observer export class DocumentView extends React.Component { @@ -34,6 +35,11 @@ export class DocumentView extends React.Component { return this.props.Document.GetData(KeyStore.Layout, TextField, String("

Error loading layout data

")); } + @computed + get annotatedlayout(): string { + return this.props.Document.GetData(KeyStore.AnnotatedLayout, TextField, String("

Error loading layout data

")); + } + @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array()); @@ -51,7 +57,7 @@ export class DocumentView extends React.Component { public get ScalingToScreenSpace(): number { if (this.props.ContainingCollectionView != undefined && this.props.ContainingCollectionView.props.ContainingDocumentView != undefined) { - let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetData(KeyStore.Scale, NumberField, Number(1)); + let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetNumber(KeyStore.Scale, 1); return this.props.ContainingCollectionView.props.ContainingDocumentView.ScalingToScreenSpace * ss; } return 1; @@ -81,7 +87,7 @@ export class DocumentView extends React.Component { Yy = ry - COLLECTION_BORDER_WIDTH; } - let Ss = this.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)); + let Ss = this.props.Document.GetNumber(KeyStore.Scale, 1); let Panxx = this.props.Document.GetData(KeyStore.PanX, NumberField, Number(0)); let Panyy = this.props.Document.GetData(KeyStore.PanY, NumberField, Number(0)); let LocalX = (ContainerX - (Xx + Panxx)) / Ss; @@ -115,7 +121,7 @@ export class DocumentView extends React.Component { // first transform the local point into the parent collection's coordinate space. let containingDocView = this.props.ContainingCollectionView != undefined ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; if (containingDocView != undefined) { - let ss = containingDocView.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)); + let ss = containingDocView.props.Document.GetNumber(KeyStore.Scale, 1) * this.props.Scaling; let panxx = containingDocView.props.Document.GetData(KeyStore.PanX, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; let panyy = containingDocView.props.Document.GetData(KeyStore.PanY, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; let { ScreenX, ScreenY } = containingDocView.TransformToScreenPoint(parentX, parentY, ss, panxx, panyy); @@ -138,6 +144,14 @@ export class DocumentView extends React.Component { 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. } + var annotated = { console.log(test) }} + />; + bindings["BackgroundView"] = this.annotatedlayout ? annotated : null; return (
{ @@ -67,7 +68,9 @@ export class ImageBox extends React.Component { mainSrc={images[this._photoIndex]} nextSrc={images[(this._photoIndex + 1) % images.length]} prevSrc={images[(this._photoIndex + images.length - 1) % images.length]} - onCloseRequest={() => this.setState({ isOpen: false })} + onCloseRequest={action(() => + this._isOpen = false + )} onMovePrevRequest={action(() => this._photoIndex = (this._photoIndex + images.length - 1) % images.length )} @@ -82,10 +85,11 @@ export class ImageBox extends React.Component { let field = this.props.doc.Get(this.props.fieldKey); let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; + let width = this.props.doc.GetNumber(KeyStore.Width, 1); return (
- Image not found + Image not found {this.lightbox(path)}
) } diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 993102613..67a5f86fb 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -42,11 +42,14 @@ export namespace KeyStore { export const PanX = new Key("PanX"); export const PanY = new Key("PanY"); export const Scale = new Key("Scale"); + export const NativeWidth = new Key("NativeWidth"); export const Width = new Key("Width"); export const Height = new Key("Height"); export const ZIndex = new Key("ZIndex"); export const Data = new Key("Data"); + export const Annotations = new Key("Annotations"); export const Layout = new Key("Layout"); + export const AnnotatedLayout = new Key("AnnotatedLayout"); export const LayoutKeys = new Key("LayoutKeys"); export const LayoutFields = new Key("LayoutFields"); export const ColumnsKey = new Key("SchemaColumns"); -- cgit v1.2.3-70-g09d2 From 2541c2cd562251143050554f3c0117caed6d9345 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Feb 2019 10:48:03 -0500 Subject: still struggling with sizing issues. --- src/client/views/collections/CollectionDockingView.tsx | 5 +++-- src/client/views/collections/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/ImageBox.scss | 3 ++- src/client/views/nodes/ImageBox.tsx | 3 +-- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 15a586282..e3d50eb80 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -243,8 +243,9 @@ export class CollectionDockingView extends CollectionViewBase { setTimeout(function () { var htmlElement = document.getElementById(containingDiv); container.on('resize', (e: any) => { - state.doc.SetNumber(KeyStore.Width, htmlElement!.clientWidth); - state.doc.SetNumber(KeyStore.Height, htmlElement!.clientHeight); + // state.doc.SetNumber(KeyStore.Width, htmlElement!.clientWidth); + // if (htmlElement!.clientHeight > 0) + // state.doc.SetNumber(KeyStore.Height, htmlElement!.clientHeight); }) ReactDOM.render((
{this.props.BackgroundView} diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 83392311b..2bd8b1d3c 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -1,7 +1,8 @@ .imageBox-cont { padding: 0vw; - position: absolute + position: absolute; + width: 100% } .imageBox-button { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index b96e717ed..60be5f94d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -85,11 +85,10 @@ export class ImageBox extends React.Component { let field = this.props.doc.Get(this.props.fieldKey); let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; - let width = this.props.doc.GetNumber(KeyStore.Width, 1); return (
- Image not found + Image not found {this.lightbox(path)}
) } -- cgit v1.2.3-70-g09d2 From 7a93f60c9529e5d175e617fc7c07145a9b33e572 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Feb 2019 15:49:06 -0500 Subject: more updates to resizing, etc. --- src/client/documents/Documents.ts | 4 +- src/client/views/Main.tsx | 6 +-- .../views/collections/CollectionDockingView.tsx | 63 +++++++++++++++------- .../views/collections/CollectionFreeFormView.tsx | 7 +-- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionViewBase.tsx | 5 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 9 +++- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 3 +- 10 files changed, 68 insertions(+), 35 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7512d25cb..72fa608ad 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -127,7 +127,7 @@ export namespace Documents { imageProto.Set(KeyStore.NativeHeight, new NumberField(300)); imageProto.Set(KeyStore.Width, new NumberField(300)); imageProto.Set(KeyStore.Height, new NumberField(300)); - imageProto.Set(KeyStore.Layout, new TextField("")); + imageProto.Set(KeyStore.Layout, new TextField(CollectionFreeFormView.LayoutString("AnnotationsKey"))); imageProto.Set(KeyStore.BackgroundLayout, new TextField(ImageBox.LayoutString())); // imageProto.SetField(KeyStore.Layout, new TextField('
')); imageProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations])); @@ -161,7 +161,7 @@ export namespace Documents { collectionProto.Set(KeyStore.PanY, new NumberField(0)); collectionProto.Set(KeyStore.Width, new NumberField(300)); collectionProto.Set(KeyStore.Height, new NumberField(300)); - collectionProto.Set(KeyStore.Layout, new TextField(CollectionFreeFormView.LayoutString())); + collectionProto.Set(KeyStore.Layout, new TextField(CollectionFreeFormView.LayoutString("DataKey"))); collectionProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return collectionProto; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index b58704264..ba92cc17e 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -40,7 +40,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { //runInAction(() => { - let doc1 = Documents.TextDocument({ title: "hello" }); + let doc1 = Documents.TextDocument({ title: "hello", width: 400, height: 300 }); let doc2 = doc1.MakeDelegate(); doc2.Set(KS.X, new NumberField(150)); doc2.Set(KS.Y, new NumberField(20)); @@ -62,7 +62,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { // x: 650, y: 500, width: 600, height: 600, title: "cat 2" // }); - let docset2 = [doc4, doc1, doc3]; + let docset2 = [doc3, doc1, doc2]; let doc6 = Documents.CollectionDocument(docset2, { x: 350, y: 100, width: 600, height: 600, title: "docking collection" }); @@ -76,7 +76,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { mainNodes.Data.push(doc3); // mainNodes.Data.push(doc5); // mainNodes.Data.push(doc1); - //mainNodes.Data.push(doc2); + // mainNodes.Data.push(doc2); mainNodes.Data.push(doc6); mainContainer.Set(KeyStore.Data, mainNodes); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e3d50eb80..d3e90d11c 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -2,7 +2,7 @@ import FlexLayout from "flexlayout-react"; import * as GoldenLayout from "golden-layout"; import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; -import { action, computed } from "mobx"; +import { action, computed, reaction, observable } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import { Document } from "../../../fields/Document"; @@ -44,7 +44,7 @@ export class CollectionDockingView extends CollectionViewBase { const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; const value: Document[] = Document.GetData(fieldKey, ListField, []); var docs = value.map(doc => { - return { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } }; + return { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc, scaling: 1 } }; }); return new GoldenLayout({ settings: { @@ -111,6 +111,7 @@ export class CollectionDockingView extends CollectionViewBase { public static myLayout: any = null; + public rcs: Array = new Array(); private static _dragDiv: any = null; private static _dragParent: HTMLElement | null = null; private static _dragElement: HTMLDivElement; @@ -119,7 +120,7 @@ export class CollectionDockingView extends CollectionViewBase { var newItemConfig = { type: 'component', componentName: 'documentViewComponent', - componentState: { doc: dragDoc } + componentState: { doc: dragDoc, scaling: 1 } }; this._dragElement = dragElement; this._dragParent = dragElement.parentElement; @@ -160,7 +161,6 @@ export class CollectionDockingView extends CollectionViewBase { CollectionDockingView.myLayout._maximizedStack = null; } } - // // Creates a vertical split on the right side of the docking view, and then adds the Document to that split // @@ -241,21 +241,8 @@ export class CollectionDockingView extends CollectionViewBase { var containingDiv = "component_" + me.nextId(); container.getElement().html("
"); setTimeout(function () { - var htmlElement = document.getElementById(containingDiv); - container.on('resize', (e: any) => { - // state.doc.SetNumber(KeyStore.Width, htmlElement!.clientWidth); - // if (htmlElement!.clientHeight > 0) - // state.doc.SetNumber(KeyStore.Height, htmlElement!.clientHeight); - }) - ReactDOM.render(( - Transform.Identity} - Scaling={1} - ContainingCollectionView={me} DocumentView={undefined} /> - ), - htmlElement - ); + state.rc = new RenderClass(containingDiv, state.doc, me, container); + me.rcs.push(state.rc); if (CollectionDockingView.myLayout._maxstack != null) { CollectionDockingView.myLayout._maxstack.click(); } @@ -294,4 +281,42 @@ export class CollectionDockingView extends CollectionViewBase {
); } +} + +class RenderClass { + + @observable _resizeCount: number = 0; + + _collectionDockingView: CollectionDockingView; + _htmlElement: any; + _document: Document; + constructor(containingDiv: string, doc: Document, me: CollectionDockingView, container: any) { + this._collectionDockingView = me; + this._htmlElement = document.getElementById(containingDiv); + this._document = doc; + container.on('resize', action((e: any) => { + var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0); + if (this._htmlElement != null && this._htmlElement.childElementCount > 0 && nativeWidth > 0) { + let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1; + (this._htmlElement!.children[0] as any).style.transformOrigin = "0px 0px"; + (this._htmlElement!.children[0] as any).style.transform = `translate(0px,0px) scale(${scaling}, ${scaling}) `; + (this._htmlElement!.children[0] as any).style.width = nativeWidth.toString() + "px"; + } + })); + + this.render(); + } + render() { + var nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0); + let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1; + ReactDOM.render(( + Transform.Identity} + Scaling={scaling} + ContainingCollectionView={this._collectionDockingView} DocumentView={undefined} /> + ), + this._htmlElement + ); + } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 977a03f58..15450d737 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -17,7 +17,7 @@ import { Transform } from "../../util/Transform"; @observer export class CollectionFreeFormView extends CollectionViewBase { - public static LayoutString() { return CollectionViewBase.LayoutString("CollectionFreeFormView"); } + public static LayoutString(fieldKey: string = "DataKey") { return CollectionViewBase.LayoutString("CollectionFreeFormView", fieldKey); } private _containerRef = React.createRef(); private _canvasRef = React.createRef(); private _lastX: number = 0; @@ -218,6 +218,7 @@ export class CollectionFreeFormView extends CollectionViewBase { const value: Document[] = Document.GetList(this.props.CollectionFieldKey, []); const panx: number = Document.GetNumber(KeyStore.PanX, 0); const pany: number = Document.GetNumber(KeyStore.PanY, 0); + var me = this; return (
{this.props.BackgroundView} @@ -240,7 +241,7 @@ export class CollectionFreeFormView extends CollectionViewBase { AddDocument={this.addDocument} RemoveDocument={this.removeDocument} GetTransform={this.getTransform} - Scaling={this.resizeScaling} + Scaling={1} ContainingCollectionView={this} DocumentView={undefined} />); })}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 331c4f6fe..f1e882e20 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -27,7 +27,7 @@ export class CollectionSchemaView extends CollectionViewBase { let props: FieldViewProps = { doc: rowProps.value[0], fieldKey: rowProps.value[1], - DocumentViewForField: undefined + DocumentViewForField: undefined, } let contents = ( diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index eea7908ce..7e2fcb39d 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -19,6 +19,7 @@ export interface CollectionViewProps { ContainingDocumentView: Opt; GetTransform: () => Transform; BackgroundView: Opt; + Scaling: number; } export const COLLECTION_BORDER_WIDTH = 2; @@ -26,8 +27,8 @@ export const COLLECTION_BORDER_WIDTH = 2; @observer export class CollectionViewBase extends React.Component { - public static LayoutString(collectionType: string) { - return `<${collectionType} DocumentForCollection={Document} CollectionFieldKey={DataKey} ContainingDocumentView={DocumentView}/>`; + public static LayoutString(collectionType: string, fieldKey: string = "DataKey") { + return `<${collectionType} Scaling={Scaling} DocumentForCollection={Document} CollectionFieldKey={${fieldKey}} ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`; } @computed public get active(): boolean { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 54d3a1b56..9cd42a069 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -238,7 +238,7 @@ export class CollectionFreeFormDocumentView extends DocumentView { onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}> - +
); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 691ac6311..3a73f2fde 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -115,7 +115,7 @@ export class DocumentView extends React.Component { if (this.props.ContainingCollectionView instanceof CollectionDockingView) { var { translateX: rx, translateY: ry } = Utils.GetScreenTransform(this.MainContent.current!); Xx = rx - COLLECTION_BORDER_WIDTH; - Yy = ry - COLLECTION_BORDER_WIDTH; + Yy = ry - COLLECTION_BORDER_WIDTH + 18 * Ss; } let W = COLLECTION_BORDER_WIDTH; @@ -158,8 +158,13 @@ export class DocumentView extends React.Component { onError={(test: any) => { console.log(test) }} />; bindings["BackgroundView"] = this.backgroundLayout ? annotated : null; + + 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 ( -
+
{ return (
) diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 60be5f94d..2fa70734d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -85,10 +85,11 @@ export class ImageBox extends React.Component { let field = this.props.doc.Get(this.props.fieldKey); let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; + let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1); return (
- Image not found + Image not found {this.lightbox(path)}
) } -- cgit v1.2.3-70-g09d2 From c93c3e1970c6ecc91b60f1782e82b1bfdc7fef30 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 13 Feb 2019 04:50:56 -0500 Subject: A lot of stuff working, a lot of other stuff not working --- .vscode/launch.json | 6 +- src/client/util/DragManager.ts | 2 + src/client/util/SelectionManager.ts | 12 +- src/client/util/Transform.ts | 70 ++++---- src/client/views/DocumentDecorations.tsx | 39 ++++- src/client/views/Main.tsx | 1 + .../views/collections/CollectionDockingView.tsx | 10 +- .../views/collections/CollectionFreeFormView.tsx | 55 +++--- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionViewBase.tsx | 10 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 138 +--------------- src/client/views/nodes/DocumentView.tsx | 184 +++++++++++++++++++-- src/client/views/nodes/FieldView.tsx | 6 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 4 +- 15 files changed, 303 insertions(+), 240 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/.vscode/launch.json b/.vscode/launch.json index 9a0a9afb4..546ede805 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,11 @@ "sourceMaps": true, "breakOnLoad": true, "url": "http://localhost:1050", - "webRoot": "${workspaceFolder}" + "webRoot": "${workspaceFolder}", + "skipFiles": [ + "${workspaceRoot}/node_modules/**/*.js", + "${workspaceRoot}/node_modules/**/*.ts", + ] }, { "type": "node", diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f4dcce7c8..93b927f8b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -78,6 +78,8 @@ 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}px`; + dragElement.style.height = `${rect.height}px`; dragDiv.appendChild(dragElement); _lastPointerX = dragData["xOffset"] + rect.left; _lastPointerY = dragData["yOffset"] + rect.top; 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 = []; + SelectedDocuments: Array = []; @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 { + export function SelectedDocuments(): Array { return manager.SelectedDocuments; } } \ No newline at end of file diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 3edc8d569..8ae3f837f 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -23,29 +23,13 @@ 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; - return this; - } - - preTranslated = (x: number, y: number): Transform => { - return this.copy().preTranslate(x, y); - } - scale = (scale: number): Transform => { this._scale *= scale; + this._translateX *= scale; + this._translateY *= scale; return this; } - scaled = (scale: number): Transform => { - return this.copy().scale(scale); - } - 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; @@ -53,21 +37,6 @@ export class Transform { return this; } - scaledAbout = (scale: number, x: number, y: number): Transform => { - return this.copy().scaleAbout(scale, x, y); - } - - 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 => { this._translateX += transform._translateX * this._scale; this._translateY += transform._translateY * this._scale; @@ -75,8 +44,15 @@ export class Transform { return this; } - transformed = (transform: Transform): Transform => { - return this.copy().transform(transform); + 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; + return this; } preTransform = (transform: Transform): Transform => { @@ -86,6 +62,30 @@ export class Transform { return this; } + translated = (x: number, y: number): Transform => { + return this.copy().translate(x, y); + } + + 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 => { return this.copy().preTransform(transform); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 85b44307f..5abe3f5b2 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -4,6 +4,8 @@ import { SelectionManager } from "../util/SelectionManager"; 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 { @@ -25,9 +27,12 @@ export class DocumentDecorations extends React.Component { !(element.props.ContainingCollectionView instanceof CollectionFreeFormView)) { return bounds; } - let transform = element.getTransform().inverse(); + let transform = element.props.GetTransform().inverse(); var [sptX, sptY] = transform.transformPoint(0, 0); - var [bptX, bptY] = transform.transformDirection(element.width, element.height); + // 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(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) @@ -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.x += dX * (actualdW - element.width); - element.y += 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 6ca0000b8..c7ad3e249 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -84,6 +84,7 @@ ReactDOM.render(( Transform.Identity} Scaling={1} + isTopMost={true} ContainingCollectionView={undefined} DocumentView={undefined} /> diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d3e90d11c..c870a9cf0 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -16,6 +16,7 @@ import "./CollectionDockingView.scss"; import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; import React = require("react"); import { changeDependenciesStateTo0 } from "mobx/lib/internal"; +import { Utils } from "../../../Utils"; @observer export class CollectionDockingView extends CollectionViewBase { @@ -100,6 +101,7 @@ export class CollectionDockingView extends CollectionViewBase { return ( Transform.Identity} + isTopMost={true} Scaling={1} ContainingCollectionView={this} DocumentView={undefined} />); } @@ -307,12 +309,16 @@ class RenderClass { this.render(); } render() { - var nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0); + let nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0); let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1; ReactDOM.render(( Transform.Identity} + GetTransform={() => { + let { scale, translateX, translateY } = Utils.GetScreenTransform(this._htmlElement); + return this._collectionDockingView.props.GetTransform().scale(scale).translate(-translateX, -translateY) + }} + isTopMost={true} Scaling={scaling} ContainingCollectionView={this._collectionDockingView} DocumentView={undefined} /> ), diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 975eaaae8..7947b1c51 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,21 @@ 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.x = (screenX - translateX) / currScale; - doc.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; + const transform = doc.props.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 +93,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 +104,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.GetTransform().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; @@ -124,15 +123,14 @@ export class CollectionFreeFormView extends CollectionViewBase { // 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 localTransform = this.getLocalTransform(); - let deltaScale = (1 - (e.deltaY / coefficient)) * transform.Scale; - let newDeltaScale = this.isAnnotationOverlay ? Math.max(1, deltaScale) : deltaScale; + let deltaScale = (1 - (e.deltaY / coefficient)); let [x, y] = transform.transformPoint(e.clientX, e.clientY); - localTransform.scaleAbout(newDeltaScale, x, y); + let localTransform = this.getLocalTransform(); + localTransform.scaleAbout(deltaScale, x, y); - this.props.DocumentForCollection.SetNumber(KeyStore.Scale, newDeltaScale); + this.props.DocumentForCollection.SetNumber(KeyStore.Scale, localTransform.Scale); this.SetPan(localTransform.TranslateX, localTransform.TranslateY); } @@ -182,7 +180,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(fieldKey, []); @@ -213,12 +211,12 @@ export class CollectionFreeFormView extends CollectionViewBase { getTransform = (): Transform => { const [x, y] = this.translate; - return this.props.GetTransform().scaled(this.scale).translate(x, y); + return this.props.GetTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform().inverse()) } getLocalTransform = (): Transform => { const [x, y] = this.translate; - return new Transform(x, y, this.scale); + return Transform.Identity.scale(this.scale).translate(x, y); } render() { @@ -249,8 +247,9 @@ export class CollectionFreeFormView extends CollectionViewBase { AddDocument={this.addDocument} RemoveDocument={this.removeDocument} GetTransform={this.getTransform} + isTopMost={false} Scaling={1} - ContainingCollectionView={this} DocumentView={undefined} />); + ContainingCollectionView={this} DocumentView={this.props.ContainingDocumentView} />); })}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f1e882e20..adae8560e 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -27,7 +27,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 = ( @@ -110,6 +111,7 @@ export class CollectionSchemaView extends CollectionViewBase { AddDocument={this.addDocument} RemoveDocument={this.removeDocument} GetTransform={() => Transform.Identity}//TODO This should probably be an actual transform Scaling={1} + isTopMost={false} DocumentView={undefined} ContainingCollectionView={this} /> ) } else { diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index cf5bc70c4..2c950c8ae 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -18,6 +18,9 @@ export interface CollectionViewProps { DocumentForCollection: Document; ContainingDocumentView: Opt; GetTransform: () => Transform; + isSelected: () => boolean; + isTopMost: boolean; + select: (ctrlPressed: boolean) => void; BackgroundView: Opt; Scaling: number; } @@ -29,16 +32,15 @@ export class CollectionViewBase extends React.Component { public static LayoutString(collectionType: string, fieldKey: string = "DataKey") { return `<${collectionType} Scaling={Scaling} DocumentForCollection={Document} - GetTransform={GetTransform} CollectionFieldKey={${fieldKey}} + GetTransform={GetTransform} 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 9cd42a069..54bc7327b 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(); +export class CollectionFreeFormDocumentView extends React.Component { + private _mainCont = React.createRef(); constructor(props: DocumentViewProps) { super(props); @@ -95,130 +92,6 @@ 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.x, this.y); @@ -234,11 +107,10 @@ export class CollectionFreeFormDocumentView extends DocumentView { height: freestyling ? this.height : "100%", position: freestyling ? "absolute" : "relative", zIndex: freestyling ? this.zIndex : 0, - }} - onContextMenu={this.onContextMenu} - onPointerDown={this.onPointerDown}> + backgroundColor: "transparent" + }} > - +
); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d7ecc6d9d..cb080c08e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -16,6 +16,9 @@ import { ImageBox } from "../nodes/ImageBox"; import "./NodeView.scss"; import React = require("react"); import { Transform } from "../../util/Transform"; +import { SelectionManager } from "../../util/SelectionManager"; +import { DragManager } from "../../util/DragManager"; +import { ContextMenu } from "../ContextMenu"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? export interface DocumentViewProps { @@ -26,24 +29,34 @@ export interface DocumentViewProps { AddDocument?: (doc: Document) => void; RemoveDocument?: (doc: Document) => boolean; GetTransform: () => Transform; + isTopMost: boolean; Scaling: number; } @observer export class DocumentView extends React.Component { - protected _mainCont = React.createRef(); + private _mainCont = React.createRef(); get MainContent() { return this._mainCont; } + get screenRect(): ClientRect | DOMRect { + if (this._mainCont.current) { + return this._mainCont.current.getBoundingClientRect(); + } + return new DOMRect(); + } @computed get layout(): string { return this.props.Document.GetData(KeyStore.Layout, TextField, String("

Error loading layout data

")); } @computed - get backgroundLayout(): string { - return this.props.Document.GetData(KeyStore.BackgroundLayout, TextField, String("

Error loading layout data

")); + get backgroundLayout(): string | undefined { + let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField); + if (field && field !== "") { + return field.Data; + } } @computed @@ -56,6 +69,134 @@ export class DocumentView extends React.Component { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array()); } + @computed + 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); + } + } + + @action + dragComplete = (e: DragManager.DragCompleteEvent) => { + } + + @computed + get topMost(): boolean { + return this.props.ContainingCollectionView == undefined || this.props.ContainingCollectionView instanceof CollectionDockingView; + } + + 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.GetTransform().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 + }) + } + } + 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.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(); + + 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 // @@ -69,9 +210,19 @@ export class DocumentView extends React.Component { 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 Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } @@ -82,26 +233,29 @@ export class DocumentView extends React.Component { 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. + let annotated = null; + let backgroundLayout = this.backgroundLayout; + if (backgroundLayout) { + annotated = { console.log(test) }} + />; } - var annotated = { console.log(test) }} - />; - bindings["BackgroundView"] = this.backgroundLayout ? annotated : null; + bindings.BackgroundView = annotated; 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 ( -
+
+ isSelected: () => boolean; + isTopMost: boolean; } @observer export class FieldView extends React.Component { - 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 { 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 { } 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 { 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 { 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 ( Date: Sat, 16 Feb 2019 19:12:11 -0500 Subject: Fixed issues with Document updates and changed how FieldView layout string works --- package-lock.json | 188 ++++++++++++++++++++- package.json | 1 + src/Utils.ts | 12 ++ .../views/collections/CollectionDockingView.tsx | 26 ++- .../views/collections/CollectionFreeFormView.tsx | 42 +++-- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionViewBase.tsx | 25 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 10 +- src/client/views/nodes/DocumentView.tsx | 56 +++++- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/fields/Document.ts | 13 +- src/server/ServerUtil.ts | 2 +- 14 files changed, 309 insertions(+), 76 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/package-lock.json b/package-lock.json index 2f0f8d4d0..0140e192f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -936,6 +936,11 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=" + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -1109,6 +1114,11 @@ } } }, + "base62": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz", + "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==" + }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", @@ -1750,8 +1760,7 @@ "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" }, "commondir": { "version": "1.0.1", @@ -1759,6 +1768,36 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "commoner": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz", + "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=", + "requires": { + "commander": "^2.5.0", + "detective": "^4.3.1", + "glob": "^5.0.15", + "graceful-fs": "^4.1.2", + "iconv-lite": "^0.4.5", + "mkdirp": "^0.5.0", + "private": "^0.1.6", + "q": "^1.1.2", + "recast": "^0.11.17" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -2286,6 +2325,11 @@ } } }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, "del": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", @@ -2371,6 +2415,15 @@ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", "dev": true }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "requires": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -2605,6 +2658,15 @@ "tapable": "^1.0.0" } }, + "envify": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz", + "integrity": "sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=", + "requires": { + "jstransform": "^11.0.3", + "through": "~2.3.4" + } + }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -2679,6 +2741,11 @@ "estraverse": "^4.1.1" } }, + "esprima-fb": { + "version": "15001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz", + "integrity": "sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE=" + }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", @@ -3005,6 +3072,25 @@ "websocket-driver": ">=0.5.1" } }, + "fbjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz", + "integrity": "sha1-lja3cF9bqWhNRLcveDISVK/IYPc=", + "requires": { + "core-js": "^1.0.0", + "loose-envify": "^1.0.0", + "promise": "^7.0.3", + "ua-parser-js": "^0.7.9", + "whatwg-fetch": "^0.9.0" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -4202,6 +4288,11 @@ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" }, + "immutable": { + "version": "4.0.0-rc.12", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz", + "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==" + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -4678,6 +4769,11 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stringify-pretty-compact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-1.2.0.tgz", + "integrity": "sha512-/11Pj1OyX814QMKO7K8l85SHPTr/KsFxHp8GE2zVa0BtJgGimDjXHfM3FhC7keQdWDea7+nXf+f1de7ATZcZkQ==" + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4731,6 +4827,25 @@ "verror": "1.10.0" } }, + "jstransform": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz", + "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=", + "requires": { + "base62": "^1.1.0", + "commoner": "^0.10.1", + "esprima-fb": "^15001.1.0-dev-harmony-fb", + "object-assign": "^2.0.0", + "source-map": "^0.4.2" + }, + "dependencies": { + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + } + } + }, "jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", @@ -4740,6 +4855,27 @@ "promise": "^7.0.1" } }, + "jsx-to-string": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsx-to-string/-/jsx-to-string-1.4.0.tgz", + "integrity": "sha1-Ztw013PaufQP6ZPP+ZQOXaZVtwU=", + "requires": { + "immutable": "^4.0.0-rc.9", + "json-stringify-pretty-compact": "^1.0.1", + "react": "^0.14.0" + }, + "dependencies": { + "react": { + "version": "0.14.9", + "resolved": "https://registry.npmjs.org/react/-/react-0.14.9.tgz", + "integrity": "sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE=", + "requires": { + "envify": "^3.0.0", + "fbjs": "^0.6.1" + } + } + } + }, "jwa": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.2.0.tgz", @@ -9752,6 +9888,11 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -10042,6 +10183,11 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -10267,6 +10413,29 @@ "readable-stream": "^2.0.2" } }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "requires": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -11617,6 +11786,11 @@ "native-promise-only": "^0.8.1" } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -11820,6 +11994,11 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.1.tgz", "integrity": "sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA==" }, + "ua-parser-js": { + "version": "0.7.19", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", + "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -12862,6 +13041,11 @@ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", "dev": true }, + "whatwg-fetch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", + "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA=" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 3a245cfd0..94bf5a217 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "flexlayout-react": "^0.3.3", "golden-layout": "^1.5.9", "jsonwebtoken": "^8.4.0", + "jsx-to-string": "^1.4.0", "lodash": "^4.17.11", "mobx": "^5.9.0", "mobx-react": "^5.3.5", diff --git a/src/Utils.ts b/src/Utils.ts index ce4f7ac3e..c9c006aa8 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -31,6 +31,18 @@ export class Utils { return { scale, translateX, translateY }; } + public static CopyText(text: string) { + var textArea = document.createElement("textarea"); + textArea.value = text; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { document.execCommand('copy'); } catch (err) { } + + document.body.removeChild(textArea); + } + public static Emit(socket: Socket | SocketIOClient.Socket, message: Message, args: T) { socket.emit(message.Message, args); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b8e040388..d9e261f55 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import React = require("react"); import FlexLayout from "flexlayout-react"; -import { action, observable, computed } from "mobx"; +import { action, computed } from "mobx"; import { Document } from "../../../fields/Document"; import { DocumentView } from "../nodes/DocumentView"; import { ListField } from "../../../fields/ListField"; @@ -13,17 +13,18 @@ import 'golden-layout/src/css/goldenlayout-dark-theme.css'; import * as GoldenLayout from "golden-layout"; import * as ReactDOM from 'react-dom'; import { DragManager } from "../../util/DragManager"; -import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; +import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; +import { FieldView } from "../nodes/FieldView"; @observer export class CollectionDockingView extends CollectionViewBase { private static UseGoldenLayout = true; - public static LayoutString() { return CollectionViewBase.LayoutString("CollectionDockingView"); } + public static LayoutString() { return FieldView.LayoutString(CollectionDockingView) } private _containerRef = React.createRef(); @computed private get modelForFlexLayout() { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; + const { fieldKey: fieldKey, doc: Document } = this.props; const value: Document[] = Document.GetData(fieldKey, ListField, []); var docs = value.map(doc => { return { type: 'tabset', weight: 50, selected: 0, children: [{ type: "tab", name: doc.Title, component: doc.Id }] }; @@ -39,7 +40,7 @@ export class CollectionDockingView extends CollectionViewBase { } @computed private get modelForGoldenLayout(): any { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; + const { fieldKey: fieldKey, doc: Document } = this.props; const value: Document[] = Document.GetData(fieldKey, ListField, []); var docs = value.map(doc => { return { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } }; @@ -50,9 +51,6 @@ export class CollectionDockingView extends CollectionViewBase { }, content: [{ type: 'row', content: docs }] }); } - constructor(props: CollectionViewProps) { - super(props); - } componentDidMount: () => void = () => { if (this._containerRef.current && CollectionDockingView.UseGoldenLayout) { @@ -67,8 +65,8 @@ export class CollectionDockingView extends CollectionViewBase { @action - onResize = (event: any) => { - var cur = this.props.ContainingDocumentView!.MainContent.current; + onResize = () => { + var cur = this.props.DocumentViewForField!.MainContent.current; // bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed CollectionDockingView.myLayout.updateSize(cur!.getBoundingClientRect().width, cur!.getBoundingClientRect().height); @@ -91,7 +89,7 @@ export class CollectionDockingView extends CollectionViewBase { if (component === "button") { return ; } - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; + const { fieldKey: fieldKey, doc: Document } = this.props; const value: Document[] = Document.GetData(fieldKey, ListField, []); for (var i: number = 0; i < value.length; i++) { if (value[i].Id === component) { @@ -195,7 +193,6 @@ export class CollectionDockingView extends CollectionViewBase { goldenLayoutFactory() { CollectionDockingView.myLayout = this.modelForGoldenLayout; - var layout = CollectionDockingView.myLayout; CollectionDockingView.myLayout.on('tabCreated', function (tab: any) { if (CollectionDockingView._dragDiv) { CollectionDockingView._dragDiv.removeChild(CollectionDockingView._dragElement); @@ -251,10 +248,9 @@ export class CollectionDockingView extends CollectionViewBase { render() { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; - const value: Document[] = Document.GetData(fieldKey, ListField, []); + const { fieldKey: fieldKey, doc: Document } = this.props; // bcz: not sure why, but I need these to force the flexlayout to update when the collection size changes. - var s = this.props.ContainingDocumentView != undefined ? this.props.ContainingDocumentView!.ScalingToScreenSpace : 1; + var s = this.props.DocumentViewForField != undefined ? this.props.DocumentViewForField!.ScalingToScreenSpace : 1; var w = Document.GetData(KeyStore.Width, NumberField, Number(0)) / s; var h = Document.GetData(KeyStore.Height, NumberField, Number(0)) / s; diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index e3a43aa5b..e6b1d103d 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -5,7 +5,7 @@ import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocum import { DragManager } from "../../util/DragManager"; import "./CollectionFreeFormView.scss"; import { Utils } from "../../../Utils"; -import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; +import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; import { SelectionManager } from "../../util/SelectionManager"; import { KeyStore } from "../../../fields/KeyStore"; import { Document } from "../../../fields/Document"; @@ -13,19 +13,17 @@ import { ListField } from "../../../fields/ListField"; import { NumberField } from "../../../fields/NumberField"; import { Documents } from "../../documents/Documents"; import { FieldWaiting } from "../../../fields/Field"; +import { FakeJsxArgs } from "../nodes/DocumentView"; +import { FieldView } from "../nodes/FieldView"; @observer export class CollectionFreeFormView extends CollectionViewBase { - public static LayoutString() { return CollectionViewBase.LayoutString("CollectionFreeFormView"); } + public static LayoutString() { return FieldView.LayoutString(CollectionFreeFormView); } private _canvasRef = React.createRef(); private _nodeContainerRef = React.createRef(); private _lastX: number = 0; private _lastY: number = 0; - constructor(props: CollectionViewProps) { - super(props); - } - @action drop = (e: Event, de: DragManager.DropEvent) => { const doc = de.data["document"]; @@ -38,7 +36,7 @@ export class CollectionFreeFormView extends CollectionViewBase { const xOffset = de.data["xOffset"] as number || 0; const yOffset = de.data["yOffset"] as number || 0; const { scale, translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); - let sscale = this.props.ContainingDocumentView!.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)) + let sscale = this.props.DocumentViewForField!.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)) const screenX = de.x - xOffset; const screenY = de.y - yOffset; const docX = (screenX - translateX) / sscale / scale; @@ -91,11 +89,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.GetData(KeyStore.PanX, NumberField, Number(0)); - let y = this.props.DocumentForCollection.GetData(KeyStore.PanY, NumberField, Number(0)); - this.props.DocumentForCollection.SetData(KeyStore.PanX, x + (e.pageX - this._lastX) / currScale, NumberField); - this.props.DocumentForCollection.SetData(KeyStore.PanY, y + (e.pageY - this._lastY) / currScale, NumberField); + let currScale: number = this.props.DocumentViewForField!.ScalingToScreenSpace; + let x = this.props.doc.GetData(KeyStore.PanX, NumberField, Number(0)); + let y = this.props.doc.GetData(KeyStore.PanY, NumberField, Number(0)); + this.props.doc.SetData(KeyStore.PanX, x + (e.pageX - this._lastX) / currScale, NumberField); + this.props.doc.SetData(KeyStore.PanY, y + (e.pageY - this._lastY) / currScale, NumberField); } this._lastX = e.pageX; this._lastY = e.pageY; @@ -105,7 +103,7 @@ export class CollectionFreeFormView extends CollectionViewBase { onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - let { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY); + let { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.DocumentViewForField!.TransformToLocalPoint(e.pageX, e.pageY); var deltaScale = (1 - (e.deltaY / 1000)) * Ss; @@ -115,9 +113,9 @@ export class CollectionFreeFormView extends CollectionViewBase { let dx = ContainerX - newContainerX; let dy = ContainerY - newContainerY; - this.props.DocumentForCollection.Set(KeyStore.Scale, new NumberField(deltaScale)); - this.props.DocumentForCollection.SetData(KeyStore.PanX, Panxx + dx, NumberField); - this.props.DocumentForCollection.SetData(KeyStore.PanY, Panyy + dy, NumberField); + this.props.doc.Set(KeyStore.Scale, new NumberField(deltaScale)); + this.props.doc.SetData(KeyStore.PanX, Panxx + dx, NumberField); + this.props.doc.SetData(KeyStore.PanY, Panyy + dy, NumberField); } @action @@ -127,8 +125,8 @@ export class CollectionFreeFormView extends CollectionViewBase { let fReader = new FileReader() let file = e.dataTransfer.items[0].getAsFile(); let that = this; - const panx: number = this.props.DocumentForCollection.GetData(KeyStore.PanX, NumberField, Number(0)); - const pany: number = this.props.DocumentForCollection.GetData(KeyStore.PanY, NumberField, Number(0)); + const panx: number = this.props.doc.GetData(KeyStore.PanX, NumberField, Number(0)); + const pany: number = this.props.doc.GetData(KeyStore.PanY, NumberField, Number(0)); let x = e.pageX - panx let y = e.pageY - pany @@ -138,11 +136,11 @@ export class CollectionFreeFormView extends CollectionViewBase { let doc = Documents.ImageDocument(url, { x: x, y: y }) - let docs = that.props.DocumentForCollection.GetT(KeyStore.Data, ListField); + let docs = that.props.doc.GetT(KeyStore.Data, ListField); if (docs != FieldWaiting) { if (!docs) { docs = new ListField(); - that.props.DocumentForCollection.Set(KeyStore.Data, docs) + that.props.doc.Set(KeyStore.Data, docs) } docs.Data.push(doc); } @@ -159,7 +157,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @action bringToFront(doc: CollectionFreeFormDocumentView) { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; + const { fieldKey: fieldKey, doc: Document } = this.props; const value: Document[] = Document.GetList(fieldKey, []); var topmost = value.reduce((topmost, d) => Math.max(d.GetNumber(KeyStore.ZIndex, 0), topmost), -1000); @@ -176,7 +174,7 @@ export class CollectionFreeFormView extends CollectionViewBase { } render() { - const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; + const { fieldKey: fieldKey, doc: Document } = this.props; // const value: Document[] = Document.GetList(fieldKey, []); const lvalue = Document.GetT>(fieldKey, ListField); if (!lvalue || lvalue === "") { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 8a1e21847..9f32ccb72 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -17,7 +17,7 @@ import { Field } from "../../../fields/Field"; @observer export class CollectionSchemaView extends CollectionViewBase { - public static LayoutString() { return CollectionViewBase.LayoutString("CollectionSchemaView"); } + public static LayoutString() { return FieldView.LayoutString(CollectionSchemaView); } @observable selectedIndex = 0; @@ -97,7 +97,7 @@ export class CollectionSchemaView extends CollectionViewBase { } render() { - const { DocumentForCollection: Document, CollectionFieldKey: fieldKey } = this.props; + const { doc: Document, fieldKey: fieldKey } = this.props; const children = Document.GetList(fieldKey, []); const columns = Document.GetList(KS.ColumnsKey, [KS.Title, KS.Data, KS.Author]) diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 8bb10b743..4fcbb1699 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -10,42 +10,33 @@ import React = require("react"); import { DocumentView } from "../nodes/DocumentView"; import { CollectionDockingView } from "./CollectionDockingView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; - - -export interface CollectionViewProps { - CollectionFieldKey: Key; - DocumentForCollection: Document; - ContainingDocumentView: Opt; -} +import { FieldViewProps } from "../nodes/FieldView"; export const COLLECTION_BORDER_WIDTH = 2; @observer -export class CollectionViewBase extends React.Component { +export class CollectionViewBase extends React.Component { - public static LayoutString(collectionType: string) { - return `<${collectionType} DocumentForCollection={Document} CollectionFieldKey={DataKey} ContainingDocumentView={DocumentView}/>`; - } @computed public get active(): boolean { - var isSelected = (this.props.ContainingDocumentView instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView)); + var isSelected = (this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)); 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.DocumentViewForField != undefined && ( + this.props.DocumentViewForField.props.ContainingCollectionView == undefined || + this.props.DocumentViewForField.props.ContainingCollectionView instanceof CollectionDockingView); return isSelected || childSelected || topMost; } @action addDocument = (doc: Document): void => { //TODO This won't create the field if it doesn't already exist - const value = this.props.DocumentForCollection.GetData(this.props.CollectionFieldKey, ListField, new Array()) + const value = this.props.doc.GetData(this.props.fieldKey, ListField, new Array()) value.push(doc); } @action removeDocument = (doc: Document): void => { //TODO This won't create the field if it doesn't already exist - const value = this.props.DocumentForCollection.GetData(this.props.CollectionFieldKey, ListField, new Array()) + const value = this.props.doc.GetData(this.props.fieldKey, ListField, new Array()) if (value.indexOf(doc) !== -1) { value.splice(value.indexOf(doc), 1) diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 9e6407768..bfd50da81 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -10,6 +10,7 @@ import { ContextMenu } from "../ContextMenu"; import "./NodeView.scss"; import React = require("react"); import { DocumentView, DocumentViewProps } from "./DocumentView"; +import { Utils } from "../../../Utils"; @observer @@ -188,7 +189,6 @@ export class CollectionFreeFormDocumentView extends DocumentView { 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 @@ -198,9 +198,15 @@ export class CollectionFreeFormDocumentView extends DocumentView { 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); } + + ContextMenu.Instance.addItem({ + description: "Copy ID", event: () => { + Utils.CopyText(this.props.Document.Id) + } + }) + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b219f2279..3767d28c6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,7 +1,7 @@ import { action, computed } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; -import { Opt, FieldWaiting } from "../../../fields/Field"; +import { Opt, FieldWaiting, Field } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; @@ -23,6 +23,48 @@ export interface DocumentViewProps { DocumentView: Opt // needed only to set ContainingDocumentView on CollectionViewProps when invoked from JsxParser -- is there a better way? ContainingCollectionView: Opt; } +export interface JsxArgs extends DocumentViewProps { + Keys: { [name: string]: Key } + Fields: { [name: string]: Field } +} + +/* +This function is pretty much a hack that lets us fill out the fields in JsxArgs with something that +jsx-to-string can recover the jsx from +Example usage of this function: + public static LayoutString() { + let args = FakeJsxArgs(["Data"]); + return jsxToString( + , + { useFunctionCode: true, functionNameOnly: true } + ) + } +*/ +export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { + let Keys: { [name: string]: any } = {} + let Fields: { [name: string]: any } = {} + for (const key of keys) { + let fn = () => { } + Object.defineProperty(fn, "name", { value: key + "Key" }) + Keys[key] = fn; + } + for (const field of fields) { + let fn = () => { } + Object.defineProperty(fn, "name", { value: field }) + Fields[field] = fn; + } + let args: JsxArgs = { + Document: function Document() { }, + DocumentView: function DocumentView() { }, + Keys, + Fields + } as any; + return args; +} + @observer export class DocumentView extends React.Component { @@ -51,9 +93,9 @@ export class DocumentView extends React.Component { @computed public get ScalingToScreenSpace(): number { if (this.props.ContainingCollectionView != undefined && - this.props.ContainingCollectionView.props.ContainingDocumentView != undefined) { - let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetData(KeyStore.Scale, NumberField, Number(1)); - return this.props.ContainingCollectionView.props.ContainingDocumentView.ScalingToScreenSpace * ss; + this.props.ContainingCollectionView.props.DocumentViewForField != undefined) { + let ss = this.props.ContainingCollectionView.props.doc.GetData(KeyStore.Scale, NumberField, Number(1)); + return this.props.ContainingCollectionView.props.DocumentViewForField.ScalingToScreenSpace * ss; } return 1; } @@ -65,8 +107,8 @@ export class DocumentView extends React.Component { // if this collection view is nested within another collection view, then // first transform the screen point into the parent collection's coordinate space. let { LocalX: parentX, LocalY: parentY } = this.props.ContainingCollectionView != undefined && - this.props.ContainingCollectionView.props.ContainingDocumentView != undefined ? - this.props.ContainingCollectionView.props.ContainingDocumentView.TransformToLocalPoint(screenX, screenY) : + this.props.ContainingCollectionView.props.DocumentViewForField != undefined ? + this.props.ContainingCollectionView.props.DocumentViewForField.TransformToLocalPoint(screenX, screenY) : { LocalX: screenX, LocalY: screenY }; let ContainerX: number = parentX - COLLECTION_BORDER_WIDTH; let ContainerY: number = parentY - COLLECTION_BORDER_WIDTH; @@ -114,7 +156,7 @@ export class DocumentView extends React.Component { // 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 != undefined ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; + let containingDocView = this.props.ContainingCollectionView != undefined ? this.props.ContainingCollectionView.props.DocumentViewForField : undefined; if (containingDocView != undefined) { let ss = containingDocView.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)); let panxx = containingDocView.props.Document.GetData(KeyStore.PanX, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 12371eb2e..fae124528 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -25,7 +25,7 @@ export interface FieldViewProps { @observer export class FieldView extends React.Component { - public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} />`; } + public static LayoutString(fieldType: { name: string }) { return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} />`; } @computed get field(): FieldValue { const { doc, fieldKey } = this.props; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8bc4c902c..39d7bf4f0 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -34,7 +34,7 @@ import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView @observer export class FormattedTextBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString("FormattedTextBox"); } + public static LayoutString() { return FieldView.LayoutString(FormattedTextBox) } private _ref: React.RefObject; private _editorView: Opt; private _reactionDisposer: Opt; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ab20f140c..013b8b7d3 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -14,7 +14,7 @@ import { observable, action } from 'mobx'; @observer export class ImageBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString("ImageBox"); } + public static LayoutString() { return FieldView.LayoutString(ImageBox) } private _ref: React.RefObject; private _downX: number = 0; private _downY: number = 0; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index fce316b17..3067621be 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -9,7 +9,7 @@ import { Server } from "../client/Server"; import { Types } from "../server/Message"; export class Document extends Field { - public fields: ObservableMap }> = new ObservableMap(); + public fields: ObservableMap = new ObservableMap(); public _proxies: ObservableMap = new ObservableMap(); constructor(id?: string, save: boolean = true) { @@ -45,17 +45,20 @@ export class Document extends Field { } else { let doc: FieldValue = this; while (doc && doc != FieldWaiting && field != FieldWaiting) { - if (!doc.fields.has(key.Id)) { - if (doc._proxies.has(key.Id)) { + let curField = doc.fields.get(key.Id); + let curProxy = doc._proxies.get(key.Id); + if (!curField || (curProxy && curField.field.Id !== curProxy)) { + if (curProxy) { field = Server.GetDocumentField(doc, key); break; } if ((doc.fields.has(KeyStore.Prototype.Id) || doc._proxies.has(KeyStore.Prototype.Id))) { doc = doc.GetPrototype(); - } else + } else { break; + } } else { - field = doc.fields.get(key.Id)!.field; + field = curField.field; break; } } diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 03b9751da..46c409ec4 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -32,7 +32,7 @@ export class ServerUtils { case Types.Key: return new Key(data, id, false) case Types.Image: - return new ImageField(data, id, false) + return new ImageField(new URL(data), id, false) case Types.List: return ListField.FromJson(id, data) case Types.Document: -- cgit v1.2.3-70-g09d2 From e5a14d6dddccc922bb253323b461ac2500c33b7c Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Tue, 19 Feb 2019 18:24:41 -0500 Subject: Different options based on selection --- src/client/views/ContextMenu.scss | 7 +++---- src/client/views/ContextMenu.tsx | 6 ++++-- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 2 -- src/client/views/nodes/FormattedTextBox.tsx | 12 +++++++++++- src/client/views/nodes/ImageBox.tsx | 11 ++++++++++- 5 files changed, 28 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index dc5907f14..2ac5d3b52 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -13,7 +13,6 @@ display: flex; justify-content: center; align-items: center; - flex-direction: column; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; @@ -34,6 +33,6 @@ width: 8vw; } -// #mySearch { -// font-size: 1.5vw; -// } \ No newline at end of file +#mySearch { + font-size: 1.4vw; +} \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 4a216ca21..2359c673d 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; -import { observable } from "mobx"; +import { observable, action } from "mobx"; import { observer } from "mobx-react"; import "./ContextMenu.scss" @@ -23,11 +23,13 @@ export class ContextMenu extends React.Component { ContextMenu.Instance = this; } + @action clearItems() { this._items = [] this._display = "none" } + @action addItem(item: ContextMenuProps) { if (this._items.indexOf(item) === -1) { this._items.push(item); @@ -58,7 +60,7 @@ export class ContextMenu extends React.Component { render() { return ( -
+
{this._items.map(prop => { return diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 54d3a1b56..f37232c08 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -203,7 +203,6 @@ export class CollectionFreeFormDocumentView extends DocumentView { } if (this.topMost) { - ContextMenu.Instance.clearItems() ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) } @@ -211,7 +210,6 @@ export class CollectionFreeFormDocumentView extends DocumentView { // 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 }) diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8f959762a..0fe6befda 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -13,6 +13,7 @@ import { RichTextField } from "../../../fields/RichTextField"; import { FieldViewProps, FieldView } from "./FieldView"; import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; import { observer } from "mobx-react"; +import { ContextMenu } from "../../views/ContextMenu"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document @@ -114,6 +115,15 @@ export class FormattedTextBox extends React.Component { e.stopPropagation(); } } + + //REPLACE THIS WITH CAPABILITIES SPECIFC TO THIS TYPE OF NODE + textCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); + } + render() { return (
{ whiteSpace: "initial" }} onPointerDown={this.onPointerDown} - ref={this._ref} />) + ref={this._ref} onContextMenu={this.specificContextMenu} />) } } \ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 60be5f94d..f363487c3 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -11,6 +11,7 @@ import { FieldWaiting } from '../../../fields/Field'; import { observer } from "mobx-react" import { observable, action, spy } from 'mobx'; import { KeyStore } from '../../../fields/Key'; +import { ContextMenu } from "../../views/ContextMenu"; @observer export class ImageBox extends React.Component { @@ -81,13 +82,21 @@ export class ImageBox extends React.Component { } } + //REPLACE THIS WITH CAPABILITIES SPECIFC TO THIS TYPE OF NODE + imageCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability }); + } + render() { let field = this.props.doc.Get(this.props.fieldKey); let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; return ( -
+
Image not found {this.lightbox(path)}
) -- cgit v1.2.3-70-g09d2 From c439f11ba9695703697f7abc53a7cc2fd2d5c1a2 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 25 Feb 2019 12:38:47 -0500 Subject: fixes for dropping documents without a know height. --- src/client/documents/Documents.ts | 6 +--- src/client/views/DocumentDecorations.tsx | 23 ++++++++-------- .../views/collections/CollectionFreeFormView.tsx | 30 ++++++++++++++------ src/client/views/collections/CollectionView.tsx | 11 ++++++-- .../views/collections/CollectionViewBase.tsx | 4 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 32 +++++----------------- src/client/views/nodes/DocumentView.tsx | 4 ++- src/client/views/nodes/FormattedTextBox.tsx | 5 +++- src/client/views/nodes/ImageBox.tsx | 13 +++++++-- src/fields/Document.ts | 2 +- src/fields/Field.ts | 3 ++ 11 files changed, 73 insertions(+), 60 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2dfff6235..15ecfbfe6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -112,9 +112,7 @@ export namespace Documents { imageProto.Set(KeyStore.X, new NumberField(0)); imageProto.Set(KeyStore.Y, new NumberField(0)); imageProto.Set(KeyStore.NativeWidth, new NumberField(300)); - imageProto.Set(KeyStore.NativeHeight, new NumberField(300)); imageProto.Set(KeyStore.Width, new NumberField(300)); - imageProto.Set(KeyStore.Height, new NumberField(300)); imageProto.Set(KeyStore.Layout, new TextField(CollectionView.LayoutString("AnnotationsKey"))); imageProto.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) imageProto.Set(KeyStore.BackgroundLayout, new TextField(ImageBox.LayoutString())); @@ -151,9 +149,7 @@ export namespace Documents { doc.Set(KeyStore.BackgroundLayout, new TextField(EmbeddedCaption())); doc.Set(KeyStore.OverlayLayout, new TextField(FixedCaption())); doc.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations, KeyStore.Caption])); - - let annotation = Documents.TextDocument({ title: "hello" }); - doc.Set(KeyStore.Annotations, new ListField([annotation])); + console.log("" + doc.GetNumber(KeyStore.Height, 311)); return doc; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2f012913d..975a125f7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -104,25 +104,26 @@ export class DocumentDecorations extends React.Component { const rect = element.screenRect(); if (rect.width !== 0) { let doc = element.props.Document; - let width = doc.GetOrCreate(KeyStore.Width, NumberField); - let height = doc.GetOrCreate(KeyStore.Height, NumberField); + let width = doc.GetNumber(KeyStore.Width, 0); + let nwidth = doc.GetNumber(KeyStore.NativeWidth, 0); + let nheight = doc.GetNumber(KeyStore.NativeHeight, 0); + let height = doc.GetNumber(KeyStore.Height, nwidth ? nheight / nwidth * width : 0); let x = doc.GetOrCreate(KeyStore.X, NumberField); let y = doc.GetOrCreate(KeyStore.Y, 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); + let scale = width / rect.width; + let actualdW = Math.max(width + (dW * scale), 20); + let actualdH = Math.max(height + (dH * scale), 20); + x.Data += dX * (actualdW - width); + y.Data += dY * (actualdH - height); var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = doc.GetNumber(KeyStore.NativeHeight, 0); if (nativeWidth > 0 && nativeHeight > 0) { if (Math.abs(dW) > Math.abs(dH)) actualdH = nativeHeight / nativeWidth * actualdW; - else - actualdW = nativeWidth / nativeHeight * actualdH; + else actualdW = nativeWidth / nativeHeight * actualdH; } - width.Data = actualdW; - height.Data = actualdH; + doc.SetNumber(KeyStore.Width, actualdW); + doc.SetNumber(KeyStore.Height, actualdH); } }) } diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index c40da6eaa..7cad2cc03 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -102,18 +102,30 @@ export class CollectionFreeFormView extends CollectionViewBase { e.stopPropagation(); e.preventDefault(); 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); + if (e.ctrlKey) { + var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + const coefficient = 1000; + let deltaScale = (1 - (e.deltaY / coefficient)); + this.props.Document.SetNumber(KeyStore.NativeWidth, nativeWidth * deltaScale); + this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight * deltaScale); + e.stopPropagation(); + e.preventDefault(); + } else { + // 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 localTransform = this.getLocalTransform(); - localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + let deltaScale = (1 - (e.deltaY / coefficient)); + let [x, y] = transform.transformPoint(e.clientX, e.clientY); - this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); - this.SetPan(localTransform.TranslateX, localTransform.TranslateY); + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + + this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); + this.SetPan(localTransform.TranslateX, localTransform.TranslateY); + } } @action diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 90080ab43..88c15da07 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -11,6 +11,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; import { CollectionDockingView } from "./CollectionDockingView"; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionViewProps } from "./CollectionViewBase"; +import { Field } from "../../../fields/Field"; @@ -39,9 +40,13 @@ export class CollectionView extends React.Component { } @action addDocument = (doc: Document): void => { - //TODO This won't create the field if it doesn't already exist - const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array()) - value.push(doc); + if (this.props.Document.Get(this.props.fieldKey) instanceof Field) { + //TODO This won't create the field if it doesn't already exist + const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array()) + value.push(doc); + } else { + this.props.Document.SetData(this.props.fieldKey, [doc], ListField); + } } @action diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 7e269caf1..f64a48c18 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -60,7 +60,7 @@ export class CollectionViewBase extends React.Component let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); - if (html) { + if (html && html.indexOf(" if (item.kind === "string" && item.type.indexOf("uri") != -1) { e.dataTransfer.items[i].getAsString(function (s) { action(() => { - var img = Documents.ImageDocument(s, { ...options, nativeWidth: 300, nativeHeight: 300, width: 300, height: 300 }) + var img = Documents.ImageDocument(s, { ...options, nativeWidth: 300, width: 300, }) let docs = that.props.Document.GetT(KeyStore.Data, ListField); if (docs != FieldWaiting) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d7243421a..50dc5a619 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -27,44 +27,26 @@ export class CollectionFreeFormDocumentView extends React.Component 0 && this.nativeHeight > 0) { + if (this.nativeWidth && this.nativeHeight) { this.props.Document.SetNumber(KeyStore.Height, this.nativeHeight / this.nativeWidth * w) } } - @computed - get height(): number { - return this.props.Document.GetNumber(KeyStore.Height, 0); - } - @computed - get nativeHeight(): number { - return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); - } - set height(h: number) { this.props.Document.SetData(KeyStore.Height, h, NumberField); - if (this.nativeWidth > 0 && this.nativeHeight > 0) { + if (this.nativeWidth && this.nativeHeight) { this.props.Document.SetNumber(KeyStore.Width, this.nativeWidth / this.nativeHeight * h) } } - @computed - get zIndex(): number { - return this.props.Document.GetNumber(KeyStore.ZIndex, 0); - } - set zIndex(h: number) { this.props.Document.SetData(KeyStore.ZIndex, h, NumberField) } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ad1328e5d..212697442 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -196,6 +196,7 @@ export class DocumentView extends React.Component { } @computed get mainContent() { + var val = this.props.Document.Id; return { transform: `scale(${scaling},${scaling})` }} onContextMenu={this.onContextMenu} - onPointerDown={this.onPointerDown} > + onPointerDown={this.onPointerDown} + > {this.mainContent}
) diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 60ee0b5e1..a58e1955f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -111,10 +111,13 @@ export class FormattedTextBox extends React.Component { e.stopPropagation(); } } + onPointerWheel = (e: React.WheelEvent): void => { + e.stopPropagation(); + } render() { - var val = this.props.doc.Get(this.props.fieldKey); return (
) } } \ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index b5ce8b28c..4fe73fb8d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -9,12 +9,14 @@ import { FieldWaiting } from '../../../fields/Field'; import { observer } from "mobx-react" import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; +import { element } from 'prop-types'; @observer export class ImageBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(ImageBox) } private _ref: React.RefObject; + private _imgRef: React.RefObject; private _downX: number = 0; private _downY: number = 0; private _lastTap: number = 0; @@ -25,12 +27,20 @@ export class ImageBox extends React.Component { super(props); this._ref = React.createRef(); + this._imgRef = React.createRef(); this.state = { photoIndex: 0, isOpen: false, }; } + @action + onLoad = (target: any) => { + var h = this._imgRef.current!.naturalHeight; + var w = this._imgRef.current!.naturalWidth; + this.props.doc.SetNumber(KeyStore.NativeHeight, this.props.doc.GetNumber(KeyStore.NativeWidth, 0) * h / w) + } + componentDidMount() { } @@ -84,10 +94,9 @@ export class ImageBox extends React.Component { let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1); - return (
- Image not found + Image not found {this.lightbox(path)}
) } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 0d7d357a0..4e68b3b4d 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -31,7 +31,7 @@ export class Document extends Field { } public Width = () => { return this.GetNumber(KeyStore.Width, 0) } - public Height = () => { return this.GetNumber(KeyStore.Height, 0) } + public Height = () => { return this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0) * this.GetNumber(KeyStore.Width, 0) : 0) } public Scale = () => { return this.GetNumber(KeyStore.Scale, 1) } @computed diff --git a/src/fields/Field.ts b/src/fields/Field.ts index c7e0232af..d48509a47 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -1,6 +1,7 @@ import { Utils } from "../Utils"; import { Types } from "../server/Message"; +import { computed } from "mobx"; export function Cast(field: FieldValue, ctor: { new(): T }): Opt { if (field) { @@ -25,6 +26,8 @@ export abstract class Field { } private id: FieldId; + + @computed get Id(): FieldId { return this.id; } -- cgit v1.2.3-70-g09d2 From 8772cc68e850653af72dbd9aced73d529900173b Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Mon, 25 Feb 2019 18:24:46 -0500 Subject: No wrapping --- src/client/views/ContextMenu.scss | 21 +++++++++++++++------ .../views/collections/CollectionSchemaView.tsx | 11 ++++++++++- src/client/views/collections/CollectionViewBase.tsx | 11 ++++++++++- src/client/views/nodes/FormattedTextBox.tsx | 11 +++-------- src/client/views/nodes/ImageBox.tsx | 2 +- 5 files changed, 39 insertions(+), 17 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 2ac5d3b52..c810aef3e 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -4,14 +4,15 @@ z-index: 1000; box-shadow: #AAAAAA .2vw .2vw .4vw; flex-direction: column; //E + // border-radius: 20px; } .contextMenu-item { - width: 10vw; - height: 4vh; - background: #DDDDDD; + width: auto; //10vw + height: auto; //4vh + background: #F0F8FF; // background: #DDDDDD; display: flex; - justify-content: center; + justify-content: left; //center align-items: center; -webkit-touch-callout: none; -webkit-user-select: none; @@ -20,11 +21,17 @@ -ms-user-select: none; user-select: none; transition: all .1s; + border-width: .11px; + border-color: rgb(187, 186, 186); + border-bottom-style: solid; + border-top-style: none; + padding: 10px; + white-space: nowrap; } .contextMenu-item:hover { transition: all .1s; - background: #AAAAAA + background: #B0E0E6; // background: #AAAAAA } .contextMenu-description { @@ -34,5 +41,7 @@ } #mySearch { - font-size: 1.4vw; + font-size: 1.5vw; + border-left-style: none; + border-right-style: none; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 331c4f6fe..d924cb163 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -15,6 +15,7 @@ import { KeyStore as KS, Key } from "../../../fields/Key"; import { Document } from "../../../fields/Document"; import { Field } from "../../../fields/Field"; import { Transform } from "../../util/Transform"; +import { ContextMenu } from "../ContextMenu"; @observer export class CollectionSchemaView extends CollectionViewBase { @@ -98,6 +99,14 @@ export class CollectionSchemaView extends CollectionViewBase { } } + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE + collectionCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Collection Capability", event: this.collectionCapability }); + } + render() { const { DocumentForCollection: Document, CollectionFieldKey: fieldKey } = this.props; const children = Document.GetList(fieldKey, []); @@ -116,7 +125,7 @@ export class CollectionSchemaView extends CollectionViewBase { content =
} return ( -
+
{ public static LayoutString(collectionType: string) { - return `<${collectionType} DocumentForCollection={Document} CollectionFieldKey={DataKey} ContainingDocumentView={DocumentView}/>`; + return `<${collectionType} onContextMenu={this.specificContextMenu} DocumentForCollection={Document} CollectionFieldKey={DataKey} ContainingDocumentView={DocumentView}/>`; } + + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE + collectionCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Collection Capability", event: this.collectionCapability }); + } + @computed public get active(): boolean { var isSelected = (this.props.ContainingDocumentView instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView)); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0fe6befda..23eca4e24 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -116,7 +116,7 @@ export class FormattedTextBox extends React.Component { } } - //REPLACE THIS WITH CAPABILITIES SPECIFC TO THIS TYPE OF NODE + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE textCapability = (e: React.MouseEvent): void => { } @@ -125,12 +125,7 @@ export class FormattedTextBox extends React.Component { } render() { - return (
) + return (
) } } \ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index f363487c3..0f10ef0ef 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -82,7 +82,7 @@ export class ImageBox extends React.Component { } } - //REPLACE THIS WITH CAPABILITIES SPECIFC TO THIS TYPE OF NODE + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE imageCapability = (e: React.MouseEvent): void => { } -- cgit v1.2.3-70-g09d2