aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DocumentDecorations.tsx17
-rw-r--r--src/Main.tsx54
-rw-r--r--src/Utils.ts2
-rw-r--r--src/documents/Documents.ts37
-rw-r--r--src/fields/Document.ts6
-rw-r--r--src/fields/Key.ts1
-rw-r--r--src/util/DragManager.ts23
-rw-r--r--src/viewmodels/DocumentViewModel.ts11
-rw-r--r--src/views/collections/CollectionDockingView.scss386
-rw-r--r--src/views/collections/CollectionDockingView.tsx202
-rw-r--r--src/views/collections/CollectionFreeFormView.scss (renamed from src/views/freeformcanvas/CollectionFreeFormView.scss)4
-rw-r--r--src/views/collections/CollectionFreeFormView.tsx (renamed from src/views/freeformcanvas/CollectionFreeFormView.tsx)72
-rw-r--r--src/views/nodes/DocumentView.tsx94
-rw-r--r--src/views/nodes/FieldTextBox.tsx22
-rw-r--r--src/views/nodes/TextNodeView.tsx8
15 files changed, 792 insertions, 147 deletions
diff --git a/src/DocumentDecorations.tsx b/src/DocumentDecorations.tsx
index 8145ba732..1cf875ea5 100644
--- a/src/DocumentDecorations.tsx
+++ b/src/DocumentDecorations.tsx
@@ -1,10 +1,9 @@
-import {observable, computed} from "mobx";
+import { observable, computed } from "mobx";
import React = require("react");
-import {DocumentView} from "./views/nodes/DocumentView";
-import {SelectionManager} from "./util/SelectionManager";
-import {observer} from "mobx-react";
+import { SelectionManager } from "./util/SelectionManager";
+import { observer } from "mobx-react";
import './DocumentDecorations.scss'
-import {CollectionFreeFormView} from "./views/freeformcanvas/CollectionFreeFormView";
+import { CollectionFreeFormView } from "./views/collections/CollectionFreeFormView";
@observer
export class DocumentDecorations extends React.Component {
@@ -20,15 +19,19 @@ export class DocumentDecorations extends React.Component {
}
@computed
- get Bounds(): {x: number, y: number, b: number, r: number} {
+ get Bounds(): { x: number, y: number, b: number, r: number } {
return SelectionManager.SelectedDocuments().reduce((bounds, element) => {
+ if (element.props.ContainingCollectionView != undefined &&
+ !(element.props.ContainingCollectionView instanceof CollectionFreeFormView)) {
+ return bounds;
+ }
var spt = element.TransformToScreenPoint(0, 0);
var bpt = element.TransformToScreenPoint(element.width, element.height);
return {
x: Math.min(spt.ScreenX, bounds.x), y: Math.min(spt.ScreenY, bounds.y),
r: Math.max(bpt.ScreenX, bounds.r), b: Math.max(bpt.ScreenY, bounds.b)
}
- }, {x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE});
+ }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
}
@computed
diff --git a/src/Main.tsx b/src/Main.tsx
index 7560abca7..02b866753 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -12,10 +12,9 @@ import { configure, runInAction, action } from 'mobx';
import { NodeStore } from './stores/NodeStore';
import { Documents } from './documents/Documents';
import { DocumentDecorations } from './DocumentDecorations';
-import { CollectionFreeFormView } from './views/freeformcanvas/CollectionFreeFormView';
+import { CollectionFreeFormView } from './views/collections/CollectionFreeFormView';
import { ListField } from './fields/ListField';
import { DocumentView } from './views/nodes/DocumentView';
-import { DocumentViewModel } from './viewmodels/DocumentViewModel';
import { ContextMenu } from './views/ContextMenu';
configure({
@@ -23,8 +22,8 @@ configure({
});
const mainNodeCollection = new Array<Document>();
-let mainContainer = Documents.CollectionDocument(mainNodeCollection, {
- x: 0, y: 0, width: window.screen.width, height: window.screen.height
+let mainContainer = Documents.DockDocument(mainNodeCollection, {
+ x: 0, y: 0, width: window.screen.width, height: window.screen.height, title: "main container"
})
window.addEventListener("drop", function (e) {
@@ -39,37 +38,48 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
}
}), true)
-ReactDOM.render((
- <div style={{ display: "grid" }}>
- <h1>Dash Web</h1>
- <DocumentView Document={mainContainer} ContainingCollectionView={undefined} ContainingDocumentView={undefined} />
- <DocumentDecorations />
- <ContextMenu />
- </div>), document.getElementById('root'));
-runInAction(() => {
- let doc1 = Documents.TextDocument("Hello world");
+//runInAction(() =>
+{
+ let doc1 = Documents.TextDocument("Hello world", { title: "hello" });
let doc2 = doc1.MakeDelegate();
doc2.SetField(KS.X, new NumberField(150));
doc2.SetField(KS.Y, new NumberField(20));
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 docset = new Array<Document>(doc1, doc2, doc3);
let doc4 = Documents.CollectionDocument(docset, {
- x: 0, y: 400
+ x: 0, y: 400, title: "mini collection"
});
let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
- x: 650, y: 500
+ x: 650, y: 500, width: 600, height: 600, title: "cat"
});
- let mainNodes = mainContainer.GetFieldT(KeyStore.Data, ListField);
+ let docset2 = new Array<Document>(doc4, doc1, doc3);
+ let doc6 = Documents.DockDocument(docset2, {
+ x: 350, y: 100, width: 600, height: 600, title: "docking collection"
+ });
+ let mainNodes = null;// mainContainer.GetFieldT(KeyStore.Data, ListField);
if (!mainNodes) {
mainNodes = new ListField<Document>();
- mainContainer.SetField(KeyStore.Data, mainNodes);
}
- mainNodes.Data.push(doc1);
- mainNodes.Data.push(doc2);
+ // mainNodes.Data.push(doc1);
+ // mainNodes.Data.push(doc2);
mainNodes.Data.push(doc4);
- mainNodes.Data.push(doc3);
+ // mainNodes.Data.push(doc3);
mainNodes.Data.push(doc5);
-}); \ No newline at end of file
+ // mainNodes.Data.push(doc1);
+ mainNodes.Data.push(doc2);
+ //mainNodes.Data.push(doc6);
+ mainContainer.SetField(KeyStore.Data, mainNodes);
+}
+//);
+
+ReactDOM.render((
+ <div style={{ display: "grid" }}>
+ <h1>Dash Web</h1>
+ <DocumentView Document={mainContainer} ContainingCollectionView={undefined} ContainingDocumentView={undefined} />
+ <DocumentDecorations />
+ <ContextMenu />
+ </div>),
+ document.getElementById('root')); \ No newline at end of file
diff --git a/src/Utils.ts b/src/Utils.ts
index 948b6176e..cc1d8f6c6 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -13,7 +13,7 @@ export class Utils {
public static GetScreenTransform(ele: HTMLElement): { scale: number, translateX: number, translateY: number } {
const rect = ele.getBoundingClientRect();
- const scale = rect.width / ele.offsetWidth;
+ const scale = ele.offsetWidth == 0 && rect.width == 0 ? 1 : rect.width / ele.offsetWidth;
const translateX = rect.left;
const translateY = rect.top;
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts
index 60fa79eea..318a6d7a3 100644
--- a/src/documents/Documents.ts
+++ b/src/documents/Documents.ts
@@ -3,12 +3,15 @@ import { KeyStore } from "../fields/Key";
import { TextField } from "../fields/TextField";
import { NumberField } from "../fields/NumberField";
import { ListField } from "../fields/ListField";
+import { FieldTextBox } from "../views/nodes/FieldTextBox";
+import { CollectionDockingView } from "../views/collections/CollectionDockingView";
interface DocumentOptions {
x?: number;
y?: number;
width?: number;
height?: number;
+ title?: string;
}
export namespace Documents {
@@ -25,6 +28,9 @@ export namespace Documents {
if (options.height) {
doc.SetFieldValue(KeyStore.Height, options.height, NumberField);
}
+ if (options.title) {
+ doc.SetFieldValue(KeyStore.Title, options.title, TextField);
+ }
doc.SetFieldValue(KeyStore.Scale, 1, NumberField);
doc.SetFieldValue(KeyStore.PanX, 0, NumberField);
doc.SetFieldValue(KeyStore.PanY, 0, NumberField);
@@ -38,8 +44,8 @@ export namespace Documents {
textProto.SetField(KeyStore.Y, new NumberField(0));
textProto.SetField(KeyStore.Width, new NumberField(300));
textProto.SetField(KeyStore.Height, new NumberField(150));
- textProto.SetField(KeyStore.Layout, new TextField("<FieldTextBox doc={Document} fieldKey={DataKey} />"));
- textProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data]));
+ textProto.SetField(KeyStore.Layout, new TextField(FieldTextBox.LayoutString()));
+ textProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ]));
}
return textProto;
}
@@ -51,6 +57,29 @@ export namespace Documents {
return doc;
}
+
+ let dockProto: Document;
+ function GetDockPrototype(): Document {
+ if (!dockProto) {
+ dockProto = new Document();
+ dockProto.SetField(KeyStore.X, new NumberField(0));
+ dockProto.SetField(KeyStore.Y, new NumberField(0));
+ dockProto.SetField(KeyStore.Width, new NumberField(300));
+ dockProto.SetField(KeyStore.Height, new NumberField(150));
+ dockProto.SetField(KeyStore.Layout, new TextField(CollectionDockingView.LayoutString()));
+ dockProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ]));
+ }
+ return dockProto;
+ }
+
+ export function DockDocument(documents: Array<Document>, options: DocumentOptions = {}): Document {
+ let doc = GetDockPrototype().MakeDelegate();
+ setupOptions(doc, options);
+ doc.SetField(KeyStore.Data, new ListField(documents));
+ return doc;
+ }
+
+
let imageProto: Document;
function GetImagePrototype(): Document {
if (!imageProto) {
@@ -61,7 +90,7 @@ export namespace Documents {
imageProto.SetField(KeyStore.Height, new NumberField(300));
imageProto.SetField(KeyStore.Layout, new TextField('<img src={Data} draggable="false" width="100%" alt="Image not found"/>'));
// imageProto.SetField(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />'));
- imageProto.SetField(KeyStore.LayoutFields, new ListField([KeyStore.Data]));
+ imageProto.SetField(KeyStore.LayoutFields, new ListField([ KeyStore.Data ]));
}
return imageProto;
}
@@ -85,7 +114,7 @@ export namespace Documents {
collectionProto.SetField(KeyStore.Width, new NumberField(300));
collectionProto.SetField(KeyStore.Height, new NumberField(300));
collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>'));
- collectionProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data]));
+ collectionProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ]));
}
return collectionProto;
}
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 4945d1474..0551a74b0 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -1,12 +1,16 @@
import { Field, Cast, Opt } from "./Field"
import { Key, KeyStore } from "./Key"
-import { ObservableMap } from "mobx";
import { NumberField } from "./NumberField";
+import { ObservableMap, computed } from "mobx";
import { TextField } from "./TextField";
export class Document extends Field {
private fields: ObservableMap<Key, Field> = new ObservableMap();
+ static _untitledDocName = "<untitled>";
+ @computed
+ public get Title() { return this.GetFieldValue(KeyStore.Title, TextField, Document._untitledDocName); }
+
GetField(key: Key, ignoreProto: boolean = false): Opt<Field> {
let field: Opt<Field>;
if (ignoreProto) {
diff --git a/src/fields/Key.ts b/src/fields/Key.ts
index f8418d5c0..61b3cdd37 100644
--- a/src/fields/Key.ts
+++ b/src/fields/Key.ts
@@ -34,6 +34,7 @@ export namespace KeyStore {
export let Prototype = new Key("Prototype");
export let X = new Key("X");
export let Y = new Key("Y");
+ export let Title = new Key("Title");
export let PanX = new Key("PanX");
export let PanY = new Key("PanY");
export let Scale = new Key("Scale");
diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts
index e523408a3..ca5b6c0ea 100644
--- a/src/util/DragManager.ts
+++ b/src/util/DragManager.ts
@@ -1,7 +1,7 @@
-import {Opt} from "../fields/Field";
-import {DocumentView} from "../views/nodes/DocumentView";
-import {DocumentDecorations} from "../DocumentDecorations";
-import {SelectionManager} from "./SelectionManager";
+import { Opt } from "../fields/Field";
+import { DocumentView } from "../views/nodes/DocumentView";
+import { DocumentDecorations } from "../DocumentDecorations";
+import { SelectionManager } from "./SelectionManager";
export namespace DragManager {
export let rootId = "root";
@@ -33,7 +33,7 @@ export namespace DragManager {
}
export class DropEvent {
- constructor(readonly x: number, readonly y: number, readonly data: {[ id: string ]: any}) {}
+ constructor(readonly x: number, readonly y: number, readonly data: { [ id: string ]: any }) { }
}
export interface DropHandlers {
@@ -56,7 +56,10 @@ export namespace DragManager {
};
}
- export function StartDrag(ele: HTMLElement, dragData: {[ id: string ]: any}, options: DragOptions) {
+
+ let _lastPointerX: number = 0;
+ let _lastPointerY: number = 0;
+ export function StartDrag(ele: HTMLElement, dragData: { [ id: string ]: any }, options: DragOptions) {
if (!dragDiv) {
const root = document.getElementById(rootId);
if (!root) {
@@ -76,6 +79,8 @@ export namespace DragManager {
dragElement.style.transformOrigin = "0 0";
dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`;
dragDiv.appendChild(dragElement);
+ _lastPointerX = dragData[ "xOffset" ] + rect.left;
+ _lastPointerY = dragData[ "yOffset" ] + rect.top;
let hideSource = false;
if (typeof options.hideSource === "boolean") {
@@ -91,8 +96,8 @@ export namespace DragManager {
const moveHandler = (e: PointerEvent) => {
e.stopPropagation();
e.preventDefault();
- x += e.movementX;
- y += e.movementY;
+ x += e.clientX - _lastPointerX; _lastPointerX = e.clientX;
+ y += e.clientY - _lastPointerY; _lastPointerY = e.clientY;
dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`;
};
const upHandler = (e: PointerEvent) => {
@@ -107,7 +112,7 @@ export namespace DragManager {
document.addEventListener("pointerup", upHandler);
}
- function FinishDrag(dragEle: HTMLElement, e: PointerEvent, options: DragOptions, dragData: {[ index: string ]: any}) {
+ function FinishDrag(dragEle: HTMLElement, e: PointerEvent, options: DragOptions, dragData: { [ index: string ]: any }) {
dragDiv.removeChild(dragEle);
const target = document.elementFromPoint(e.x, e.y);
if (!target) {
diff --git a/src/viewmodels/DocumentViewModel.ts b/src/viewmodels/DocumentViewModel.ts
deleted file mode 100644
index 008275f3c..000000000
--- a/src/viewmodels/DocumentViewModel.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Document } from "../fields/Document";
-
-export class DocumentViewModel {
- constructor(private doc: Document) {
-
- }
-
- get Doc(): Document {
- return this.doc;
- }
-} \ No newline at end of file
diff --git a/src/views/collections/CollectionDockingView.scss b/src/views/collections/CollectionDockingView.scss
new file mode 100644
index 000000000..43af7c538
--- /dev/null
+++ b/src/views/collections/CollectionDockingView.scss
@@ -0,0 +1,386 @@
+
+.collectiondockingview-container {
+ position: relative;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ .flexlayout__layout {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ overflow:hidden;
+ }
+
+ .flexlayout__splitter {
+ background-color: black;
+ }
+
+ .flexlayout__splitter:hover {
+ background-color: #333;
+ }
+
+ .flexlayout__splitter_drag {
+ border-radius: 5px;
+ background-color: #444;
+ z-index: 1000;
+ }
+
+ .flexlayout__outline_rect {
+ position: absolute;
+ cursor: move;
+ border: 2px solid #cfe8ff;
+ box-shadow: inset 0 0 60px rgba(0, 0, 0, .2);
+ border-radius: 5px;
+ z-index: 1000;
+ box-sizing: border-box;
+ }
+
+ .flexlayout__outline_rect_edge {
+ cursor: move;
+ border: 2px solid #b7d1b5;
+ box-shadow: inset 0 0 60px rgba(0, 0, 0, .2);
+ border-radius: 5px;
+ z-index: 1000;
+ box-sizing: border-box;
+ }
+
+ .flexlayout__edge_rect {
+ position: absolute;
+ z-index: 1000;
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, .2);
+ background-color: lightgray;
+ }
+
+ .flexlayout__drag_rect {
+ position: absolute;
+ cursor: move;
+ border: 2px solid #aaaaaa;
+ box-shadow: inset 0 0 60px rgba(0, 0, 0, .3);
+ border-radius: 5px;
+ z-index: 1000;
+ box-sizing: border-box;
+ background-color:#eeeeee;
+ opacity: 0.9;
+ text-align: center;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ overflow:hidden;
+ padding:10px;
+ word-wrap: break-word;
+ }
+
+ .flexlayout__tabset {
+ overflow: hidden;
+ background-color: #222;
+ box-sizing: border-box;
+ }
+
+ .flexlayout__tab {
+ overflow: auto;
+ position: absolute;
+ box-sizing: border-box;
+ background-color: #222;
+ }
+
+ .flexlayout__tab_button {
+ cursor: pointer;
+ padding: 2px 8px 3px 8px;
+ margin: 2px;
+ /*box-shadow: inset 0px 0px 5px rgba(0, 0, 0, .15);*/
+ /*border-top-left-radius: 3px;*/
+ /*border-top-right-radius: 3px;*/
+ float:left;
+ vertical-align: top;
+ box-sizing: border-box;
+
+ }
+
+ .flexlayout__tab_button--selected {
+ color: #ddd;
+ background-color: #222;
+ }
+
+ .flexlayout__tab_button--unselected {
+ color: gray;
+ }
+
+ .flexlayout__tab_button_leading {
+ float: left;
+ display:inline-block;
+ }
+
+ .flexlayout__tab_button_content {
+ float: left;
+ display:inline-block;
+ }
+
+ .flexlayout__tab_button_textbox {
+ float: left;
+ border: none;
+ color:lightgreen;
+ background-color:#222;
+ }
+ .flexlayout__tab_button_textbox:focus {
+ outline: none;
+ }
+
+ .flexlayout__tab_button_trailing {
+ float: left;
+ display:inline-block;
+ margin-left:5px;
+ margin-top:3px;
+ width:8px;
+ height:8px;
+ }
+
+ .flexlayout__tab_button:hover .flexlayout__tab_button_trailing,
+ .flexlayout__tab_button--selected .flexlayout__tab_button_trailing{
+ //background: transparent url("../images/close_white.png") no-repeat center;
+ }
+
+ .flexlayout__tab_button_overflow {
+ float: left;
+ width: 20px;
+ height:15px;
+ margin-top:2px;
+ padding-left:12px;
+ border:none;
+ font-size: 10px;
+ color:lightgray;
+ font-family: Arial, sans-serif;
+ //background: transparent url("../images/more.png") no-repeat left;
+ }
+
+ .flexlayout__tabset_header
+ {
+ position: absolute;
+ left: 0;
+ right: 0;
+ color:#eee;
+ background-color: #212121;
+ padding:3px 3px 3px 5px;
+ /*box-shadow: inset 0px 0px 3px 0px rgba(136, 136, 136, 0.54);*/
+ box-sizing: border-box;
+ }
+
+ .flexlayout__tab_header_inner {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 10000px;
+ }
+
+ .flexlayout__tab_header_outer {
+ background-color: black;
+ position: absolute;
+ left: 0;
+ right: 0;
+ /*top: 0px;*/
+ /*height: 100px;*/
+ overflow: hidden;
+ }
+
+ .flexlayout__tabset-selected
+ {
+ //background-image: linear-gradient(#111, #444);
+ }
+
+ .flexlayout__tabset-maximized
+ {
+ //background-image: linear-gradient(#666, #333);
+ }
+
+ .flexlayout__tab_toolbar {
+ position:absolute;
+ display:flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ top:0;
+ bottom:0;
+ right:0;
+ }
+
+ .flexlayout__tab_toolbar_button-min {
+ width:20px;
+ height:20px;
+ border:none;
+ outline-width: 0;
+ //background: transparent url("../images/maximize.png") no-repeat center;
+
+ }
+ .flexlayout__tab_toolbar_button-max {
+ width:20px;
+ height:20px;
+ border:none;
+ outline-width: 0;
+ //background: transparent url("../images/restore.png") no-repeat center;
+ }
+
+ .flexlayout__popup_menu {
+ }
+
+ .flexlayout__popup_menu_item {
+ padding: 2px 10px 2px 10px;
+ color:#ddd;
+ }
+
+ .flexlayout__popup_menu_item:hover {
+ background-color: #444444;
+ }
+
+ .flexlayout__popup_menu_container {
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, .15);
+ border: 1px solid #555;
+ background: #222;
+ border-radius:3px;
+ position:absolute;
+ z-index:1000;
+ }
+
+
+ .flexlayout__border_top {
+ background-color:black;
+ border-bottom: 1px solid #ddd;
+ box-sizing: border-box;
+ overflow:hidden;
+ }
+
+ .flexlayout__border_bottom {
+ background-color:black;
+ border-top: 1px solid #333;
+ box-sizing: border-box;
+ overflow:hidden;
+ }
+ .flexlayout__border_left {
+ background-color:black;
+ border-right: 1px solid #333;
+ box-sizing: border-box;
+ overflow:hidden;
+ }
+
+ .flexlayout__border_right {
+ background-color:black;
+ border-left: 1px solid #333;
+ box-sizing: border-box;
+ overflow:hidden;
+ }
+
+ .flexlayout__border_inner_bottom{
+ display: flex;
+ }
+
+ .flexlayout__border_inner_left {
+ position:absolute;
+ white-space: nowrap;
+ right: 23px;
+ transform-origin: top right;
+ transform: rotate(-90deg);
+ }
+
+ .flexlayout__border_inner_right {
+ position:absolute;
+ white-space: nowrap;
+ left: 23px;
+ transform-origin: top left;
+ transform: rotate(90deg);
+ }
+
+ .flexlayout__border_button {
+ background-color: #222;
+ color:white;
+ display:inline-block;
+ white-space:nowrap;
+
+ cursor: pointer;
+ padding: 2px 8px 3px 8px;
+ margin: 2px;
+ vertical-align: top;
+ box-sizing: border-box;
+ }
+
+ .flexlayout__border_button--selected {
+ color: #ddd;
+ background-color: #222;
+ }
+
+ .flexlayout__border_button--unselected {
+ color: gray;
+ }
+
+ .flexlayout__border_button_leading {
+ float: left;
+ display:inline;
+ }
+
+ .flexlayout__border_button_content {
+ display:inline-block;
+ }
+
+ .flexlayout__border_button_textbox {
+ float: left;
+ border: none;
+ color:green;
+ background-color:#ddd;
+ }
+ .flexlayout__border_button_textbox:focus {
+ outline: none;
+ }
+
+ .flexlayout__border_button_trailing {
+ display:inline-block;
+ margin-left:5px;
+ margin-top:3px;
+ width:8px;
+ height:8px;
+ }
+
+ .flexlayout__border_button:hover .flexlayout__border_button_trailing,
+ .flexlayout__border_button--selected .flexlayout__border_button_trailing{
+ //background: transparent url("../images/close_white.png") no-repeat center;
+ }
+
+
+ .flexlayout__border_toolbar_left {
+ position:absolute;
+ display: flex;
+ flex-direction: column-reverse;
+ align-items: center;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ .flexlayout__border_toolbar_right {
+ position:absolute;
+ display: flex;
+ flex-direction: column-reverse;
+ align-items: center;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ .flexlayout__border_toolbar_top {
+ position:absolute;
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ top:0;
+ bottom:0;
+ right:0;
+ }
+
+ .flexlayout__border_toolbar_bottom {
+ position:absolute;
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ top:0;
+ bottom:0;
+ right:0;
+ }
+
+} \ No newline at end of file
diff --git a/src/views/collections/CollectionDockingView.tsx b/src/views/collections/CollectionDockingView.tsx
new file mode 100644
index 000000000..3d0c39c9d
--- /dev/null
+++ b/src/views/collections/CollectionDockingView.tsx
@@ -0,0 +1,202 @@
+import { observer } from "mobx-react";
+import { KeyStore } from "../../fields/Key";
+import React = require("react");
+import FlexLayout from "flexlayout-react";
+import { action, observable, computed } from "mobx";
+import { Document } from "../../fields/Document";
+import { DocumentView, CollectionViewProps } from "../nodes/DocumentView";
+import { ListField } from "../../fields/ListField";
+import { NumberField } from "../../fields/NumberField";
+import { SSL_OP_SINGLE_DH_USE } from "constants";
+import { SelectionManager } from "../../util/SelectionManager";
+import { ContextMenu } from "../ContextMenu";
+import "./CollectionDockingView.scss"
+import 'golden-layout/src/css/goldenlayout-base.css';
+import 'golden-layout/src/css/goldenlayout-dark-theme.css';
+import * as GoldenLayout from "golden-layout";
+import * as ReactDOM from 'react-dom';
+
+@observer
+export class CollectionDockingView extends React.Component<CollectionViewProps> {
+
+ private static UseGoldenLayout = true;
+ public static LayoutString() { return '<CollectionDockingView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>'; }
+ private _containerRef = React.createRef<HTMLDivElement>();
+ @computed
+ private get modelForFlexLayout() {
+ const { fieldKey, Document: Document } = this.props;
+ const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+ var docs = value.map(doc => {
+ return { type: 'tabset', weight: 50, selected: 0, children: [ { type: "tab", name: doc.Title, component: doc.Id } ] };
+ });
+ return FlexLayout.Model.fromJson({
+ global: {}, borders: [],
+ layout: {
+ "type": "row",
+ "weight": 100,
+ "children": docs
+ }
+ });
+ }
+ @computed
+ private get modelForGoldenLayout(): any {
+ const { fieldKey, Document: Document } = this.props;
+ const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+ var docs = value.map(doc => {
+ return { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } };
+ });
+ return new GoldenLayout({ content: [ { type: 'row', content: docs } ] });
+ }
+ constructor(props: CollectionViewProps) {
+ super(props);
+ }
+
+ public static BORDER_WIDTH = 2;
+ public static TAB_HEADER_HEIGHT = 20;
+
+ @computed
+ public get active(): boolean {
+ var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView));
+ var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this);
+ var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined;
+ return isSelected || childSelected || topMost;
+ }
+
+ componentDidMount: () => void = () => {
+ if (this._containerRef.current && CollectionDockingView.UseGoldenLayout) {
+ this.goldenLayoutFactory();
+ }
+ }
+ private nextId = (function () { var _next_id = 0; return function () { return _next_id++; } })();
+
+ @action
+ addDocument = (doc: Document): void => {
+ //TODO This won't create the field if it doesn't already exist
+ const value = this.props.Document.GetFieldValue(this.props.fieldKey, ListField, new Array<Document>())
+ value.push(doc);
+ }
+
+ @action
+ removeDocument = (doc: Document): void => {
+ //TODO This won't create the field if it doesn't already exist
+ const value = this.props.Document.GetFieldValue(this.props.fieldKey, ListField, new Array<Document>())
+ if (value.indexOf(doc) !== -1) {
+ value.splice(value.indexOf(doc), 1)
+
+ SelectionManager.DeselectAll()
+ ContextMenu.Instance.clearItems()
+ }
+ }
+ @action
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (e.button === 2 && this.active) {
+ e.stopPropagation();
+ e.preventDefault();
+ } else {
+ if (e.buttons === 1 && this.active) {
+ e.stopPropagation();
+ }
+ }
+ }
+
+ flexLayoutFactory = (node: any): any => {
+ var component = node.getComponent();
+ if (component === "button") {
+ return <button>{node.getName()}</button>;
+ }
+ const { fieldKey, Document: Document } = this.props;
+ const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+ for (var i: number = 0; i < value.length; i++) {
+ if (value[ i ].Id === component) {
+ return (<DocumentView key={value[ i ].Id} ContainingCollectionView={this} Document={value[ i ]} ContainingDocumentView={this.props.ContainingDocumentView} />);
+ }
+ }
+ if (component === "text") {
+ return (<div className="panel">Panel {node.getName()}</div>);
+ }
+ }
+
+ goldenLayoutFactory() {
+ var myLayout = this.modelForGoldenLayout;
+
+ myLayout.on('stackCreated', function (stack: any) {
+ stack.header.controlsContainer.find('.lm_close') //get the close icon
+ .off('click') //unbind the current click handler
+ .click(function () {
+ if (confirm('really close this?')) {
+ stack.remove();
+ }
+ });
+ });
+
+ myLayout.on('tabCreated', function (tab: any) {
+ tab.setTitle(tab.contentItem.config.componentState.doc.Title);
+ tab.closeElement.off('click') //unbind the current click handler
+ .click(function () {
+ if (confirm('really close this?')) {
+ tab.contentItem.remove();
+ }
+ });
+ });
+
+ var me = this;
+ myLayout.registerComponent('documentViewComponent', function (container: any, state: any) {
+ // bcz: this is crufty
+ // calling html() causes a div tag to be added in the DOM with id 'containingDiv'.
+ // Apparently, we need to wait to allow a live html div element to actually be instantiated.
+ // After a timeout, we lookup the live html div element and add our React DocumentView to it.
+ var containingDiv = "component_" + me.nextId();
+ container.getElement().html("<div id='" + containingDiv + "'></div>");
+ setTimeout(function () {
+ ReactDOM.render((
+ <DocumentView key={state.doc.Id} Document={state.doc} ContainingCollectionView={me} ContainingDocumentView={me.props.ContainingDocumentView} />
+ ),
+ document.getElementById(containingDiv)
+ )
+ }, 0);
+ });
+ myLayout.container = this._containerRef.current;
+ myLayout.init();
+ }
+
+
+ render() {
+ const { fieldKey, Document: Document } = this.props;
+ const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+ // bcz: not sure why, but I need these to force the flexlayout to update when the collection size changes.
+ var s = this.props.ContainingDocumentView!.ScalingToScreenSpace;
+ var w = Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)) / s;
+ var h = Document.GetFieldValue(KeyStore.Height, NumberField, Number(0)) / s;
+
+ if (CollectionDockingView.UseGoldenLayout) {
+ return (
+ <div className="border" style={{
+ borderStyle: "solid",
+ borderWidth: `${CollectionDockingView.BORDER_WIDTH}px`,
+ }}>
+ <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef}
+ style={{
+ width: "100%",
+ height: "100%"
+ }} >
+ </div>
+ </div>
+ );
+ } else {
+ return (
+ <div className="border" style={{
+ borderStyle: "solid",
+ borderWidth: `${CollectionDockingView.BORDER_WIDTH}px`,
+ }}>
+ <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef}
+ style={{
+ width: s > 1 ? "100%" : w - 2 * CollectionDockingView.BORDER_WIDTH,
+ height: s > 1 ? "100%" : h - 2 * CollectionDockingView.BORDER_WIDTH
+ }} >
+ <FlexLayout.Layout model={this.modelForFlexLayout} factory={this.flexLayoutFactory} />
+ </div>
+ </div>
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.scss b/src/views/collections/CollectionFreeFormView.scss
index 6ad6ad86c..870e48556 100644
--- a/src/views/freeformcanvas/CollectionFreeFormView.scss
+++ b/src/views/collections/CollectionFreeFormView.scss
@@ -1,9 +1,7 @@
.collectionfreeformview-container {
- position: absolute;
+ position: relative;
top: 0;
left: 0;
- width: 100%;
- height: 100%;
overflow: hidden;
.collectionfreeformview {
position: absolute;
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/collections/CollectionFreeFormView.tsx
index 00b912294..736bcb786 100644
--- a/src/views/freeformcanvas/CollectionFreeFormView.tsx
+++ b/src/views/collections/CollectionFreeFormView.tsx
@@ -1,33 +1,26 @@
-import {observer} from "mobx-react";
-import {Key, KeyStore} from "../../fields/Key";
+import { observer } from "mobx-react";
+import { Key, KeyStore } from "../../fields/Key";
import React = require("react");
-import {action, observable, computed} from "mobx";
-import {Document} from "../../fields/Document";
-import {DocumentViewModel} from "../../viewmodels/DocumentViewModel";
-import {DocumentView} from "../nodes/DocumentView";
-import {ListField} from "../../fields/ListField";
-import {NumberField} from "../../fields/NumberField";
-import {SSL_OP_SINGLE_DH_USE} from "constants";
-import {DocumentDecorations} from "../../DocumentDecorations";
-import {SelectionManager} from "../../util/SelectionManager";
-import {Documents} from "../../documents/Documents";
-import {ContextMenu} from "../ContextMenu";
-import {Opt} from "../../fields/Field";
-import {DragManager} from "../../util/DragManager";
-import {Utils} from "../../Utils";
-
-interface IProps {
- fieldKey: Key;
- Document: Document;
- ContainingDocumentView: Opt<DocumentView>;
-}
+import { action, observable, computed } from "mobx";
+import { Document } from "../../fields/Document";
+import { DocumentView, CollectionViewProps } from "../nodes/DocumentView";
+import { ListField } from "../../fields/ListField";
+import { NumberField } from "../../fields/NumberField";
+import { SSL_OP_SINGLE_DH_USE } from "constants";
+import { SelectionManager } from "../../util/SelectionManager";
+import { Documents } from "../../documents/Documents";
+import { ContextMenu } from "../ContextMenu";
+import { DragManager } from "../../util/DragManager";
+import "./CollectionFreeFormView.scss";
+import { Utils } from "../../Utils";
+import { CollectionDockingView } from "./CollectionDockingView";
@observer
-export class CollectionFreeFormView extends React.Component<IProps> {
+export class CollectionFreeFormView extends React.Component<CollectionViewProps> {
private _containerRef = React.createRef<HTMLDivElement>();
private _canvasRef = React.createRef<HTMLDivElement>();
- constructor(props: IProps) {
+ constructor(props: CollectionViewProps) {
super(props);
}
@@ -37,30 +30,24 @@ export class CollectionFreeFormView extends React.Component<IProps> {
public get active(): boolean {
var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView));
var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this);
- var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined;
+ var topMost = this.props.ContainingDocumentView != undefined && (
+ this.props.ContainingDocumentView.props.ContainingCollectionView == undefined ||
+ this.props.ContainingDocumentView.props.ContainingCollectionView instanceof CollectionDockingView);
return isSelected || childSelected || topMost;
}
drop = (e: Event, de: DragManager.DropEvent) => {
- const ele = this._canvasRef.current;
- if (!ele) {
- return;
- }
const doc = de.data[ "document" ];
- const xOffset = de.data[ "xOffset" ] as number || 0;
- const yOffset = de.data[ "yOffset" ] as number || 0;
if (doc instanceof DocumentView) {
if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) {
doc.props.ContainingCollectionView.removeDocument(doc.props.Document);
this.addDocument(doc.props.Document);
}
- const {scale, translateX, translateY} = Utils.GetScreenTransform(ele);
- const screenX = de.x - xOffset;
- const screenY = de.y - yOffset;
- const docX = (screenX - translateX) / scale;
- const docY = (screenY - translateY) / scale;
- doc.x = docX;
- doc.y = docY;
+ const xOffset = de.data[ "xOffset" ] as number || 0;
+ const yOffset = de.data[ "yOffset" ] as number || 0;
+ let { LocalX, LocalY } = this.props.ContainingDocumentView!.TransformToLocalPoint(de.x - xOffset, de.y - yOffset);
+ doc.x = LocalX;
+ doc.y = LocalY;
}
e.stopPropagation();
}
@@ -117,11 +104,11 @@ export class CollectionFreeFormView extends React.Component<IProps> {
onPointerWheel = (e: React.WheelEvent): void => {
e.stopPropagation();
- let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY} = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY);
+ let { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY);
var deltaScale = (1 - (e.deltaY / 1000)) * Ss;
- var newContainerX = LocalX * deltaScale + W / 2 - W / 2 * deltaScale + Panxx + Xx;
+ var newContainerX = LocalX * deltaScale + Panxx + Xx;
var newContainerY = LocalY * deltaScale + Panyy + Yy;
let dx = ContainerX - newContainerX;
@@ -185,7 +172,7 @@ export class CollectionFreeFormView extends React.Component<IProps> {
onDragOver = (e: React.DragEvent): void => {
}
render() {
- const {fieldKey, Document: Document} = this.props;
+ const { fieldKey, Document: Document } = this.props;
const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
@@ -199,9 +186,8 @@ export class CollectionFreeFormView extends React.Component<IProps> {
<div className="collectionfreeformview-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()} style={{
width: "100%",
height: `calc(100% - 2*${CollectionFreeFormView.BORDER_WIDTH}px)`,
- overflow: "hidden"
}} onDrop={this.onDrop} onDragOver={this.onDragOver} ref={this._containerRef}>
- <div className="collectionfreeformview" style={{transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})`, transformOrigin: `left, top`}} ref={this._canvasRef}>
+ <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})`, transformOrigin: `left, top` }} ref={this._canvasRef}>
<div className="node-container">
{value.map(doc => {
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx
index be072a458..1e4cc1cca 100644
--- a/src/views/nodes/DocumentView.tsx
+++ b/src/views/nodes/DocumentView.tsx
@@ -4,27 +4,47 @@ import { computed, observable, action } from "mobx";
import { KeyStore, Key } from "../../fields/Key";
import { NumberField } from "../../fields/NumberField";
import { TextField } from "../../fields/TextField";
-import { DocumentViewModel } from "../../viewmodels/DocumentViewModel";
import { ListField } from "../../fields/ListField";
import { FieldTextBox } from "../nodes/FieldTextBox"
import { Document } from "../../fields/Document";
-import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView"
+import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"
+import { CollectionDockingView } from "../collections/CollectionDockingView"
import "./NodeView.scss"
import { SelectionManager } from "../../util/SelectionManager";
-import { DocumentDecorations } from "../../DocumentDecorations";
import { ContextMenu } from "../ContextMenu";
import { Opt } from "../../fields/Field";
import { DragManager } from "../../util/DragManager";
const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
-interface IProps {
+interface DocumentViewProps {
Document: Document;
- ContainingCollectionView: Opt<CollectionFreeFormView>;
+ ContainingCollectionView: Opt<CollectionView>;
ContainingDocumentView: Opt<DocumentView>
}
+export interface CollectionViewProps {
+ fieldKey: Key;
+ Document: Document;
+ ContainingDocumentView: Opt<DocumentView>;
+}
+
+// these properties are set via the render() method of the DocumentView when it creates this node.
+// However, these properties are set below in the LayoutString() static method
+export interface DocumentFieldViewProps {
+ fieldKey: Key;
+ doc: Document;
+ containingDocumentView: DocumentView
+}
+
+interface CollectionView {
+ addDocument: (doc: Document) => void;
+ removeDocument: (doc: Document) => void;
+ active: boolean;
+ props: CollectionViewProps;
+}
+
@observer
-class DocumentContents extends React.Component<IProps> {
+class DocumentContents extends React.Component<DocumentViewProps> {
@computed
get layout(): string {
@@ -44,16 +64,16 @@ class DocumentContents extends React.Component<IProps> {
let doc = this.props.Document;
let bindings = { ...this.props } as any;
for (const key of this.layoutKeys) {
- bindings[key.Name + "Key"] = key;
+ bindings[ key.Name + "Key" ] = key;
}
for (const key of this.layoutFields) {
let field = doc.GetField(key);
if (field) {
- bindings[key.Name] = field.GetValue();
+ bindings[ key.Name ] = field.GetValue();
}
}
return <JsxParser
- components={{ FieldTextBox, CollectionFreeFormView }}
+ components={{ FieldTextBox, CollectionFreeFormView, CollectionDockingView }}
bindings={bindings}
jsx={this.layout}
showWarnings={true}
@@ -66,12 +86,15 @@ class DocumentContents extends React.Component<IProps> {
}
@observer
-export class DocumentView extends React.Component<IProps> {
+export class DocumentView extends React.Component<DocumentViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
private _contextMenuCanOpen = false;
private _downX: number = 0;
private _downY: number = 0;
+ constructor(props: DocumentViewProps) {
+ super(props);
+ }
get screenRect(): ClientRect | DOMRect {
if (this._mainCont.current) {
return this._mainCont.current.getBoundingClientRect();
@@ -135,10 +158,9 @@ export class DocumentView extends React.Component<IProps> {
//
@computed
public get ScalingToScreenSpace(): number {
- let containingDocView = this.props.ContainingDocumentView;
- if (containingDocView != undefined) {
- let ss = containingDocView.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
- return containingDocView.ScalingToScreenSpace * ss;
+ if (this.props.ContainingDocumentView != undefined) {
+ let ss = this.props.ContainingDocumentView.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
+ return this.props.ContainingDocumentView.ScalingToScreenSpace * ss;
}
return 1;
}
@@ -147,7 +169,7 @@ export class DocumentView extends React.Component<IProps> {
// Converts a coordinate in the screen space of the app into a local document coordinate.
//
public TransformToLocalPoint(screenX: number, screenY: number) {
- let ContainerX = screenX;
+ let ContainerX = screenX - CollectionFreeFormView.BORDER_WIDTH;
let ContainerY = screenY - CollectionFreeFormView.BORDER_WIDTH;
// if this collection view is nested within another collection view, then
@@ -158,16 +180,16 @@ export class DocumentView extends React.Component<IProps> {
ContainerY = LocalY - CollectionFreeFormView.BORDER_WIDTH;
}
- let W = this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0));
- let Xx = this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
- let Yy = this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
+ let dockingViewChromeHack = this.props.ContainingCollectionView instanceof CollectionDockingView;
+ let Xx = dockingViewChromeHack ? 0 : this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
+ let Yy = dockingViewChromeHack ? CollectionDockingView.TAB_HEADER_HEIGHT : this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
let Ss = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
let Panxx = this.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
let Panyy = this.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
- let LocalX = (ContainerX - (Xx + Panxx) - W / 2) / Ss + W / 2;
+ let LocalX = (ContainerX - (Xx + Panxx)) / Ss;
let LocalY = (ContainerY - (Yy + Panyy)) / Ss;
- return { LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY };
+ return { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY };
}
//
@@ -175,11 +197,12 @@ export class DocumentView extends React.Component<IProps> {
//
public TransformToScreenPoint(localX: number, localY: number, Ss: number = 1, Panxx: number = 0, Panyy: number = 0): { ScreenX: number, ScreenY: number } {
- let W = this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0));
+ let dockingViewChromeHack = this.props.ContainingCollectionView instanceof CollectionDockingView;
+ let W = CollectionFreeFormView.BORDER_WIDTH; // this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0));
let H = CollectionFreeFormView.BORDER_WIDTH;
- let Xx = this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
- let Yy = this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
- let parentX = (localX - W / 2) * Ss + (Xx + Panxx) + W / 2;
+ let Xx = dockingViewChromeHack ? 0 : this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
+ let Yy = dockingViewChromeHack ? CollectionDockingView.TAB_HEADER_HEIGHT : this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
+ let parentX = (localX - W) * Ss + (Xx + Panxx) + W;
let parentY = (localY - H) * Ss + (Yy + Panyy) + H;
// if this collection view is nested within another collection view, then
@@ -200,9 +223,11 @@ export class DocumentView extends React.Component<IProps> {
this._downX = e.clientX;
this._downY = e.clientY;
this._contextMenuCanOpen = e.button == 2;
- if (this.active) {
+ if (this.active && !e.isDefaultPrevented()) {
e.stopPropagation();
- // e.preventDefault();
+ if (e.buttons === 2) {
+ e.preventDefault();
+ }
document.removeEventListener("pointermove", this.onPointerMove)
document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp)
@@ -215,10 +240,10 @@ export class DocumentView extends React.Component<IProps> {
if (this._mainCont.current != null && this.props.ContainingCollectionView != null) {
this._contextMenuCanOpen = false;
const rect = this.screenRect;
- let dragData: { [id: string]: any } = {};
- dragData["document"] = this;
- dragData["xOffset"] = e.x - rect.left;
- dragData["yOffset"] = e.y - rect.top;
+ let dragData: { [ id: string ]: any } = {};
+ dragData[ "document" ] = this;
+ dragData[ "xOffset" ] = e.x - rect.left;
+ dragData[ "yOffset" ] = e.y - rect.top;
DragManager.StartDrag(this._mainCont.current, dragData, {
handlers: {
dragComplete: this.dragComplete,
@@ -272,12 +297,14 @@ export class DocumentView extends React.Component<IProps> {
}
}
+
render() {
+ var freestyling = this.props.ContainingCollectionView === undefined || this.props.ContainingCollectionView instanceof CollectionFreeFormView;
return (
<div className="node" ref={this._mainCont} style={{
- transform: this.transform,
- width: this.width,
- height: this.height,
+ transform: freestyling ? this.transform : "",
+ width: freestyling ? this.width : "100%",
+ height: freestyling ? this.height : "100%",
}}
onContextMenu={this.onContextMenu}
onPointerDown={this.onPointerDown}>
@@ -285,5 +312,4 @@ export class DocumentView extends React.Component<IProps> {
</div>
);
}
-
} \ No newline at end of file
diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx
index 4539bbab0..20dfde1d2 100644
--- a/src/views/nodes/FieldTextBox.tsx
+++ b/src/views/nodes/FieldTextBox.tsx
@@ -14,11 +14,10 @@ import { undo, redo, history } from "prosemirror-history"
import { Opt } from "../../fields/Field";
import "./FieldTextBox.scss"
+import { DocumentFieldViewProps } from "./DocumentView";
+import { SelectionManager } from "../../util/SelectionManager";
+
-interface IProps {
- fieldKey: Key;
- doc: Document;
-}
// FieldTextBox: Displays an editable plain text node that maps to a specified Key of a Document
//
@@ -36,12 +35,14 @@ 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.
//
-export class FieldTextBox extends React.Component<IProps> {
+export class FieldTextBox extends React.Component<DocumentFieldViewProps> {
+
+ public static LayoutString() { return "<FieldTextBox doc={Document} containingDocumentView={ContainingDocumentView} fieldKey={DataKey} />"; }
private _ref: React.RefObject<HTMLDivElement>;
private _editorView: Opt<EditorView>;
private _reactionDisposer: Opt<IReactionDisposer>;
- constructor(props: IProps) {
+ constructor(props: DocumentFieldViewProps) {
super(props);
this._ref = React.createRef();
@@ -111,8 +112,13 @@ export class FieldTextBox extends React.Component<IProps> {
const { fieldKey, doc } = this.props;
doc.SetFieldValue(fieldKey, e.target.value, TextField);
}
-
+ onPointerDown = (e: React.PointerEvent): void => {
+ let me = this;
+ if (e.buttons === 1 && SelectionManager.IsSelected(me.props.containingDocumentView)) {
+ e.stopPropagation();
+ }
+ }
render() {
- return (<div className="fieldTextBox-cont" ref={this._ref} />)
+ return (<div className="fieldTextBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} />)
}
} \ No newline at end of file
diff --git a/src/views/nodes/TextNodeView.tsx b/src/views/nodes/TextNodeView.tsx
index 4831e658c..ab762df12 100644
--- a/src/views/nodes/TextNodeView.tsx
+++ b/src/views/nodes/TextNodeView.tsx
@@ -1,7 +1,7 @@
-import { observer } from "mobx-react";
-import { StaticTextNodeStore } from "../../stores/StaticTextNodeStore";
+import {observer} from "mobx-react";
+import {StaticTextNodeStore} from "../../stores/StaticTextNodeStore";
import "./NodeView.scss";
-import { TopBar } from "./TopBar";
+import {TopBar} from "./TopBar";
import React = require("react");
interface IProps {
@@ -14,7 +14,7 @@ export class TextNodeView extends React.Component<IProps> {
render() {
let store = this.props.store;
return (
- <div className="node text-node" style={{ transform: store.Transform }}>
+ <div className="node text-node" style={{transform: store.Transform}}>
<TopBar store={store} />
<div className="scroll-box">
<div className="content">