aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authortschicke-brown <tyler_schicke@brown.edu>2019-02-19 21:58:18 -0500
committerGitHub <noreply@github.com>2019-02-19 21:58:18 -0500
commitdae1c5a1ac8b141ea26711db2977faa0be655137 (patch)
tree6fd1cfe02eaeaf1dc074a26cc4cde39c3313d1f3 /src/client/views/collections
parent02db8b435396f3b6ea605ce327828f02b41080ef (diff)
parent6bd1ed0fc3d070343ecd72de13383f9ad8b1e250 (diff)
Merge pull request #8 from browngraphicslab/server_database_merge
Server database merge
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx112
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx66
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx8
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx12
4 files changed, 105 insertions, 93 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 885a4bece..ceb638ab4 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,21 +1,23 @@
import * as GoldenLayout from "golden-layout";
import 'golden-layout/src/css/goldenlayout-base.css';
import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, computed, reaction, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Document } from "../../../fields/Document";
-import { KeyStore } from "../../../fields/Key";
-import { ListField } from "../../../fields/ListField";
+import { action, computed, observable, reaction, trace } from "mobx";
import { DragManager } from "../../util/DragManager";
import { DocumentView } from "../nodes/DocumentView";
+import { Document } from "../../../fields/Document";
import "./CollectionDockingView.scss";
-import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase";
+import { CollectionViewBase, COLLECTION_BORDER_WIDTH, CollectionViewProps } from "./CollectionViewBase";
import React = require("react");
import * as ReactDOM from 'react-dom';
import Measure from "react-measure";
import { Utils } from "../../../Utils";
-import { FieldId } from "../../../fields/Field";
+import { FieldId, FieldWaiting, Field } from "../../../fields/Field";
import { Server } from "../../Server";
+import { observer } from "mobx-react";
+import { ListField } from "../../../fields/ListField";
+import { KeyStore } from "../../../fields/KeyStore";
+import { Opt } from "../../../fields/Field";
+import { TextField } from "../../../fields/TextField";
@observer
export class CollectionDockingView extends CollectionViewBase {
@@ -41,6 +43,7 @@ export class CollectionDockingView extends CollectionViewBase {
private _containerRef = React.createRef<HTMLDivElement>();
private _makeFullScreen: boolean = false;
private _maximizedStack: any = null;
+ private _forceRecreate: boolean = false;
constructor(props: CollectionViewProps) {
super(props);
@@ -91,16 +94,10 @@ export class CollectionDockingView extends CollectionViewBase {
type: 'stack',
content: [CollectionDockingView.makeDocumentConfig(document)]
};
- var newContentItem = new this._goldenLayout._typeToItem[newItemStackConfig.type](this._goldenLayout, newItemStackConfig, parent);
+ var newContentItem = new this._goldenLayout._typeToItem[newItemStackConfig.type](this._goldenLayout, newItemStackConfig, null);
if (this._goldenLayout.root.contentItems[0].isRow) {
- var rowlayout = this._goldenLayout.root.contentItems[0];
- var lastRowItem = rowlayout.contentItems[rowlayout.contentItems.length - 1];
-
- lastRowItem.config["width"] *= 0.5;
- newContentItem.config["width"] = lastRowItem.config["width"];
- rowlayout.addChild(newContentItem, rowlayout.contentItems.length, true);
- rowlayout.callDownwards('setSize');
+ this._goldenLayout.root.contentItems[0].addChild(newContentItem);
}
else {
var collayout = this._goldenLayout.root.contentItems[0];
@@ -112,19 +109,35 @@ export class CollectionDockingView extends CollectionViewBase {
collayout.config["width"] = 50;
newContentItem.config["width"] = 50;
- collayout.parent.callDownwards('setSize');
}
+ this.stateChanged(); // shouldn't need to do either of these ... but our react component doesn't render when we add it manually like this.
+ this.setupGoldenLayout(true); // this forces it to render by the brute force method of recreating the whole golden layout
}
- componentDidMount: () => void = () => {
- if (this._containerRef.current) {
-
- this._goldenLayout = new GoldenLayout(JSON.parse(this.props.Document.GetText(KeyStore.Data, "")));
+ setupGoldenLayout(force: boolean = false) {
+ var config = this.props.Document.GetText(KeyStore.Data, "");
+ if (config) {
+ if (!this._goldenLayout)
+ this._goldenLayout = new GoldenLayout(JSON.parse(config));
+ else {
+ if (!force && JSON.stringify(this._goldenLayout.toConfig()) == JSON.stringify(JSON.parse(config)))
+ return;
+ this._goldenLayout.destroy();
+ this._goldenLayout = new GoldenLayout(JSON.parse(config));
+ }
this._goldenLayout.on('tabCreated', this.tabCreated);
this._goldenLayout.on('stackCreated', this.stackCreated);
this._goldenLayout.registerComponent('DocumentFrameRenderer', DockedFrameRenderer);
this._goldenLayout.container = this._containerRef.current;
this._goldenLayout.init();
+ this._goldenLayout.on('stateChanged', this.stateChanged);
+ }
+ }
+ componentDidMount: () => void = () => {
+ if (this._containerRef.current) {
+ reaction(
+ () => this.props.Document.GetText(KeyStore.Data, ""),
+ () => this.setupGoldenLayout(), { fireImmediately: true });
window.addEventListener('resize', this.onResize); // bcz: would rather add this event to the parent node, but resize events only come from Window
}
@@ -134,7 +147,7 @@ export class CollectionDockingView extends CollectionViewBase {
}
@action
onResize = (event: any) => {
- var cur = this.props.ContainingDocumentView!.MainContent.current;
+ var cur = this._containerRef.current;
// bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed
this._goldenLayout.updateSize(cur!.getBoundingClientRect().width, cur!.getBoundingClientRect().height);
@@ -152,21 +165,26 @@ export class CollectionDockingView extends CollectionViewBase {
}
}
+ stateChanged = () => {
+ // if (!this._pointerIsDown) {
+ var json = JSON.stringify(this._goldenLayout.toConfig());
+ this.props.Document.SetText(KeyStore.Data, json)
+ //}
+ }
+
tabCreated = (tab: any) => {
- {
- if (this._dragDiv) {
- this._dragDiv.removeChild(this._dragElement);
- this._dragParent!.removeChild(this._dragFakeElement!);
- this._dragParent!.appendChild(this._dragElement!);
- DragManager.Root().removeChild(this._dragDiv);
- this._dragDiv = null;
- }
- //tab.setTitle(tab.contentItem.config.componentState.title);
- tab.closeElement.off('click') //unbind the current click handler
- .click(function () {
- tab.contentItem.remove();
- });
+ if (this._dragDiv) {
+ this._dragDiv.removeChild(this._dragElement);
+ this._dragParent!.removeChild(this._dragFakeElement!);
+ this._dragParent!.appendChild(this._dragElement!);
+ DragManager.Root().removeChild(this._dragDiv);
+ this._dragDiv = null;
+ this.stateChanged();
}
+ tab.closeElement.off('click') //unbind the current click handler
+ .click(function () {
+ tab.contentItem.remove();
+ });
}
stackCreated = (stack: any) => {
@@ -187,13 +205,8 @@ export class CollectionDockingView extends CollectionViewBase {
render() {
- const { fieldKey: fieldKey, Document: Document } = this.props;
- const value: Document[] = Document.GetData(fieldKey, ListField, []);
- // bcz: not sure why, but I need these to force the flexlayout to update when the collection size changes.
- // tfs: we should be able to use this.props.ScreenToLocalTransform to get s right?
- var s = this.props.ContainingDocumentView != undefined ? this.props.ContainingDocumentView!.ScalingToScreenSpace : 1;
- var w = Document.GetNumber(KeyStore.Width, 0) / s;
- var h = Document.GetNumber(KeyStore.Height, 0) / s;
+ this.props.Document.GetNumber(KeyStore.Width, 0); // bcz: needed to force render when window size changes
+ this.props.Document.GetNumber(KeyStore.Height, 0);
return (
<div className="collectiondockingview-container" id="menuContainer"
onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef}
@@ -213,28 +226,35 @@ interface DockedFrameProps {
@observer
export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
- private _mainCont = React.createRef<HTMLDivElement>();
+ _mainCont: any = null;
constructor(props: any) {
super(props);
+ Server.GetField(this.props.documentId, (f) => { this.Document = f as Document; })
+ }
+
+ setMainCont: any = (element: any) => {
+ this._mainCont = element;
}
@observable
private _parentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ParentScaling prop of the DocumentView
- @computed
- private get Document() { return Server.GetField(this.props.documentId, () => { }) as Document }
+ @observable
+ private Document: Opt<Document>;
render() {
+ if (!this.Document)
+ return <div></div>
let nativeWidth = this.Document.GetNumber(KeyStore.NativeWidth, 0);
var layout = this.Document.GetText(KeyStore.Layout, "");
var content =
- <div ref={this._mainCont}>
+ <div ref={this.setMainCont}>
<DocumentView key={this.Document.Id} Document={this.Document}
AddDocument={undefined}
RemoveDocument={undefined}
Scaling={this._parentScaling}
ScreenToLocalTransform={() => {
- let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!);
+ let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont);
var props = CollectionDockingView.Instance.props;
return props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._parentScaling)
}}
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 2c0a3f478..54757cce5 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -1,13 +1,11 @@
import { observer } from "mobx-react";
import React = require("react");
-import { action, observable, computed } from "mobx";
+import { action, computed } from "mobx";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DragManager } from "../../util/DragManager";
import "./CollectionFreeFormView.scss";
-import { Utils } from "../../../Utils";
-import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase";
-import { SelectionManager } from "../../util/SelectionManager";
-import { Key, KeyStore } from "../../../fields/Key";
+import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase";
+import { KeyStore } from "../../../fields/KeyStore";
import { Document } from "../../../fields/Document";
import { ListField } from "../../../fields/ListField";
import { NumberField } from "../../../fields/NumberField";
@@ -19,17 +17,12 @@ import { DocumentView } from "../nodes/DocumentView";
@observer
export class CollectionFreeFormView extends CollectionViewBase {
public static LayoutString(fieldKey: string = "DataKey") { return CollectionViewBase.LayoutString("CollectionFreeFormView", fieldKey); }
- private _containerRef = React.createRef<HTMLDivElement>();
private _canvasRef = React.createRef<HTMLDivElement>();
private _lastX: number = 0;
private _lastY: number = 0;
private _downX: number = 0;
private _downY: number = 0;
- constructor(props: CollectionViewProps) {
- super(props);
- }
-
@computed
get isAnnotationOverlay() { return this.props.fieldKey == KeyStore.Annotations; }
@@ -47,7 +40,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
const doc: DocumentView = de.data["document"];
- var me = this;
if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) {
doc.props.ContainingCollectionView.removeDocument(doc.props.Document);
this.addDocument(doc.props.Document);
@@ -55,7 +47,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
const xOffset = de.data["xOffset"] as number || 0;
const yOffset = de.data["yOffset"] as number || 0;
//this should be able to use translate and scale methods on an Identity transform, no?
- const transform = me.getTransform();
+ const transform = this.getTransform();
const screenX = de.x - xOffset;
const screenY = de.y - yOffset;
const [x, y] = transform.transformPoint(screenX, screenY);
@@ -65,9 +57,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
e.stopPropagation();
}
- componentDidMount() {
- if (this._containerRef.current) {
- DragManager.MakeDropTarget(this._containerRef.current, {
+ private dropDisposer?: DragManager.DragDropDisposer;
+ createDropTarget = (ele: HTMLDivElement) => {
+ if (this.dropDisposer) {
+ this.dropDisposer();
+ }
+ if (ele) {
+ this.dropDisposer = DragManager.MakeDropTarget(ele, {
handlers: {
drop: this.drop
}
@@ -119,7 +115,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
onPointerWheel = (e: React.WheelEvent): void => {
e.stopPropagation();
e.preventDefault();
- let modes = ['pixels', 'lines', 'page'];
let coefficient = 1000;
// if (modes[e.deltaMode] == 'pixels') coefficient = 50;
// else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height??
@@ -155,7 +150,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
let x = e.pageX - panx
let y = e.pageY - pany
- fReader.addEventListener("load", action("drop", (event) => {
+ fReader.addEventListener("load", action("drop", () => {
if (fReader.result) {
let url = "" + fReader.result;
let doc = Documents.ImageDocument(url, {
@@ -177,25 +172,25 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
}
- onDragOver = (e: React.DragEvent): void => {
+ onDragOver = (): void => {
}
@action
bringToFront(doc: DocumentView) {
const { fieldKey: fieldKey, Document: Document } = this.props;
- const value: Document[] = Document.GetList<Document>(fieldKey, []);
- var topmost = value.reduce((topmost, d) => Math.max(d.GetNumber(KeyStore.ZIndex, 0), topmost), -1000);
- value.map(d => {
- var zind = d.GetNumber(KeyStore.ZIndex, 0);
- if (zind != topmost - 1 - (topmost - zind) && d != doc.props.Document) {
- d.SetData(KeyStore.ZIndex, topmost - 1 - (topmost - zind), NumberField);
+ const value: Document[] = Document.GetList<Document>(fieldKey, []).slice();
+ value.sort((doc1, doc2) => {
+ if (doc1 === doc.props.Document) {
+ return 1;
}
- })
-
- if (doc.props.Document.GetNumber(KeyStore.ZIndex, 0) != 0) {
- doc.props.Document.SetData(KeyStore.ZIndex, 0, NumberField);
- }
+ if (doc2 === doc.props.Document) {
+ return -1;
+ }
+ return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
+ }).map((doc, index) => {
+ doc.SetNumber(KeyStore.ZIndex, index + 1)
+ });
}
@computed
@@ -220,11 +215,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
render() {
- const Document: Document = this.props.Document;
- const value: Document[] = Document.GetList<Document>(this.props.fieldKey, []);
+ const { fieldKey, Document } = this.props;
+ // const value: Document[] = Document.GetList<Document>(fieldKey, []);
+ const lvalue = Document.GetT<ListField<Document>>(fieldKey, ListField);
+ if (!lvalue || lvalue === "<Waiting>") {
+ return <p>Error loading collection data</p>
+ }
const panx: number = Document.GetNumber(KeyStore.PanX, 0);
const pany: number = Document.GetNumber(KeyStore.PanY, 0);
- var me = this;
return (
<div className="collectionfreeformview-container"
@@ -236,13 +234,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
style={{
borderWidth: `${COLLECTION_BORDER_WIDTH}px`,
}}
- ref={this._containerRef}>
+ ref={this.createDropTarget}>
<div className="collectionfreeformview"
style={{ width: "100%", transformOrigin: "left top", transform: ` translate(${panx}px, ${pany}px) scale(${this.zoomScaling}, ${this.zoomScaling})` }}
ref={this._canvasRef}>
{this.props.BackgroundView ? this.props.BackgroundView() : null}
- {value.map(doc => {
+ {lvalue.Data.map(doc => {
return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc}
AddDocument={this.addDocument}
RemoveDocument={this.removeDocument}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 5c95aca99..719783fd7 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "./CollectionViewBas
import { DocumentView } from "../nodes/DocumentView";
import { EditableView } from "../EditableView";
import { CompileScript, ToField } from "../../util/Scripting";
-import { KeyStore as KS, Key, KeyStore } from "../../../fields/Key";
+import { KeyStore } from "../../../fields/KeyStore";
import { Document } from "../../../fields/Document";
import { Field } from "../../../fields/Field";
import { Transform } from "../../util/Transform";
@@ -19,7 +19,7 @@ import Measure from "react-measure";
@observer
export class CollectionSchemaView extends CollectionViewBase {
- public static LayoutString() { return CollectionViewBase.LayoutString("CollectionSchemaView"); }
+ public static LayoutString() { return FieldView.LayoutString(CollectionSchemaView); }
@observable
selectedIndex = 0;
@@ -106,8 +106,8 @@ export class CollectionSchemaView extends CollectionViewBase {
render() {
const { Document: Document, fieldKey: fieldKey } = this.props;
const children = Document.GetList<Document>(fieldKey, []);
- const columns = Document.GetList(KS.ColumnsKey,
- [KS.Title, KS.Data, KS.Author])
+ const columns = Document.GetList(KeyStore.ColumnsKey,
+ [KeyStore.Title, KeyStore.Data, KeyStore.Author])
let content;
var me = this;
if (this.selectedIndex != -1) {
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 1e20da8d2..0acc890d8 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -1,22 +1,17 @@
import { action, computed } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
-import { Opt } from "../../../fields/Field";
-import { Key, KeyStore } from "../../../fields/Key";
+import { Key } from "../../../fields/Key";
import { ListField } from "../../../fields/ListField";
import { SelectionManager } from "../../util/SelectionManager";
import { ContextMenu } from "../ContextMenu";
import React = require("react");
-import { DocumentView } from "../nodes/DocumentView";
-import { CollectionDockingView } from "./CollectionDockingView";
-import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { Transform } from "../../util/Transform";
export interface CollectionViewProps {
fieldKey: Key;
Document: Document;
- ContainingDocumentView: Opt<DocumentView>;
ScreenToLocalTransform: () => Transform;
isSelected: () => boolean;
isTopMost: boolean;
@@ -32,12 +27,11 @@ export class CollectionViewBase extends React.Component<CollectionViewProps> {
public static LayoutString(collectionType: string, fieldKey: string = "DataKey") {
return `<${collectionType} Document={Document}
ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} isSelected={isSelected} select={select}
- isTopMost={isTopMost}
- ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`;
+ isTopMost={isTopMost} BackgroundView={BackgroundView} />`;
}
@computed
public get active(): boolean {
- var isSelected = (this.props.ContainingDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView));
+ var isSelected = this.props.isSelected();
var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this);
var topMost = this.props.isTopMost;
return isSelected || childSelected || topMost;