diff options
| author | Bob Zeleznik <zzzman@gmail.com> | 2019-04-14 22:59:58 -0400 |
|---|---|---|
| committer | Bob Zeleznik <zzzman@gmail.com> | 2019-04-14 22:59:58 -0400 |
| commit | c6360fb4aed348f6f6a3c7412b6acc0d1990c239 (patch) | |
| tree | 3018ea887b40bacac92a137206d5e5f5c34a12bd /src/client/views/collections/collectionFreeForm | |
| parent | 5fbee077873c3dd0a9b5939babbaa1fd4dfe1393 (diff) | |
| parent | c787b0eac374b4dabf6ede7ee40e77a28815d5c8 (diff) | |
merged with master
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
11 files changed, 335 insertions, 367 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index e84f0c5ad..081b3eb6c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,15 +23,15 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo let l = this.props.LinkDocs; let a = this.props.A; let b = this.props.B; - let x1 = a.GetNumber(KeyStore.X, 0) + a.GetNumber(KeyStore.Width, 0) / 2; - let y1 = a.GetNumber(KeyStore.Y, 0) + a.GetNumber(KeyStore.Height, 0) / 2; - let x2 = b.GetNumber(KeyStore.X, 0) + b.GetNumber(KeyStore.Width, 0) / 2; - let y2 = b.GetNumber(KeyStore.Y, 0) + b.GetNumber(KeyStore.Height, 0) / 2; + let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2); + let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2); + let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2); + let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2); return ( <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown} style={{ strokeWidth: `${l.length * 5}` }} x1={`${x1}`} y1={`${y1}`} x2={`${x2}`} y2={`${y2}`} /> - ) + ); } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss index 4341c82f7..30e158603 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss @@ -1,6 +1,8 @@ .collectionfreeformlinksview-svgCanvas{ transform: translate(-10000px,-10000px); position: absolute; + top: 0; + left: 0; width: 20000px; height: 20000px; pointer-events: none; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index eb20b3100..2f684a54e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,72 +1,80 @@ -import { computed, reaction, runInAction, trace } from "mobx"; +import { computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; import { ListField } from "../../../../fields/ListField"; import { Utils } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; import { DocumentView } from "../../nodes/DocumentView"; -import { CollectionViewProps } from "../CollectionViewBase"; +import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); -import v5 = require("uuid/v5"); @observer export class CollectionFreeFormLinksView extends React.Component<CollectionViewProps> { + _brushReactionDisposer?: IReactionDisposer; componentDidMount() { - reaction(() => { - return DocumentManager.Instance.getAllDocumentViews(this.props.Document).map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)) - }, () => { - let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document); - for (let i = 0; i < views.length; i++) { - for (let j = i + 1; j < views.length; j++) { - let srcDoc = views[j].props.Document; - let dstDoc = views[i].props.Document; - let x1 = srcDoc.GetNumber(KeyStore.X, 0); - let x1w = srcDoc.GetNumber(KeyStore.Width, -1); - let x2 = dstDoc.GetNumber(KeyStore.X, 0); - let x2w = dstDoc.GetNumber(KeyStore.Width, -1); - if (x1w < 0 || x2w < 0) - continue; - dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) => - srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => { - let dstTarg = (protoDest ? protoDest : dstDoc); - let srcTarg = (protoSrc ? protoSrc : srcDoc); - let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => { - let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]); - return (bdocs.length == 0 || (bdocs[0] == dstTarg && bdocs[1] == srcTarg) || (bdocs[0] == srcTarg && bdocs[1] == dstTarg)) - }); - let brushAction = (field: ListField<Document>) => { - let found = findBrush(field); - if (found != -1) - field.Data.splice(found, 1); - }; - if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 20) { - let linkDoc: Document = new Document(); - linkDoc.SetText(KeyStore.Title, "Histogram Brush"); - linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title); - linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField); - - brushAction = brushAction = (field: ListField<Document>) => (findBrush(field) == -1) && field.Data.push(linkDoc); + this._brushReactionDisposer = reaction(() => this.props.Document.GetList<Document>(this.props.fieldKey, []).map(doc => doc.GetNumber(KeyStore.X, 0)), + () => { + let views = this.props.Document.GetList<Document>(this.props.fieldKey, []); + for (let i = 0; i < views.length; i++) { + for (let j = 0; j < views.length; j++) { + let srcDoc = views[j]; + let dstDoc = views[i]; + let x1 = srcDoc.GetNumber(KeyStore.X, 0); + let x1w = srcDoc.GetNumber(KeyStore.Width, -1); + let x2 = dstDoc.GetNumber(KeyStore.X, 0); + let x2w = dstDoc.GetNumber(KeyStore.Width, -1); + if (x1w < 0 || x2w < 0 || i === j) { + continue; + } + let dstTarg = dstDoc; + let srcTarg = srcDoc; + let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => { + let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); + }); + let brushAction = (field: ListField<Document>) => { + let found = findBrush(field); + if (found !== -1) { + console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); + field.Data.splice(found, 1); } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + }; + if (Math.abs(x1 + x1w - x2) < 20) { + let linkDoc: Document = new Document(); + linkDoc.SetText(KeyStore.Title, "Histogram Brush"); + linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title); + linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField); + + brushAction = (field: ListField<Document>) => { + if (findBrush(field) === -1) { + console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); + (findBrush(field) === -1) && field.Data.push(linkDoc); + } + }; } - ))) + dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + + } } - } - }) + }); + } + componentWillUnmount() { + if (this._brushReactionDisposer) { + this._brushReactionDisposer(); + } } documentAnchors(view: DocumentView) { let equalViews = [view]; let containerDoc = view.props.Document.GetT(KeyStore.AnnotationOn, Document); - if (containerDoc && containerDoc != FieldWaiting && containerDoc instanceof Document) { - equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.GetPrototype() as Document) + if (containerDoc && containerDoc instanceof Document) { + equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.GetPrototype()!); } - return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document == this.props.Document); + return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @computed @@ -76,19 +84,18 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP let targetViews = this.documentAnchors(connection.b); let possiblePairs: { a: Document, b: Document, }[] = []; srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); - possiblePairs.map(possiblePair => { - if (!drawnPairs.reduce((found, drawnPair) => { - let match = (possiblePair.a == drawnPair.a && possiblePair.b == drawnPair.b); - if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id == connection.l.Id, false)) - drawnPair.l.push(connection.l); + possiblePairs.map(possiblePair => + drawnPairs.reduce((found, drawnPair) => { + let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); + if (match && !drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { + drawnPair.l.push(connection.l); } return match || found; - }, false)) { - drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] as Document[] }); - } - }) - return drawnPairs + }, false) + || + drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }) + ); + return drawnPairs; }, [] as { a: Document, b: Document, l: Document[] }[]); return connections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss new file mode 100644 index 000000000..c5b8fc5e8 --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss @@ -0,0 +1,24 @@ +@import "globalCssVariables"; + +.collectionFreeFormRemoteCursors-cont { + + position:absolute; + z-index: $remoteCursors-zindex; + transform-origin: 'center center'; +} +.collectionFreeFormRemoteCursors-canvas { + + position:absolute; + width: 20px; + height: 20px; + opacity: 0.5; + border-radius: 50%; + border: 2px solid black; +} +.collectionFreeFormRemoteCursors-symbol { + font-size: 14; + color: black; + // fontStyle: "italic", + margin-left: -12; + margin-top: 4; +}
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 19382e66f..751ea8190 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,21 +1,8 @@ -import { action, computed, observable } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; -import { TextField } from "../../../../fields/TextField"; -import { DragManager } from "../../../util/DragManager"; -import { Transform } from "../../../util/Transform"; -import { undoBatch } from "../../../util/UndoManager"; -import { InkingCanvas } from "../../InkingCanvas"; -import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; -import { CollectionViewBase, CollectionViewProps, CursorEntry } from "../CollectionViewBase"; -import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; +import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; -import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; @@ -70,43 +57,23 @@ export class CollectionFreeFormRemoteCursors extends React.Component<CollectionV let id = entry.Data[0][0]; let email = entry.Data[0][1]; let point = entry.Data[1]; - this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22") + this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22"); return ( - <div - key={id} - style={{ - position: "absolute", - transform: `translate(${point[0] - 10}px, ${point[1] - 10}px)`, - zIndex: 10000, - transformOrigin: 'center center', - }} + <div key={id} className="collectionFreeFormRemoteCursors-cont" + style={{ transform: `translate(${point[0] - 10}px, ${point[1] - 10}px)` }} > - <canvas - ref={(el) => { if (el) this.crosshairs = el }} + <canvas className="collectionFreeFormRemoteCursors-canvas" + ref={(el) => { if (el) this.crosshairs = el; }} width={20} height={20} - style={{ - position: 'absolute', - width: "20px", - height: "20px", - opacity: 0.5, - borderRadius: "50%", - border: "2px solid black" - }} /> - <p - style={{ - fontSize: 14, - color: "black", - // fontStyle: "italic", - marginLeft: -12, - marginTop: 4 - }} - >{email[0].toUpperCase()}</p> + <p className="collectionFreeFormRemoteCursors-symbol"> + {email[0].toUpperCase()} + </p> </div> ); } - }) + }); } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 81d21d89a..26c794e91 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -1,7 +1,13 @@ -@import "../../global_variables"; - +@import "../../globalCssVariables"; +.collectionfreeformview-measure { + position: inherit; + top: 0; + left: 0; + width: 100%; + height: 100%; + } .collectionfreeformview { - position: absolute; + position: inherit; top: 0; left: 0; width: 100%; @@ -10,7 +16,7 @@ } .collectionfreeformview-container { .collectionfreeformview > .jsx-parser { - position: absolute; + position: inherit; height: 100%; width: 100%; } @@ -22,11 +28,13 @@ // background-size: 30px 30px; // } + border-width: $COLLECTION_BORDER_WIDTH; box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw; - border: 0px solid $light-color-secondary; + border-color: $light-color-secondary; + border-style: solid; border-radius: $border-radius; box-sizing: border-box; - position: relative; + position: absolute; overflow: hidden; top: 0; left: 0; @@ -35,18 +43,20 @@ } .collectionfreeformview-overlay { .collectionfreeformview > .jsx-parser { - position: absolute; + position: inherit; height: 100%; } .formattedTextBox-cont { background: $light-color-secondary; } - + opacity: 0.99; - border: 0px solid transparent; + border-width: 0; + border-color: transparent; + border-style: solid; border-radius: $border-radius; box-sizing: border-box; - position:relative; + position: absolute; overflow: hidden; top: 0; left: 0; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c5178f69d..c3ab80f8d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,28 +1,33 @@ -import { action, computed, observable, trace } from "mobx"; +import { action, computed, observable, runInAction, untracked } from "mobx"; import { observer } from "mobx-react"; +import Measure from "react-measure"; import { Document } from "../../../../fields/Document"; import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; import { TextField } from "../../../../fields/TextField"; +import { emptyFunction, returnFalse } from "../../../../Utils"; +import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager } from "../../../util/DragManager"; +import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; +import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; import { InkingCanvas } from "../../InkingCanvas"; +import { Main } from "../../Main"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; -import { CollectionViewBase } from "../CollectionViewBase"; +import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; +import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); -import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; -import { PreviewCursor } from "./PreviewCursor"; +import { MainOverlayTextBox } from "../../MainOverlayTextBox"; @observer -export class CollectionFreeFormView extends CollectionViewBase { +export class CollectionFreeFormView extends CollectionSubView { public _canvasRef = React.createRef<HTMLDivElement>(); private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type) @@ -33,21 +38,23 @@ export class CollectionFreeFormView extends CollectionViewBase { } public addDocument = (newBox: Document, allowDuplicates: boolean) => { - let added = this.props.addDocument(newBox, false); - this.bringToFront(newBox); - return added; + if (this.isAnnotationOverlay) { + newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); + } + return this.props.addDocument(this.bringToFront(newBox), false); } public selectDocuments = (docs: Document[]) => { - this.props.CollectionView.SelectedDocs.length = 0; - docs.map(d => this.props.CollectionView.SelectedDocs.push(d.Id)); + SelectionManager.DeselectAll; + docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv => + SelectionManager.SelectDoc(dv!, true)); } public getActiveDocuments = () => { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page == curPage || page == -1) { + if (page === curPage || page === -1) { active.push(doc); } return active; @@ -58,46 +65,44 @@ export class CollectionFreeFormView extends CollectionViewBase { @observable public DownY: number = 0; @observable private _lastX: number = 0; @observable private _lastY: number = 0; + @observable private _pwidth: number = 0; + @observable private _pheight: number = 0; - @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } - @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); } + @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); } - @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this.props.panelWidth() / 2 : 0; } // shift so pan position is at center of window for non-overlay collections - @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this.props.panelHeight() / 2 : 0; }// shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this._pwidth / 2 : 0; } // shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this._pheight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { - if (super.drop(e, de)) { - if (de.data instanceof DragManager.DocumentDragData) { - let screenX = de.x - (de.data.xOffset as number || 0); - let screenY = de.y - (de.data.yOffset as number || 0); - const [x, y] = this.getTransform().transformPoint(screenX, screenY); - let dragDoc = de.data.draggedDocuments[0]; - let dragX = dragDoc.GetNumber(KeyStore.X, 0); - let dragY = dragDoc.GetNumber(KeyStore.Y, 0); - de.data.draggedDocuments.map(d => { - let docX = d.GetNumber(KeyStore.X, 0); - let docY = d.GetNumber(KeyStore.Y, 0); - d.SetNumber(KeyStore.X, x + (docX - dragX)); - d.SetNumber(KeyStore.Y, y + (docY - dragY)); + if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { + const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); + if (de.data.droppedDocuments.length) { + let dropX = de.data.droppedDocuments[0].GetNumber(KeyStore.X, 0); + let dropY = de.data.droppedDocuments[0].GetNumber(KeyStore.Y, 0); + de.data.droppedDocuments.map(d => { + d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX)); + d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY)); if (!d.GetNumber(KeyStore.Width, 0)) { d.SetNumber(KeyStore.Width, 300); + } + if (!d.GetNumber(KeyStore.Height, 0)) { d.SetNumber(KeyStore.Height, 300); } this.bringToFront(d); - }) + }); } return true; } return false; } - @action cleanupInteractions = () => { document.removeEventListener("pointermove", this.onPointerMove); @@ -106,15 +111,13 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerDown = (e: React.PointerEvent): void => { - if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling != 1)) || e.button == 0) && this.props.active()) { + if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || e.button === 0) && this.props.active()) { document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); this._lastX = this.DownX = e.pageX; this._lastY = this.DownY = e.pageY; - if (this.props.isSelected()) - e.stopPropagation(); } } @@ -128,10 +131,31 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble && this.props.active()) { - if ((!this.isAnnotationOverlay || this.zoomScaling != 1) && !e.shiftKey) { + if ((!this.isAnnotationOverlay || this.zoomScaling !== 1) && !e.shiftKey) { let x = this.props.Document.GetNumber(KeyStore.PanX, 0); let y = this.props.Document.GetNumber(KeyStore.PanY, 0); + let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); + if (!this.isAnnotationOverlay) { + let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0; + let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx; + let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0; + let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny; + let ranges = docs.filter(doc => doc).reduce((range, doc) => { + let x = doc.GetNumber(KeyStore.X, 0); + let xe = x + doc.GetNumber(KeyStore.Width, 0); + let y = doc.GetNumber(KeyStore.Y, 0); + let ye = y + doc.GetNumber(KeyStore.Height, 0); + return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], + [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; + }, [[minx, maxx], [miny, maxy]]); + let panelwidth = this._pwidth / this.scale / 2; + let panelheight = this._pheight / this.scale / 2; + if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx; + if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx; + if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy; + if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy; + } this.SetPan(x - dx, y - dy); this._lastX = e.pageX; this._lastY = e.pageY; @@ -143,7 +167,9 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerWheel = (e: React.WheelEvent): void => { - this.props.select(false); + // if (!this.props.active()) { + // return; + // } e.stopPropagation(); let coefficient = 1000; @@ -157,26 +183,30 @@ export class CollectionFreeFormView extends CollectionViewBase { 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?? + // 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)); - if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) + if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling; + } let [x, y] = transform.transformPoint(e.clientX, e.clientY); - let localTransform = this.getLocalTransform() - localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y); // console.log(localTransform) this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale); + e.stopPropagation(); + e.preventDefault(); } } @action private SetPan(panX: number, panY: number) { + MainOverlayTextBox.Instance.SetTextDoc(); var x1 = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY)); @@ -206,9 +236,9 @@ export class CollectionFreeFormView extends CollectionViewBase { return -1; } return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); - }).map((doc, index) => { - doc.SetNumber(KeyStore.ZIndex, index + 1) - }); + }).map((doc, index) => + doc.SetNumber(KeyStore.ZIndex, index + 1)); + return doc; } @computed get backgroundLayout(): string | undefined { @@ -228,85 +258,105 @@ export class CollectionFreeFormView extends CollectionViewBase { let x = doc.GetNumber(KeyStore.X, 0) + doc.GetNumber(KeyStore.Width, 0) / 2; let y = doc.GetNumber(KeyStore.Y, 0) + doc.GetNumber(KeyStore.Height, 0) / 2; this.SetPan(x, y); - this.props.focus(this.props.Document); } - getDocumentViewProps(document: Document): DocumentViewProps { + getDocumentViewProps(document: Document, opacity: number): DocumentViewProps { return { Document: document, - AddDocument: this.props.addDocument, - RemoveDocument: this.props.removeDocument, + opacity: opacity, + addDocument: this.props.addDocument, + removeDocument: this.props.removeDocument, + moveDocument: this.props.moveDocument, ScreenToLocalTransform: this.getTransform, isTopMost: false, - SelectOnLoad: document.Id == this._selectOnLoaded, + selectOnLoad: document.Id === this._selectOnLoaded, PanelWidth: document.Width, PanelHeight: document.Height, ContentScaling: this.noScaling, ContainingCollectionView: this.props.CollectionView, - focus: this.focusDocument - } + focus: this.focusDocument, + parentActive: this.props.active, + onActiveChanged: this.props.active, + }; } @computed get views() { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); - return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { + let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page == curPage || page == -1) - prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />); + var zoom = doc.GetNumber(KeyStore.Zoom, 1); + var dv = DocumentManager.Instance.getDocumentView(doc); + let opacity = this.isAnnotationOverlay && (!dv || !SelectionManager.IsSelected(dv)) ? 1 - Math.abs(zoom - this.scale) : 1; + if ((page === curPage || page === -1)) { + prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc, opacity)} />); + } return prev; - }, [] as JSX.Element[]) + }, [] as JSX.Element[]); + + setTimeout(() => { // bcz: surely there must be a better way .... + this._selectOnLoaded = ""; + }, 600); + + return docviews; } @computed get backgroundView() { return !this.backgroundLayout ? (null) : - (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)} - layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={() => false} select={() => { }} />); + (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)} + layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); } @computed get overlayView() { return !this.overlayLayout ? (null) : - (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)} - layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={() => false} select={() => { }} />); + (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)} + layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); } - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) - getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) - getLocalTransform = (): Transform => Transform.Identity.scale(1 / this.scale).translate(this.panX, this.panY); + @computed + get borderWidth() { + return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; + } + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()); + getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); + getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; render() { - let [dx, dy] = [this.centeringShiftX, this.centeringShiftY]; - + const [dx, dy] = [this.centeringShiftX, this.centeringShiftY]; const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0); const pany: number = -this.props.Document.GetNumber(KeyStore.PanY, 0); + const zoom: number = this.zoomScaling;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire + const backgroundView = this.backgroundView; // needs to be a variable outside of the <Measure> otherwise, reactions won't fire + const overlayView = this.overlayView;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire return ( - <div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`} - onPointerDown={this.onPointerDown} onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))} - onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel} - style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} ref={this.createDropTarget}> - <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} - addDocument={this.addDocument} removeDocument={this.props.removeDocument} - getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}> - <PreviewCursor container={this} addLiveTextDocument={this.addLiveTextBox} - getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} > - <div className="collectionfreeformview" ref={this._canvasRef} - style={{ transform: `translate(${dx}px, ${dy}px) scale(${this.zoomScaling}, ${this.zoomScaling}) translate(${panx}px, ${pany}px)` }}> - {this.backgroundView} - <CollectionFreeFormLinksView {...this.props}> - <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} > - {this.childViews} - </InkingCanvas> - </CollectionFreeFormLinksView> - <CollectionFreeFormRemoteCursors {...this.props} /> + <Measure onResize={(r: any) => runInAction(() => { this._pwidth = r.entry.width; this._pheight = r.entry.height; })}> + {({ measureRef }) => ( + <div className={`collectionfreeformview-measure`} ref={measureRef}> + <div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`} + onPointerDown={this.onPointerDown} onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))} + onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel} ref={this.createDropTarget}> + <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} + addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox} + getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}> + <div className="collectionfreeformview" ref={this._canvasRef} + style={{ transform: `translate(${dx}px, ${dy}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}> + {backgroundView} + <CollectionFreeFormLinksView {...this.props}> + <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} > + {this.childViews} + </InkingCanvas> + </CollectionFreeFormLinksView> + <CollectionFreeFormRemoteCursors {...this.props} /> + </div> + {overlayView} + </MarqueeView> </div> - {this.overlayView} - </PreviewCursor> - </MarqueeView> - </div> + </div>)} + </Measure> ); } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 1ee3b244b..ae0a9fd48 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -1,6 +1,8 @@ .marqueeView { - position: absolute; + position: inherit; + top:0; + left:0; width:100%; height:100%; } @@ -11,4 +13,14 @@ border-width: 1px; border-color: black; pointer-events: none; + .marquee-legend { + bottom:-18px; + left:0; + position: absolute; + font-size: 9; + white-space:nowrap; + } + .marquee-legend::after { + content: "Press: C (collection), or Delete" + } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e2239c8be..dbab790d4 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable, trace } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../../fields/Document"; import { FieldWaiting } from "../../../../fields/Field"; @@ -7,10 +7,11 @@ import { KeyStore } from "../../../../fields/KeyStore"; import { Documents } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; +import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; +import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; -import { PreviewCursor } from "./PreviewCursor"; import React = require("react"); interface MarqueeViewProps { @@ -21,6 +22,7 @@ interface MarqueeViewProps { activeDocuments: () => Document[]; selectDocuments: (docs: Document[]) => void; removeDocument: (doc: Document) => boolean; + addLiveTextDocument: (doc: Document) => void; } @observer @@ -32,12 +34,13 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @observable _downY: number = 0; @observable _used: boolean = false; @observable _visible: boolean = false; + _showOnUp: boolean = false; static DRAG_THRESHOLD = 4; @action cleanupInteractions = (all: boolean = false) => { if (all) { - document.removeEventListener("pointermove", this.onPointerMove, true) + document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); } else { this._used = true; @@ -47,12 +50,32 @@ export class MarqueeView extends React.Component<MarqueeViewProps> } @action + onKeyPress = (e: KeyboardEvent) => { + // Mixing events between React and Native is finicky. In FormattedTextBox, we set the + // DASHFormattedTextBoxHandled flag when a text box consumes a key press so that we can ignore + // the keyPress here. + //if not these keys, make a textbox if preview cursor is active! + if (!e.ctrlKey && !e.altKey && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { + //make textbox and add it to this collection + let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY); + let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "typed text" }); + this.props.addLiveTextDocument(newBox); + PreviewCursor.Visible = false; + e.stopPropagation(); + } + } + hideCursor = () => { + document.removeEventListener("keypress", this.onKeyPress, false); + } + @action onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons == 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { + if (e.buttons === 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; - document.addEventListener("pointermove", this.onPointerMove, true) + this._showOnUp = true; + document.removeEventListener("keypress", this.onKeyPress, false); + document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } @@ -63,7 +86,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this._lastX = e.pageX; this._lastY = e.pageY; if (!e.cancelBubble) { - if (!this._used && e.buttons == 1 && !e.altKey && !e.metaKey && + if (Math.abs(this._downX - e.clientX) > 4 || Math.abs(this._downY - e.clientY) > 4) { + this._showOnUp = false; + PreviewCursor.Visible = false; + } + if (!this._used && e.buttons === 1 && !e.altKey && !e.metaKey && (Math.abs(this._lastX - this._downX) > MarqueeView.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > MarqueeView.DRAG_THRESHOLD)) { this._visible = true; } @@ -76,11 +103,16 @@ export class MarqueeView extends React.Component<MarqueeViewProps> onPointerUp = (e: PointerEvent): void => { this.cleanupInteractions(true); this._visible = false; - let mselect = this.marqueeSelect(); - if (!e.shiftKey) { - SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); + if (this._showOnUp) { + PreviewCursor.Show(this.hideCursor, this._downX, this._downY); + document.addEventListener("keypress", this.onKeyPress, false); + } else { + let mselect = this.marqueeSelect(); + if (!e.shiftKey) { + SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); + } + this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } - this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } intersectRect(r1: { left: number, top: number, width: number, height: number }, @@ -94,20 +126,21 @@ export class MarqueeView extends React.Component<MarqueeViewProps> let top = this._downY < this._lastY ? this._downY : this._lastY; let topLeft = this.props.getTransform().transformPoint(left, top); let size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) } + return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } + @undoBatch @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key == "Backspace" || e.key == "Delete") { + if (e.key === "Backspace" || e.key === "Delete") { this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - if (ink && ink != FieldWaiting) { + if (ink && ink !== FieldWaiting) { this.marqueeInkDelete(ink.Data); } this.cleanupInteractions(); } - if (e.key == "c") { + if (e.key === "c") { let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); @@ -118,7 +151,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> return d; }); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - let inkData = ink && ink != FieldWaiting ? ink.Data : undefined; + let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined; //setTimeout(() => { let newCollection = Documents.FreeformDocument(selected, { x: bounds.left, @@ -135,6 +168,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this.marqueeInkDelete(inkData); // }, 100); this.cleanupInteractions(); + SelectionManager.DeselectAll(); } } @action @@ -146,7 +180,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) { idata.set(key, { - pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }), + pathData: value.pathData.map(val => ({ x: val.x + centerShiftX, y: val.y + centerShiftY })), color: value.color, width: value.width, tool: value.tool, @@ -175,13 +209,15 @@ export class MarqueeView extends React.Component<MarqueeViewProps> let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { + var z = doc.GetNumber(KeyStore.Zoom, 1); var x = doc.GetNumber(KeyStore.X, 0); var y = doc.GetNumber(KeyStore.Y, 0); - var w = doc.GetNumber(KeyStore.Width, 0); - var h = doc.GetNumber(KeyStore.Height, 0); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) - selection.push(doc) - }) + var w = doc.GetNumber(KeyStore.Width, 0) / z; + var h = doc.GetNumber(KeyStore.Height, 0) / z; + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); return selection; } @@ -189,7 +225,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps> get marqueeDiv() { let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} /> + return <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} > + <span className="marquee-legend" /> + </div>; } render() { diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss deleted file mode 100644 index 21210be2b..000000000 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss +++ /dev/null @@ -1,23 +0,0 @@ - -.previewCursor { - color: black; - position: absolute; - transform-origin: left top; - pointer-events: none; -} -.previewCursorView { - position: absolute; - width:100%; - height:100%; -} - -//this is an animation for the blinking cursor! -// @keyframes blink { -// 0% {opacity: 0} -// 49%{opacity: 0} -// 50% {opacity: 1} -// } - -// #previewCursor { -// animation: blink 1s infinite; -// }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx deleted file mode 100644 index 93c98f7b0..000000000 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { action, observable, trace, computed, reaction } from "mobx"; -import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { Documents } from "../../../documents/Documents"; -import { Transform } from "../../../util/Transform"; -import { CollectionFreeFormView } from "./CollectionFreeFormView"; -import "./PreviewCursor.scss"; -import React = require("react"); -import { interfaceDeclaration } from "babel-types"; - - -export interface PreviewCursorProps { - getTransform: () => Transform; - getContainerTransform: () => Transform; - container: CollectionFreeFormView; - addLiveTextDocument: (doc: Document) => void; -} - -@observer -export class PreviewCursor extends React.Component<PreviewCursorProps> { - @observable _lastX: number = 0; - @observable _lastY: number = 0; - @observable public _visible: boolean = false; - @observable public DownX: number = 0; - @observable public DownY: number = 0; - _showOnUp: boolean = false; - - @action - cleanupInteractions = () => { - document.removeEventListener("pointerup", this.onPointerUp, true); - document.removeEventListener("pointermove", this.onPointerMove, true); - } - - @action - onPointerDown = (e: React.PointerEvent) => { - if (e.button == 0 && this.props.container.props.active()) { - document.removeEventListener("keypress", this.onKeyPress, false); - this._showOnUp = true; - this.DownX = e.pageX; - this.DownY = e.pageY; - document.addEventListener("pointerup", this.onPointerUp, true); - document.addEventListener("pointermove", this.onPointerMove, true); - } - } - @action - onPointerMove = (e: PointerEvent): void => { - if (Math.abs(this.DownX - e.clientX) > 4 || Math.abs(this.DownY - e.clientY) > 4) { - this._showOnUp = false; - this._visible = false; - } - } - - @action - onPointerUp = (e: PointerEvent): void => { - if (this._showOnUp) { - document.addEventListener("keypress", this.onKeyPress, false); - this._lastX = this.DownX; - this._lastY = this.DownY; - this._visible = true; - } - this.cleanupInteractions(); - } - - @action - onKeyPress = (e: KeyboardEvent) => { - // Mixing events between React and Native is finicky. In FormattedTextBox, we set the - // DASHFormattedTextBoxHandled flag when a text box consumes a key press so that we can ignore - // the keyPress here. - //if not these keys, make a textbox if preview cursor is active! - if (!e.ctrlKey && !e.altKey && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { - //make textbox and add it to this collection - let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY); - let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "typed text" }); - this.props.addLiveTextDocument(newBox); - document.removeEventListener("keypress", this.onKeyPress, false); - this._visible = false; - e.stopPropagation(); - } - } - - getPoint = () => this.props.getContainerTransform().transformPoint(this._lastX, this._lastY); - getVisible = () => this._visible; - setVisible = (v: boolean) => { - this._visible = v; - document.removeEventListener("keypress", this.onKeyPress, false); - } - render() { - return ( - <div className="previewCursorView" onPointerDown={this.onPointerDown}> - {this.props.children} - <PreviewCursorPrompt setVisible={this.setVisible} getPoint={this.getPoint} getVisible={this.getVisible} /> - </div> - ) - } -} - -export interface PromptProps { - getPoint: () => number[]; - getVisible: () => boolean; - setVisible: (v: boolean) => void; -} - -@observer -export class PreviewCursorPrompt extends React.Component<PromptProps> { - private _promptRef = React.createRef<HTMLDivElement>(); - - //when focus is lost, this will remove the preview cursor - @action onBlur = (): void => this.props.setVisible(false); - - render() { - let p = this.props.getPoint(); - if (this.props.getVisible() && this._promptRef.current) - this._promptRef.current.focus(); - return <div className="previewCursor" id="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={this._promptRef} - style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, opacity: this.props.getVisible() ? 1 : 0 }}> - I - </div >; - } -}
\ No newline at end of file |
