aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2019-01-29 10:47:28 -0500
committerbob <bcz@cs.brown.edu>2019-01-29 10:47:28 -0500
commit0402105238f24785a1229dbbb37f2e4dba958f88 (patch)
tree0b932c896d956c9b3ccf4be054a2bebea1a04d8e /src
parent832297c980e8de78ead9cba85dad4d46bdd32b88 (diff)
playing with a docking view.
Diffstat (limited to 'src')
-rw-r--r--src/DocumentDecorations.tsx14
-rw-r--r--src/Main.tsx19
-rw-r--r--src/documents/Documents.ts36
-rw-r--r--src/viewmodels/DocumentViewModel.ts11
-rw-r--r--src/views/collections/CollectionDockingView.scss393
-rw-r--r--src/views/collections/CollectionDockingView.tsx154
-rw-r--r--src/views/collections/CollectionFreeFormView.scss6
-rw-r--r--src/views/collections/CollectionFreeFormView.tsx (renamed from src/views/freeformcanvas/CollectionFreeFormView.tsx)49
-rw-r--r--src/views/freeformcanvas/CollectionFreeFormView.scss13
-rw-r--r--src/views/nodes/DocumentView.tsx35
-rw-r--r--src/views/nodes/FieldTextBox.tsx49
11 files changed, 670 insertions, 109 deletions
diff --git a/src/DocumentDecorations.tsx b/src/DocumentDecorations.tsx
index 8145ba732..7899db9c9 100644
--- a/src/DocumentDecorations.tsx
+++ b/src/DocumentDecorations.tsx
@@ -1,10 +1,10 @@
-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 { DocumentView } from "./views/nodes/DocumentView";
+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,7 +20,7 @@ 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) => {
var spt = element.TransformToScreenPoint(0, 0);
var bpt = element.TransformToScreenPoint(element.width, element.height);
@@ -28,7 +28,7 @@ export class DocumentDecorations extends React.Component {
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..6ccb940f4 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({
@@ -60,16 +59,20 @@ runInAction(() => {
x: 0, y: 400
});
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
+ });
+ let doc6 = Documents.DockDocument("", {
+ x: 350, y: 100
});
let mainNodes = 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(doc4);
- mainNodes.Data.push(doc3);
- mainNodes.Data.push(doc5);
+ // mainNodes.Data.push(doc1);
+ // mainNodes.Data.push(doc2);
+ // mainNodes.Data.push(doc4);
+ // mainNodes.Data.push(doc3);
+ // mainNodes.Data.push(doc5);
+ mainNodes.Data.push(doc6);
}); \ No newline at end of file
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts
index 145da7557..a0bd021d8 100644
--- a/src/documents/Documents.ts
+++ b/src/documents/Documents.ts
@@ -1,9 +1,10 @@
-import {Document} from "../fields/Document";
-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 { Document } from "../fields/Document";
+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;
@@ -52,6 +53,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(text: string, options: DocumentOptions = {}): Document {
+ let doc = GetDockPrototype().MakeDelegate();
+ setupOptions(doc, options);
+ // doc.SetField(KeyStore.Data, new TextField(text));
+ return doc;
+ }
+
+
let imageProto: Document;
function GetImagePrototype(): Document {
if (!imageProto) {
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..dc29defdc
--- /dev/null
+++ b/src/views/collections/CollectionDockingView.scss
@@ -0,0 +1,393 @@
+
+.collectiondockingview-container {
+ position: relative;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ .collectiondockingview {
+ position: relative;
+ top: 0;
+ left: 0;.flexlayout__layout {
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ position: absolute;
+ 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;
+ color:white;
+ }
+
+ .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..51323e94b
--- /dev/null
+++ b/src/views/collections/CollectionDockingView.tsx
@@ -0,0 +1,154 @@
+import { observer } from "mobx-react";
+import { Key, 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, DocumentFieldViewProps, 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"
+
+
+@observer
+export class CollectionDockingView extends React.Component<CollectionViewProps> {
+
+ public static LayoutString() { return '<CollectionDockingView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>'; }
+
+
+ private _times: number = 0;
+ private _containerRef = React.createRef<HTMLDivElement>();
+ private _canvasRef = React.createRef<HTMLDivElement>();
+ private _json = {
+ global: {},
+ borders: [],
+ layout: {
+ "type": "row",
+ "weight": 100,
+ "children": [
+ {
+ "type": "tabset",
+ "weight": 50,
+ "selected": 0,
+ "children": [
+ {
+ "type": "tab",
+ "name": "CHILD #1",
+ "component": "grid",
+ }
+ ]
+ },
+ {
+ "type": "tabset",
+ "weight": 50,
+ "selected": 0,
+ "children": [
+ {
+ "type": "tab",
+ "name": "CHILD #2",
+ "component": "grid",
+ }
+ ]
+ }
+ ]
+ }
+ };
+ private _model: any;
+ constructor(props: CollectionViewProps) {
+ super(props);
+ this._model = FlexLayout.Model.fromJson(this._json);
+ }
+
+ public static BORDER_WIDTH = 2;
+
+ @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() {
+ // if (this._containerRef.current) {
+ // DragManager.MakeDropTarget(this._containerRef.current, {
+ // handlers: {
+ // drop: this.drop
+ // }
+ // });
+ // }
+ }
+
+
+ @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 && SelectionManager.IsSelected(this.props.ContainingDocumentView!)) {
+ e.stopPropagation();
+ }
+ }
+ }
+ factory = (node: any): any => {
+ var component = node.getComponent();
+ if (component === "button") {
+ return <button>{node.getName()}</button>;
+ }
+ if (component === "grid") {
+ let which = this._times++ % 3;
+ if (which == 0)
+ return <div style={{ backgroundColor: "blue", width: 100, height: 100 }}></div>
+ if (which == 1)
+ return <div style={{ backgroundColor: "yellow", width: 100, height: 100 }}></div>
+ if (which == 2)
+ return <div style={{ backgroundColor: "red", width: 100, height: 100 }}></div>
+ }
+ }
+
+ render() {
+ const { fieldKey, Document: Document } = this.props;
+
+ const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+ const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
+ const pany: number = Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
+ const currScale: number = Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
+ return (
+ <div className="border" style={{
+ borderStyle: "solid",
+ borderWidth: `${CollectionDockingView.BORDER_WIDTH}px`,
+ }}>
+ <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} style={{
+ width: "100%",
+ height: `calc(100% - 2*${CollectionDockingView.BORDER_WIDTH}px)`,
+ }} ref={this._containerRef}>
+ <div className="collectiondockingview" ref={this._canvasRef}>
+ <FlexLayout.Layout model={this._model} factory={this.factory} />
+ </div>
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/views/collections/CollectionFreeFormView.scss b/src/views/collections/CollectionFreeFormView.scss
new file mode 100644
index 000000000..31e9985bc
--- /dev/null
+++ b/src/views/collections/CollectionFreeFormView.scss
@@ -0,0 +1,6 @@
+.collectionfreeformview-container {
+ position: relative;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/collections/CollectionFreeFormView.tsx
index 00b912294..479d883d6 100644
--- a/src/views/freeformcanvas/CollectionFreeFormView.tsx
+++ b/src/views/collections/CollectionFreeFormView.tsx
@@ -1,33 +1,25 @@
-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";
@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);
}
@@ -54,7 +46,7 @@ export class CollectionFreeFormView extends React.Component<IProps> {
doc.props.ContainingCollectionView.removeDocument(doc.props.Document);
this.addDocument(doc.props.Document);
}
- const {scale, translateX, translateY} = Utils.GetScreenTransform(ele);
+ const { scale, translateX, translateY } = Utils.GetScreenTransform(ele);
const screenX = de.x - xOffset;
const screenY = de.y - yOffset;
const docX = (screenX - translateX) / scale;
@@ -117,7 +109,7 @@ 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, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY);
var deltaScale = (1 - (e.deltaY / 1000)) * Ss;
@@ -185,7 +177,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 +191,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/freeformcanvas/CollectionFreeFormView.scss b/src/views/freeformcanvas/CollectionFreeFormView.scss
deleted file mode 100644
index 6ad6ad86c..000000000
--- a/src/views/freeformcanvas/CollectionFreeFormView.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.collectionfreeformview-container {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- overflow: hidden;
- .collectionfreeformview {
- position: absolute;
- top: 0;
- left: 0;
- }
-} \ No newline at end of file
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx
index 6e874c5a8..3ee70213f 100644
--- a/src/views/nodes/DocumentView.tsx
+++ b/src/views/nodes/DocumentView.tsx
@@ -4,11 +4,11 @@ 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";
@@ -17,14 +17,35 @@ 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 {
@@ -53,7 +74,7 @@ class DocumentContents extends React.Component<IProps> {
}
}
return <JsxParser
- components={{ FieldTextBox, CollectionFreeFormView }}
+ components={{ FieldTextBox, CollectionFreeFormView, CollectionDockingView }}
bindings={bindings}
jsx={this.layout}
showWarnings={true}
@@ -66,7 +87,7 @@ 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;
diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx
index 8568d04c5..20dfde1d2 100644
--- a/src/views/nodes/FieldTextBox.tsx
+++ b/src/views/nodes/FieldTextBox.tsx
@@ -1,30 +1,23 @@
-import {Key, KeyStore} from "../../fields/Key";
-import {Document} from "../../fields/Document";
-import {observer} from "mobx-react";
-import {TextField} from "../../fields/TextField";
+import { Key, KeyStore } from "../../fields/Key";
+import { Document } from "../../fields/Document";
+import { observer } from "mobx-react";
+import { TextField } from "../../fields/TextField";
import React = require("react")
-import {action, observable, reaction, IReactionDisposer} from "mobx";
+import { action, observable, reaction, IReactionDisposer } from "mobx";
-import {schema} from "prosemirror-schema-basic";
-import {EditorState, Transaction} from "prosemirror-state"
-import {EditorView} from "prosemirror-view"
-import {keymap} from "prosemirror-keymap"
-import {baseKeymap} from "prosemirror-commands"
-import {undo, redo, history} from "prosemirror-history"
-import {Opt} from "../../fields/Field";
+import { schema } from "prosemirror-schema-basic";
+import { EditorState, Transaction } from "prosemirror-state"
+import { EditorView } from "prosemirror-view"
+import { keymap } from "prosemirror-keymap"
+import { baseKeymap } from "prosemirror-commands"
+import { undo, redo, history } from "prosemirror-history"
+import { Opt } from "../../fields/Field";
import "./FieldTextBox.scss"
-import {DocumentView} from "./DocumentView";
-import {SelectionManager} from "../../util/SelectionManager";
+import { DocumentFieldViewProps } from "./DocumentView";
+import { SelectionManager } from "../../util/SelectionManager";
-// 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
-interface IProps {
- fieldKey: Key;
- doc: Document;
- containingDocumentView: DocumentView
-}
// FieldTextBox: Displays an editable plain text node that maps to a specified Key of a Document
//
@@ -42,14 +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} />";}
+ 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();
@@ -61,19 +54,19 @@ export class FieldTextBox extends React.Component<IProps> {
if (this._editorView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- const {doc, fieldKey} = this.props;
+ const { doc, fieldKey } = this.props;
doc.SetFieldValue(fieldKey, JSON.stringify(state.toJSON()), TextField);
}
}
componentDidMount() {
let state: EditorState;
- const {doc, fieldKey} = this.props;
+ const { doc, fieldKey } = this.props;
const config = {
schema,
plugins: [
history(),
- keymap({"Mod-z": undo, "Mod-y": redo}),
+ keymap({ "Mod-z": undo, "Mod-y": redo }),
keymap(baseKeymap)
]
};
@@ -116,7 +109,7 @@ export class FieldTextBox extends React.Component<IProps> {
@action
onChange(e: React.ChangeEvent<HTMLInputElement>) {
- const {fieldKey, doc} = this.props;
+ const { fieldKey, doc } = this.props;
doc.SetFieldValue(fieldKey, e.target.value, TextField);
}
onPointerDown = (e: React.PointerEvent): void => {