aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DocumentDecorations.scss86
-rw-r--r--src/client/views/DocumentDecorations.tsx270
-rw-r--r--src/client/views/InkingCanvas.scss19
-rw-r--r--src/client/views/InkingCanvas.tsx67
-rw-r--r--src/client/views/InkingStroke.tsx9
-rw-r--r--src/client/views/Main.scss7
-rw-r--r--src/client/views/Main.tsx3
-rw-r--r--src/client/views/collections/CollectionDockingView.scss2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionPDFView.scss2
-rw-r--r--src/client/views/collections/CollectionVideoView.scss2
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx24
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx55
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx46
-rw-r--r--src/client/views/collections/collectionFreeForm/PreviewCursor.scss4
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.scss20
-rw-r--r--src/client/views/nodes/DocumentView.tsx365
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx289
-rw-r--r--src/client/views/nodes/PDFBox.scss4
-rw-r--r--src/client/views/nodes/PDFBox.tsx32
-rw-r--r--src/client/views/nodes/Sticky.tsx138
-rw-r--r--src/client/views/nodes/WebBox.scss2
28 files changed, 1005 insertions, 485 deletions
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 7a43f3087..c4e4aed8e 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -1,39 +1,91 @@
@import "global_variables";
+
#documentDecorations-container {
position: absolute;
+ top: 0;
+ left:0;
display: grid;
z-index: 1000;
- grid-template-rows: 8px 1fr 8px 30px;
- grid-template-columns: 8px 1fr 8px;
+ grid-template-rows: 20px 8px 1fr 8px;
+ grid-template-columns: 8px 8px 1fr 8px 8px;
pointer-events: none;
+
#documentDecorations-centerCont {
+ grid-column:3;
background: none;
}
+
.documentDecorations-resizer {
pointer-events: auto;
background: $alt-accent;
opacity: 0.8;
}
+
+ #documentDecorations-topLeftResizer,
+ #documentDecorations-leftResizer,
+ #documentDecorations-bottomLeftResizer {
+ grid-column: 1
+ }
+
+ #documentDecorations-topResizer,
+ #documentDecorations-bottomResizer {
+ grid-column-start: 2;
+ grid-column-end: 5;
+ }
+
+ #documentDecorations-bottomRightResizer,
+ #documentDecorations-topRightResizer,
+ #documentDecorations-rightResizer {
+ grid-column-start:5;
+ grid-column-end:7;
+ }
+
#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;
}
+ .title{
+ width:100%;
+ background: lightblue;
+ grid-column-start:3;
+ 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;
+ grid-column-start: 1;
+ grid-column-end: 3;
+ pointer-events: all;
+ text-align: center;
+}
.documentDecorations-background {
- background:lightblue;
+ background: lightblue;
position: absolute;
opacity: 0.1;
}
@@ -70,7 +122,8 @@
// }
// }
.linkFlyout {
- grid-column: 1/4
+ grid-column: 1/4;
+ margin-left: 25px;
}
.linkButton-empty:hover {
@@ -85,6 +138,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 faba3b6ea..c7e4a269a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,37 +1,84 @@
-import { action, computed, observable, trace } from "mobx";
+import { action, computed, observable, trace, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { KeyStore } from '../../fields/KeyStore';
+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";
import { CollectionView } from "./collections/CollectionView";
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;
@observer
-export class DocumentDecorations extends React.Component {
+export class DocumentDecorations extends React.Component<{}, { value: string }> {
static Instance: DocumentDecorations
private _resizer = ""
private _isPointerDown = false;
-
+ private keyinput: React.RefObject<HTMLInputElement>;
+ private _documents: DocumentView[] = SelectionManager.SelectedDocuments();
private _resizeBorderWidth = 16;
+ private _linkBoxHeight = 30;
+ private _titleHeight = 20;
private _linkButton = React.createRef<HTMLDivElement>();
+ private _linkerButton = React.createRef<HTMLDivElement>();
+ //@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;
@observable private _hidden = false;
+ @observable private _opacity = 1;
@observable private _dragging = false;
+
constructor(props: Readonly<{}>) {
super(props)
-
DocumentDecorations.Instance = this
+ this.handleChange = this.handleChange.bind(this);
+ this.keyinput = React.createRef();
+ }
+
+ @action
+ handleChange = (event: any) => {
+ this._title = event.target.value;
+ };
+
+ @action
+ enterPressed = (e: any) => {
+ var key = e.keyCode || e.which;
+ // enter pressed
+ if (key == 13) {
+ var text = e.target.value;
+ if (text[0] == '#') {
+ let command = text.slice(1, text.length);
+ this._fieldKey = new Key(command)
+ // if (command == "Title" || command == "title") {
+ // this._fieldKey = KeyStore.Title;
+ // }
+ // else if (command == "Width" || command == "width") {
+ // this._fieldKey = KeyStore.Width;
+ // }
+ this._title = "changed"
+ // TODO: Change field with switch statement
+ }
+ else {
+ this._title = "changed";
+ }
+ e.target.blur();
+ }
}
@computed
get Bounds(): { x: number, y: number, b: number, r: number } {
+ this._documents = SelectionManager.SelectedDocuments();
return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
if (documentView.props.isTopMost) {
return bounds;
@@ -79,12 +126,14 @@ export class DocumentDecorations extends React.Component {
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
- })
+ DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont!.current!), dragData,
+ e.x, e.y,
+ {
+ handlers: {
+ dragComplete: action(() => this._dragging = false),
+ },
+ hideSource: true
+ })
e.stopPropagation();
}
@@ -95,6 +144,53 @@ export class DocumentDecorations extends React.Component {
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) {
+ 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) {
@@ -107,18 +203,40 @@ export class DocumentDecorations extends React.Component {
}
}
- 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, e.pageX, e.pageY, {
+ 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 => {
@@ -127,18 +245,35 @@ export class DocumentDecorations extends React.Component {
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)
- 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 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, e.x, e.y, {
+ handlers: {
+ dragComplete: action(() => { }),
+ },
+ hideSource: false
+ })
+ }
}
e.stopPropagation();
}
@@ -230,6 +365,19 @@ export class DocumentDecorations extends React.Component {
}
}
+ getValue = (): string => {
+ if (this._title === "changed" && this._documents.length > 0) {
+ let field = this._documents[0].props.Document.Get(this._fieldKey);
+ if (field instanceof TextField) {
+ return (field as TextField).GetValue();
+ }
+ else if (field instanceof NumberField) {
+ return (field as NumberField).GetValue().toString();
+ }
+ }
+ return this._title;
+ }
+
changeFlyoutContent = (): void => {
}
@@ -238,6 +386,8 @@ export class DocumentDecorations extends React.Component {
// }
render() {
var bounds = this.Bounds;
+ // console.log(this._documents.length)
+ // let test = this._documents[0].props.Document.Title;
if (this.Hidden) {
return (null);
}
@@ -255,43 +405,45 @@ export class DocumentDecorations extends React.Component {
linkButton = (<Flyout
anchorPoint={anchorPoints.RIGHT_TOP}
content={
- <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent}>
- </LinkMenu>
+ <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent} />
}>
<div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} >{linkCount}</div>
</Flyout>);
}
- return (
- <div className="documentDecorations">
- <div className="documentDecorations-background" style={{
- width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
- height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
- left: bounds.x - this._resizeBorderWidth / 2,
- top: bounds.y - this._resizeBorderWidth / 2,
- pointerEvents: this._dragging ? "none" : "all",
- zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0,
- }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} >
- </div>
- <div id="documentDecorations-container" style={{
- width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
- height: (bounds.b - bounds.y + this._resizeBorderWidth + 30) + "px",
- left: bounds.x - this._resizeBorderWidth / 2,
- top: bounds.y - this._resizeBorderWidth / 2,
- }}>
- <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-leftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-centerCont"></div>
- <div id="documentDecorations-rightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
-
- <div title="View Links" className="linkFlyout" ref={this._linkButton}>{linkButton}</div>
-
- </div >
+ return (<div className="documentDecorations">
+ <div className="documentDecorations-background" style={{
+ width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
+ height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
+ left: bounds.x - this._resizeBorderWidth / 2,
+ top: bounds.y - this._resizeBorderWidth / 2,
+ pointerEvents: this._dragging ? "none" : "all",
+ zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0,
+ }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} >
</div>
+ <div id="documentDecorations-container" style={{
+ width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
+ height: (bounds.b - bounds.y + this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight) + "px",
+ left: bounds.x - this._resizeBorderWidth / 2,
+ top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
+ opacity: this._opacity
+ }}>
+ <div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}>...</div>
+ <input ref={this.keyinput} className="title" type="text" name="dynbox" value={this.getValue()} onChange={this.handleChange} onPointerDown={this.onPointerDown} onKeyPress={this.enterPressed} />
+ <div className="documentDecorations-closeButton" onPointerDown={this.onCloseDown}>X</div>
+ <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-leftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-centerCont"></div>
+ <div id="documentDecorations-rightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+
+ <div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton} </div>
+ <div className="linkButton-linker" ref={this._linkerButton} onPointerDown={this.onLinkerButtonDown}>∞</div>
+ </div >
+ </div>
)
}
} \ No newline at end of file
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index 214c70280..c5a2a50cb 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -2,18 +2,21 @@
.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect {
position: absolute;
- top: -50000px;
- left: -50000px;
- width: 100000px;
- height: 100000px;
- .inkingCanvas-children {
- transform: translate(50000px, 50000px);
- pointer-events: none;
- }
+ top: 0;
+ left:0;
+ width: 8192px;
+ height: 8192px;
cursor:"crosshair";
pointer-events: auto;
}
+.inkingCanvas-canSelect,
+.inkingCanvas-noSelect {
+ top:-50000px;
+ left:-50000px;
+ width: 100000px;
+ height: 100000px;
+}
.inkingCanvas-noSelect {
pointer-events: none;
cursor: "arrow";
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index f7a3601bc..fed349af3 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -1,4 +1,4 @@
-import { action, computed, trace } from "mobx";
+import { action, computed, trace, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../fields/Document";
import { FieldWaiting } from "../../fields/Field";
@@ -10,34 +10,47 @@ import "./InkingCanvas.scss";
import { InkingControl } from "./InkingControl";
import { InkingStroke } from "./InkingStroke";
import React = require("react");
-import { undoBatch } from "../util/UndoManager";
+import { undoBatch, UndoManager } from "../util/UndoManager";
interface InkCanvasProps {
getScreenTransform: () => Transform;
Document: Document;
+ children: () => JSX.Element[];
}
@observer
export class InkingCanvas extends React.Component<InkCanvasProps> {
- static InkOffset: number = 50000;
+ private strokeBatch?: UndoManager.Batch;
+
+ maxCanvasDim = 8192 / 2; // 1/2 of the maximum canvas dimension for Chrome
+ @observable inkMidX: number = 0;
+ @observable inkMidY: number = 0;
private _currentStrokeId: string = "";
public static IntersectStrokeRect(stroke: StrokeData, selRect: { left: number, top: number, width: number, height: number }): boolean {
return stroke.pathData.reduce((inside: boolean, val) => inside ||
- (
- selRect.left < val.x - InkingCanvas.InkOffset &&
- selRect.left + selRect.width > val.x - InkingCanvas.InkOffset &&
- selRect.top < val.y - InkingCanvas.InkOffset &&
- selRect.top + selRect.height > val.y - InkingCanvas.InkOffset
- ), false);
+ (selRect.left < val.x && selRect.left + selRect.width > val.x &&
+ selRect.top < val.y && selRect.top + selRect.height > val.y)
+ , false);
+ }
+
+ componentDidMount() {
+ this.props.Document.GetTAsync(KeyStore.Ink, InkField, ink => runInAction(() => {
+ if (ink) {
+ let bounds = Array.from(ink.Data).reduce(([mix, max, miy, may], [id, strokeData]) =>
+ strokeData.pathData.reduce(([mix, max, miy, may], p) =>
+ [Math.min(mix, p.x), Math.max(max, p.x), Math.min(miy, p.y), Math.max(may, p.y)],
+ [mix, max, miy, may]),
+ [Number.MAX_VALUE, Number.MIN_VALUE, Number.MAX_VALUE, Number.MIN_VALUE]);
+ this.inkMidX = (bounds[0] + bounds[1]) / 2;
+ this.inkMidY = (bounds[2] + bounds[3]) / 2;
+ }
+ }));
}
@computed
get inkData(): StrokeMap {
let map = this.props.Document.GetT(KeyStore.Ink, InkField);
- if (!map || map === FieldWaiting) {
- return new Map;
- }
- return new Map(map.Data);
+ return !map || map === FieldWaiting ? new Map : new Map(map.Data);
}
set inkData(value: StrokeMap) {
@@ -49,6 +62,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
if (e.button != 0 || e.altKey || e.ctrlKey || InkingControl.Instance.selectedTool === InkTool.None) {
return;
}
+
document.addEventListener("pointermove", this.onPointerMove, true);
document.addEventListener("pointerup", this.onPointerUp, true);
e.stopPropagation();
@@ -57,6 +71,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
if (InkingControl.Instance.selectedTool != InkTool.Eraser) {
// start the new line, saves a uuid to represent the field of the stroke
this._currentStrokeId = Utils.GenerateGuid();
+ this.strokeBatch = UndoManager.StartBatch("drawing stroke");
this.inkData.set(this._currentStrokeId, {
pathData: [this.relativeCoordinatesForEvent(e.clientX, e.clientY)],
color: InkingControl.Instance.selectedColor,
@@ -64,12 +79,19 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
tool: InkingControl.Instance.selectedTool,
page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
});
+ this.strokeBatch.end();
}
- }
+ };
+ @action
onPointerUp = (e: PointerEvent): void => {
document.removeEventListener("pointermove", this.onPointerMove, true);
document.removeEventListener("pointerup", this.onPointerUp, true);
+ let coord = this.relativeCoordinatesForEvent(e.clientX, e.clientY);
+ if (Math.abs(coord.x - this.inkMidX) > 500 || Math.abs(coord.y - this.inkMidY) > 500) {
+ this.inkMidX = coord.x;
+ this.inkMidY = coord.y;
+ }
e.stopPropagation();
e.preventDefault();
}
@@ -91,11 +113,10 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
relativeCoordinatesForEvent = (ex: number, ey: number): { x: number, y: number } => {
let [x, y] = this.props.getScreenTransform().transformPoint(ex, ey);
- x += InkingCanvas.InkOffset;
- y += InkingCanvas.InkOffset;
return { x, y };
}
+ @undoBatch
@action
removeLine = (id: string): void => {
let data = this.inkData;
@@ -105,30 +126,32 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
@computed
get drawnPaths() {
- // parse data from server
let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1)
let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => {
if (strokeData.page == -1 || strokeData.page == curPage)
paths.push(<InkingStroke key={id} id={id} line={strokeData.pathData}
+ offsetX={this.maxCanvasDim - this.inkMidX}
+ offsetY={this.maxCanvasDim - this.inkMidY}
color={strokeData.color} width={strokeData.width}
tool={strokeData.tool} deleteCallback={this.removeLine} />)
return paths;
}, [] as JSX.Element[]);
- return [<svg className={`inkingCanvas-paths-markers`} key="Markers" >
+ return [<svg className={`inkingCanvas-paths-markers`} key="Markers"
+ style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
{paths.filter(path => path.props.tool == InkTool.Highlighter)}
</svg>,
- <svg className={`inkingCanvas-paths-ink`} key="Pens" >
+ <svg className={`inkingCanvas-paths-ink`} key="Pens"
+ style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
{paths.filter(path => path.props.tool != InkTool.Highlighter)}
</svg>];
}
render() {
let svgCanvasStyle = InkingControl.Instance.selectedTool != InkTool.None ? "canSelect" : "noSelect";
-
return (
<div className="inkingCanvas" >
- <svg className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} />
- {(this.props.children as any)() /* bcz: is there a better way to know that children is a function? */}
+ <div className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} />
+ {this.props.children()}
{this.drawnPaths}
</div >
)
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 52111c711..615f8af7e 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -6,6 +6,8 @@ import React = require("react");
interface StrokeProps {
+ offsetX: number;
+ offsetY: number;
id: string;
line: Array<{ x: number, y: number }>;
color: string;
@@ -28,7 +30,7 @@ export class InkingStroke extends React.Component<StrokeProps> {
}
parseData = (line: Array<{ x: number, y: number }>): string => {
- return !line.length ? "" : "M " + line.map(p => p.x + " " + p.y).join(" L ");
+ return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L ");
}
createStyle() {
@@ -43,14 +45,13 @@ export class InkingStroke extends React.Component<StrokeProps> {
}
}
-
render() {
let pathStyle = this.createStyle();
let pathData = this.parseData(this.props.line);
+ let pointerEvents: any = InkingControl.Instance.selectedTool == InkTool.Eraser ? "all" : "none";
return (
- <path className={(this._strokeTool === InkTool.Highlighter) ? "highlight" : ""}
- d={pathData} style={{ ...pathStyle, pointerEvents: "all" }} strokeLinejoin="round" strokeLinecap="round"
+ <path d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} strokeLinejoin="round" strokeLinecap="round"
onPointerOver={this.deleteStroke} onPointerDown={this.deleteStroke} />
)
}
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/Main.tsx b/src/client/views/Main.tsx
index 6f66f8f38..237eb3b6e 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -13,7 +13,7 @@ import { Documents } from '../documents/Documents';
import { Server } from '../Server';
import { setupDrag } from '../util/DragManager';
import { Transform } from '../util/Transform';
-import { UndoManager } from '../util/UndoManager';
+import { UndoManager, undoBatch } from '../util/UndoManager';
import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { ContextMenu } from './ContextMenu';
@@ -51,6 +51,7 @@ import '../northstar/utils/Extensions'
import { HistogramOperation } from '../northstar/operations/HistogramOperation';
import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel';
import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel';
+import { CollectionView } from './collections/CollectionView';
@observer
export class Main extends React.Component {
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/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4d9985db3..d453bfef3 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -200,7 +200,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
let tab = (e.target as any).parentElement as HTMLElement;
Server.GetField(docid, action((f: Opt<Field>) => {
if (f instanceof Document)
- DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]),
+ DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), e.pageX, e.pageY,
{
handlers: {
dragComplete: action(() => { }),
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 2042b2712..d8f4a0be5 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -18,6 +18,8 @@ import * as rp from "request-promise";
import { ServerUtils } from "../../../server/ServerUtil";
import { Server } from "../../Server";
import { emptyStatement } from "babel-types";
+import { CollectionDockingView } from "./CollectionDockingView";
+import { runReactions } from "mobx/lib/internal";
export interface CollectionViewProps {
fieldKey: Key;
@@ -83,7 +85,8 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
if (de.data instanceof DragManager.DocumentDragData) {
if (de.data.aliasOnDrop) {
[KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key =>
- de.data.draggedDocuments.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null));
+ de.data.draggedDocuments.map((draggedDocument: Document, i: number) =>
+ draggedDocument.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? de.data.droppedDocuments[i].SetNumber(key, f.Data) : null)));
}
let added = de.data.droppedDocuments.reduce((added, d) => this.props.addDocument(d, false), true);
if (added && de.data.removeDocument && !de.data.aliasOnDrop) {
@@ -92,6 +95,24 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
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;
}
@@ -108,6 +129,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
}
if (type.indexOf("pdf") !== -1) {
ctor = Documents.PdfDocument;
+ options.nativeWidth = 1200;
}
if (type.indexOf("html") !== -1) {
if (path.includes('localhost')) {
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<CollectionFreeFo
let l = this.props.LinkDocs;
let a = this.props.A;
let b = this.props.B;
- let x1 = a.GetNumber(KeyStore.X, 0) + a.GetNumber(KeyStore.Width, 0) / 2;
- let y1 = a.GetNumber(KeyStore.Y, 0) + a.GetNumber(KeyStore.Height, 0) / 2;
- let x2 = b.GetNumber(KeyStore.X, 0) + b.GetNumber(KeyStore.Width, 0) / 2;
- let y2 = b.GetNumber(KeyStore.Y, 0) + b.GetNumber(KeyStore.Height, 0) / 2;
+ let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2);
+ let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2);
+ let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2);
+ let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2);
return (
<line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
index 4341c82f7..30e158603 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
@@ -1,6 +1,8 @@
.collectionfreeformlinksview-svgCanvas{
transform: translate(-10000px,-10000px);
position: absolute;
+ top: 0;
+ left: 0;
width: 20000px;
height: 20000px;
pointer-events: none;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index eb20b3100..d4809ac1c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -12,6 +12,7 @@ import "./CollectionFreeFormLinksView.scss";
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
import v5 = require("uuid/v5");
+import { find } from "async";
@observer
export class CollectionFreeFormLinksView extends React.Component<CollectionViewProps> {
@@ -22,40 +23,44 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
}, () => {
let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document);
for (let i = 0; i < views.length; i++) {
- for (let j = i + 1; j < views.length; j++) {
+ for (let j = 0; j < views.length; j++) {
let srcDoc = views[j].props.Document;
let dstDoc = views[i].props.Document;
let x1 = srcDoc.GetNumber(KeyStore.X, 0);
let x1w = srcDoc.GetNumber(KeyStore.Width, -1);
let x2 = dstDoc.GetNumber(KeyStore.X, 0);
let x2w = dstDoc.GetNumber(KeyStore.Width, -1);
- if (x1w < 0 || x2w < 0)
+ if (x1w < 0 || x2w < 0 || i == j)
continue;
- dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
- srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
- let dstTarg = (protoDest ? protoDest : dstDoc);
- let srcTarg = (protoSrc ? protoSrc : srcDoc);
- let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => {
- let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
- return (bdocs.length == 0 || (bdocs[0] == dstTarg && bdocs[1] == srcTarg) || (bdocs[0] == srcTarg && bdocs[1] == dstTarg))
- });
- let brushAction = (field: ListField<Document>) => {
- let found = findBrush(field);
- if (found != -1)
- field.Data.splice(found, 1);
- };
- if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 20) {
- let linkDoc: Document = new Document();
- linkDoc.SetText(KeyStore.Title, "Histogram Brush");
- linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title);
- linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
+ let dstTarg = dstDoc;
+ let srcTarg = srcDoc;
+ let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => {
+ let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : [];
+ return (bdocs.length && ((bdocs[0] == dstTarg && bdocs[1] == srcTarg)) ? true : false)
+ });
+ let brushAction = (field: ListField<Document>) => {
+ let found = findBrush(field);
+ if (found != -1) {
+ console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title);
+ field.Data.splice(found, 1);
+ }
+ };
+ if (Math.abs(x1 + x1w - x2) < 20) {
+ let linkDoc: Document = new Document();
+ linkDoc.SetText(KeyStore.Title, "Histogram Brush");
+ linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title);
+ linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
- brushAction = brushAction = (field: ListField<Document>) => (findBrush(field) == -1) && field.Data.push(linkDoc);
+ brushAction = brushAction = (field: ListField<Document>) => {
+ if (findBrush(field) == -1) {
+ console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title);
+ (findBrush(field) == -1) && field.Data.push(linkDoc);
}
- dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
- srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
- }
- )))
+ };
+ }
+ dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+ srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+
}
}
})
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 81d21d89a..79d520069 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -26,7 +26,7 @@
border: 0px solid $light-color-secondary;
border-radius: $border-radius;
box-sizing: border-box;
- position: relative;
+ position: absolute;
overflow: hidden;
top: 0;
left: 0;
@@ -41,12 +41,12 @@
.formattedTextBox-cont {
background: $light-color-secondary;
}
-
+
opacity: 0.99;
border: 0px solid transparent;
border-radius: $border-radius;
box-sizing: border-box;
- position:relative;
+ position:absolute;
overflow: hidden;
top: 0;
left: 0;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2dcf645d0..37bb78151 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 {
@@ -73,20 +74,27 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (super.drop(e, de)) {
- if (de.data instanceof DragManager.DocumentDragData) {
- let screenX = de.x - (de.data.xOffset as number || 0);
- let screenY = de.y - (de.data.yOffset as number || 0);
+ 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(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.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/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 20132a4b1..df150a045 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -102,7 +102,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
if (e.key == "Backspace" || e.key == "Delete") {
this.marqueeSelect().map(d => this.props.removeDocument(d));
let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- if (ink && ink != FieldWaiting && ink.Data) {
+ if (ink && ink != FieldWaiting) {
this.marqueeInkDelete(ink.Data);
}
this.cleanupInteractions();
@@ -118,24 +118,24 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return d;
});
let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- if (ink && ink != FieldWaiting && ink.Data) {
- //setTimeout(() => {
- let newCollection = Documents.FreeformDocument(selected, {
- x: bounds.left,
- y: bounds.top,
- panx: 0,
- pany: 0,
- width: bounds.width,
- height: bounds.height,
- backgroundColor: "Transparent",
- ink: this.marqueeInkSelect(ink.Data),
- title: "a nested collection"
- });
- this.props.addDocument(newCollection, false);
- this.marqueeInkDelete(ink.Data);
- }
+ let inkData = ink && ink != FieldWaiting ? ink.Data : undefined;
+ //setTimeout(() => {
+ let newCollection = Documents.FreeformDocument(selected, {
+ x: bounds.left,
+ y: bounds.top,
+ panx: 0,
+ pany: 0,
+ width: bounds.width,
+ height: bounds.height,
+ backgroundColor: "Transparent",
+ ink: inkData ? this.marqueeInkSelect(inkData) : undefined,
+ title: "a nested collection"
+ });
+ this.props.addDocument(newCollection, false);
+ this.marqueeInkDelete(inkData);
// }, 100);
this.cleanupInteractions();
+ SelectionManager.DeselectAll();
}
}
@action
@@ -159,15 +159,17 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
}
@action
- marqueeInkDelete(ink: Map<any, any>, ) {
+ marqueeInkDelete(ink?: Map<any, any>) {
// bcz: this appears to work but when you restart all the deleted strokes come back -- InkField isn't observing its changes so they aren't written to the DB.
// ink.forEach((value: StrokeData, key: string, map: any) =>
// InkingCanvas.IntersectStrokeRect(value, this.Bounds) && ink.delete(key));
- let idata = new Map();
- ink.forEach((value: StrokeData, key: string, map: any) =>
- !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
- this.props.container.props.Document.SetDataOnPrototype(KeyStore.Ink, idata, InkField);
+ if (ink) {
+ let idata = new Map();
+ ink.forEach((value: StrokeData, key: string, map: any) =>
+ !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
+ this.props.container.props.Document.SetDataOnPrototype(KeyStore.Ink, idata, InkField);
+ }
}
marqueeSelect() {
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<DocumentView
return <DocumentView {...this.props}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
/>
}
+ 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 85a115f1c..5126e69f9 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,23 +1,43 @@
@import "../global_variables";
+
.documentView-node {
position: absolute;
+ top: 0;
+ left:0;
background: $light-color; //overflow: hidden;
+
&.minimized {
width: 30px;
height: 30px;
}
+
.top {
background: #232323;
height: 20px;
cursor: pointer;
}
+
.content {
padding: 20px 20px;
height: auto;
box-sizing: border-box;
}
+
.scroll-box {
overflow-y: scroll;
height: calc(100% - 20px);
}
}
+
+.minimized-box {
+ height: 10px;
+ width: 10px;
+ border-radius: 2px;
+ background: $dark-color
+}
+
+.minimized-box:hover {
+ 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 1195128dc..7514e782d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,11 +1,13 @@
import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
-import { Field, Opt, FieldWaiting } from "../../../fields/Field";
+import { Field, FieldWaiting, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
+import { BooleanField } from "../../../fields/BooleanField";
import { TextField } from "../../../fields/TextField";
+import { ServerUtils } from "../../../server/ServerUtil";
import { Utils } from "../../../Utils";
import { Documents } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
@@ -18,8 +20,6 @@ import { ContextMenu } from "../ContextMenu";
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
-import { ServerUtils } from "../../../server/ServerUtil";
-
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView>;
@@ -35,8 +35,8 @@ export interface DocumentViewProps {
SelectOnLoad: boolean;
}
export interface JsxArgs extends DocumentViewProps {
- Keys: { [name: string]: Key }
- Fields: { [name: string]: Field }
+ Keys: { [name: string]: Key };
+ Fields: { [name: string]: Field };
}
/*
@@ -55,16 +55,16 @@ Example usage of this function:
}
*/
export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
- let Keys: { [name: string]: any } = {}
- let Fields: { [name: string]: any } = {}
+ let Keys: { [name: string]: any } = {};
+ let Fields: { [name: string]: any } = {};
for (const key of keys) {
- let fn = () => { }
- Object.defineProperty(fn, "name", { value: key + "Key" })
+ let fn = () => { };
+ Object.defineProperty(fn, "name", { value: key + "Key" });
Keys[key] = fn;
}
for (const field of fields) {
- let fn = () => { }
- Object.defineProperty(fn, "name", { value: field })
+ let fn = () => { };
+ Object.defineProperty(fn, "name", { value: field });
Fields[field] = fn;
}
let args: JsxArgs = {
@@ -85,53 +85,94 @@ export interface JsxBindings {
[prop: string]: any;
}
-
-
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
private _downX: number = 0;
private _downY: number = 0;
+
private _reactionDisposer: Opt<IReactionDisposer>;
- @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); }
- @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; }
- @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
- @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
- @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
- screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
+ @computed get active(): boolean {
+ return (
+ SelectionManager.IsSelected(this) ||
+ !this.props.ContainingCollectionView ||
+ this.props.ContainingCollectionView.active()
+ );
+ }
+ @computed get topMost(): boolean {
+ return (
+ !this.props.ContainingCollectionView ||
+ this.props.ContainingCollectionView.collectionViewType ==
+ CollectionViewType.Docking
+ );
+ }
+ @computed get layout(): string {
+ return this.props.Document.GetText(
+ KeyStore.Layout,
+ "<p>Error loading layout data</p>"
+ );
+ }
+ @computed get layoutKeys(): Key[] {
+ return this.props.Document.GetData(
+ KeyStore.LayoutKeys,
+ ListField,
+ new Array<Key>()
+ );
+ }
+ @computed get layoutFields(): Key[] {
+ return this.props.Document.GetData(
+ KeyStore.LayoutFields,
+ ListField,
+ new Array<Key>()
+ );
+ }
+ screenRect = (): ClientRect | DOMRect =>
+ this._mainCont.current
+ ? this._mainCont.current.getBoundingClientRect()
+ : new DOMRect();
onPointerDown = (e: React.PointerEvent): void => {
this._downX = e.clientX;
this._downY = e.clientY;
if (e.shiftKey && e.buttons === 2) {
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()) {
e.stopPropagation();
- document.removeEventListener("pointermove", this.onPointerMove)
+ document.removeEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp)
+ document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointerup", this.onPointerUp);
}
}
- }
+ };
private dropDisposer?: DragManager.DragDropDisposer;
componentDidMount() {
if (this._mainCont.current) {
- this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+ 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(),
+ () =>
+ this.props.ContainingCollectionView &&
+ this.props.ContainingCollectionView.SelectedDocs.slice(),
() => {
- if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.indexOf(this.props.Document.Id) != -1)
+ if (
+ this.props.ContainingCollectionView &&
+ this.props.ContainingCollectionView.SelectedDocs.indexOf(
+ this.props.Document.Id
+ ) != -1
+ )
SelectionManager.SelectDoc(this, true);
- });
+ }
+ );
}
componentDidUpdate() {
@@ -139,7 +180,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
this.dropDisposer();
}
if (this._mainCont.current) {
- this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+ this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+ handlers: { drop: this.drop.bind(this) }
+ });
}
}
@@ -147,7 +190,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
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();
}
@@ -155,22 +203,28 @@ export class DocumentView extends React.Component<DocumentViewProps> {
startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
if (this._mainCont.current) {
- const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ const [left, top] = this.props
+ .ScreenToLocalTransform()
+ .inverse()
+ .transformPoint(0, 0);
let dragData = new DragManager.DocumentDragData([this.props.Document]);
dragData.aliasOnDrop = dropAliasOfDraggedDoc;
dragData.xOffset = x - left;
dragData.yOffset = y - top;
dragData.removeDocument = (dropCollectionView: CollectionView) => {
- if (this.props.RemoveDocument && this.props.ContainingCollectionView !== dropCollectionView) {
+ if (
+ this.props.RemoveDocument &&
+ this.props.ContainingCollectionView !== dropCollectionView
+ ) {
this.props.RemoveDocument(this.props.Document);
}
- }
- DragManager.StartDocumentDrag([this._mainCont.current], dragData, {
+ };
+ DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, {
handlers: {
- dragComplete: action(() => { }),
+ dragComplete: action(() => { })
},
hideSource: !dropAliasOfDraggedDoc
- })
+ });
}
}
@@ -178,52 +232,77 @@ export class DocumentView extends React.Component<DocumentViewProps> {
if (e.cancelBubble) {
return;
}
- if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
- document.removeEventListener("pointermove", this.onPointerMove)
+ if (
+ Math.abs(this._downX - e.clientX) > 3 ||
+ Math.abs(this._downY - e.clientY) > 3
+ ) {
+ document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
if (!this.topMost || e.buttons == 2 || e.altKey) {
- this.startDragging(e.x, e.y, e.ctrlKey || e.altKey);
+ this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey);
}
}
e.stopPropagation();
e.preventDefault();
- }
+ };
onPointerUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onPointerMove)
- document.removeEventListener("pointerup", this.onPointerUp)
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
e.stopPropagation();
- if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
+ if (!SelectionManager.IsSelected(this) &&
+ Math.abs(e.clientX - this._downX) < 4 &&
+ Math.abs(e.clientY - this._downY) < 4
+ ) {
SelectionManager.SelectDoc(this, e.ctrlKey);
}
- }
+ };
stopPropogation = (e: React.SyntheticEvent) => {
e.stopPropagation();
- }
+ };
deleteClicked = (): void => {
if (this.props.RemoveDocument) {
this.props.RemoveDocument(this.props.Document);
}
- }
+ };
fieldsClicked = (e: React.MouseEvent): void => {
if (this.props.AddDocument) {
- this.props.AddDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false);
+ this.props.AddDocument(
+ Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }),
+ false
+ );
}
- }
+ };
fullScreenClicked = (e: React.MouseEvent): void => {
CollectionDockingView.Instance.OpenFullScreen(this.props.Document);
ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- }
+ ContextMenu.Instance.addItem({
+ description: "Close Full Screen",
+ event: this.closeFullScreenClicked
+ });
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
+ };
closeFullScreenClicked = (e: React.MouseEvent): void => {
CollectionDockingView.Instance.CloseFullScreen();
ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- }
+ ContextMenu.Instance.addItem({
+ description: "Full Screen",
+ event: this.fullScreenClicked
+ });
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
+ };
+
+ @action
+ public minimize = (): void => {
+ this.props.Document.SetData(
+ KeyStore.Minimized,
+ true as boolean,
+ BooleanField
+ );
+ SelectionManager.DeselectAll();
+ };
@action
drop = (e: Event, de: DragManager.DropEvent) => {
@@ -235,23 +314,37 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
let linkDoc: Document = new Document();
- destDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
- sourceDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
- linkDoc.Set(KeyStore.Title, new TextField("New Link"));
- linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
- linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+ destDoc.GetTAsync(KeyStore.Prototype, Document).then(protoDest =>
+ sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
+ runInAction(() => {
+ linkDoc.Set(KeyStore.Title, new TextField("New Link"));
+ linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
+ linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
- let dstTarg = (protoDest ? protoDest : destDoc);
- let srcTarg = (protoSrc ? protoSrc : sourceDoc);
- linkDoc.Set(KeyStore.LinkedToDocs, dstTarg);
- linkDoc.Set(KeyStore.LinkedFromDocs, srcTarg);
- dstTarg.GetOrCreateAsync(KeyStore.LinkedFromDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) })
- srcTarg.GetOrCreateAsync(KeyStore.LinkedToDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) })
- }))
- )
+ let dstTarg = protoDest ? protoDest : destDoc;
+ let srcTarg = protoSrc ? protoSrc : sourceDoc;
+ linkDoc.Set(KeyStore.LinkedToDocs, dstTarg);
+ linkDoc.Set(KeyStore.LinkedFromDocs, srcTarg);
+ dstTarg.GetOrCreateAsync(
+ KeyStore.LinkedFromDocs,
+ ListField,
+ field => {
+ (field as ListField<Document>).Data.push(linkDoc);
+ }
+ );
+ srcTarg.GetOrCreateAsync(
+ KeyStore.LinkedToDocs,
+ ListField,
+ field => {
+ (field as ListField<Document>).Data.push(linkDoc);
+ }
+ );
+ })
+ )
+ );
e.stopPropagation();
}
- }
+ };
onDrop = (e: React.DragEvent) => {
if (e.isDefaultPrevented()) {
@@ -265,22 +358,43 @@ export class DocumentView extends React.Component<DocumentViewProps> {
e.stopPropagation();
e.preventDefault();
}
- }
+ };
@action
onContextMenu = (e: React.MouseEvent): void => {
e.stopPropagation();
- let moved = Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3;
+ let moved =
+ Math.abs(this._downX - e.clientX) > 3 ||
+ Math.abs(this._downY - e.clientY) > 3;
if (moved || e.isDefaultPrevented()) {
- e.preventDefault()
+ e.preventDefault();
return;
}
- e.preventDefault()
+ e.preventDefault();
- ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
- ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked })
- ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) })
- ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) })
+ if (!this.isMinimized()) {
+ ContextMenu.Instance.addItem({
+ description: "Minimize",
+ event: this.minimize
+ });
+ }
+ ContextMenu.Instance.addItem({
+ description: "Full Screen",
+ event: this.fullScreenClicked
+ });
+ ContextMenu.Instance.addItem({
+ description: "Fields",
+ event: this.fieldsClicked
+ });
+ ContextMenu.Instance.addItem({
+ description: "Center",
+ event: () => this.props.focus(this.props.Document)
+ });
+ ContextMenu.Instance.addItem({
+ description: "Open Right",
+ event: () =>
+ CollectionDockingView.Instance.AddRightSplit(this.props.Document)
+ });
ContextMenu.Instance.addItem({
description: "Copy URL",
event: () => {
@@ -294,48 +408,95 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
});
//ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
if (!this.topMost) {
// DocumentViews should stop propagation of this event
e.stopPropagation();
}
- ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ ContextMenu.Instance.addItem({
+ description: "Delete",
+ event: this.deleteClicked
+ });
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
SelectionManager.SelectDoc(this, e.ctrlKey);
- }
+ };
+ isMinimized = () => {
+ let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField);
+ if (field && field !== FieldWaiting) {
+ return field.Data;
+ }
+ };
+
+ @action
+ expand = () => {
+ this.props.Document.SetData(
+ KeyStore.Minimized,
+ false as boolean,
+ BooleanField
+ );
+ };
isSelected = () => {
return SelectionManager.IsSelected(this);
- }
+ };
select = (ctrlPressed: boolean) => {
- SelectionManager.SelectDoc(this, ctrlPressed)
- }
+ SelectionManager.SelectDoc(this, ctrlPressed);
+ };
render() {
if (!this.props.Document) {
- return (null);
+ 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);
- var backgroundcolor = this.props.Document.GetText(KeyStore.BackgroundColor, "");
- return (
- <div className="documentView-node" ref={this._mainCont}
- style={{
- background: backgroundcolor,
- width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
- height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
- transformOrigin: "left top",
- transform: `scale(${scaling} , ${scaling})`
- }}
- onDrop={this.onDrop}
- onContextMenu={this.onContextMenu}
- onPointerDown={this.onPointerDown} >
- <DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />
- </div >
- )
+
+ if (this.isMinimized()) {
+ return (
+ <div
+ className="minimized-box"
+ ref={this._mainCont}
+ style={{
+ transformOrigin: "left top",
+ transform: `scale(${scaling} , ${scaling})`
+ }}
+ onClick={this.expand}
+ onDrop={this.onDrop}
+ onPointerDown={this.onPointerDown}
+ />
+ );
+ } else {
+ var backgroundcolor = this.props.Document.GetText(
+ KeyStore.BackgroundColor,
+ ""
+ );
+ return (
+ <div
+ className="documentView-node"
+ ref={this._mainCont}
+ style={{
+ background: backgroundcolor,
+ width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
+ height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
+ transformOrigin: "left top",
+ transform: `scale(${scaling} , ${scaling})`
+ }}
+ onDrop={this.onDrop}
+ onContextMenu={this.onContextMenu}
+ onPointerDown={this.onPointerDown}
+ >
+ <DocumentContentsView
+ {...this.props}
+ isSelected={this.isSelected}
+ select={this.select}
+ layoutKey={KeyStore.Layout}
+ />
+ </div>
+ );
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 512ad7d70..0c0efc437 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -3,28 +3,25 @@ import { baseKeymap } from "prosemirror-commands";
import { history, redo, undo } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
import { schema } from "../../util/RichTextSchema";
-import { EditorState, Transaction, } from "prosemirror-state";
+import { EditorState, Transaction } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { Opt, FieldWaiting } from "../../../fields/Field";
import "./FormattedTextBox.scss";
-import React = require("react")
+import React = require("react");
import { RichTextField } from "../../../fields/RichTextField";
import { FieldViewProps, FieldView } from "./FieldView";
-import { Plugin } from 'prosemirror-state'
-import { Decoration, DecorationSet } from 'prosemirror-view'
-import { TooltipTextMenu } from "../../util/TooltipTextMenu"
+import { Plugin } from "prosemirror-state";
+import { Decoration, DecorationSet } from "prosemirror-view";
+import { TooltipTextMenu } from "../../util/TooltipTextMenu";
import { ContextMenu } from "../../views/ContextMenu";
import { inpRules } from "../../util/RichTextRules";
const { buildMenuItems } = require("prosemirror-example-setup");
const { menuBar } = require("prosemirror-menu");
-
-
-
// FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
//
// HTML Markup: <FormattedTextBox Doc={Document's ID} FieldKey={Key's name + "Key"}
-//
+//
// In Code, the node's HTML is specified in the document's parameterized structure as:
// document.SetField(KeyStore.Layout, "<FormattedTextBox doc={doc} fieldKey={<KEYNAME>Key} />");
// and the node's binding to the specified document KEYNAME as:
@@ -33,145 +30,161 @@ const { menuBar } = require("prosemirror-menu");
// 'fieldKey' property to the Key stored in LayoutKeys
// and 'doc' property to the document that is being rendered
//
-// When rendered() by React, this extracts the TextController from the Document stored at the
-// specified Key and assigns it to an HTML input node. When changes are made to this node,
+// When rendered() by React, this extracts the TextController from the Document stored at the
+// specified Key and assigns it to an HTML input node. When changes are made to this node,
// this will edit the document and assign the new value to that field.
//]
export class FormattedTextBox extends React.Component<FieldViewProps> {
-
- public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(FormattedTextBox, fieldStr) }
- private _ref: React.RefObject<HTMLDivElement>;
- private _editorView: Opt<EditorView>;
- private _reactionDisposer: Opt<IReactionDisposer>;
-
- constructor(props: FieldViewProps) {
- super(props);
-
- this._ref = React.createRef();
- this.onChange = this.onChange.bind(this);
+ public static LayoutString(fieldStr: string = "DataKey") {
+ return FieldView.LayoutString(FormattedTextBox, fieldStr);
+ }
+ private _ref: React.RefObject<HTMLDivElement>;
+ private _editorView: Opt<EditorView>;
+ private _reactionDisposer: Opt<IReactionDisposer>;
+
+ constructor(props: FieldViewProps) {
+ super(props);
+
+ this._ref = React.createRef();
+ this.onChange = this.onChange.bind(this);
+ }
+
+ dispatchTransaction = (tx: Transaction) => {
+ if (this._editorView) {
+ const state = this._editorView.state.apply(tx);
+ this._editorView.updateState(state);
+ const { doc, fieldKey } = this.props;
+ doc.SetDataOnPrototype(
+ fieldKey,
+ JSON.stringify(state.toJSON()),
+ RichTextField
+ );
+ // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField);
}
-
- dispatchTransaction = (tx: Transaction) => {
- if (this._editorView) {
- const state = this._editorView.state.apply(tx);
- this._editorView.updateState(state);
- const { doc, fieldKey } = this.props;
- doc.SetDataOnPrototype(fieldKey, JSON.stringify(state.toJSON()), RichTextField);
- // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField);
- }
+ };
+
+ componentDidMount() {
+ let state: EditorState;
+ const config = {
+ schema,
+ inpRules, //these currently don't do anything, but could eventually be helpful
+ plugins: [
+ history(),
+ keymap({ "Mod-z": undo, "Mod-y": redo }),
+ keymap(baseKeymap),
+ this.tooltipMenuPlugin()
+ ]
+ };
+
+ let field = this.props.doc.GetT(this.props.fieldKey, RichTextField);
+ if (field && field != FieldWaiting && field.Data) {
+ state = EditorState.fromJSON(config, JSON.parse(field.Data));
+ } else {
+ state = EditorState.create(config);
}
-
- componentDidMount() {
- let state: EditorState;
- const config = {
- schema,
- inpRules, //these currently don't do anything, but could eventually be helpful
- plugins: [
- history(),
- keymap({ "Mod-z": undo, "Mod-y": redo }),
- keymap(baseKeymap),
- this.tooltipMenuPlugin()
- ]
- };
-
- let field = this.props.doc.GetT(this.props.fieldKey, RichTextField);
- if (field && field != FieldWaiting && field.Data) {
- state = EditorState.fromJSON(config, JSON.parse(field.Data));
- } else {
- state = EditorState.create(config);
- }
- if (this._ref.current) {
- this._editorView = new EditorView(this._ref.current, {
- state,
- dispatchTransaction: this.dispatchTransaction
- });
- }
-
- this._reactionDisposer = reaction(() => {
- const field = this.props.doc.GetT(this.props.fieldKey, RichTextField);
- return field && field != FieldWaiting ? field.Data : undefined;
- }, (field) => {
- if (field && this._editorView) {
- this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field)));
- }
- })
- if (this.props.selectOnLoad) {
- this.props.select();
- this._editorView!.focus();
- }
+ if (this._ref.current) {
+ this._editorView = new EditorView(this._ref.current, {
+ state,
+ dispatchTransaction: this.dispatchTransaction
+ });
}
- componentWillUnmount() {
- if (this._editorView) {
- this._editorView.destroy();
+ this._reactionDisposer = reaction(
+ () => {
+ const field = this.props.doc.GetT(this.props.fieldKey, RichTextField);
+ return field && field != FieldWaiting ? field.Data : undefined;
+ },
+ field => {
+ if (field && this._editorView) {
+ this._editorView.updateState(
+ EditorState.fromJSON(config, JSON.parse(field))
+ );
}
- if (this._reactionDisposer) {
- this._reactionDisposer();
- }
- }
-
- shouldComponentUpdate() {
- return false;
- }
-
- @action
- onChange(e: React.ChangeEvent<HTMLInputElement>) {
- const { fieldKey, doc } = this.props;
- doc.SetOnPrototype(fieldKey, new RichTextField(e.target.value))
- // doc.SetData(fieldKey, e.target.value, RichTextField);
- }
- onPointerDown = (e: React.PointerEvent): void => {
- if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
- e.stopPropagation();
- }
- }
-
- //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
- textCapability = (e: React.MouseEvent): void => {
- }
-
- specificContextMenu = (e: React.MouseEvent): void => {
- ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability });
- // ContextMenu.Instance.addItem({
- // description: "Submenu",
- // items: [
- // {
- // description: "item 1", event:
- // },
- // {
- // description: "item 2", event:
- // }
- // ]
- // })
- // e.stopPropagation()
-
- }
-
- onPointerWheel = (e: React.WheelEvent): void => {
- e.stopPropagation();
+ }
+ );
+ if (this.props.selectOnLoad) {
+ this.props.select();
+ this._editorView!.focus();
}
+ }
- tooltipMenuPlugin() {
- return new Plugin({
- view(_editorView) {
- return new TooltipTextMenu(_editorView)
- }
- })
+ componentWillUnmount() {
+ if (this._editorView) {
+ this._editorView.destroy();
}
- onKeyPress(e: React.KeyboardEvent) {
- e.stopPropagation();
- // stop propagation doesn't seem to stop propagation of native keyboard events.
- // so we set a flag on the native event that marks that the event's been handled.
- // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
+ if (this._reactionDisposer) {
+ this._reactionDisposer();
}
- render() {
- return (<div className="formattedTextBox-cont"
- onKeyDown={this.onKeyPress}
- onKeyPress={this.onKeyPress}
- onPointerDown={this.onPointerDown}
- onContextMenu={this.specificContextMenu}
- // tfs: do we need this event handler
- onWheel={this.onPointerWheel}
- ref={this._ref} />)
+ }
+
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ @action
+ onChange(e: React.ChangeEvent<HTMLInputElement>) {
+ const { fieldKey, doc } = this.props;
+ doc.SetOnPrototype(fieldKey, new RichTextField(e.target.value));
+ // doc.SetData(fieldKey, e.target.value, RichTextField);
+ }
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
+ e.stopPropagation();
}
-} \ No newline at end of file
+ };
+
+ //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
+ textCapability = (e: React.MouseEvent): void => {};
+
+ specificContextMenu = (e: React.MouseEvent): void => {
+ ContextMenu.Instance.addItem({
+ description: "Text Capability",
+ event: this.textCapability
+ });
+
+ // ContextMenu.Instance.addItem({
+ // description: "Submenu",
+ // items: [
+ // {
+ // description: "item 1", event:
+ // },
+ // {
+ // description: "item 2", event:
+ // }
+ // ]
+ // })
+ // e.stopPropagation()
+ };
+
+ onPointerWheel = (e: React.WheelEvent): void => {
+ e.stopPropagation();
+ };
+
+ tooltipMenuPlugin() {
+ return new Plugin({
+ view(_editorView) {
+ return new TooltipTextMenu(_editorView);
+ }
+ });
+ }
+ onKeyPress(e: React.KeyboardEvent) {
+ e.stopPropagation();
+ // stop propagation doesn't seem to stop propagation of native keyboard events.
+ // so we set a flag on the native event that marks that the event's been handled.
+ // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
+ }
+ render() {
+ return (
+ <div
+ className="formattedTextBox-cont"
+ onKeyDown={this.onKeyPress}
+ onKeyPress={this.onKeyPress}
+ onPointerDown={this.onPointerDown}
+ onContextMenu={this.specificContextMenu}
+ // tfs: do we need this event handler
+ onWheel={this.onPointerWheel}
+ ref={this._ref}
+ />
+ );
+ }
+}
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/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index ba022b007..7039b0c41 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,7 @@ 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";
+import { SelectionManager } from "../../util/SelectionManager";
/** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
* This method renders PDF and puts all kinds of functionalities such as annotation, highlighting,
@@ -58,6 +58,8 @@ export class PDFBox extends React.Component<FieldViewProps> {
private _mainDiv = React.createRef<HTMLDivElement>()
private _pdf = React.createRef<HTMLCanvasElement>();
+ @observable private _renderAsSvg = true;
+
//very useful for keeping track of X and y position throughout the PDF Canvas
private initX: number = 0;
private initY: number = 0;
@@ -92,9 +94,9 @@ export class PDFBox extends React.Component<FieldViewProps> {
componentDidMount() {
this._reactionDisposer = reaction(
- () => [this.curPage, this.thumbnailPage],
+ () => [SelectionManager.SelectedDocuments().slice()],
() => {
- if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage != this.thumbnailPage) {
+ if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage != this.thumbnailPage && !this.props.isSelected()) {
this.saveThumbnail();
this._interactive = true;
}
@@ -159,7 +161,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
document.execCommand("HiliteColor", false, colour);
}
- if (sel && range) {
+ if (range && sel) {
sel.removeAllRanges();
sel.addRange(range);
@@ -376,18 +378,21 @@ export class PDFBox extends React.Component<FieldViewProps> {
@action
saveThumbnail = () => {
+ this._renderAsSvg = false;
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 })
- .then(function (dataUrl: string) {
+ 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(action((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));
- })
+ me._renderAsSvg = true;
+ }))
.catch(function (error: any) {
console.error('oops, something went wrong!', error);
});
- }, 1000);
+ }, 250);
}
@action
@@ -427,9 +432,6 @@ export class PDFBox extends React.Component<FieldViewProps> {
this.props.doc.SetNumber(KeyStore.Height, nativeHeight / nativeWidth * this.props.doc.GetNumber(KeyStore.Width, 0));
this.props.doc.SetNumber(KeyStore.NativeHeight, nativeHeight);
}
- if (!this.props.doc.GetT(KeyStore.Thumbnail, ImageField)) {
- this.saveThumbnail();
- }
}
@computed
@@ -439,7 +441,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
let pdfUrl = this.props.doc.GetT(this.props.fieldKey, PDFField);
let xf = this.props.doc.GetNumber(KeyStore.NativeHeight, 0) / renderHeight;
return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
- <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`}>
+ <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : ""}>
<Measure onResize={this.setScaling}>
{({ measureRef }) =>
<div className="pdfBox-page" ref={measureRef}>
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<IProps> {
+ private initX: number = 0;
+ private initY: number = 0;
- private initX: number = 0;
- private initY: number = 0;
+ private _ref = React.createRef<HTMLCanvasElement>();
+ private ctx: any; //context that keeps track of sticky canvas
- private _ref = React.createRef<HTMLCanvasElement>();
- 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 (
- <div onPointerDown={this.drawDown}>
- <canvas ref={this._ref} height={this.props.Height} width={this.props.Width}
- style={{
- position: "absolute",
- top: "20px",
- left: "0px",
- zIndex: 1,
- background: "yellow",
- transform: `translate(${this.props.X}px, ${this.props.Y}px)`,
- opacity: 0.4
- }}
- />
-
- </div>
- );
- }
-} \ No newline at end of file
+ render() {
+ return (
+ <div onPointerDown={this.drawDown}>
+ <canvas
+ ref={this._ref}
+ height={this.props.Height}
+ width={this.props.Width}
+ style={{
+ position: "absolute",
+ top: "20px",
+ left: "0px",
+ zIndex: 1,
+ background: "yellow",
+ transform: `translate(${this.props.X}px, ${this.props.Y}px)`,
+ opacity: 0.4
+ }}
+ />
+ </div>
+ );
+ }
+}
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;