aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/DocumentDecorations.scss51
-rw-r--r--src/DocumentDecorations.tsx40
-rw-r--r--src/Main.scss5
-rw-r--r--src/Main.tsx23
-rw-r--r--src/documents/Documents.ts1
-rw-r--r--src/util/DragManager.ts109
-rw-r--r--src/views/freeformcanvas/CollectionFreeFormView.tsx4
-rw-r--r--src/views/nodes/DocumentView.tsx49
-rw-r--r--src/views/nodes/FieldTextBox.scss3
-rw-r--r--src/views/nodes/FieldTextBox.tsx3
10 files changed, 194 insertions, 94 deletions
diff --git a/src/DocumentDecorations.scss b/src/DocumentDecorations.scss
index fff4d201a..2840d782b 100644
--- a/src/DocumentDecorations.scss
+++ b/src/DocumentDecorations.scss
@@ -1,34 +1,31 @@
#documentDecorations-container {
position: absolute;
- z-index: 1000;
display: grid;
grid-template-rows: 20px 1fr 20px;
grid-template-columns: 20px 1fr 20px;
pointer-events: none;
-}
-
-#documentDecorations-centerCont {
- background: none;
-}
-
-.documentDecorations-resizer {
- pointer-events: auto;
- background: lightblue;
- 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;
+ #documentDecorations-centerCont {
+ background: none;
+ }
+ .documentDecorations-resizer {
+ pointer-events: auto;
+ background: lightblue;
+ 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;
+ }
} \ No newline at end of file
diff --git a/src/DocumentDecorations.tsx b/src/DocumentDecorations.tsx
index d7466dcac..cf7c6d8b5 100644
--- a/src/DocumentDecorations.tsx
+++ b/src/DocumentDecorations.tsx
@@ -15,44 +15,21 @@ export class DocumentDecorations extends React.Component {
}
get x(): number {
- let left = Number.MAX_VALUE;
- SelectionManager.SelectedDocuments().forEach(element => {
- if (element.mainCont.current !== null) {
- left = Math.min(element.mainCont.current.getBoundingClientRect().left, left)
- }
- });
- return left;
+ return SelectionManager.SelectedDocuments().reduce((left, element) => Math.min(element.screenRect.left, left), Number.MAX_VALUE);
}
get y(): number {
- let top = Number.MAX_VALUE;
- SelectionManager.SelectedDocuments().forEach(element => {
- if (element.mainCont.current !== null) {
- top = Math.min(element.mainCont.current.getBoundingClientRect().top, top)
- }
- });
- return top;
+ return SelectionManager.SelectedDocuments().reduce((top, element) => Math.min(element.screenRect.top, top), Number.MAX_VALUE);
}
get height(): number {
- return (SelectionManager.SelectedDocuments().reduce((bottom, element) => {
- if (element.mainCont.current !== null) {
- return Math.max(element.mainCont.current.getBoundingClientRect().bottom, bottom)
- }
- else {
- return bottom
- }
- }, Number.MIN_VALUE)) - this.y;
+ return (SelectionManager.SelectedDocuments().reduce((bottom, element) => Math.max(element.screenRect.bottom, bottom),
+ Number.MIN_VALUE)) - this.y;
}
get width(): number {
- let right = Number.MIN_VALUE;
- SelectionManager.SelectedDocuments().forEach(element => {
- if (element.mainCont.current !== null) {
- right = Math.max(element.mainCont.current.getBoundingClientRect().right, right)
- }
- });
- return right - this.x;
+ return SelectionManager.SelectedDocuments().reduce((right, element) => Math.max(element.screenRect.right, right),
+ Number.MIN_VALUE) - this.x;
}
private _resizer = ""
@@ -129,8 +106,9 @@ export class DocumentDecorations extends React.Component {
}
SelectionManager.SelectedDocuments().forEach(element => {
- if (element.mainCont.current !== null) {
- let scale = element.width / element.mainCont.current.getBoundingClientRect().width;
+ const rect = element.screenRect;
+ if (rect.width !== 0) {
+ let scale = element.width / rect.width;
let actualdW = Math.max(element.width + (dW * scale), 20);
let actualdH = Math.max(element.height + (dH * scale), 20);
element.x += dX * (actualdW - element.width);
diff --git a/src/Main.scss b/src/Main.scss
index f986d2c96..5fa5b2728 100644
--- a/src/Main.scss
+++ b/src/Main.scss
@@ -22,4 +22,9 @@ h1 {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
+}
+
+p {
+ margin: 0px;
+ padding: 0px;
} \ No newline at end of file
diff --git a/src/Main.tsx b/src/Main.tsx
index 9ce1dd4e9..7c132f179 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -21,40 +21,27 @@ configure({
const mainNodeCollection = new NodeCollectionStore();
ReactDOM.render((
<div>
- <h1>Dash Web</h1>
- <DocumentDecorations />
<FreeFormCanvas store={mainNodeCollection} />
+ <DocumentDecorations />
+ <button onClick={minus}>-</button>
</div>), document.getElementById('root'));
+function minus() {
-
-// create a bunch of text and video nodes (you probably want to delete this at some point)
-let numNodes = 300;
-let maxX = 10000;
-let maxY = 10000;
-let nodes:NodeStore[] = []
-for (let i = 0; i < numNodes; i++) {
- nodes.push(new StaticTextNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Text Node Title", Text: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?" }));
}
-
-for (let i = 0; i < 20; i++) {
- nodes.push(new VideoNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Video Node Title", Url: "http://cs.brown.edu/people/peichman/downloads/cted.mp4" }));
-}
-
runInAction(() => {
- mainNodeCollection.AddNodes(nodes);
let doc1 = Documents.TextDocument("Hello world");
let doc2 = doc1.MakeDelegate();
doc2.SetField(KS.X, new NumberField(150));
doc2.SetField(KS.Y, new NumberField(20));
- let doc3 = Documents.ImageDocument("https://static.boredpanda.com/blog/wp-content/uploads/2018/04/5acb63d83493f__700-png.jpg", {
+ let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
x: 450, y: 500
});
let docset = new Array<Document>(doc1, doc2);
let doc4 = Documents.CollectionDocument(docset, {
x: 100, y: 400
});
- let doc5 = Documents.ImageDocument("https://static.boredpanda.com/blog/wp-content/uploads/2018/04/5acb63d83493f__700-png.jpg", {
+ let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
x: 650, y: 500
});
mainNodeCollection.Docs.push(doc1);
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts
index cc08f4123..084666b95 100644
--- a/src/documents/Documents.ts
+++ b/src/documents/Documents.ts
@@ -57,6 +57,7 @@ export namespace Documents {
imageProto.SetField(KeyStore.Width, new NumberField(300));
imageProto.SetField(KeyStore.Height, new NumberField(300));
imageProto.SetField(KeyStore.Layout, new TextField('<img src={Data} alt="Image not found"/>'));
+ // imageProto.SetField(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />'));
imageProto.SetField(KeyStore.LayoutFields, new ListField([KeyStore.Data]));
}
return imageProto;
diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts
new file mode 100644
index 000000000..1da590072
--- /dev/null
+++ b/src/util/DragManager.ts
@@ -0,0 +1,109 @@
+import { Opt } from "../fields/Field";
+
+export namespace DragManager {
+ export let rootId = "root";
+ let dragDiv: HTMLDivElement;
+
+ export enum DragButtons {
+ Left = 1, Right = 2, Both = Left | Right
+ }
+
+ interface DragOptions {
+ handlers: DragHandlers;
+
+ buttons: number;
+ }
+
+ export interface DragDisposer {
+ (): void;
+ }
+
+ export class DragStartEvent {
+ private _cancelled: boolean = false;
+ get cancelled() { return this._cancelled };
+
+ cancel() { this._cancelled = true; };
+ }
+
+ export class DragCompleteEvent {
+
+ }
+
+ export interface DragHandlers {
+ dragStart: (e: DragStartEvent) => void;
+ dragComplete: (e: DragCompleteEvent) => void;
+ }
+
+ export function MakeDraggable(element: HTMLElement, options: DragOptions): DragDisposer {
+ if ("draggable" in element.dataset) {
+ throw new Error("Element is already draggable, can't make it draggable again");
+ }
+ element.dataset["draggable"] = "true";
+ const dispose = () => {
+ document.removeEventListener("pointerup", upHandler);
+ document.removeEventListener("pointermove", startDragHandler);
+ }
+ const startDragHandler = (e: PointerEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ dispose();
+ StartDrag(element, e, options);
+ }
+ const upHandler = (e: PointerEvent) => {
+ dispose();
+ };
+ const downHandler = (e: PointerEvent) => {
+ document.addEventListener("pointermove", startDragHandler);
+ document.addEventListener("pointerup", upHandler);
+ };
+ element.addEventListener("pointerdown", downHandler);
+
+ return () => {
+ element.removeEventListener("pointerdown", downHandler);
+ element.dataset["draggable"] = undefined;
+ }
+ }
+
+ function StartDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions) {
+ if (!dragDiv) {
+ const root = document.getElementById(rootId);
+ if (!root) {
+ throw new Error("No root element found");
+ }
+ dragDiv = document.createElement("div");
+ root.appendChild(dragDiv);
+ }
+ if ((e.buttons & options.buttons) === 0) {
+ return;
+ }
+ let event = new DragStartEvent();
+ options.handlers.dragStart(event);
+ if (event.cancelled) {
+ return;
+ }
+ let x = e.x, y = e.y;
+ let dragElement = ele.cloneNode(true) as HTMLElement;
+ dragElement.style.position = "absolute";
+ dragElement.style.transform = `translate(${x}px, ${y}px)`;
+ dragDiv.appendChild(dragElement);
+
+ const moveHandler = (e: PointerEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ x += e.movementX;
+ y += e.movementY;
+ dragElement.style.transform = `translate(${x}px, ${y}px)`;
+ };
+ const upHandler = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", moveHandler, true);
+ document.removeEventListener("pointerup", upHandler);
+ FinishDrag(dragElement, options);
+ };
+ document.addEventListener("pointermove", moveHandler, true);
+ document.addEventListener("pointerup", upHandler);
+ }
+
+ function FinishDrag(ele: HTMLElement, options: DragOptions) {
+ dragDiv.removeChild(ele);
+ }
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx
index 4e9e0cd21..d9a88fcd3 100644
--- a/src/views/freeformcanvas/CollectionFreeFormView.tsx
+++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx
@@ -14,7 +14,7 @@ import { DocumentDecorations } from "../../DocumentDecorations";
interface IProps {
fieldKey: Key;
doc: Document;
- isSelected: boolean;
+ isSelected: () => boolean;
}
@observer
@@ -28,7 +28,7 @@ export class CollectionFreeFormView extends React.Component<IProps> {
@action
onPointerDown = (e: React.PointerEvent): void => {
- if (!this.props.isSelected) {
+ if (!this.props.isSelected()) {
return;
}
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx
index e37172943..cdc20cdfe 100644
--- a/src/views/nodes/DocumentView.tsx
+++ b/src/views/nodes/DocumentView.tsx
@@ -12,6 +12,8 @@ import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView
import "./NodeView.scss"
import { SelectionManager } from "../../util/SelectionManager";
import { DocumentDecorations } from "../../DocumentDecorations";
+import { SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS } from "constants";
+import { DragManager } from "../../util/DragManager";
const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
interface IProps {
@@ -22,8 +24,11 @@ interface IProps {
export class DocumentView extends React.Component<IProps> {
private _mainCont = React.createRef<HTMLDivElement>();
- get mainCont(): React.RefObject<HTMLDivElement> {
- return this._mainCont
+ get screenRect(): ClientRect | DOMRect {
+ if(this._mainCont.current) {
+ return this._mainCont.current.getBoundingClientRect();
+ }
+ return new DOMRect();
}
@computed
@@ -83,13 +88,26 @@ export class DocumentView extends React.Component<IProps> {
}
@computed
- get selected() : boolean {
+ get selected(): boolean {
return SelectionManager.IsSelected(this)
}
private _isPointerDown = false;
+ componentDidMount() {
+ if(this._mainCont.current) {
+ DragManager.MakeDraggable(this._mainCont.current, {
+ buttons: 3,
+ handlers: {
+ dragComplete: () => {},
+ dragStart: () => {}
+ }
+ })
+ }
+ }
+
onPointerDown = (e: React.PointerEvent): void => {
+ return;
e.stopPropagation();
if (e.button === 2) {
this._isPointerDown = true;
@@ -97,8 +115,9 @@ export class DocumentView extends React.Component<IProps> {
document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointerup", this.onPointerUp);
+ } else {
+ SelectionManager.SelectDoc(this, e.ctrlKey)
}
- SelectionManager.SelectDoc(this, e.ctrlKey)
}
onPointerUp = (e: PointerEvent): void => {
@@ -108,8 +127,6 @@ export class DocumentView extends React.Component<IProps> {
this._isPointerDown = false;
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
- console.log(this.x);
- console.log(this.y)
DocumentDecorations.Instance.opacity = 1
}
}
@@ -126,8 +143,8 @@ export class DocumentView extends React.Component<IProps> {
}
onDragStart = (e: React.DragEvent<HTMLDivElement>): void => {
- if (this.mainCont.current !== null) {
- this.mainCont.current.style.opacity = "0";
+ if (this._mainCont.current !== null) {
+ this._mainCont.current.style.opacity = "0";
// e.dataTransfer.setDragImage()
}
}
@@ -136,7 +153,7 @@ export class DocumentView extends React.Component<IProps> {
let doc = this.props.dvm.Doc;
let bindings: any = {
doc: doc,
- isSelected: this.selected
+ isSelected: () => this.selected
};
for (const key of this.layoutKeys) {
bindings[key.Name + "Key"] = key;
@@ -147,22 +164,24 @@ export class DocumentView extends React.Component<IProps> {
bindings[key.Name] = field.GetValue();
}
}
-
+
return (
<div className="node" ref={this._mainCont} style={{
- transform: this.transform,
- width: this.width,
- height: this.height,
- }}
+ transform: this.transform,
+ width: this.width,
+ height: this.height,
+ }}
onContextMenu={
(e) => {
e.preventDefault()
- }}
+ }}
onPointerDown={this.onPointerDown}>
<JsxParser
components={{ FieldTextBox, FreeFormCanvas, CollectionFreeFormView }}
bindings={bindings}
jsx={this.layout}
+ showWarnings={true}
+ onError={(test: any) => { console.log(test) }}
/>
</div>
);
diff --git a/src/views/nodes/FieldTextBox.scss b/src/views/nodes/FieldTextBox.scss
new file mode 100644
index 000000000..2885caa4c
--- /dev/null
+++ b/src/views/nodes/FieldTextBox.scss
@@ -0,0 +1,3 @@
+.ProseMirror:focus {
+ outline: none !important
+} \ No newline at end of file
diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx
index dbac3906a..2cd55e26e 100644
--- a/src/views/nodes/FieldTextBox.tsx
+++ b/src/views/nodes/FieldTextBox.tsx
@@ -13,6 +13,8 @@ import {baseKeymap} from "prosemirror-commands"
import {undo, redo, history} from "prosemirror-history"
import { Opt } from "../../fields/Field";
+import "./FieldTextBox.scss"
+
interface IProps {
fieldKey:Key;
doc:Document;
@@ -34,7 +36,6 @@ interface IProps {
// specified Key and assigns it to an HTML input node. When changes are made tot his node,
// this will edit the document and assign the new value to that field.
//
-@observer
export class FieldTextBox extends React.Component<IProps> {
private _ref: React.RefObject<HTMLDivElement>;
private _editorView: Opt<EditorView>;