From 61aa3a0a34a647a7f414fbeb72345675a5154433 Mon Sep 17 00:00:00 2001 From: ab Date: Mon, 18 Feb 2019 18:18:53 -0500 Subject: title --- src/client/views/DocumentDecorations.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index e8b93a18b..5c99c52ea 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -2,7 +2,7 @@ position: absolute; display: grid; z-index: 1000; - grid-template-rows: 20px 1fr 20px; + grid-template-rows: 20px 20px 1fr 20px; grid-template-columns: 20px 1fr 20px; pointer-events: none; #documentDecorations-centerCont { @@ -29,4 +29,10 @@ #documentDecorations-rightResizer { cursor: ew-resize; } + .title{ + background: lightblue; + grid-column-start:1; + grid-column-end: 4; + cursor: ne-resize; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2886c2859bfc6ad396fc4bab3e90cf18da5442f1 Mon Sep 17 00:00:00 2001 From: ab Date: Mon, 18 Feb 2019 19:01:17 -0500 Subject: input title --- src/client/views/DocumentDecorations.scss | 2 +- src/client/views/DocumentDecorations.tsx | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 5c99c52ea..9bafbda44 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -33,6 +33,6 @@ background: lightblue; grid-column-start:1; grid-column-end: 4; - cursor: ne-resize; + pointer-events: auto; } } \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index dcfedfcd1..b44e32c52 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -8,7 +8,7 @@ import ContentEditable from 'react-contenteditable' import { KeyStore } from '../../fields/Key' @observer -export class DocumentDecorations extends React.Component { +export class DocumentDecorations extends React.Component<{}, { value: string }> { static Instance: DocumentDecorations private _resizer = "" private _isPointerDown = false; @@ -17,12 +17,13 @@ export class DocumentDecorations extends React.Component { constructor(props: Readonly<{}>) { super(props) DocumentDecorations.Instance = this - this.state = { html: "hi" }; + this.state = { value: document.title }; + this.handleChange = this.handleChange.bind(this); } - // handleChange = evt => { - // this.setState({ html: evt.target.value }); - // }; + handleChange(event: any) { + this.setState({ value: event.target.value }); + }; @computed get Bounds(): { x: number, y: number, b: number, r: number } { @@ -146,8 +147,8 @@ export class DocumentDecorations extends React.Component { top: bounds.y - 20 - 20, opacity: this.opacity }}> - {/**/} -
{document.title}
+ + {/*
{document.title}
*/}
e.preventDefault()}>
e.preventDefault()}>
e.preventDefault()}>
-- cgit v1.2.3-70-g09d2 From 8448679e0a260ec881c54a10578bc464cd38f04e Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 1 Apr 2019 17:05:42 -0400 Subject: added dragging multiple items. --- src/client/northstar/dash-nodes/HistogramBox.tsx | 4 +- src/client/util/DragManager.ts | 168 +++++++++++---------- src/client/views/DocumentDecorations.scss | 6 + src/client/views/DocumentDecorations.tsx | 109 +++++++++---- src/client/views/Main.tsx | 7 +- .../views/collections/CollectionDockingView.tsx | 11 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewBase.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 ++- src/client/views/nodes/DocumentView.tsx | 15 +- 10 files changed, 213 insertions(+), 134 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a968def96..49ebe5ebc 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -54,7 +54,7 @@ export class HistogramBox extends React.Component { @action dropX = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField); + let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); if (h && h != FieldWaiting) { this.HistoOp.X = h.Data.X; } @@ -65,7 +65,7 @@ export class HistogramBox extends React.Component { @action dropY = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField); + let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); if (h && h != FieldWaiting) { this.HistoOp.Y = h.Data.X; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 70b1c9829..9ffe964ef 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -14,9 +14,9 @@ export function setupDrag(_reference: React.RefObject, docFunc: document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); - var dragData = new DragManager.DocumentDragData(docFunc()); + var dragData = new DragManager.DocumentDragData([docFunc()]); dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag(_reference.current!, dragData); + DragManager.StartDocumentDrag([_reference.current!], dragData); }); let onRowUp = action((e: PointerEvent): void => { document.removeEventListener("pointermove", onRowMove); @@ -27,7 +27,7 @@ export function setupDrag(_reference: React.RefObject, docFunc: if (e.button == 0) { e.stopPropagation(); if (e.shiftKey) { - CollectionDockingView.Instance.StartOtherDrag(docFunc(), e); + CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); } else { document.addEventListener("pointermove", onRowMove); document.addEventListener('pointerup', onRowUp); @@ -101,20 +101,21 @@ export namespace DragManager { } export class DocumentDragData { - constructor(dragDoc: Document) { - this.draggedDocument = dragDoc; - this.droppedDocument = dragDoc; + constructor(dragDoc: Document[]) { + this.draggedDocuments = dragDoc; + this.droppedDocuments = dragDoc; } - draggedDocument: Document; - droppedDocument: Document; + draggedDocuments: Document[]; + droppedDocuments: Document[]; xOffset?: number; yOffset?: number; aliasOnDrop?: boolean; removeDocument?: (collectionDrop: CollectionView) => void; [id: string]: any; } - export function StartDocumentDrag(ele: HTMLElement, dragData: DocumentDragData, options?: DragOptions) { - StartDrag(ele, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocument = dragData.aliasOnDrop ? dragData.draggedDocument.CreateAlias() : dragData.draggedDocument); + + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, options?: DragOptions) { + StartDrag(eles, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments); } export class LinkDragData { @@ -125,49 +126,58 @@ export namespace DragManager { [id: string]: any; } export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, options?: DragOptions) { - StartDrag(ele, dragData, options); + StartDrag([ele], dragData, options); } - function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { if (!dragDiv) { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv" DragManager.Root().appendChild(dragDiv); } - const w = ele.offsetWidth, h = ele.offsetHeight; - const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, scaleY = rect.height / h; - let x = rect.left, y = rect.top; - // const offsetX = e.x - rect.left, offsetY = e.y - rect.top; - - let dragElement = ele.cloneNode(true) as HTMLElement; - dragElement.style.opacity = "0.7"; - dragElement.style.position = "absolute"; - dragElement.style.bottom = ""; - dragElement.style.left = ""; - dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width / scaleX}px`; - dragElement.style.height = `${rect.height / scaleY}px`; - - // bcz: PDFs don't show up if you clone them because they contain a canvas. - // however, PDF's have a thumbnail field that contains an image of their canvas. - // So we replace the pdf's canvas with the image thumbnail - const doc: Document = dragData["draggedDocument"]; - if (doc) { - var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; - let thumbnail = doc.GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]) + + let scaleXs: number[] = []; + let scaleYs: number[] = []; + let xs: number[] = []; + let ys: number[] = []; + + const docs: Document[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + let dragElements = eles.map(ele => { + const w = ele.offsetWidth, h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, scaleY = rect.height / h; + let x = rect.left, y = rect.top; + xs.push(x); ys.push(y); + scaleXs.push(scaleX); scaleYs.push(scaleY); + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; + dragElement.style.position = "absolute"; + dragElement.style.bottom = ""; + dragElement.style.left = ""; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.zIndex = "1000"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; + + // bcz: PDFs don't show up if you clone them because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of their canvas. + // So we replace the pdf's canvas with the image thumbnail + if (docs.length) { + var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; + let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + if (pdfBox && pdfBox.childElementCount && thumbnail) { + let img = new Image(); + img!.src = thumbnail.toString(); + img!.style.position = "absolute"; + img!.style.width = `${rect.width / scaleX}px`; + img!.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img!, pdfBox.children[0]) + } } - } - dragDiv.appendChild(dragElement); + dragDiv.appendChild(dragElement); + return dragElement; + }); let hideSource = false; if (options) { @@ -177,62 +187,64 @@ export namespace DragManager { hideSource = options.hideSource(); } } - const wasHidden = ele.hidden; - if (hideSource) { - ele.hidden = true; - } + eles.map(ele => ele.hidden = hideSource); + const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - x += e.movementX; - y += e.movementY; if (dragData instanceof DocumentDragData) dragData.aliasOnDrop = e.ctrlKey || e.altKey; if (e.shiftKey) { abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(doc, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); + CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); } - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElements.map((dragElement, i) => dragElement.style.transform = `translate(${xs[i] += e.movementX}px, ${ys[i] += e.movementY}px) scale(${scaleXs[i]}, ${scaleYs[i]})`); }; const abortDrag = () => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - dragDiv.removeChild(dragElement); - ele.hidden = false; + dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + eles.map(ele => ele.hidden = false); } const upHandler = (e: PointerEvent) => { abortDrag(); - FinishDrag(ele, e, dragData, options, finishDrag); + FinishDrag(eles, e, dragData, options, finishDrag); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } - function FinishDrag(dragEle: HTMLElement, e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { - let parent = dragEle.parentElement; - if (parent) - parent.removeChild(dragEle); + function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { + let removed = dragEles.map(dragEle => { + let parent = dragEle.parentElement; + if (parent) + parent.removeChild(dragEle); + return [dragEle, parent]; + }); const target = document.elementFromPoint(e.x, e.y); - if (parent) - parent.appendChild(dragEle); - if (!target) { - return; - } - if (finishDrag) - finishDrag(dragData); - - target.dispatchEvent(new CustomEvent("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData + removed.map(r => { + let dragEle: HTMLElement = r[0]!; + let parent: HTMLElement | null = r[1]; + if (parent) + parent.appendChild(dragEle); + }); + if (target) { + if (finishDrag) + finishDrag(dragData); + + target.dispatchEvent(new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + })); + + if (options) { + options.handlers.dragComplete({}); } - })); - - if (options) { - options.handlers.dragComplete({}); } DocumentDecorations.Instance.Hidden = false; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 11595aa01..7a43f3087 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -32,6 +32,12 @@ } } +.documentDecorations-background { + background:lightblue; + position: absolute; + opacity: 0.1; +} + // position: absolute; // display: grid; // z-index: 1000; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 47098c3b5..faba3b6ea 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,14 +1,14 @@ -import { observable, computed, action } from "mobx"; -import React = require("react"); -import { SelectionManager } from "../util/SelectionManager"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import './DocumentDecorations.scss' -import { KeyStore } from '../../fields/KeyStore' +import { KeyStore } from '../../fields/KeyStore'; +import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; -import { props } from "bluebird"; import { DragManager } from "../util/DragManager"; +import { SelectionManager } from "../util/SelectionManager"; +import { CollectionView } from "./collections/CollectionView"; +import './DocumentDecorations.scss'; import { LinkMenu } from "./nodes/LinkMenu"; -import { ListField } from "../../fields/ListField"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -22,6 +22,7 @@ export class DocumentDecorations extends React.Component { private _resizeBorderWidth = 16; private _linkButton = React.createRef(); @observable private _hidden = false; + @observable private _dragging = false; constructor(props: Readonly<{}>) { super(props) @@ -50,6 +51,50 @@ export class DocumentDecorations extends React.Component { public get Hidden() { return this._hidden; } public set Hidden(value: boolean) { this._hidden = value; } + _lastDrag: number[] = [0, 0]; + onBackgroundDown = (e: React.PointerEvent): void => { + document.removeEventListener("pointermove", this.onBackgroundMove); + document.addEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + document.addEventListener("pointerup", this.onBackgroundUp); + this._lastDrag = [e.clientX, e.clientY] + e.stopPropagation(); + e.preventDefault(); + } + + @action + onBackgroundMove = (e: PointerEvent): void => { + let dragDocView = SelectionManager.SelectedDocuments()[0]; + const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); + dragData.aliasOnDrop = false; + dragData.xOffset = e.x - left; + dragData.yOffset = e.y - top; + dragData.removeDocument = (dropCollectionView: CollectionView) => + dragData.draggedDocuments.map(d => { + if (dragDocView.props.RemoveDocument && dragDocView.props.ContainingCollectionView !== dropCollectionView) { + dragDocView.props.RemoveDocument(d); + } + }); + this._dragging = true; + document.removeEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont!.current!), dragData, { + handlers: { + dragComplete: action(() => this._dragging = false), + }, + hideSource: true + }) + e.stopPropagation(); + } + + onBackgroundUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + e.stopPropagation(); + e.preventDefault(); + } + onPointerDown = (e: React.PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { @@ -191,7 +236,6 @@ export class DocumentDecorations extends React.Component { // buttonOnPointerUp = (e: React.PointerEvent): void => { // e.stopPropagation(); // } - render() { var bounds = this.Bounds; if (this.Hidden) { @@ -218,25 +262,36 @@ export class DocumentDecorations extends React.Component { ); } return ( -
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
- -
{linkButton}
- -
+
+
1 ? 1000 : 0, + }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} > +
+
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+ +
{linkButton}
+ +
+
) } } \ No newline at end of file diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 75855c3d1..6f66f8f38 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -218,7 +218,8 @@ export class Main extends React.Component { focusDocument = (doc: Document) => { } noScaling = () => 1; - get content() { + @computed + get mainContent() { return !this.mainContainer ? (null) : + runInAction(() => { this.pwidth = r.entry.width; this.pheight = r.entry.height; })}> {({ measureRef }) =>
- {this.content} + {this.mainContent}
}
- {this.nodesMenu} {this.miscButtons} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f123149dd..c6cbc05e7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -47,9 +47,10 @@ export class CollectionDockingView extends React.Component { }, button: 0 }) + public StartOtherDrag(dragDocs: Document[], e: any) { + dragDocs.map(dragDoc => + this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener. + onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 })); } @action @@ -199,7 +200,7 @@ export class CollectionDockingView extends React.Component) => { if (f instanceof Document) - DragManager.StartDocumentDrag(tab, new DragManager.DocumentDragData(f as Document), + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), { handlers: { dragComplete: action(() => { }), @@ -265,6 +266,7 @@ export class CollectionDockingView extends React.Component { } render() { + trace(); if (!this._document) return (null); var content = diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index a1498e0ae..014aa1d8f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -113,7 +113,7 @@ export class CollectionView extends React.Component { if (index !== -1) { value.splice(index, 1) - SelectionManager.DeselectAll() + //SelectionManager.DeselectAll() ContextMenu.Instance.clearItems() return true; } diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 987f3cb6c..316d20c9d 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -82,9 +82,9 @@ export class CollectionViewBase extends React.Component if (de.data instanceof DragManager.DocumentDragData) { if (de.data.aliasOnDrop) { [KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key => - de.data.draggedDocument.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); + de.data.draggedDocuments.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); } - let added = this.props.addDocument(de.data.droppedDocument, false); + let added = de.data.droppedDocuments.reduce((added, d) => this.props.addDocument(d, false), true); if (added && de.data.removeDocument && !de.data.aliasOnDrop) { de.data.removeDocument(this.props.CollectionView); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 60fb95ff5..c5178f69d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -77,13 +77,20 @@ export class CollectionFreeFormView extends CollectionViewBase { 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); - de.data.droppedDocument.SetNumber(KeyStore.X, x); - de.data.droppedDocument.SetNumber(KeyStore.Y, y); - if (!de.data.droppedDocument.GetNumber(KeyStore.Width, 0)) { - de.data.droppedDocument.SetNumber(KeyStore.Width, 300); - de.data.droppedDocument.SetNumber(KeyStore.Height, 300); - } - this.bringToFront(de.data.droppedDocument); + 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 (!d.GetNumber(KeyStore.Width, 0)) { + d.SetNumber(KeyStore.Width, 300); + d.SetNumber(KeyStore.Height, 300); + } + this.bringToFront(d); + }) } return true; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 71613ca4f..1195128dc 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -106,7 +106,7 @@ export class DocumentView extends React.Component { if (this.props.isTopMost) { this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey); } - else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e); + else CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e); e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { @@ -125,9 +125,7 @@ export class DocumentView extends React.Component { if (this._mainCont.current) { this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); } - runInAction(() => { - DocumentManager.Instance.DocumentViews.push(this); - }) + runInAction(() => DocumentManager.Instance.DocumentViews.push(this)) this._reactionDisposer = reaction( () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(), () => { @@ -149,10 +147,7 @@ export class DocumentView extends React.Component { if (this.dropDisposer) { this.dropDisposer(); } - runInAction(() => { - DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); - - }) + runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1)) if (this._reactionDisposer) { this._reactionDisposer(); } @@ -161,7 +156,7 @@ export class DocumentView extends React.Component { startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) { if (this._mainCont.current) { const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - let dragData = new DragManager.DocumentDragData(this.props.Document); + let dragData = new DragManager.DocumentDragData([this.props.Document]); dragData.aliasOnDrop = dropAliasOfDraggedDoc; dragData.xOffset = x - left; dragData.yOffset = y - top; @@ -170,7 +165,7 @@ export class DocumentView extends React.Component { this.props.RemoveDocument(this.props.Document); } } - DragManager.StartDocumentDrag(this._mainCont.current, dragData, { + DragManager.StartDocumentDrag([this._mainCont.current], dragData, { handlers: { dragComplete: action(() => { }), }, -- cgit v1.2.3-70-g09d2 From 7fdf7396a8bdb2e4f8c3b27ca99a36727d85adae Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Mon, 1 Apr 2019 23:07:04 -0400 Subject: minimize sorta works??? --- src/client/util/DragManager.ts | 485 +++++++++++++++++------------- src/client/views/DocumentDecorations.scss | 9 +- src/client/views/nodes/DocumentView.scss | 6 +- src/client/views/nodes/DocumentView.tsx | 32 +- src/client/views/nodes/Sticky.tsx | 138 ++++----- 5 files changed, 375 insertions(+), 295 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 9ffe964ef..ee0b5333c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,251 +1,312 @@ import { DocumentDecorations } from "../views/DocumentDecorations"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; -import { Document } from "../../fields/Document" +import { Document } from "../../fields/Document"; import { action } from "mobx"; import { ImageField } from "../../fields/ImageField"; import { KeyStore } from "../../fields/KeyStore"; import { CollectionView } from "../views/collections/CollectionView"; import { DocumentView } from "../views/nodes/DocumentView"; -export function setupDrag(_reference: React.RefObject, docFunc: () => Document, removeFunc: (containingCollection: CollectionView) => void = () => { }) { - let onRowMove = action((e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); +export function setupDrag( + _reference: React.RefObject, + docFunc: () => Document, + removeFunc: (containingCollection: CollectionView) => void = () => {} +) { + let onRowMove = action( + (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener('pointerup', onRowUp); - var dragData = new DragManager.DocumentDragData([docFunc()]); - dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData); - }); - let onRowUp = action((e: PointerEvent): void => { - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener('pointerup', onRowUp); - }); - let onItemDown = (e: React.PointerEvent) => { - // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { - e.stopPropagation(); - if (e.shiftKey) { - CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); - } else { - document.addEventListener("pointermove", onRowMove); - document.addEventListener('pointerup', onRowUp); - } - } - //} + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.removeDocument = removeFunc; + DragManager.StartDocumentDrag([_reference.current!], dragData); + } + ); + let onRowUp = action( + (e: PointerEvent): void => { + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + } + ); + let onItemDown = (e: React.PointerEvent) => { + // if (this.props.isSelected() || this.props.isTopMost) { + if (e.button == 0) { + e.stopPropagation(); + if (e.shiftKey) { + CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); + } else { + document.addEventListener("pointermove", onRowMove); + document.addEventListener("pointerup", onRowUp); + } } - return onItemDown; + //} + }; + return onItemDown; } export namespace DragManager { - export function Root() { - const root = document.getElementById("root"); - if (!root) { - throw new Error("No root element found"); - } - return root; + export function Root() { + const root = document.getElementById("root"); + if (!root) { + throw new Error("No root element found"); } + return root; + } - let dragDiv: HTMLDivElement; + let dragDiv: HTMLDivElement; - export enum DragButtons { - Left = 1, Right = 2, Both = Left | Right - } + export enum DragButtons { + Left = 1, + Right = 2, + Both = Left | Right + } - interface DragOptions { - handlers: DragHandlers; + interface DragOptions { + handlers: DragHandlers; - hideSource: boolean | (() => boolean); - } + hideSource: boolean | (() => boolean); + } - export interface DragDropDisposer { - (): void; - } + export interface DragDropDisposer { + (): void; + } - export class DragCompleteEvent { - } + export class DragCompleteEvent {} - export interface DragHandlers { - dragComplete: (e: DragCompleteEvent) => void; - } + export interface DragHandlers { + dragComplete: (e: DragCompleteEvent) => void; + } - export interface DropOptions { - handlers: DropHandlers; - } - export class DropEvent { - constructor(readonly x: number, readonly y: number, readonly data: { [id: string]: any }) { } - } + export interface DropOptions { + handlers: DropHandlers; + } + export class DropEvent { + constructor( + readonly x: number, + readonly y: number, + readonly data: { [id: string]: any } + ) {} + } + export interface DropHandlers { + drop: (e: Event, de: DropEvent) => void; + } + export function MakeDropTarget( + element: HTMLElement, + options: DropOptions + ): DragDropDisposer { + if ("canDrop" in element.dataset) { + throw new Error( + "Element is already droppable, can't make it droppable again" + ); + } + element.dataset["canDrop"] = "true"; + const handler = (e: Event) => { + const ce = e as CustomEvent; + options.handlers.drop(e, ce.detail); + }; + element.addEventListener("dashOnDrop", handler); + return () => { + element.removeEventListener("dashOnDrop", handler); + delete element.dataset["canDrop"]; + }; + } - export interface DropHandlers { - drop: (e: Event, de: DropEvent) => void; + export class DocumentDragData { + constructor(dragDoc: Document[]) { + this.draggedDocuments = dragDoc; + this.droppedDocuments = dragDoc; } + draggedDocuments: Document[]; + droppedDocuments: Document[]; + xOffset?: number; + yOffset?: number; + aliasOnDrop?: boolean; + removeDocument?: (collectionDrop: CollectionView) => void; + [id: string]: any; + } + export function StartDocumentDrag( + eles: HTMLElement[], + dragData: DocumentDragData, + options?: DragOptions + ) { + StartDrag( + eles, + dragData, + options, + (dropData: { [id: string]: any }) => + (dropData.droppedDocuments = dragData.aliasOnDrop + ? dragData.draggedDocuments.map(d => d.CreateAlias()) + : dragData.draggedDocuments) + ); + } - export function MakeDropTarget(element: HTMLElement, options: DropOptions): DragDropDisposer { - if ("canDrop" in element.dataset) { - throw new Error("Element is already droppable, can't make it droppable again"); - } - element.dataset["canDrop"] = "true"; - const handler = (e: Event) => { - const ce = e as CustomEvent; - options.handlers.drop(e, ce.detail); - }; - element.addEventListener("dashOnDrop", handler); - return () => { - element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"] - }; + export class LinkDragData { + constructor(linkSourceDoc: DocumentView) { + this.linkSourceDocumentView = linkSourceDoc; } - - export class DocumentDragData { - constructor(dragDoc: Document[]) { - this.draggedDocuments = dragDoc; - this.droppedDocuments = dragDoc; - } - draggedDocuments: Document[]; - droppedDocuments: Document[]; - xOffset?: number; - yOffset?: number; - aliasOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; - [id: string]: any; + linkSourceDocumentView: DocumentView; + [id: string]: any; + } + export function StartLinkDrag( + ele: HTMLElement, + dragData: LinkDragData, + options?: DragOptions + ) { + StartDrag([ele], dragData, options); + } + function StartDrag( + eles: HTMLElement[], + dragData: { [id: string]: any }, + options?: DragOptions, + finishDrag?: (dropData: { [id: string]: any }) => void + ) { + if (!dragDiv) { + dragDiv = document.createElement("div"); + dragDiv.className = "dragManager-dragDiv"; + DragManager.Root().appendChild(dragDiv); } - export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, options?: DragOptions) { - StartDrag(eles, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments); - } + let scaleXs: number[] = []; + let scaleYs: number[] = []; + let xs: number[] = []; + let ys: number[] = []; - export class LinkDragData { - constructor(linkSourceDoc: DocumentView) { - this.linkSourceDocumentView = linkSourceDoc; - } - linkSourceDocumentView: DocumentView; - [id: string]: any; - } - export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, options?: DragOptions) { - StartDrag([ele], dragData, options); - } - function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { - if (!dragDiv) { - dragDiv = document.createElement("div"); - dragDiv.className = "dragManager-dragDiv" - DragManager.Root().appendChild(dragDiv); + const docs: Document[] = + dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + let dragElements = eles.map(ele => { + const w = ele.offsetWidth, + h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, + scaleY = rect.height / h; + let x = rect.left, + y = rect.top; + xs.push(x); + ys.push(y); + scaleXs.push(scaleX); + scaleYs.push(scaleY); + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; + console.log(dragElement); + dragElement.style.position = "absolute"; + dragElement.style.bottom = ""; + dragElement.style.left = ""; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.zIndex = "1000"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; + + // bcz: PDFs don't show up if you clone them because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of their canvas. + // So we replace the pdf's canvas with the image thumbnail + if (docs.length) { + var pdfBox = dragElement.getElementsByClassName( + "pdfBox-cont" + )[0] as HTMLElement; + let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + if (pdfBox && pdfBox.childElementCount && thumbnail) { + let img = new Image(); + img!.src = thumbnail.toString(); + img!.style.position = "absolute"; + img!.style.width = `${rect.width / scaleX}px`; + img!.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img!, pdfBox.children[0]); } + } - let scaleXs: number[] = []; - let scaleYs: number[] = []; - let xs: number[] = []; - let ys: number[] = []; - - const docs: Document[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; - let dragElements = eles.map(ele => { - const w = ele.offsetWidth, h = ele.offsetHeight; - const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, scaleY = rect.height / h; - let x = rect.left, y = rect.top; - xs.push(x); ys.push(y); - scaleXs.push(scaleX); scaleYs.push(scaleY); - let dragElement = ele.cloneNode(true) as HTMLElement; - dragElement.style.opacity = "0.7"; - dragElement.style.position = "absolute"; - dragElement.style.bottom = ""; - dragElement.style.left = ""; - dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width / scaleX}px`; - dragElement.style.height = `${rect.height / scaleY}px`; - - // bcz: PDFs don't show up if you clone them because they contain a canvas. - // however, PDF's have a thumbnail field that contains an image of their canvas. - // So we replace the pdf's canvas with the image thumbnail - if (docs.length) { - var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; - let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]) - } - } - - dragDiv.appendChild(dragElement); - return dragElement; - }); + dragDiv.appendChild(dragElement); + return dragElement; + }); - let hideSource = false; - if (options) { - if (typeof options.hideSource === "boolean") { - hideSource = options.hideSource; - } else { - hideSource = options.hideSource(); - } - } - eles.map(ele => ele.hidden = hideSource); - - const moveHandler = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - if (dragData instanceof DocumentDragData) - dragData.aliasOnDrop = e.ctrlKey || e.altKey; - if (e.shiftKey) { - abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); - } - dragElements.map((dragElement, i) => dragElement.style.transform = `translate(${xs[i] += e.movementX}px, ${ys[i] += e.movementY}px) scale(${scaleXs[i]}, ${scaleYs[i]})`); - }; - - const abortDrag = () => { - document.removeEventListener("pointermove", moveHandler, true); - document.removeEventListener("pointerup", upHandler); - dragElements.map(dragElement => dragDiv.removeChild(dragElement)); - eles.map(ele => ele.hidden = false); - } - const upHandler = (e: PointerEvent) => { - abortDrag(); - FinishDrag(eles, e, dragData, options, finishDrag); - }; - document.addEventListener("pointermove", moveHandler, true); - document.addEventListener("pointerup", upHandler); + let hideSource = false; + if (options) { + if (typeof options.hideSource === "boolean") { + hideSource = options.hideSource; + } else { + hideSource = options.hideSource(); + } } + eles.map(ele => (ele.hidden = hideSource)); - function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { - let removed = dragEles.map(dragEle => { - let parent = dragEle.parentElement; - if (parent) - parent.removeChild(dragEle); - return [dragEle, parent]; - }); - const target = document.elementFromPoint(e.x, e.y); - removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) - parent.appendChild(dragEle); + const moveHandler = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (dragData instanceof DocumentDragData) + dragData.aliasOnDrop = e.ctrlKey || e.altKey; + if (e.shiftKey) { + abortDrag(); + CollectionDockingView.Instance.StartOtherDrag(docs, { + pageX: e.pageX, + pageY: e.pageY, + preventDefault: () => {}, + button: 0 }); - if (target) { - if (finishDrag) - finishDrag(dragData); - - target.dispatchEvent(new CustomEvent("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData - } - })); - - if (options) { - options.handlers.dragComplete({}); - } - } - DocumentDecorations.Instance.Hidden = false; + } + dragElements.map( + (dragElement, i) => + (dragElement.style.transform = `translate(${(xs[i] += + e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ + scaleXs[i] + }, ${scaleYs[i]})`) + ); + }; + + const abortDrag = () => { + document.removeEventListener("pointermove", moveHandler, true); + document.removeEventListener("pointerup", upHandler); + dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + eles.map(ele => (ele.hidden = false)); + }; + const upHandler = (e: PointerEvent) => { + abortDrag(); + FinishDrag(eles, e, dragData, options, finishDrag); + }; + document.addEventListener("pointermove", moveHandler, true); + document.addEventListener("pointerup", upHandler); + } + + function FinishDrag( + dragEles: HTMLElement[], + e: PointerEvent, + dragData: { [index: string]: any }, + options?: DragOptions, + finishDrag?: (dragData: { [index: string]: any }) => void + ) { + let removed = dragEles.map(dragEle => { + let parent = dragEle.parentElement; + if (parent) parent.removeChild(dragEle); + return [dragEle, parent]; + }); + const target = document.elementFromPoint(e.x, e.y); + removed.map(r => { + let dragEle: HTMLElement = r[0]!; + let parent: HTMLElement | null = r[1]; + if (parent) parent.appendChild(dragEle); + }); + if (target) { + if (finishDrag) finishDrag(dragData); + + target.dispatchEvent( + new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + }) + ); + + if (options) { + options.handlers.dragComplete({}); + } } -} \ No newline at end of file + DocumentDecorations.Instance.Hidden = false; + } +} diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 7a43f3087..8f5470574 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -1,4 +1,5 @@ @import "global_variables"; + #documentDecorations-container { position: absolute; display: grid; @@ -6,26 +7,32 @@ grid-template-rows: 8px 1fr 8px 30px; grid-template-columns: 8px 1fr 8px; pointer-events: none; + #documentDecorations-centerCont { background: none; } + .documentDecorations-resizer { pointer-events: auto; background: $alt-accent; opacity: 0.8; } + #documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { cursor: nwse-resize; } + #documentDecorations-topRightResizer, #documentDecorations-bottomLeftResizer { cursor: nesw-resize; } + #documentDecorations-topResizer, #documentDecorations-bottomResizer { cursor: ns-resize; } + #documentDecorations-leftResizer, #documentDecorations-rightResizer { cursor: ew-resize; @@ -33,7 +40,7 @@ } .documentDecorations-background { - background:lightblue; + background: lightblue; position: absolute; opacity: 0.1; } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 4eda50204..23e072344 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -30,10 +30,12 @@ height: 10px; width: 10px; border-radius: 2px; - background: #232323 + background: $dark-color } .minimized-box:hover { - background: #232323 + background: $main-accent; + transform: scale(1.15); + cursor: pointer; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 085307461..713c12975 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -7,7 +7,6 @@ import { observable } from "mobx"; import { library } from "@fortawesome/fontawesome-svg-core"; -import { faSquare } from "@fortawesome/free-solid-svg-icons"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { Field, Opt, FieldWaiting } from "../../../fields/Field"; @@ -33,8 +32,6 @@ import React = require("react"); import { ServerUtils } from "../../../server/ServerUtil"; import { DocumentDecorations } from "../DocumentDecorations"; -library.add(faSquare); - export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Document; @@ -438,6 +435,11 @@ export class DocumentView extends React.Component { return this.minimized; }; + @action + expand = () => { + this.minimized = false; + }; + isSelected = () => { return SelectionManager.IsSelected(this); }; @@ -450,18 +452,26 @@ export class DocumentView extends React.Component { if (!this.props.Document) { return null; } + + var scaling = this.props.ContentScaling(); + var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + if (this.minimized) { return ( - // -
+
); } else { - var scaling = this.props.ContentScaling(); - var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); - var nativeHeight = this.props.Document.GetNumber( - KeyStore.NativeHeight, - 0 - ); var backgroundcolor = this.props.Document.GetText( KeyStore.BackgroundColor, "" diff --git a/src/client/views/nodes/Sticky.tsx b/src/client/views/nodes/Sticky.tsx index d57dd5c0b..4a4d69e90 100644 --- a/src/client/views/nodes/Sticky.tsx +++ b/src/client/views/nodes/Sticky.tsx @@ -1,83 +1,83 @@ -import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import React = require("react") -import { observer } from "mobx-react" -import 'react-pdf/dist/Page/AnnotationLayer.css' +import "react-image-lightbox/style.css"; // This only needs to be imported once in your app +import React = require("react"); +import { observer } from "mobx-react"; +import "react-pdf/dist/Page/AnnotationLayer.css"; interface IProps { - Height: number; - Width: number; - X: number; - Y: number; + Height: number; + Width: number; + X: number; + Y: number; } /** - * Sticky, also known as area highlighting, is used to highlight large selection of the PDF file. - * Improvements that could be made: maybe store line array and store that somewhere for future rerendering. - * - * Written By: Andrew Kim + * Sticky, also known as area highlighting, is used to highlight large selection of the PDF file. + * Improvements that could be made: maybe store line array and store that somewhere for future rerendering. + * + * Written By: Andrew Kim */ @observer export class Sticky extends React.Component { + private initX: number = 0; + private initY: number = 0; - private initX: number = 0; - private initY: number = 0; + private _ref = React.createRef(); + private ctx: any; //context that keeps track of sticky canvas - private _ref = React.createRef(); - private ctx: any; //context that keeps track of sticky canvas - - /** - * drawing. Registers the first point that user clicks when mouse button is pressed down on canvas - */ - drawDown = (e: React.PointerEvent) => { - if (this._ref.current) { - this.ctx = this._ref.current.getContext("2d"); - let mouse = e.nativeEvent; - this.initX = mouse.offsetX; - this.initY = mouse.offsetY; - this.ctx.beginPath(); - this.ctx.lineTo(this.initX, this.initY); - this.ctx.strokeStyle = "black"; - document.addEventListener("pointermove", this.drawMove); - document.addEventListener("pointerup", this.drawUp); - } + /** + * drawing. Registers the first point that user clicks when mouse button is pressed down on canvas + */ + drawDown = (e: React.PointerEvent) => { + if (this._ref.current) { + this.ctx = this._ref.current.getContext("2d"); + let mouse = e.nativeEvent; + this.initX = mouse.offsetX; + this.initY = mouse.offsetY; + this.ctx.beginPath(); + this.ctx.lineTo(this.initX, this.initY); + this.ctx.strokeStyle = "black"; + document.addEventListener("pointermove", this.drawMove); + document.addEventListener("pointerup", this.drawUp); } + }; - //when user drags - drawMove = (e: PointerEvent): void => { - //x and y mouse movement - let x = this.initX += e.movementX, - y = this.initY += e.movementY; - //connects the point - this.ctx.lineTo(x, y); - this.ctx.stroke(); - - } + //when user drags + drawMove = (e: PointerEvent): void => { + //x and y mouse movement + let x = (this.initX += e.movementX), + y = (this.initY += e.movementY); + //connects the point + this.ctx.lineTo(x, y); + this.ctx.stroke(); + }; - /** - * when user lifts the mouse, the drawing ends - */ - drawUp = (e: PointerEvent) => { - this.ctx.closePath(); - console.log(this.ctx); - document.removeEventListener("pointermove", this.drawMove); - } + /** + * when user lifts the mouse, the drawing ends + */ + drawUp = (e: PointerEvent) => { + this.ctx.closePath(); + console.log(this.ctx); + document.removeEventListener("pointermove", this.drawMove); + }; - render() { - return ( -
- - -
- ); - } -} \ No newline at end of file + render() { + return ( +
+ +
+ ); + } +} -- cgit v1.2.3-70-g09d2 From 3b456da9c1d90abcfcf33fc6fd762cad1dff7ca7 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 3 Apr 2019 12:10:31 -0400 Subject: merged with changes to DocumentDecorations so you can minimize/maximize without menu --- src/client/views/DocumentDecorations.scss | 6 +++++- src/client/views/DocumentDecorations.tsx | 25 ++++++++++++++++++++++++- src/client/views/nodes/DocumentView.tsx | 14 +++++++------- 3 files changed, 36 insertions(+), 9 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index c72623546..befe175b5 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -39,12 +39,16 @@ } .title{ background: lightblue; - grid-column-start:1; + grid-column-start:2; grid-column-end: 4; pointer-events: auto; } } +.documentDecorations-minimizeButton { + background: rgb(250, 57, 9); + pointer-events: all; +} .documentDecorations-background { background: lightblue; position: absolute; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 572c265f3..b74737ec9 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -139,11 +139,33 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.preventDefault(); } + onMinimizeDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + document.removeEventListener("pointermove", this.onMinimizeMove); + document.addEventListener("pointermove", this.onMinimizeMove); + document.removeEventListener("pointerup", this.onMinimizeUp); + document.addEventListener("pointerup", this.onMinimizeUp); + } + } + onMinimizeMove = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + } + } + onMinimizeUp = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + SelectionManager.SelectedDocuments().map(dv => dv.minimize()); + document.removeEventListener("pointermove", this.onMinimizeMove); + document.removeEventListener("pointerup", this.onMinimizeUp); + } + } + onPointerDown = (e: React.PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { this._isPointerDown = true; - console.log("Pointer down"); this._resizer = e.currentTarget.id; document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); @@ -339,6 +361,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, opacity: this._opacity }}> +
v
e.preventDefault()}>
e.preventDefault()}>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2b9372e15..bc627015c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -70,18 +70,18 @@ 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 = () => {}; + let fn = () => { }; Object.defineProperty(fn, "name", { value: key + "Key" }); Keys[key] = fn; } for (const field of fields) { - let fn = () => {}; + let fn = () => { }; Object.defineProperty(fn, "name", { value: field }); Fields[field] = fn; } let args: JsxArgs = { - Document: function Document() {}, - DocumentView: function DocumentView() {}, + Document: function Document() { }, + DocumentView: function DocumentView() { }, Keys, Fields } as any; @@ -115,7 +115,7 @@ export class DocumentView extends React.Component { return ( !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == - CollectionViewType.Docking + CollectionViewType.Docking ); } @computed get layout(): string { @@ -233,7 +233,7 @@ export class DocumentView extends React.Component { }; DragManager.StartDocumentDrag([this._mainCont.current], dragData, { handlers: { - dragComplete: action(() => {}) + dragComplete: action(() => { }) }, hideSource: !dropAliasOfDraggedDoc }); @@ -307,7 +307,7 @@ export class DocumentView extends React.Component { }; @action - minimize = (e: React.MouseEvent): void => { + public minimize = (): void => { this.props.Document.SetData( KeyStore.Minimized, true as boolean, -- cgit v1.2.3-70-g09d2 From b78aff5115862cbfa5e704422cb738aa7fd73c64 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 4 Apr 2019 14:13:29 -0400 Subject: fixed a number of smaller issues related to linking --- src/client/northstar/dash-nodes/HistogramBox.scss | 5 + src/client/util/DragManager.ts | 533 +++++++------- src/client/util/SelectionManager.ts | 74 +- src/client/views/DocumentDecorations.scss | 61 +- src/client/views/DocumentDecorations.tsx | 81 ++- src/client/views/InkingCanvas.scss | 2 + src/client/views/Main.scss | 7 + .../views/collections/CollectionDockingView.scss | 2 +- .../views/collections/CollectionPDFView.scss | 2 + .../views/collections/CollectionVideoView.scss | 2 + .../views/collections/CollectionViewBase.tsx | 20 + .../CollectionFreeFormLinkView.tsx | 8 +- .../CollectionFreeFormLinksView.scss | 2 + .../collectionFreeForm/CollectionFreeFormView.scss | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +- .../collectionFreeForm/MarqueeView.scss | 2 + .../collectionFreeForm/PreviewCursor.scss | 4 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 + src/client/views/nodes/DocumentView.scss | 2 + src/client/views/nodes/PDFBox.scss | 4 + src/client/views/nodes/WebBox.scss | 2 + src/fields/Document.ts | 773 +++++++++++---------- 22 files changed, 882 insertions(+), 727 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index b11840a65..94da36e29 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -1,6 +1,8 @@ .histogrambox-container { padding: 0vw; position: absolute; + top: 0; + left:0; text-align: center; width: 100%; height: 100%; @@ -8,6 +10,7 @@ } .histogrambox-xaxislabel { position:absolute; + left:0; width:100%; text-align: center; bottom:0; @@ -19,11 +22,13 @@ position:absolute; height:100%; width: 25px; + left:0; bottom:0; background: lightgray; } .histogrambox-yaxislabel-text { position:absolute; + left:0; transform-origin: left; transform: rotate(-90deg); text-align: center; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c0f482e18..e8f8cce7c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,304 +8,307 @@ import { CollectionView } from "../views/collections/CollectionView"; import { DocumentView } from "../views/nodes/DocumentView"; export function setupDrag( - _reference: React.RefObject, - docFunc: () => Document, - removeFunc: (containingCollection: CollectionView) => void = () => {} + _reference: React.RefObject, + docFunc: () => Document, + removeFunc: (containingCollection: CollectionView) => void = () => { } ) { - let onRowMove = action( - (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); + let onRowMove = action( + (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - var dragData = new DragManager.DocumentDragData([docFunc()]); - dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData); - } - ); - let onRowUp = action( - (e: PointerEvent): void => { - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - } - ); - let onItemDown = (e: React.PointerEvent) => { - // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { - e.stopPropagation(); - if (e.shiftKey) { - CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); - } else { - document.addEventListener("pointermove", onRowMove); - document.addEventListener("pointerup", onRowUp); - } - } - //} - }; - return onItemDown; + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.removeDocument = removeFunc; + DragManager.StartDocumentDrag([_reference.current!], dragData); + } + ); + let onRowUp = action( + (e: PointerEvent): void => { + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + } + ); + let onItemDown = (e: React.PointerEvent) => { + // if (this.props.isSelected() || this.props.isTopMost) { + if (e.button == 0) { + e.stopPropagation(); + if (e.shiftKey) { + CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); + } else { + document.addEventListener("pointermove", onRowMove); + document.addEventListener("pointerup", onRowUp); + } + } + //} + }; + return onItemDown; } export namespace DragManager { - export function Root() { - const root = document.getElementById("root"); - if (!root) { - throw new Error("No root element found"); + export function Root() { + const root = document.getElementById("root"); + if (!root) { + throw new Error("No root element found"); + } + return root; } - return root; - } - let dragDiv: HTMLDivElement; + let dragDiv: HTMLDivElement; - export enum DragButtons { - Left = 1, - Right = 2, - Both = Left | Right - } + export enum DragButtons { + Left = 1, + Right = 2, + Both = Left | Right + } - interface DragOptions { - handlers: DragHandlers; + interface DragOptions { + handlers: DragHandlers; - hideSource: boolean | (() => boolean); - } + hideSource: boolean | (() => boolean); + } - export interface DragDropDisposer { - (): void; - } + export interface DragDropDisposer { + (): void; + } - export class DragCompleteEvent {} + export class DragCompleteEvent { } - export interface DragHandlers { - dragComplete: (e: DragCompleteEvent) => void; - } + export interface DragHandlers { + dragComplete: (e: DragCompleteEvent) => void; + } - export interface DropOptions { - handlers: DropHandlers; - } - export class DropEvent { - constructor( - readonly x: number, - readonly y: number, - readonly data: { [id: string]: any } - ) {} - } + export interface DropOptions { + handlers: DropHandlers; + } + export class DropEvent { + constructor( + readonly x: number, + readonly y: number, + readonly data: { [id: string]: any } + ) { } + } - export interface DropHandlers { - drop: (e: Event, de: DropEvent) => void; - } + export interface DropHandlers { + drop: (e: Event, de: DropEvent) => void; + } - export function MakeDropTarget( - element: HTMLElement, - options: DropOptions - ): DragDropDisposer { - if ("canDrop" in element.dataset) { - throw new Error( - "Element is already droppable, can't make it droppable again" - ); + export function MakeDropTarget( + element: HTMLElement, + options: DropOptions + ): DragDropDisposer { + if ("canDrop" in element.dataset) { + throw new Error( + "Element is already droppable, can't make it droppable again" + ); + } + element.dataset["canDrop"] = "true"; + const handler = (e: Event) => { + const ce = e as CustomEvent; + options.handlers.drop(e, ce.detail); + }; + element.addEventListener("dashOnDrop", handler); + return () => { + element.removeEventListener("dashOnDrop", handler); + delete element.dataset["canDrop"]; + }; } - element.dataset["canDrop"] = "true"; - const handler = (e: Event) => { - const ce = e as CustomEvent; - options.handlers.drop(e, ce.detail); - }; - element.addEventListener("dashOnDrop", handler); - return () => { - element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"]; - }; - } - export class DocumentDragData { - constructor(dragDoc: Document[]) { - this.draggedDocuments = dragDoc; - this.droppedDocuments = dragDoc; + export class DocumentDragData { + constructor(dragDoc: Document[]) { + this.draggedDocuments = dragDoc; + this.droppedDocuments = dragDoc; + } + draggedDocuments: Document[]; + droppedDocuments: Document[]; + xOffset?: number; + yOffset?: number; + aliasOnDrop?: boolean; + removeDocument?: (collectionDrop: CollectionView) => void; + [id: string]: any; } - draggedDocuments: Document[]; - droppedDocuments: Document[]; - xOffset?: number; - yOffset?: number; - aliasOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; - [id: string]: any; - } - export function StartDocumentDrag( - eles: HTMLElement[], - dragData: DocumentDragData, - options?: DragOptions - ) { - StartDrag( - eles, - dragData, - options, - (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.aliasOnDrop - ? dragData.draggedDocuments.map(d => d.CreateAlias()) - : dragData.draggedDocuments) - ); - } + export function StartDocumentDrag( + eles: HTMLElement[], + dragData: DocumentDragData, + options?: DragOptions + ) { + StartDrag( + eles, + dragData, + options, + (dropData: { [id: string]: any }) => + (dropData.droppedDocuments = dragData.aliasOnDrop + ? dragData.draggedDocuments.map(d => d.CreateAlias()) + : dragData.draggedDocuments) + ); + } - export class LinkDragData { - constructor(linkSourceDoc: DocumentView) { - this.linkSourceDocumentView = linkSourceDoc; + export class LinkDragData { + constructor(linkSourceDoc: DocumentView) { + this.linkSourceDocumentView = linkSourceDoc; + } + droppedDocuments: Document[] = []; + linkSourceDocumentView: DocumentView; + [id: string]: any; } - linkSourceDocumentView: DocumentView; - [id: string]: any; - } - export function StartLinkDrag( - ele: HTMLElement, - dragData: LinkDragData, - options?: DragOptions - ) { - StartDrag([ele], dragData, options); - } - function StartDrag( - eles: HTMLElement[], - dragData: { [id: string]: any }, - options?: DragOptions, - finishDrag?: (dropData: { [id: string]: any }) => void - ) { - if (!dragDiv) { - dragDiv = document.createElement("div"); - dragDiv.className = "dragManager-dragDiv"; - DragManager.Root().appendChild(dragDiv); + export function StartLinkDrag( + ele: HTMLElement, + dragData: LinkDragData, + options?: DragOptions + ) { + StartDrag([ele], dragData, options); } + function StartDrag( + eles: HTMLElement[], + dragData: { [id: string]: any }, + options?: DragOptions, + finishDrag?: (dropData: { [id: string]: any }) => void + ) { + if (!dragDiv) { + dragDiv = document.createElement("div"); + dragDiv.className = "dragManager-dragDiv"; + DragManager.Root().appendChild(dragDiv); + } - let scaleXs: number[] = []; - let scaleYs: number[] = []; - let xs: number[] = []; - let ys: number[] = []; + let scaleXs: number[] = []; + let scaleYs: number[] = []; + let xs: number[] = []; + let ys: number[] = []; - const docs: Document[] = - dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; - let dragElements = eles.map(ele => { - const w = ele.offsetWidth, - h = ele.offsetHeight; - const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, - scaleY = rect.height / h; - let x = rect.left, - y = rect.top; - xs.push(x); - ys.push(y); - scaleXs.push(scaleX); - scaleYs.push(scaleY); - let dragElement = ele.cloneNode(true) as HTMLElement; - dragElement.style.opacity = "0.7"; - dragElement.style.position = "absolute"; - dragElement.style.bottom = ""; - dragElement.style.left = ""; - dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width / scaleX}px`; - dragElement.style.height = `${rect.height / scaleY}px`; + const docs: Document[] = + dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + let dragElements = eles.map(ele => { + const w = ele.offsetWidth, + h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, + scaleY = rect.height / h; + let x = rect.left, + y = rect.top; + xs.push(x); + ys.push(y); + scaleXs.push(scaleX); + scaleYs.push(scaleY); + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; + dragElement.style.position = "absolute"; + dragElement.style.margin = "0"; + dragElement.style.top = "0"; + dragElement.style.bottom = ""; + dragElement.style.left = "0"; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.zIndex = "1000"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; - // bcz: PDFs don't show up if you clone them because they contain a canvas. - // however, PDF's have a thumbnail field that contains an image of their canvas. - // So we replace the pdf's canvas with the image thumbnail - if (docs.length) { - var pdfBox = dragElement.getElementsByClassName( - "pdfBox-cont" - )[0] as HTMLElement; - let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]); + // bcz: PDFs don't show up if you clone them because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of their canvas. + // So we replace the pdf's canvas with the image thumbnail + if (docs.length) { + var pdfBox = dragElement.getElementsByClassName( + "pdfBox-cont" + )[0] as HTMLElement; + let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + if (pdfBox && pdfBox.childElementCount && thumbnail) { + let img = new Image(); + img!.src = thumbnail.toString(); + img!.style.position = "absolute"; + img!.style.width = `${rect.width / scaleX}px`; + img!.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img!, pdfBox.children[0]); + } + } + + dragDiv.appendChild(dragElement); + return dragElement; + }); + + let hideSource = false; + if (options) { + if (typeof options.hideSource === "boolean") { + hideSource = options.hideSource; + } else { + hideSource = options.hideSource(); + } } - } + eles.map(ele => (ele.hidden = hideSource)); - dragDiv.appendChild(dragElement); - return dragElement; - }); + const moveHandler = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (dragData instanceof DocumentDragData) + dragData.aliasOnDrop = e.ctrlKey || e.altKey; + if (e.shiftKey) { + abortDrag(); + CollectionDockingView.Instance.StartOtherDrag(docs, { + pageX: e.pageX, + pageY: e.pageY, + preventDefault: () => { }, + button: 0 + }); + } + dragElements.map( + (dragElement, i) => + (dragElement.style.transform = `translate(${(xs[i] += + e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ + scaleXs[i] + }, ${scaleYs[i]})`) + ); + }; - let hideSource = false; - if (options) { - if (typeof options.hideSource === "boolean") { - hideSource = options.hideSource; - } else { - hideSource = options.hideSource(); - } + const abortDrag = () => { + document.removeEventListener("pointermove", moveHandler, true); + document.removeEventListener("pointerup", upHandler); + dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + eles.map(ele => (ele.hidden = false)); + }; + const upHandler = (e: PointerEvent) => { + abortDrag(); + FinishDrag(eles, e, dragData, options, finishDrag); + }; + document.addEventListener("pointermove", moveHandler, true); + document.addEventListener("pointerup", upHandler); } - eles.map(ele => (ele.hidden = hideSource)); - const moveHandler = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - if (dragData instanceof DocumentDragData) - dragData.aliasOnDrop = e.ctrlKey || e.altKey; - if (e.shiftKey) { - abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(docs, { - pageX: e.pageX, - pageY: e.pageY, - preventDefault: () => {}, - button: 0 + function FinishDrag( + dragEles: HTMLElement[], + e: PointerEvent, + dragData: { [index: string]: any }, + options?: DragOptions, + finishDrag?: (dragData: { [index: string]: any }) => void + ) { + let removed = dragEles.map(dragEle => { + let parent = dragEle.parentElement; + if (parent) parent.removeChild(dragEle); + return [dragEle, parent]; }); - } - dragElements.map( - (dragElement, i) => - (dragElement.style.transform = `translate(${(xs[i] += - e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ - scaleXs[i] - }, ${scaleYs[i]})`) - ); - }; - - const abortDrag = () => { - document.removeEventListener("pointermove", moveHandler, true); - document.removeEventListener("pointerup", upHandler); - dragElements.map(dragElement => dragDiv.removeChild(dragElement)); - eles.map(ele => (ele.hidden = false)); - }; - const upHandler = (e: PointerEvent) => { - abortDrag(); - FinishDrag(eles, e, dragData, options, finishDrag); - }; - document.addEventListener("pointermove", moveHandler, true); - document.addEventListener("pointerup", upHandler); - } - - function FinishDrag( - dragEles: HTMLElement[], - e: PointerEvent, - dragData: { [index: string]: any }, - options?: DragOptions, - finishDrag?: (dragData: { [index: string]: any }) => void - ) { - let removed = dragEles.map(dragEle => { - let parent = dragEle.parentElement; - if (parent) parent.removeChild(dragEle); - return [dragEle, parent]; - }); - const target = document.elementFromPoint(e.x, e.y); - removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) parent.appendChild(dragEle); - }); - if (target) { - if (finishDrag) finishDrag(dragData); + const target = document.elementFromPoint(e.x, e.y); + removed.map(r => { + let dragEle: HTMLElement = r[0]!; + let parent: HTMLElement | null = r[1]; + if (parent) parent.appendChild(dragEle); + }); + if (target) { + if (finishDrag) finishDrag(dragData); - target.dispatchEvent( - new CustomEvent("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData - } - }) - ); + target.dispatchEvent( + new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + }) + ); - if (options) { - options.handlers.dragComplete({}); - } + if (options) { + options.handlers.dragComplete({}); + } + } + DocumentDecorations.Instance.Hidden = false; } - DocumentDecorations.Instance.Hidden = false; - } } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 438659108..958c14491 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -3,48 +3,46 @@ import { DocumentView } from "../views/nodes/DocumentView"; import { Document } from "../../fields/Document"; export namespace SelectionManager { - class Manager { - @observable - SelectedDocuments: Array = []; - - @action - SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { - // if doc is not in SelectedDocuments, add it - if (!ctrlPressed) { - manager.SelectedDocuments = []; - } - - if (manager.SelectedDocuments.indexOf(doc) === -1) { - manager.SelectedDocuments.push(doc); - } + class Manager { + @observable + SelectedDocuments: Array = []; + + @action + SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + // if doc is not in SelectedDocuments, add it + if (!ctrlPressed) { + manager.SelectedDocuments = []; + } + + if (manager.SelectedDocuments.indexOf(doc) === -1) { + manager.SelectedDocuments.push(doc); + } + } } - } - const manager = new Manager(); + const manager = new Manager(); - export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { - if (!doc.isMinimized()) { - manager.SelectDoc(doc, ctrlPressed); + export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + manager.SelectDoc(doc, ctrlPressed); } - } - - export function IsSelected(doc: DocumentView): boolean { - return manager.SelectedDocuments.indexOf(doc) !== -1; - } - - export function DeselectAll(except?: Document): void { - let found: DocumentView | undefined = undefined; - if (except) { - for (let i = 0; i < manager.SelectedDocuments.length; i++) { - let view = manager.SelectedDocuments[i]; - if (view.props.Document == except) found = view; - } + + export function IsSelected(doc: DocumentView): boolean { + return manager.SelectedDocuments.indexOf(doc) !== -1; + } + + export function DeselectAll(except?: Document): void { + let found: DocumentView | undefined = undefined; + if (except) { + for (let i = 0; i < manager.SelectedDocuments.length; i++) { + let view = manager.SelectedDocuments[i]; + if (view.props.Document == except) found = view; + } + } + manager.SelectedDocuments.length = 0; + if (found) manager.SelectedDocuments.push(found); } - manager.SelectedDocuments.length = 0; - if (found) manager.SelectedDocuments.push(found); - } - export function SelectedDocuments(): Array { - return manager.SelectedDocuments; - } + export function SelectedDocuments(): Array { + return manager.SelectedDocuments; + } } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index befe175b5..080c9fa1e 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -2,13 +2,16 @@ #documentDecorations-container { position: absolute; + top: 0; + left:0; display: grid; z-index: 1000; grid-template-rows: 20px 8px 1fr 8px; - grid-template-columns: 8px 1fr 8px; + grid-template-columns: 8px 8px 1fr 8px; pointer-events: none; #documentDecorations-centerCont { + grid-column:3; background: none; } @@ -18,6 +21,24 @@ opacity: 0.8; } + #documentDecorations-topLeftResizer, + #documentDecorations-leftResizer, + #documentDecorations-bottomLeftResizer { + grid-column: 1 + } + + #documentDecorations-topResizer, + #documentDecorations-bottomResizer { + grid-column-start: 2; + grid-column-end: 4; + } + + #documentDecorations-bottomRightResizer, + #documentDecorations-topRightResizer, + #documentDecorations-rightResizer { + grid-column:4 + } + #documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { cursor: nwse-resize; @@ -39,15 +60,19 @@ } .title{ background: lightblue; - grid-column-start:2; - grid-column-end: 4; + grid-column-start:3; + grid-column-end: 5; pointer-events: auto; } } .documentDecorations-minimizeButton { - background: rgb(250, 57, 9); + background:$alt-accent; + opacity: 0.8; + grid-column-start: 1; + grid-column-end: 3; pointer-events: all; + text-align: center; } .documentDecorations-background { background: lightblue; @@ -87,7 +112,8 @@ // } // } .linkFlyout { - grid-column: 1/4 + grid-column: 1/4; + margin-left: 25px; } .linkButton-empty:hover { @@ -102,6 +128,31 @@ cursor: pointer; } +.linkButton-linker { + position:absolute; + bottom:0px; + left: 0px; + height: 20px; + width: 20px; + margin-top: 10px; + margin-right: 5px; + border-radius: 50%; + opacity: 0.9; + pointer-events: auto; + color: $dark-color; + border: $dark-color 1px solid; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 75%; + transition: transform 0.2s; + text-align: center; + display: flex; + justify-content: center; + align-items: center; +} +.linkButton-tray { + grid-column: 1/4; +} .linkButton-empty { height: 20px; width: 20px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b74737ec9..a46087c9a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,10 +1,11 @@ -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Key } from "../../fields/Key"; //import ContentEditable from 'react-contenteditable' import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; +import { Document } from "../../fields/Document"; import { TextField } from "../../fields/TextField"; import { DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; @@ -13,6 +14,7 @@ import './DocumentDecorations.scss'; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); +import { FieldWaiting } from "../../fields/Field"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -28,6 +30,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _linkBoxHeight = 30; private _titleHeight = 20; private _linkButton = React.createRef(); + private _linkerButton = React.createRef(); //@observable private _title: string = this._documents[0].props.Document.Title; @observable private _title: string = this._documents.length > 0 ? this._documents[0].props.Document.Title : ""; @observable private _fieldKey: Key = KeyStore.Title; @@ -174,18 +177,40 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } - onLinkButtonDown = (e: React.PointerEvent): void => { - // if () - // let linkMenu = new LinkMenu(SelectionManager.SelectedDocuments()[0]); - // linkMenu.Hidden = false; - console.log("down"); + onLinkerButtonDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.addEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.addEventListener("pointerup", this.onLinkerButtonUp); + } + onLinkerButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointerup", this.onLinkerButtonUp) + e.stopPropagation(); + } + onLinkerButtonMoved = (e: PointerEvent): void => { + if (this._linkerButton.current != null) { + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointerup", this.onLinkerButtonUp) + let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); + DragManager.StartLinkDrag(this._linkerButton.current, dragData, { + handlers: { + dragComplete: action(() => { }), + }, + hideSource: false + }) + } + e.stopPropagation(); + } + + onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); document.removeEventListener("pointermove", this.onLinkButtonMoved) document.addEventListener("pointermove", this.onLinkButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp) document.addEventListener("pointerup", this.onLinkButtonUp); - } onLinkButtonUp = (e: PointerEvent): void => { @@ -194,18 +219,32 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); } - onLinkButtonMoved = (e: PointerEvent): void => { if (this._linkButton.current != null) { document.removeEventListener("pointermove", this.onLinkButtonMoved) - document.removeEventListener("pointerup", this.onLinkButtonUp) - let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); - DragManager.StartLinkDrag(this._linkButton.current, dragData, { - handlers: { - dragComplete: action(() => { }), - }, - hideSource: false - }) + document.removeEventListener("pointerup", this.onLinkButtonUp); + + let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document; + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + let draggedDocs = (srcTarg && srcTarg != FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; + let draggedFromDocs = (srcTarg && srcTarg != FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : []; + draggedDocs.push(...draggedFromDocs); + if (draggedDocs.length) { + let dragData = new DragManager.DocumentDragData(draggedDocs.map(d => { + let annot = d.GetT(KeyStore.AnnotationOn, Document); // bcz: ... needs to change ... the annotationOn document may not have been retrieved yet... + return annot && annot != FieldWaiting ? annot : d; + })); + DragManager.StartDocumentDrag([this._linkButton.current], dragData, { + handlers: { + dragComplete: action(() => { }), + }, + hideSource: false + }) + } } e.stopPropagation(); } @@ -298,7 +337,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } getValue = (): string => { - console.log("value watched"); if (this._title === "changed" && this._documents.length > 0) { let field = this._documents[0].props.Document.Get(this._fieldKey); if (field instanceof TextField) { @@ -338,8 +376,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> linkButton = ( - + }>
{linkCount}
); @@ -361,7 +398,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, opacity: this._opacity }}> -
v
+
...
e.preventDefault()}>
e.preventDefault()}>
@@ -373,8 +410,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
e.preventDefault()}>
e.preventDefault()}>
-
{linkButton}
- +
{linkButton}
+
∞
) diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 35c8ee942..c5a2a50cb 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -2,6 +2,8 @@ .inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect { position: absolute; + top: 0; + left:0; width: 8192px; height: 8192px; cursor:"crosshair"; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 698a9c617..594803aab 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -7,6 +7,9 @@ body { overflow: hidden; font-family: $sans-serif; margin: 0; + position:absolute; + top: 0; + left:0; } #dash-title { @@ -158,11 +161,15 @@ button:hover { width:100%; height:100%; position:absolute; + top: 0; + left:0; } #mainContent-div { width:100%; height:100%; position:absolute; + top: 0; + left:0; } #add-options-content { display: table; diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 2706c3272..583d50c5b 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -3,7 +3,7 @@ } .collectiondockingview-container { - position: relative; + position: absolute; top: 0; left: 0; overflow: hidden; diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss index 0144625c1..0eca3f1cd 100644 --- a/src/client/views/collections/CollectionPDFView.scss +++ b/src/client/views/collections/CollectionPDFView.scss @@ -9,6 +9,8 @@ width: 100%; height: 100%; position: absolute; + top: 0; + left:0; } .collectionPdfView-backward { diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss index cbb981b13..ed56ad268 100644 --- a/src/client/views/collections/CollectionVideoView.scss +++ b/src/client/views/collections/CollectionVideoView.scss @@ -3,6 +3,8 @@ width: 100%; height: 100%; position: absolute; + top: 0; + left:0; } .collectionVideoView-time{ diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 2b0689800..daeca69e2 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -17,6 +17,8 @@ import { NumberField } from "../../../fields/NumberField"; import request = require("request"); import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; +import { CollectionDockingView } from "./CollectionDockingView"; +import { runReactions } from "mobx/lib/internal"; export interface CollectionViewProps { fieldKey: Key; @@ -92,6 +94,24 @@ export class CollectionViewBase extends React.Component e.stopPropagation(); return added; } + if (de.data instanceof DragManager.LinkDragData) { + let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; + if (sourceDoc) runInAction(() => { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + if (srcTarg && srcTarg != FieldWaiting) { + let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); + linkDocs.map(linkDoc => { + let targDoc = linkDoc.GetT(KeyStore.LinkedToDocs, Document); + if (targDoc && targDoc != FieldWaiting) { + let dropdoc = targDoc.MakeDelegate(); + de.data.droppedDocuments.push(dropdoc); + this.props.addDocument(dropdoc, false); + } + }) + } + }) + return true; + } return false; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index e84f0c5ad..3dfd74ec8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component { 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); + let droppedDocs = de.data.droppedDocuments as Document[]; + let xoff = de.data.xOffset as number || 0; + let yoff = de.data.yOffset as number || 0; + if (droppedDocs && droppedDocs.length) { + let screenX = de.x - xoff; + let screenY = de.y - yoff; const [x, y] = this.getTransform().transformPoint(screenX, screenY); - let dragDoc = de.data.draggedDocuments[0]; + let dragDoc = de.data.droppedDocuments[0]; let dragX = dragDoc.GetNumber(KeyStore.X, 0); let dragY = dragDoc.GetNumber(KeyStore.Y, 0); - de.data.draggedDocuments.map(d => { + droppedDocs.map(d => { let docX = d.GetNumber(KeyStore.X, 0); let docY = d.GetNumber(KeyStore.Y, 0); d.SetNumber(KeyStore.X, x + (docX - dragX)); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 1ee3b244b..0b406e722 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -1,6 +1,8 @@ .marqueeView { position: absolute; + top:0; + left:0; width:100%; height:100%; } diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss index 21210be2b..7a67c29bf 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss @@ -3,9 +3,13 @@ color: black; position: absolute; transform-origin: left top; + top: 0; + left:0; pointer-events: none; } .previewCursorView { + top: 0; + left:0; position: absolute; width:100%; height:100%; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d52b662bd..1a0f0cbbd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -66,8 +66,12 @@ export class CollectionFreeFormDocumentView extends React.Component } + panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); + panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); render() { return ( diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 127a6b535..5126e69f9 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -2,6 +2,8 @@ .documentView-node { position: absolute; + top: 0; + left:0; background: $light-color; //overflow: hidden; &.minimized { diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index ad947afd5..830dfe6c6 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -1,12 +1,16 @@ .react-pdf__Page { transform-origin: left top; position: absolute; + top: 0; + left:0; } .react-pdf__Document { position: absolute; } .pdfBox-buttonTray { position:absolute; + top: 0; + left:0; z-index: 25; } .pdfBox-contentContainer { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index a535b2638..c73bc0c47 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -2,6 +2,8 @@ .webBox-cont { padding: 0vw; position: absolute; + top: 0; + left:0; width: 100%; height: 100%; overflow: scroll; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 8e71019a4..92d03d765 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -9,415 +9,420 @@ import { Server } from "../client/Server"; import { Types } from "../server/Message"; import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; +import { BooleanField } from "./BooleanField"; export class Document extends Field { - //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field - public fields: ObservableMap< - string, - { key: Key; field: Field } - > = new ObservableMap(); - public _proxies: ObservableMap = new ObservableMap(); - - constructor(id?: string, save: boolean = true) { - super(id); - - if (save) { - Server.UpdateField(this); + //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field + public fields: ObservableMap< + string, + { key: Key; field: Field } + > = new ObservableMap(); + public _proxies: ObservableMap = new ObservableMap(); + + constructor(id?: string, save: boolean = true) { + super(id); + + if (save) { + Server.UpdateField(this); + } } - } - UpdateFromServer(data: [string, string][]) { - for (const key in data) { - const element = data[key]; - this._proxies.set(element[0], element[1]); - } - } - - public Width = () => { - return this.GetNumber(KeyStore.Width, 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 - public get Title(): string { - let title = this.Get(KeyStore.Title, true); - if (title) - if (title != FieldWaiting && title instanceof TextField) - return title.Data; - else return "-waiting-"; - let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle) - if (parTitle != FieldWaiting) return parTitle.Data + ".alias"; - else return "-waiting-.alias"; - return "-untitled-"; - } - - @computed - public get Fields() { - return this.fields; - } - - /** - * Get the field in the document associated with the given key. If the - * associated field has not yet been filled in from the server, a request - * to the server will automatically be sent, the value will be filled in - * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. - * @param key - The key of the value to get - * @param ignoreProto - If true, ignore any prototype this document - * might have and only search for the value on this immediate document. - * If false (default), search up the prototype chain, starting at this document, - * for a document that has a field associated with the given key, and return the first - * one found. - * - * @returns If the document does not have a field associated with the given key, returns `undefined`. - * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. - * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. - */ - Get(key: Key, ignoreProto: boolean = false): FieldValue { - let field: FieldValue; - if (ignoreProto) { - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key); - /* - The field might have been instantly filled from the cache - Maybe we want to just switch back to returning the value - from Server.GetDocumentField if it's in the cache - */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; + UpdateFromServer(data: [string, string][]) { + for (const key in data) { + const element = data[key]; + this._proxies.set(element[0], element[1]); } - } - } else { - let doc: FieldValue = this; - while (doc && doc != FieldWaiting && field != FieldWaiting) { - let curField = doc.fields.get(key.Id); - let curProxy = doc._proxies.get(key.Id); - if (!curField || (curProxy && curField.field.Id !== curProxy)) { - if (curProxy) { - Server.GetDocumentField(doc, key); - /* + } + + public Width = () => { + return this.GetNumber(KeyStore.Width, 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 + public get Title(): string { + let title = this.Get(KeyStore.Title, true); + if (title) + if (title != FieldWaiting && title instanceof TextField) + return title.Data; + else return "-waiting-"; + let parTitle = this.GetT(KeyStore.Title, TextField); + if (parTitle) + if (parTitle != FieldWaiting) return parTitle.Data + ".alias"; + else return "-waiting-.alias"; + return "-untitled-"; + } + + @computed + public get Fields() { + return this.fields; + } + + /** + * Get the field in the document associated with the given key. If the + * associated field has not yet been filled in from the server, a request + * to the server will automatically be sent, the value will be filled in + * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. + * @param key - The key of the value to get + * @param ignoreProto - If true, ignore any prototype this document + * might have and only search for the value on this immediate document. + * If false (default), search up the prototype chain, starting at this document, + * for a document that has a field associated with the given key, and return the first + * one found. + * + * @returns If the document does not have a field associated with the given key, returns `undefined`. + * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. + * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. + */ + Get(key: Key, ignoreProto: boolean = false): FieldValue { + let field: FieldValue; + if (ignoreProto) { + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key); + /* The field might have been instantly filled from the cache Maybe we want to just switch back to returning the value from Server.GetDocumentField if it's in the cache */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } } - break; - } - if ( - doc.fields.has(KeyStore.Prototype.Id) || - doc._proxies.has(KeyStore.Prototype.Id) - ) { - doc = doc.GetPrototype(); - } else { - break; - } } else { - field = curField.field; - break; + let doc: FieldValue = this; + while (doc && doc != FieldWaiting && field != FieldWaiting) { + let curField = doc.fields.get(key.Id); + let curProxy = doc._proxies.get(key.Id); + if (!curField || (curProxy && curField.field.Id !== curProxy)) { + if (curProxy) { + Server.GetDocumentField(doc, key); + /* + The field might have been instantly filled from the cache + Maybe we want to just switch back to returning the value + from Server.GetDocumentField if it's in the cache + */ + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } + break; + } + if ( + doc.fields.has(KeyStore.Prototype.Id) || + doc._proxies.has(KeyStore.Prototype.Id) + ) { + doc = doc.GetPrototype(); + } else { + break; + } + } else { + field = curField.field; + break; + } + } + if (doc == FieldWaiting) field = FieldWaiting; } - } - if (doc == FieldWaiting) field = FieldWaiting; + + return field; } - return field; - } - - /** - * Tries to get the field associated with the given key, and if there is an - * associated field, calls the given callback with that field. - * @param key - The key of the value to get - * @param callback - A function that will be called with the associated field, if it exists, - * once it is fetched from the server (this may be immediately if the field has already been fetched). - * Note: The callback will not be called if there is no associated field. - * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise - */ - GetAsync(key: Key, callback: (field: Opt) => void): void { - //TODO: This currently doesn't deal with prototypes - let field = this.fields.get(key.Id); - if (field && field.field) { - callback(field.field); - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, callback); - } else if (this._proxies.has(KeyStore.Prototype.Id)) { - this.GetTAsync(KeyStore.Prototype, Document, proto => { - if (proto) { - proto.GetAsync(key, callback); + /** + * Tries to get the field associated with the given key, and if there is an + * associated field, calls the given callback with that field. + * @param key - The key of the value to get + * @param callback - A function that will be called with the associated field, if it exists, + * once it is fetched from the server (this may be immediately if the field has already been fetched). + * Note: The callback will not be called if there is no associated field. + * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise + */ + GetAsync(key: Key, callback: (field: Opt) => void): void { + //TODO: This currently doesn't deal with prototypes + let field = this.fields.get(key.Id); + if (field && field.field) { + callback(field.field); + } else if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key, callback); + } else if (this._proxies.has(KeyStore.Prototype.Id)) { + this.GetTAsync(KeyStore.Prototype, Document, proto => { + if (proto) { + proto.GetAsync(key, callback); + } else { + callback(undefined); + } + }); } else { - callback(undefined); + callback(undefined); } - }); - } else { - callback(undefined); } - } - - GetTAsync(key: Key, ctor: { new (): T }): Promise>; - GetTAsync( - key: Key, - ctor: { new (): T }, - callback: (field: Opt) => void - ): void; - GetTAsync( - key: Key, - ctor: { new (): T }, - callback?: (field: Opt) => void - ): Promise> | void { - let fn = (cb: (field: Opt) => void) => { - return this.GetAsync(key, field => { - cb(Cast(field, ctor)); - }); - }; - if (callback) { - fn(callback); - } else { - return new Promise(res => fn(res)); + + GetTAsync(key: Key, ctor: { new(): T }): Promise>; + GetTAsync( + key: Key, + ctor: { new(): T }, + callback: (field: Opt) => void + ): void; + GetTAsync( + key: Key, + ctor: { new(): T }, + callback?: (field: Opt) => void + ): Promise> | void { + let fn = (cb: (field: Opt) => void) => { + return this.GetAsync(key, field => { + cb(Cast(field, ctor)); + }); + }; + if (callback) { + fn(callback); + } else { + return new Promise(res => fn(res)); + } } - } - - /** - * Same as {@link Document#GetAsync}, except a field of the given type - * will be created if there is no field associated with the given key, - * or the field associated with the given key is not of the given type. - * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. - */ - GetOrCreateAsync( - key: Key, - ctor: { new (): T }, - callback: (field: T) => void - ): void { - //This currently doesn't deal with prototypes - if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, field => { - if (field && field instanceof ctor) { - callback(field); + + /** + * Same as {@link Document#GetAsync}, except a field of the given type + * will be created if there is no field associated with the given key, + * or the field associated with the given key is not of the given type. + * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. + */ + GetOrCreateAsync( + key: Key, + ctor: { new(): T }, + callback: (field: T) => void + ): void { + //This currently doesn't deal with prototypes + if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key, field => { + if (field && field instanceof ctor) { + callback(field); + } else { + let newField = new ctor(); + this.Set(key, newField); + callback(newField); + } + }); } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); + let newField = new ctor(); + this.Set(key, newField); + callback(newField); } - }); - } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); } - } - - /** - * Same as {@link Document#Get}, except that it will additionally - * check if the field is of the given type. - * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc. - * @returns Same as {@link Document#Get}, except will return `undefined` - * if there is an associated field but it is of the wrong type. - */ - GetT( - key: Key, - ctor: { new (...args: any[]): T }, - ignoreProto: boolean = false - ): FieldValue { - var getfield = this.Get(key, ignoreProto); - if (getfield != FieldWaiting) { - return Cast(getfield, ctor); + + /** + * Same as {@link Document#Get}, except that it will additionally + * check if the field is of the given type. + * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc. + * @returns Same as {@link Document#Get}, except will return `undefined` + * if there is an associated field but it is of the wrong type. + */ + GetT( + key: Key, + ctor: { new(...args: any[]): T }, + ignoreProto: boolean = false + ): FieldValue { + var getfield = this.Get(key, ignoreProto); + if (getfield != FieldWaiting) { + return Cast(getfield, ctor); + } + return FieldWaiting; } - return FieldWaiting; - } - - GetOrCreate( - key: Key, - ctor: { new (): T }, - ignoreProto: boolean = false - ): T { - const field = this.GetT(key, ctor, ignoreProto); - if (field && field != FieldWaiting) { - return field; + + GetOrCreate( + key: Key, + ctor: { new(): T }, + ignoreProto: boolean = false + ): T { + const field = this.GetT(key, ctor, ignoreProto); + if (field && field != FieldWaiting) { + return field; + } + const newField = new ctor(); + this.Set(key, newField); + return newField; } - const newField = new ctor(); - this.Set(key, newField); - return newField; - } - - GetData( - key: Key, - ctor: { new (): U }, - defaultVal: T - ): T { - let val = this.Get(key); - let vval = val && val instanceof ctor ? val.Data : defaultVal; - return vval; - } - - GetHtml(key: Key, defaultVal: string): string { - return this.GetData(key, HtmlField, defaultVal); - } - - GetNumber(key: Key, defaultVal: number): number { - return this.GetData(key, NumberField, defaultVal); - } - - GetText(key: Key, defaultVal: string): string { - return this.GetData(key, TextField, defaultVal); - } - - GetList(key: Key, defaultVal: T[]): T[] { - return this.GetData>(key, ListField, defaultVal); - } - - @action - Set(key: Key, field: Field | undefined, setOnPrototype = false): void { - let old = this.fields.get(key.Id); - let oldField = old ? old.field : undefined; - if (setOnPrototype) { - this.SetOnPrototype(key, field); - } else { - if (field) { - this.fields.set(key.Id, { key, field }); - this._proxies.set(key.Id, field.Id); - // Server.AddDocumentField(this, key, field); - } else { - this.fields.delete(key.Id); - this._proxies.delete(key.Id); - // Server.DeleteDocumentField(this, key); - } - Server.UpdateField(this); + + GetData( + key: Key, + ctor: { new(): U }, + defaultVal: T + ): T { + let val = this.Get(key); + let vval = val && val instanceof ctor ? val.Data : defaultVal; + return vval; } - if (oldField || field) { - UndoManager.AddEvent({ - undo: () => this.Set(key, oldField, setOnPrototype), - redo: () => this.Set(key, field, setOnPrototype) - }); + + GetHtml(key: Key, defaultVal: string): string { + return this.GetData(key, HtmlField, defaultVal); } - } - - @action - SetOnPrototype(key: Key, field: Field | undefined): void { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.Set(key, field); - }); - } - - @action - SetDataOnPrototype( - key: Key, - value: T, - ctor: { new (): U }, - replaceWrongType = true - ) { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.SetData(key, value, ctor); - }); - } - - @action - SetData( - key: Key, - value: T, - ctor: { new (data: T): U }, - replaceWrongType = true - ) { - let field = this.Get(key, true); - if (field instanceof ctor) { - field.Data = value; - } else if (!field || replaceWrongType) { - let newField = new ctor(value); - // newField.Data = value; - this.Set(key, newField); + + GetBoolean(key: Key, defaultVal: boolean): boolean { + return this.GetData(key, BooleanField, defaultVal); } - } - - @action - SetText(key: Key, value: string, replaceWrongType = true) { - this.SetData(key, value, TextField, replaceWrongType); - } - - @action - SetNumber(key: Key, value: number, replaceWrongType = true) { - this.SetData(key, value, NumberField, replaceWrongType); - } - - GetPrototype(): FieldValue { - return this.GetT(KeyStore.Prototype, Document, true); - } - - GetAllPrototypes(): Document[] { - let protos: Document[] = []; - let doc: FieldValue = this; - while (doc && doc != FieldWaiting) { - protos.push(doc); - doc = doc.GetPrototype(); + + GetNumber(key: Key, defaultVal: number): number { + return this.GetData(key, NumberField, defaultVal); + } + + GetText(key: Key, defaultVal: string): string { + return this.GetData(key, TextField, defaultVal); + } + + GetList(key: Key, defaultVal: T[]): T[] { + return this.GetData>(key, ListField, defaultVal); + } + + @action + Set(key: Key, field: Field | undefined, setOnPrototype = false): void { + let old = this.fields.get(key.Id); + let oldField = old ? old.field : undefined; + if (setOnPrototype) { + this.SetOnPrototype(key, field); + } else { + if (field) { + this.fields.set(key.Id, { key, field }); + this._proxies.set(key.Id, field.Id); + // Server.AddDocumentField(this, key, field); + } else { + this.fields.delete(key.Id); + this._proxies.delete(key.Id); + // Server.DeleteDocumentField(this, key); + } + Server.UpdateField(this); + } + if (oldField || field) { + UndoManager.AddEvent({ + undo: () => this.Set(key, oldField, setOnPrototype), + redo: () => this.Set(key, field, setOnPrototype) + }); + } + } + + @action + SetOnPrototype(key: Key, field: Field | undefined): void { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && f.Set(key, field); + }); + } + + @action + SetDataOnPrototype( + key: Key, + value: T, + ctor: { new(): U }, + replaceWrongType = true + ) { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && f.SetData(key, value, ctor); + }); + } + + @action + SetData( + key: Key, + value: T, + ctor: { new(data: T): U }, + replaceWrongType = true + ) { + let field = this.Get(key, true); + if (field instanceof ctor) { + field.Data = value; + } else if (!field || replaceWrongType) { + let newField = new ctor(value); + // newField.Data = value; + this.Set(key, newField); + } + } + + @action + SetText(key: Key, value: string, replaceWrongType = true) { + this.SetData(key, value, TextField, replaceWrongType); + } + + @action + SetNumber(key: Key, value: number, replaceWrongType = true) { + this.SetData(key, value, NumberField, replaceWrongType); + } + + GetPrototype(): FieldValue { + return this.GetT(KeyStore.Prototype, Document, true); + } + + GetAllPrototypes(): Document[] { + let protos: Document[] = []; + let doc: FieldValue = this; + while (doc && doc != FieldWaiting) { + protos.push(doc); + doc = doc.GetPrototype(); + } + return protos; + } + + CreateAlias(id?: string): Document { + let alias = new Document(id); + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && alias.Set(KeyStore.Prototype, f); + }); + + return alias; + } + + MakeDelegate(id?: string): Document { + let delegate = new Document(id); + + delegate.Set(KeyStore.Prototype, this); + + return delegate; + } + + ToScriptString(): string { + return ""; + } + + TrySetValue(value: any): boolean { + throw new Error("Method not implemented."); + } + GetValue() { + return this.Title; + var title = + (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + + "(" + + this.Id + + ")"; + return title; + //throw new Error("Method not implemented."); + } + Copy(): Field { + throw new Error("Method not implemented."); + } + + ToJson(): { type: Types; data: [string, string][]; _id: string } { + let fields: [string, string][] = []; + this._proxies.forEach((field, key) => { + if (field) { + fields.push([key, field as string]); + } + }); + + return { + type: Types.Document, + data: fields, + _id: this.Id + }; } - return protos; - } - - CreateAlias(id?: string): Document { - let alias = new Document(id); - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && alias.Set(KeyStore.Prototype, f); - }); - - return alias; - } - - MakeDelegate(id?: string): Document { - let delegate = new Document(id); - - delegate.Set(KeyStore.Prototype, this); - - return delegate; - } - - ToScriptString(): string { - return ""; - } - - TrySetValue(value: any): boolean { - throw new Error("Method not implemented."); - } - GetValue() { - return this.Title; - var title = - (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + - "(" + - this.Id + - ")"; - return title; - //throw new Error("Method not implemented."); - } - Copy(): Field { - throw new Error("Method not implemented."); - } - - ToJson(): { type: Types; data: [string, string][]; _id: string } { - let fields: [string, string][] = []; - this._proxies.forEach((field, key) => { - if (field) { - fields.push([key, field as string]); - } - }); - - return { - type: Types.Document, - data: fields, - _id: this.Id - }; - } } -- cgit v1.2.3-70-g09d2 From e70be930dc7c8ff1e999bf163bcbb511a60bae6f Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 4 Apr 2019 17:46:33 -0400 Subject: added close button and fixed some async stuff. --- src/client/views/DocumentDecorations.scss | 17 +++++++--- src/client/views/DocumentDecorations.tsx | 38 +++++++++++++++++++--- .../views/collections/CollectionViewBase.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +++-- .../collections/collectionFreeForm/MarqueeView.tsx | 1 + src/client/views/nodes/PDFBox.tsx | 10 +++--- 6 files changed, 60 insertions(+), 17 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 080c9fa1e..d7137d7a2 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -7,7 +7,7 @@ display: grid; z-index: 1000; grid-template-rows: 20px 8px 1fr 8px; - grid-template-columns: 8px 8px 1fr 8px; + grid-template-columns: 8px 8px 1fr 8px 8px; pointer-events: none; #documentDecorations-centerCont { @@ -30,13 +30,14 @@ #documentDecorations-topResizer, #documentDecorations-bottomResizer { grid-column-start: 2; - grid-column-end: 4; + grid-column-end: 5; } #documentDecorations-bottomRightResizer, #documentDecorations-topRightResizer, #documentDecorations-rightResizer { - grid-column:4 + grid-column-start:5; + grid-column-end:7; } #documentDecorations-topLeftResizer, @@ -61,11 +62,19 @@ .title{ background: lightblue; grid-column-start:3; - grid-column-end: 5; + grid-column-end: 4; pointer-events: auto; } } +.documentDecorations-closeButton { + background:$alt-accent; + opacity: 0.8; + grid-column-start: 4; + grid-column-end: 6; + pointer-events: all; + text-align: center; +} .documentDecorations-minimizeButton { background:$alt-accent; opacity: 0.8; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index a46087c9a..8bf1a42d1 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -142,6 +142,30 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.preventDefault(); } + onCloseDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + document.removeEventListener("pointermove", this.onCloseMove); + document.addEventListener("pointermove", this.onCloseMove); + document.removeEventListener("pointerup", this.onCloseUp); + document.addEventListener("pointerup", this.onCloseUp); + } + } + onCloseMove = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + } + } + @action + onCloseUp = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 0) { + SelectionManager.SelectedDocuments().map(dv => dv.props.RemoveDocument && dv.props.RemoveDocument(dv.props.Document)); + SelectionManager.DeselectAll(); + document.removeEventListener("pointermove", this.onCloseMove); + document.removeEventListener("pointerup", this.onCloseUp); + } + } onMinimizeDown = (e: React.PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { @@ -219,7 +243,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); } - onLinkButtonMoved = (e: PointerEvent): void => { + onLinkButtonMoved = async (e: PointerEvent) => { if (this._linkButton.current != null) { document.removeEventListener("pointermove", this.onLinkButtonMoved) document.removeEventListener("pointerup", this.onLinkButtonUp); @@ -234,10 +258,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : []; draggedDocs.push(...draggedFromDocs); if (draggedDocs.length) { - let dragData = new DragManager.DocumentDragData(draggedDocs.map(d => { - let annot = d.GetT(KeyStore.AnnotationOn, Document); // bcz: ... needs to change ... the annotationOn document may not have been retrieved yet... - return annot && annot != FieldWaiting ? annot : d; - })); + let moddrag = [] as Document[]; + for (let i = 0; i < draggedDocs.length; i++) { + let doc = await draggedDocs[i].GetTAsync(KeyStore.AnnotationOn, Document); + if (doc) + moddrag.push(doc); + } + let dragData = new DragManager.DocumentDragData(moddrag); DragManager.StartDocumentDrag([this._linkButton.current], dragData, { handlers: { dragComplete: action(() => { }), @@ -400,6 +427,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> }}>
...
+
X
e.preventDefault()}>
e.preventDefault()}>
e.preventDefault()}>
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index daeca69e2..9eee23a1d 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -128,6 +128,7 @@ export class CollectionViewBase extends React.Component } if (type.indexOf("pdf") !== -1) { ctor = Documents.PdfDocument; + options.nativeWidth = 600; } if (type.indexOf("html") !== -1) { if (path.includes('localhost')) { @@ -177,7 +178,6 @@ export class CollectionViewBase extends React.Component let item = e.dataTransfer.items[i]; if (item.kind === "string" && item.type.indexOf("uri") != -1) { e.dataTransfer.items[i].getAsString(action((s: string) => { - let document: Document; request.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s), (err, res, body) => { let type = res.headers["content-type"]; if (type) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3484e963e..1ddb84a99 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -20,6 +20,7 @@ import React = require("react"); import v5 = require("uuid/v5"); import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import { PreviewCursor } from "./PreviewCursor"; +import { NumberField } from "../../../../fields/NumberField"; @observer export class CollectionFreeFormView extends CollectionViewBase { @@ -83,13 +84,17 @@ export class CollectionFreeFormView extends CollectionViewBase { let dragDoc = de.data.droppedDocuments[0]; let dragX = dragDoc.GetNumber(KeyStore.X, 0); let dragY = dragDoc.GetNumber(KeyStore.Y, 0); - droppedDocs.map(d => { + droppedDocs.map(async 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 (!d.GetNumber(KeyStore.Width, 0)) { + let docW = await d.GetTAsync(KeyStore.Width, NumberField); + let docH = await d.GetTAsync(KeyStore.Height, NumberField); + if (!docW) { d.SetNumber(KeyStore.Width, 300); + } + if (!docH) { d.SetNumber(KeyStore.Height, 300); } this.bringToFront(d); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e2239c8be..df150a045 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -135,6 +135,7 @@ export class MarqueeView extends React.Component this.marqueeInkDelete(inkData); // }, 100); this.cleanupInteractions(); + SelectionManager.DeselectAll(); } } @action diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3cb3cf782..c9fed7f66 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,5 +1,5 @@ import * as htmlToImage from "html-to-image"; -import { action, computed, observable, reaction, IReactionDisposer, trace, keys } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; import Measure from "react-measure"; @@ -10,6 +10,7 @@ import { FieldWaiting, Opt } from '../../../fields/Field'; import { ImageField } from '../../../fields/ImageField'; import { KeyStore } from '../../../fields/KeyStore'; import { PDFField } from '../../../fields/PDFField'; +import { RouteStore } from "../../../server/RouteStore"; import { Utils } from '../../../Utils'; import { Annotation } from './Annotation'; import { FieldView, FieldViewProps } from './FieldView'; @@ -17,8 +18,6 @@ import "./ImageBox.scss"; import "./PDFBox.scss"; import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here import React = require("react") -import { RouteStore } from "../../../server/RouteStore"; -import { NumberField } from "../../../fields/NumberField"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -378,8 +377,9 @@ export class PDFBox extends React.Component { saveThumbnail = () => { setTimeout(() => { var me = this; - htmlToImage.toPng(this._mainDiv.current!, - { width: me.props.doc.GetNumber(KeyStore.NativeWidth, 0), height: me.props.doc.GetNumber(KeyStore.NativeHeight, 0), quality: 0.5 }) + let nwidth = me.props.doc.GetNumber(KeyStore.NativeWidth, 0); + let nheight = me.props.doc.GetNumber(KeyStore.NativeHeight, 0); + htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 }) .then(function (dataUrl: string) { me.props.doc.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField); me.props.doc.SetNumber(KeyStore.ThumbnailPage, me.props.doc.GetNumber(KeyStore.CurPage, -1)); -- cgit v1.2.3-70-g09d2 From 39ab550efc4eedeb7a9295a68c0d23e54ad086f2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 5 Apr 2019 08:48:16 -0400 Subject: fixed doc decorations min width --- src/client/views/DocumentDecorations.scss | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index d7137d7a2..c4e4aed8e 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -60,6 +60,7 @@ cursor: ew-resize; } .title{ + width:100%; background: lightblue; grid-column-start:3; grid-column-end: 4; -- cgit v1.2.3-70-g09d2 From 4e45ad641bd34c4703188e69a93a23243f3659a4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 10 Apr 2019 21:35:12 -0400 Subject: fixed text menu and text dragging. --- src/client/util/TooltipTextMenu.tsx | 14 +++++++++----- src/client/views/DocumentDecorations.scss | 3 +++ src/client/views/Main.scss | 1 + src/client/views/Main.tsx | 23 +++++++++++++++++++---- src/client/views/nodes/FormattedTextBox.tsx | 13 +++++++++---- 5 files changed, 41 insertions(+), 13 deletions(-) (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index bd5753093..7951e5686 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -12,19 +12,23 @@ const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core'; import { wrapInList, bulletList } from 'prosemirror-schema-list'; import { faListUl } from '@fortawesome/free-solid-svg-icons'; +import { FieldViewProps } from "../views/nodes/FieldView"; +import { throwStatement } from "babel-types"; //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { private tooltip: HTMLElement; + private editorProps: FieldViewProps; - constructor(view: EditorView) { + constructor(view: EditorView, editorProps: FieldViewProps) { + this.editorProps = editorProps; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; //add the div which is the tooltip - view.dom.parentNode!.appendChild(this.tooltip); + view.dom.parentNode!.parentNode!.appendChild(this.tooltip); //add additional icons library.add(faListUl); @@ -124,13 +128,13 @@ export class TooltipTextMenu { // Find a center-ish x position from the selection endpoints (when // crossing lines, end may be more to the left) let left = Math.max((start.left + end.left) / 2, start.left + 3); - this.tooltip.style.left = (left - box.left) + "px"; - let width = Math.abs(start.left - end.left) / 2; + this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; let mid = Math.min(start.left, end.left) + width; //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 this.tooltip.style.width = 122 + "px"; - this.tooltip.style.bottom = (box.bottom - start.top) + "px"; + this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; } destroy() { this.tooltip.remove(); } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index c4e4aed8e..b2096bccb 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -1,5 +1,8 @@ @import "global_variables"; +.documentDecorations { + position: absolute; +} #documentDecorations-container { position: absolute; top: 0; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index c4da47e0e..a68b90dd4 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -176,6 +176,7 @@ button:hover { overflow: visible; top: 0; left: 0; + z-index: 1000; .formattedTextBox-cont { background-color: rgba(248, 6, 6, 0.001); width: 100%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index e96e4cbf8..b73b55fb1 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -28,7 +28,7 @@ import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; import { Server } from '../Server'; -import { setupDrag } from '../util/DragManager'; +import { setupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; @@ -38,6 +38,7 @@ import { InkingControl } from './InkingControl'; import "./Main.scss"; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/FormattedTextBox'; +import { REPLCommand } from 'repl'; @observer export class Main extends React.Component { @@ -228,6 +229,21 @@ export class Main extends React.Component { } } + textBoxDown = (e: React.PointerEvent) => { + let dragData = new DragManager.DocumentDragData([this._textDoc!]); + const [left, top] = this._textXf + .inverse() + .transformPoint(0, 0); + dragData.xOffset = e.clientX - left; + dragData.yOffset = e.clientY - top; + DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + @computed get activeTextBox() { if (this._textDoc) { @@ -239,9 +255,8 @@ export class Main extends React.Component { let s = this._textXf.transformPoint(1, 0); s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); return
-
- { }} /> - +
+ this._textXf} focus={(doc) => { }} />
; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index eb40a03a5..69086df42 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -70,12 +70,16 @@ export class FormattedTextBox extends React.Component { const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful - plugins: [ + plugins: this.props.fieldKey === KeyStore.Archives ? [ history(), keymap({ "Mod-z": undo, "Mod-y": redo }), keymap(baseKeymap), this.tooltipMenuPlugin() - ] + ] : [ + history(), + keymap({ "Mod-z": undo, "Mod-y": redo }), + keymap(baseKeymap), + ] }; if (this.props.fieldKey === KeyStore.Archives) { @@ -150,7 +154,7 @@ export class FormattedTextBox extends React.Component { // doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { + if (e.buttons === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); } } @@ -202,9 +206,10 @@ export class FormattedTextBox extends React.Component { } tooltipMenuPlugin() { + let myprops = this.props; return new Plugin({ view(_editorView) { - return new TooltipTextMenu(_editorView); + return new TooltipTextMenu(_editorView, myprops); } }); } -- cgit v1.2.3-70-g09d2 From e9cbcfa2a893572f8b92bba84dd0791e6f50be71 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 11 Apr 2019 09:34:46 -0400 Subject: cleaned up z-index stuff --- src/client/util/DragManager.ts | 3 +- src/client/views/ContextMenu.scss | 2 +- src/client/views/DocumentDecorations.scss | 33 +--------------------- src/client/views/Main.scss | 2 +- src/client/views/_global_variables.scss | 11 ++++++++ src/client/views/_global_variables.scss.d.ts | 10 +++++++ .../CollectionFreeFormRemoteCursors.scss | 24 ++++++++++++++++ .../CollectionFreeFormRemoteCursors.tsx | 32 ++++----------------- 8 files changed, 56 insertions(+), 61 deletions(-) create mode 100644 src/client/views/_global_variables.scss.d.ts create mode 100644 src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index b8a35a4d1..e500b0274 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -6,6 +6,7 @@ import { DocumentDecorations } from "../views/DocumentDecorations"; import { DocumentView } from "../views/nodes/DocumentView"; import { returnFalse, emptyFunction } from "../../Utils"; import { Main } from "../views/Main"; +import globalStyles from '../views/_global_variables.scss'; export function setupDrag(_reference: React.RefObject, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { @@ -177,7 +178,7 @@ export namespace DragManager { dragElement.style.bottom = ""; dragElement.style.left = "0"; dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; + dragElement.style.zIndex = "1000";// globalStyles.contextMenuZindex.toString(); dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index f6830d9cd..5acf598cf 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -2,7 +2,7 @@ .contextMenu-cont { position: absolute; display: flex; - z-index: 1000; + z-index: $contextMenu-zindex; box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw; flex-direction: column; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index b2096bccb..321bda384 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -8,7 +8,7 @@ top: 0; left:0; display: grid; - z-index: 1000; + z-index: $docDecorations-zindex; grid-template-rows: 20px 8px 1fr 8px; grid-template-columns: 8px 8px 1fr 8px 8px; pointer-events: none; @@ -93,37 +93,6 @@ opacity: 0.1; } -// position: absolute; -// display: grid; -// z-index: 1000; -// grid-template-rows: 20px 1fr 20px 0px; -// grid-template-columns: 20px 1fr 20px; -// pointer-events: none; -// #documentDecorations-centerCont { -// background: none; -// } -// .documentDecorations-resizer { -// pointer-events: auto; -// background: lightblue; -// opacity: 0.4; -// } -// #documentDecorations-topLeftResizer, -// #documentDecorations-bottomRightResizer { -// cursor: nwse-resize; -// } -// #documentDecorations-topRightResizer, -// #documentDecorations-bottomLeftResizer { -// cursor: nesw-resize; -// } -// #documentDecorations-topResizer, -// #documentDecorations-bottomResizer { -// cursor: ns-resize; -// } -// #documentDecorations-leftResizer, -// #documentDecorations-rightResizer { -// cursor: ew-resize; -// } -// } .linkFlyout { grid-column: 1/4; margin-left: 25px; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index a68b90dd4..7329b8eb6 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -176,7 +176,7 @@ button:hover { overflow: visible; top: 0; left: 0; - z-index: 1000; + z-index: $mainTextInput-zindex; .formattedTextBox-cont { background-color: rgba(248, 6, 6, 0.001); width: 100%; diff --git a/src/client/views/_global_variables.scss b/src/client/views/_global_variables.scss index 44a819b79..238351a77 100644 --- a/src/client/views/_global_variables.scss +++ b/src/client/views/_global_variables.scss @@ -15,3 +15,14 @@ $sans-serif: "Noto Sans", sans-serif; $serif: "Crimson Text", serif; // misc values $border-radius: 0.3em; +// + + // dragged items +$contextMenu-zindex: 1000; // context menu shows up over everything +$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc +$docDecorations-zindex: 998; // then doc decorations appear over everything else +$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? + +:export { + contextMenuZindex: $contextMenu-zindex +} \ No newline at end of file diff --git a/src/client/views/_global_variables.scss.d.ts b/src/client/views/_global_variables.scss.d.ts new file mode 100644 index 000000000..12008aeef --- /dev/null +++ b/src/client/views/_global_variables.scss.d.ts @@ -0,0 +1,10 @@ +export interface I_globalScss { + contextMenuZindex: number; // context menu shows up over everything + mainTextInputZindex: number; // then text input overlay so that it's context menu will appear over decorations, etc + docDecorationsZindex: number; // then doc decorations appear over everything else + remoteCursorsZindex: number; // ... not sure what level the remote cursors should go -- is this right? +} + +export const globalStyles: I_globalScss; + +export default globalStyles; \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss new file mode 100644 index 000000000..c38787802 --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss @@ -0,0 +1,24 @@ +@import "global_variables"; + +.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 fc832264d..751ea8190 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -59,37 +59,17 @@ export class CollectionFreeFormRemoteCursors extends React.Component - { 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" - }} /> -

{email[0].toUpperCase()}

+

+ {email[0].toUpperCase()} +

); } -- cgit v1.2.3-70-g09d2 From fd8e6bf2cacf8bed7c3363eeb777c731741266d5 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 11 Apr 2019 20:19:57 -0400 Subject: made COLLECTION_BORDER_WIDTH a CSS variable accessible from code. changed global css variable file name --- src/client/util/DragManager.ts | 5 ++-- src/client/util/TooltipTextMenu.scss | 2 +- src/client/views/ContextMenu.scss | 2 +- src/client/views/DocumentDecorations.scss | 2 +- src/client/views/InkingCanvas.scss | 2 +- src/client/views/InkingControl.scss | 2 +- src/client/views/Main.scss | 2 +- src/client/views/_global_variables.scss | 28 ------------------- src/client/views/_global_variables.scss.d.ts | 7 ----- src/client/views/_global_variables.ts | 8 ------ .../views/collections/CollectionBaseView.tsx | 1 - .../views/collections/CollectionDockingView.scss | 6 +++++ .../views/collections/CollectionDockingView.tsx | 9 +------ .../views/collections/CollectionSchemaView.scss | 6 +++-- .../views/collections/CollectionSchemaView.tsx | 10 ++++--- .../views/collections/CollectionTreeView.scss | 6 +++-- .../views/collections/CollectionTreeView.tsx | 4 +-- .../CollectionFreeFormRemoteCursors.scss | 2 +- .../collectionFreeForm/CollectionFreeFormView.scss | 10 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 ++++++++++++---------- src/client/views/globalCssVariables.scss | 29 ++++++++++++++++++++ src/client/views/globalCssVariables.scss.d.ts | 8 ++++++ src/client/views/nodes/DocumentView.scss | 2 +- src/client/views/nodes/FormattedTextBox.scss | 2 +- src/client/views/nodes/KeyValueBox.scss | 2 +- src/client/views/nodes/KeyValuePair.scss | 2 +- src/client/views/nodes/LinkBox.scss | 2 +- src/client/views/nodes/LinkEditor.scss | 2 +- 28 files changed, 99 insertions(+), 95 deletions(-) delete mode 100644 src/client/views/_global_variables.scss delete mode 100644 src/client/views/_global_variables.scss.d.ts delete mode 100644 src/client/views/_global_variables.ts create mode 100644 src/client/views/globalCssVariables.scss create mode 100644 src/client/views/globalCssVariables.scss.d.ts (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 333c474c1..3d8bbb49c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -5,8 +5,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie import { DocumentDecorations } from "../views/DocumentDecorations"; import { Main } from "../views/Main"; import { DocumentView } from "../views/nodes/DocumentView"; -// import globalStyles from "../views/_global_variables"; -import * as globalStyles from "../views/_global_variables.scss"; // bcz: why doesn't this work? +import * as globalCssVariables from "../views/globalCssVariables.scss"; export function setupDrag(_reference: React.RefObject, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { @@ -178,7 +177,7 @@ export namespace DragManager { dragElement.style.bottom = ""; dragElement.style.left = "0"; dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = globalStyles.contextMenuZindex;// "1000"; + dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index ea580d104..7deea3be6 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -1,4 +1,4 @@ -@import "../views/global_variables"; +@import "../views/globalCssVariables"; .tooltipMenu { position: absolute; diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 5acf598cf..fe884ca85 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -1,4 +1,4 @@ -@import "global_variables"; +@import "globalCssVariables"; .contextMenu-cont { position: absolute; display: flex; diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 321bda384..ce84b6106 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -1,4 +1,4 @@ -@import "global_variables"; +@import "globalCssVariables"; .documentDecorations { position: absolute; diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 42ae38c73..2c550051c 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -1,4 +1,4 @@ -@import "global_variables"; +@import "globalCssVariables"; .inkingCanvas { opacity:0.99; diff --git a/src/client/views/InkingControl.scss b/src/client/views/InkingControl.scss index 0d8fd8784..ba4ec41af 100644 --- a/src/client/views/InkingControl.scss +++ b/src/client/views/InkingControl.scss @@ -1,4 +1,4 @@ -@import "global_variables"; +@import "globalCssVariables"; .inking-control { position: absolute; left: 70px; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 7329b8eb6..f3af26f37 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -1,4 +1,4 @@ -@import "global_variables"; +@import "globalCssVariables"; @import "nodeModuleOverrides"; html, body { diff --git a/src/client/views/_global_variables.scss b/src/client/views/_global_variables.scss deleted file mode 100644 index cd6af2dac..000000000 --- a/src/client/views/_global_variables.scss +++ /dev/null @@ -1,28 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Crimson+Text:400,400i,700"); -// colors -$light-color: #fcfbf7; -$light-color-secondary: rgb(241, 239, 235); -$main-accent: #61aaa3; -// $alt-accent: #cdd5ec; -// $alt-accent: #cdeceb; -$alt-accent: #59dff7; -$lighter-alt-accent: rgb(207, 220, 240); -$intermediate-color: #9c9396; -$dark-color: #121721; -// fonts -$sans-serif: "Noto Sans", sans-serif; -// $sans-serif: "Roboto Slab", sans-serif; -$serif: "Crimson Text", serif; -// misc values -$border-radius: 0.3em; -// - - // dragged items -$contextMenu-zindex: 1000; // context menu shows up over everything -$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc -$docDecorations-zindex: 998; // then doc decorations appear over everything else -$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? - -:export { - contextMenuZindex: $contextMenu-zindex; -} \ No newline at end of file diff --git a/src/client/views/_global_variables.scss.d.ts b/src/client/views/_global_variables.scss.d.ts deleted file mode 100644 index ebee7dbce..000000000 --- a/src/client/views/_global_variables.scss.d.ts +++ /dev/null @@ -1,7 +0,0 @@ - -interface IGlobalScss { - contextMenuZindex: string; // context menu shows up over everything -} -declare const globalStyleVariables: IGlobalScss; - -export = globalStyleVariables; \ No newline at end of file diff --git a/src/client/views/_global_variables.ts b/src/client/views/_global_variables.ts deleted file mode 100644 index caedc7aad..000000000 --- a/src/client/views/_global_variables.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as globalStyleVariables from "../views/_global_variables.scss"; - -export interface IGlobalScss { - contextMenuZindex: string; // context menu shows up over everything -} -let globalStyles = globalStyleVariables as any as IGlobalScss; - -export default globalStyles; \ No newline at end of file diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index ac320eda3..0ace700ce 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -34,7 +34,6 @@ export interface CollectionViewProps extends FieldViewProps { contentRef?: React.Ref; } -export const COLLECTION_BORDER_WIDTH = 1; @observer export class CollectionBaseView extends React.Component { diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 583d50c5b..13dd9faa8 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -1,8 +1,14 @@ +@import "../../views/globalCssVariables.scss"; + .collectiondockingview-content { height: 100%; } .collectiondockingview-container { + width: 100%; + height: 100%; + border-style: solid; + border-width: $COLLECTION_BORDER_WIDTH; position: absolute; top: 0; left: 0; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 212cf8a69..05470f405 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -13,7 +13,6 @@ import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; -import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; import { ServerUtils } from "../../../server/ServerUtil"; @@ -271,13 +270,7 @@ export class CollectionDockingView extends React.Component + onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} ref={this._containerRef} /> ); } } diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index c3a2e88ac..40e49bb5f 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; //options menu styling #schemaOptionsMenuBtn { @@ -53,7 +53,9 @@ .collectionSchemaView-container { - border: 1px solid $intermediate-color; + border-width: $COLLECTION_BORDER_WIDTH; + border-color : $intermediate-color; + border-style: solid; border-radius: $border-radius; box-sizing: border-box; position: absolute; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f1b3e1b8f..0cb88eab0 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -25,7 +25,7 @@ import "./CollectionSchemaView.scss"; import { CollectionView } from "./CollectionView"; import { CollectionSubView } from "./CollectionSubView"; import { TextField } from "../../../fields/TextField"; -import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; +import * as globalCssVariables from "../../views/globalCssVariables.scss"; import { emptyFunction, returnFalse } from "../../../Utils"; @@ -245,11 +245,13 @@ export class CollectionSchemaView extends CollectionSubView { this._contentScaling = r.entry.width / selected!.GetNumber(KeyStore.NativeWidth, r.entry.width); } + @computed + get borderWidth() { return globalCssVariables.COLLECTION_BORDER_WIDTH; } getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX, - this.borderWidth).scale(1 / this._contentScaling); + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - this.borderWidth).scale(1 / this._contentScaling); focusDocument = (doc: Document) => { }; @@ -349,7 +351,7 @@ export class CollectionSchemaView extends CollectionSubView { ); return ( -
+
this.onDrop(e, {})} ref={this.createDropTarget}> {({ measureRef }) => diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index f2affbf55..973eead97 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,7 +1,9 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .collectionTreeView-dropTarget { - border: 0px solid transparent; + border-width: $COLLECTION_BORDER_WIDTH; + border-color: transparent; + border-style: solid; border-radius: $border-radius; box-sizing: border-box; height: 100%; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 659cff9fe..20ec16822 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -11,9 +11,9 @@ import { setupDrag, DragManager } from "../../util/DragManager"; import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; import { CollectionView } from "./CollectionView"; +import * as globalCssVariables from "../../views/globalCssVariables.scss"; import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); -import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; import { props } from 'bluebird'; @@ -139,7 +139,7 @@ export class CollectionTreeView extends CollectionSubView { ); return ( -
e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}> +
e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget}>
); } - 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); + @computed + get borderWidth() { + return this.isAnnotationOverlay ? 0 : globalCssVariables.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; @@ -317,8 +321,7 @@ export class CollectionFreeFormView extends CollectionSubView {
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}> + onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel} ref={this.createDropTarget}> diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss new file mode 100644 index 000000000..5c8e9c8fc --- /dev/null +++ b/src/client/views/globalCssVariables.scss @@ -0,0 +1,29 @@ +@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Crimson+Text:400,400i,700"); +// colors +$light-color: #fcfbf7; +$light-color-secondary: rgb(241, 239, 235); +$main-accent: #61aaa3; +// $alt-accent: #cdd5ec; +// $alt-accent: #cdeceb; +$alt-accent: #59dff7; +$lighter-alt-accent: rgb(207, 220, 240); +$intermediate-color: #9c9396; +$dark-color: #121721; +// fonts +$sans-serif: "Noto Sans", sans-serif; +// $sans-serif: "Roboto Slab", sans-serif; +$serif: "Crimson Text", serif; +// misc values +$border-radius: 0.3em; +// + + // dragged items +$contextMenu-zindex: 1000; // context menu shows up over everything +$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc +$docDecorations-zindex: 998; // then doc decorations appear over everything else +$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? +$COLLECTION_BORDER_WIDTH: 1; +:export { + contextMenuZindex: $contextMenu-zindex; + COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; +} \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts new file mode 100644 index 000000000..e874b815d --- /dev/null +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -0,0 +1,8 @@ + +interface IGlobalScss { + contextMenuZindex: string; // context menu shows up over everything + COLLECTION_BORDER_WIDTH: number; +} +declare const globalCssVariables: IGlobalScss; + +export = globalCssVariables; \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 5126e69f9..039d1bcc6 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .documentView-node { position: absolute; diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index d2ba52cf9..3978c3d38 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .ProseMirror { width: 100%; height: auto; diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss index 63ae75424..f60edc675 100644 --- a/src/client/views/nodes/KeyValueBox.scss +++ b/src/client/views/nodes/KeyValueBox.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .keyValueBox-cont { overflow-y: scroll; height: 100%; diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss index 64e871e1c..0bb92e5a3 100644 --- a/src/client/views/nodes/KeyValuePair.scss +++ b/src/client/views/nodes/KeyValuePair.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .container{ display: flex; diff --git a/src/client/views/nodes/LinkBox.scss b/src/client/views/nodes/LinkBox.scss index 5d5f782d2..8bc70b48f 100644 --- a/src/client/views/nodes/LinkBox.scss +++ b/src/client/views/nodes/LinkBox.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .link-container { width: 100%; height: 35px; diff --git a/src/client/views/nodes/LinkEditor.scss b/src/client/views/nodes/LinkEditor.scss index fb0c69cff..ea2e7289c 100644 --- a/src/client/views/nodes/LinkEditor.scss +++ b/src/client/views/nodes/LinkEditor.scss @@ -1,4 +1,4 @@ -@import "../global_variables"; +@import "../globalCssVariables"; .edit-container { width: 100%; height: auto; -- cgit v1.2.3-70-g09d2 From db9ee4f0d710d132e33e48cf6f105fd945941003 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 12 Apr 2019 21:18:30 -0400 Subject: combined preview cursor with marquee. moved preview cursor prompt to its own file. --- src/client/views/DocumentDecorations.scss | 2 + src/client/views/Main.scss | 2 +- src/client/views/Main.tsx | 39 +--------- src/client/views/PreviewCursor.scss | 9 +++ src/client/views/PreviewCursor.tsx | 37 ++++++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 33 ++++----- .../collections/collectionFreeForm/MarqueeView.tsx | 43 +++++++++-- .../collectionFreeForm/PreviewCursor.scss | 27 ------- .../collectionFreeForm/PreviewCursor.tsx | 85 ---------------------- 9 files changed, 103 insertions(+), 174 deletions(-) create mode 100644 src/client/views/PreviewCursor.scss create mode 100644 src/client/views/PreviewCursor.tsx delete mode 100644 src/client/views/collections/collectionFreeForm/PreviewCursor.scss delete mode 100644 src/client/views/collections/collectionFreeForm/PreviewCursor.tsx (limited to 'src/client/views/DocumentDecorations.scss') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index ce84b6106..c1a949639 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -78,6 +78,7 @@ grid-column-end: 6; pointer-events: all; text-align: center; + cursor: pointer; } .documentDecorations-minimizeButton { background:$alt-accent; @@ -86,6 +87,7 @@ grid-column-end: 3; pointer-events: all; text-align: center; + cursor: pointer; } .documentDecorations-background { background: lightblue; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index f3af26f37..13cadb10d 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -184,7 +184,7 @@ button:hover { position:absolute; top: 0; left: 0; -} + } } #mainContent-div { width:100%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 80e19c4f5..ed61aa5a7 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -40,44 +40,9 @@ import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/FormattedTextBox'; import { REPLCommand } from 'repl'; import { Key } from '../../fields/Key'; -import { truncate } from 'fs'; +import { PreviewCursor } from './PreviewCursor'; -export interface PromptProps { -} - -@observer -export class PreviewCursorPrompt extends React.Component { - private _prompt = React.createRef(); - //when focus is lost, this will remove the preview cursor - @action onBlur = (): void => { - PreviewCursorPrompt.Visible = false; - PreviewCursorPrompt.hide(); - } - - @observable static clickPoint = [0, 0]; - @observable public static Visible = false; - @observable public static hide = () => { }; - @action - public static Show(hide: any, x: number, y: number) { - this.clickPoint = [x, y]; - this.hide = hide; - setTimeout(action(() => this.Visible = true), (1)); - } - render() { - if (!PreviewCursorPrompt.clickPoint) { - return (null); - } - if (PreviewCursorPrompt.Visible && this._prompt.current) { - this._prompt.current.focus(); - } - let p = PreviewCursorPrompt.clickPoint; - return
- I -
; - } -} @observer export class Main extends React.Component { // dummy initializations keep the compiler happy @@ -429,7 +394,7 @@ export class Main extends React.Component { {({ measureRef }) =>
{this.mainContent} - +
} diff --git a/src/client/views/PreviewCursor.scss b/src/client/views/PreviewCursor.scss new file mode 100644 index 000000000..20f9b9a49 --- /dev/null +++ b/src/client/views/PreviewCursor.scss @@ -0,0 +1,9 @@ + +.previewCursor { + color: black; + position: absolute; + transform-origin: left top; + top: 0; + left:0; + pointer-events: none; +} \ No newline at end of file diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx new file mode 100644 index 000000000..ff8434681 --- /dev/null +++ b/src/client/views/PreviewCursor.tsx @@ -0,0 +1,37 @@ +import { action, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import "normalize.css"; +import * as React from 'react'; +import "./PreviewCursor.scss"; + +@observer +export class PreviewCursor extends React.Component<{}> { + private _prompt = React.createRef(); + //when focus is lost, this will remove the preview cursor + @action onBlur = (): void => { + PreviewCursor.Visible = false; + PreviewCursor.hide(); + } + + @observable static clickPoint = [0, 0]; + @observable public static Visible = false; + @observable public static hide = () => { }; + @action + public static Show(hide: any, x: number, y: number) { + this.clickPoint = [x, y]; + this.hide = hide; + setTimeout(action(() => this.Visible = true), (1)); + } + render() { + if (!PreviewCursor.clickPoint) { + return (null); + } + if (PreviewCursor.Visible && this._prompt.current) { + this._prompt.current.focus(); + } + return
+ I +
; + } +} \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 98ebbf1b3..e19dc98fa 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -23,7 +23,6 @@ import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; -import { PreviewCursor } from "./PreviewCursor"; import React = require("react"); import v5 = require("uuid/v5"); @@ -311,9 +310,9 @@ export class CollectionFreeFormView extends CollectionSubView { 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; - const blay = this.backgroundView; - const olay = this.overlayView; + const zoom: number = this.zoomScaling;// needs to be a variable outside of the otherwise, reactions won't fire + const backgroundView = this.backgroundView; // needs to be a variable outside of the otherwise, reactions won't fire + const overlayView = this.overlayView;// needs to be a variable outside of the otherwise, reactions won't fire return ( runInAction(() => { this._pwidth = r.entry.width; this._pheight = r.entry.height; })}> @@ -323,21 +322,19 @@ export class CollectionFreeFormView extends CollectionSubView { 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}> - -
- {blay} - - - {this.childViews} - - - -
- {olay} -
+
+ {backgroundView} + + + {this.childViews} + + + +
+ {overlayView}
)} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1e6faafb3..9c0d75c22 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"; @@ -8,9 +8,9 @@ import { Documents } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; 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 +21,7 @@ interface MarqueeViewProps { activeDocuments: () => Document[]; selectDocuments: (docs: Document[]) => void; removeDocument: (doc: Document) => boolean; + addLiveTextDocument: (doc: Document) => void; } @observer @@ -32,6 +33,7 @@ export class MarqueeView extends React.Component @observable _downY: number = 0; @observable _used: boolean = false; @observable _visible: boolean = false; + _showOnUp: boolean = false; static DRAG_THRESHOLD = 4; @action @@ -46,12 +48,32 @@ export class MarqueeView extends React.Component this._visible = false; } + @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()) { this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; + 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,6 +85,10 @@ export class MarqueeView extends React.Component this._lastX = e.pageX; this._lastY = e.pageY; if (!e.cancelBubble) { + 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 +102,16 @@ export class MarqueeView extends React.Component 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 }, diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss deleted file mode 100644 index 7a67c29bf..000000000 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss +++ /dev/null @@ -1,27 +0,0 @@ - -.previewCursor { - color: black; - position: absolute; - transform-origin: left top; - top: 0; - left:0; - pointer-events: none; -} -.previewCursorView { - top: 0; - left:0; - 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 64da8ecc6..000000000 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ /dev/null @@ -1,85 +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 { Main, PreviewCursorPrompt } from "../../Main"; - - -export interface PreviewCursorProps { - getTransform: () => Transform; - container: CollectionFreeFormView; - addLiveTextDocument: (doc: Document) => void; -} - -@observer -export class PreviewCursor extends React.Component { - @observable _lastX: number = 0; - @observable _lastY: number = 0; - @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; - PreviewCursorPrompt.Visible = false; - } - } - - onPointerUp = (e: PointerEvent): void => { - if (this._showOnUp) { - PreviewCursorPrompt.Show(this.hideCursor, this.DownX, this.DownY); - document.addEventListener("keypress", this.onKeyPress, false); - } - 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.DownX, this.DownY); - let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "typed text" }); - this.props.addLiveTextDocument(newBox); - PreviewCursorPrompt.Visible = false; - e.stopPropagation(); - } - } - - hideCursor = () => { - document.removeEventListener("keypress", this.onKeyPress, false); - } - render() { - return ( -
- {this.props.children} -
- ); - } -} \ No newline at end of file -- cgit v1.2.3-70-g09d2