aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
authormadelinegr <mgriswold99@gmail.com>2019-03-04 17:43:13 -0500
committermadelinegr <mgriswold99@gmail.com>2019-03-04 17:43:13 -0500
commit604c79c214ac37059346139024aa199bb47cd877 (patch)
treee82d2f613fe0596f50a201a7eecddfcf7410db58 /src/client/views
parent9b63097989d7a1bfb803b27935959945aacfae5f (diff)
parent77dc4aa8b5033d8c7896809d1417ed8305de1421 (diff)
mer conf
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/ContextMenu.scss19
-rw-r--r--src/client/views/ContextMenu.tsx14
-rw-r--r--src/client/views/ContextMenuItem.tsx10
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/EditableView.tsx7
-rw-r--r--src/client/views/Main.tsx11
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx7
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx22
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx13
-rw-r--r--src/client/views/collections/CollectionTreeView.scss33
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx153
-rw-r--r--src/client/views/collections/CollectionView.tsx32
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx9
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx52
-rw-r--r--src/client/views/nodes/FieldView.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx25
-rw-r--r--src/client/views/nodes/ImageBox.tsx11
18 files changed, 296 insertions, 127 deletions
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 234f82eb9..ea40c8e99 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -3,16 +3,16 @@
display: flex;
z-index: 1000;
box-shadow: #AAAAAA .2vw .2vw .4vw;
+ flex-direction: column;
}
.contextMenu-item {
- width: 10vw;
- height: 4vh;
- background: #DDDDDD;
+ width: auto;
+ height: auto;
+ background: #F0F8FF;
display: flex;
- justify-content: center;
+ justify-content: left;
align-items: center;
- flex-direction: column;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
@@ -20,11 +20,18 @@
-ms-user-select: none;
user-select: none;
transition: all .1s;
+ border-width: .11px;
+ border-style: none;
+ border-color: rgb(187, 186, 186);
+ border-bottom-style: solid;
+ padding: 10px;
+ white-space: nowrap;
+ font-size: 1.5vw;
}
.contextMenu-item:hover {
transition: all .1s;
- background: #AAAAAA
+ background: #B0E0E6;
}
.contextMenu-description {
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 9459d45f8..fcb934860 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -12,6 +12,8 @@ export class ContextMenu extends React.Component {
@observable private _pageX: number = 0;
@observable private _pageY: number = 0;
@observable private _display: string = "none";
+ @observable private _searchString: string = "";
+
private ref: React.RefObject<HTMLDivElement>;
@@ -45,6 +47,8 @@ export class ContextMenu extends React.Component {
this._pageX = x
this._pageY = y
+ this._searchString = "";
+
this._display = "flex"
}
@@ -62,10 +66,18 @@ export class ContextMenu extends React.Component {
render() {
return (
<div className="contextMenu-cont" style={{ left: this._pageX, top: this._pageY, display: this._display }} ref={this.ref}>
- {this._items.map(prop => {
+ <input className="contextMenu-item" type="text" placeholder="Search . . ." value={this._searchString} onChange={this.onChange}></input>
+ {this._items.filter(prop => {
+ return prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1;
+ }).map(prop => {
return <ContextMenuItem {...prop} key={prop.description} />
})}
</div>
)
}
+
+ @action
+ onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._searchString = e.target.value;
+ }
} \ No newline at end of file
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 8f00f8b3d..4801c1555 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -1,11 +1,19 @@
import React = require("react");
-import { ContextMenu } from "./ContextMenu";
export interface ContextMenuProps {
description: string;
event: (e: React.MouseEvent<HTMLDivElement>) => void;
}
+export interface SubmenuProps {
+ description: string;
+ subitems: ContextMenuProps[];
+}
+
+export interface ContextMenuItemProps {
+ type: ContextMenuProps | SubmenuProps
+}
+
export class ContextMenuItem extends React.Component<ContextMenuProps> {
render() {
return (
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 975a125f7..9fd73a33b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,4 +1,4 @@
-import { observable, computed, action } from "mobx";
+import { observable, computed } from "mobx";
import React = require("react");
import { SelectionManager } from "../util/SelectionManager";
import { observer } from "mobx-react";
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 8d9a47eaa..88ef67afa 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -27,12 +27,11 @@ export class EditableView extends React.Component<EditableProps> {
render() {
if (this.editing) {
return <input defaultValue={this.props.GetValue()} onKeyDown={this.onKeyDown} autoFocus onBlur={action(() => this.editing = false)}
- style={{ width: "100%" }}></input>
+ style={{ display: "inline" }}></input>
} else {
return (
- <div className="editableView-container-editing" style={{ display: "flex", height: "100%", maxHeight: `${this.props.height}` }}
- onClick={action(() => this.editing = true)}
- >
+ <div className="editableView-container-editing" style={{ display: "inline", height: "100%", maxHeight: `${this.props.height}` }}
+ onClick={action(() => this.editing = true)}>
{this.props.contents}
</div>
)
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 97e39377c..fbc9d1d80 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -4,7 +4,8 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Document } from '../../fields/Document';
import { KeyStore } from '../../fields/KeyStore';
-import { DocumentTransfer, MessageStore } from '../../server/Message';
+import "./Main.scss";
+import { MessageStore } from '../../server/Message';
import { Utils } from '../../Utils';
import { Documents } from '../documents/Documents';
import { Server } from '../Server';
@@ -33,7 +34,6 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
const mainDocId = "mainDoc";
let mainContainer: Document;
let mainfreeform: Document;
-console.log("HELLO WORLD")
Documents.initProtos(mainDocId, (res?: Document) => {
if (res instanceof Document) {
mainContainer = res;
@@ -59,12 +59,14 @@ Documents.initProtos(mainDocId, (res?: Document) => {
let weburl = "https://cs.brown.edu/courses/cs166/";
let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {}))
let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" }))
- let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a feeform collection" }));
+ let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" }));
let addSchemaNode = action(() => Documents.SchemaDocument([Documents.TextDocument()], { width: 200, height: 200, title: "a schema collection" }));
let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" }));
let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" }));
- let addClick = (creator: () => Document) => action(() => mainfreeform.GetList<Document>(KeyStore.Data, []).push(creator()));
+ let addClick = (creator: () => Document) => action(() =>
+ mainfreeform.GetList<Document>(KeyStore.Data, []).push(creator())
+ );
let imgRef = React.createRef<HTMLDivElement>();
let webRef = React.createRef<HTMLDivElement>();
@@ -82,6 +84,7 @@ Documents.initProtos(mainDocId, (res?: Document) => {
PanelHeight={() => 0}
isTopMost={true}
SelectOnLoad={false}
+ focus={() => { }}
ContainingCollectionView={undefined} />
<DocumentDecorations />
<ContextMenu />
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index ad7164e33..c51fba908 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,13 +1,13 @@
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, observable, reaction } from "mobx";
+import { action, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
-import Measure from "react-measure";
import { Document } from "../../../fields/Document";
-import { FieldId, Opt, Field } from "../../../fields/Field";
import { KeyStore } from "../../../fields/KeyStore";
+import Measure from "react-measure";
+import { FieldId, Opt, Field } from "../../../fields/Field";
import { Utils } from "../../../Utils";
import { Server } from "../../Server";
import { undoBatch } from "../../util/UndoManager";
@@ -269,6 +269,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ScreenToLocalTransform={this.ScreenToLocalTransform}
isTopMost={true}
SelectOnLoad={false}
+ focus={(doc: Document) => { }}
ContainingCollectionView={undefined} />
</div>
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 5e9dcd5d5..f71f2791c 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -163,7 +163,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
onKeyDown = (e: React.KeyboardEvent<Element>) => {
//if not these keys, make a textbox if preview cursor is active!
- if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
+ if (!e.ctrlKey && !e.altKey) {
if (this._previewCursorVisible) {
//make textbox and add it to this collection
let [x, y] = this.getTransform().transformPoint(this._downX, this._downY); (this._downX, this._downY);
@@ -208,12 +208,21 @@ export class CollectionFreeFormView extends CollectionViewBase {
return field.Data;
}
}
+
+ focusDocument = (doc: Document) => {
+ let x = doc.GetNumber(KeyStore.X, 0) + doc.GetNumber(KeyStore.Width, 0) / 2;
+ let y = doc.GetNumber(KeyStore.Y, 0) + doc.GetNumber(KeyStore.Height, 0) / 2;
+ this.SetPan(x, y);
+ this.props.focus(this.props.Document);
+ }
+
+
@computed
get views() {
const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
if (lvalue && lvalue != FieldWaiting) {
return lvalue.Data.map(doc => {
- return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc} ref={focus}
+ return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc}
AddDocument={this.props.addDocument}
RemoveDocument={this.props.removeDocument}
ScreenToLocalTransform={this.getTransform}
@@ -222,7 +231,9 @@ export class CollectionFreeFormView extends CollectionViewBase {
ContentScaling={this.noScaling}
PanelWidth={doc.Width}
PanelHeight={doc.Height}
- ContainingCollectionView={this.props.CollectionView} />);
+ ContainingCollectionView={this.props.CollectionView}
+ focus={this.focusDocument}
+ />);
})
}
return null;
@@ -257,7 +268,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
//when focus is lost, this will remove the preview cursor
@action
- onBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
+ onBlur = (e: React.FocusEvent<HTMLDivElement>): void => {
this._previewCursorVisible = false;
}
@@ -275,9 +286,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0);
const pany: number = -this.props.Document.GetNumber(KeyStore.PanY, 0);
- // const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0) + this.centeringShiftX;
- // const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0) + this.centeringShiftY;
- console.log("center:", this.getLocalTransform().transformPoint(this.centeringShiftX, this.centeringShiftY));
return (
<div className="collectionfreeformview-container"
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 5bcd501cc..49f95c014 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,14 +1,15 @@
import React = require("react")
-import { action, observable, trace } from "mobx";
+import { action, observable } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
import "react-table/react-table.css";
import { Document } from "../../../fields/Document";
-import { Field, FieldWaiting } from "../../../fields/Field";
+import { Field } from "../../../fields/Field";
import { KeyStore } from "../../../fields/KeyStore";
import { CompileScript, ToField } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
+import { ContextMenu } from "../ContextMenu";
import { EditableView } from "../EditableView";
import { DocumentView } from "../nodes/DocumentView";
import { FieldView, FieldViewProps } from "../nodes/FieldView";
@@ -58,7 +59,7 @@ export class CollectionSchemaView extends CollectionViewBase {
return field || "";
}}
SetValue={(value: string) => {
- let script = CompileScript(value);
+ let script = CompileScript(value, undefined, true);
if (!script.compiled) {
return false;
}
@@ -175,6 +176,8 @@ export class CollectionSchemaView extends CollectionViewBase {
return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling);
}
+ focusDocument = (doc: Document) => { }
+
render() {
const columns = this.props.Document.GetList(KeyStore.ColumnsKey, [KeyStore.Title, KeyStore.Data, KeyStore.Author])
const children = this.props.Document.GetList<Document>(this.props.fieldKey, []);
@@ -191,7 +194,9 @@ export class CollectionSchemaView extends CollectionViewBase {
ContentScaling={this.getContentScaling}
PanelWidth={this.getPanelWidth}
PanelHeight={this.getPanelHeight}
- ContainingCollectionView={this.props.CollectionView} />
+ ContainingCollectionView={this.props.CollectionView}
+ focus={this.focusDocument}
+ />
</div>
}
</Measure>
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index c488e2894..f8d580a7b 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -1,3 +1,8 @@
+#body {
+ padding: 20px;
+ background: #bbbbbb;
+}
+
ul {
list-style: none;
}
@@ -10,25 +15,23 @@ li {
padding-left: 0;
}
-/* ALL THESE SPACINGS ARE SUPER HACKY RIGHT NOW HANNAH PLS HELP */
-
-li:before {
- content: '\2014';
- margin-right: 0.7em;
+.bullet {
+ width: 1.5em;
+ display: inline-block;
}
-.collapsed:before {
- content: '\25b6';
- margin-right: 0.65em;
+.collectionTreeView-dropTarget {
+ border-style: solid;
+ box-sizing: border-box;
+ height: 100%;
}
-.uncollapsed:before {
- content: '\25bc';
- margin-right: 0.5em;
+.docContainer {
+ display: inline-table;
}
-.collectionTreeView-dropTarget {
- border-style: solid;
- box-sizing: border-box;
- height:100%;
+.delete-button {
+ color: #999999;
+ float: right;
+ margin-left: 1em;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index c0d6bd4f7..efc22cdc5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -7,12 +7,20 @@ import React = require("react")
import { TextField } from "../../../fields/TextField";
import { observable, action } from "mobx";
import "./CollectionTreeView.scss";
+import { EditableView } from "../EditableView";
import { setupDrag } from "../../util/DragManager";
import { FieldWaiting } from "../../../fields/Field";
import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
export interface TreeViewProps {
document: Document;
+ deleteDoc: (doc: Document) => void;
+}
+
+export enum BulletType {
+ Collapsed,
+ Collapsible,
+ List
}
@observer
@@ -25,41 +33,101 @@ class TreeView extends React.Component<TreeViewProps> {
@observable
collapsed: boolean = false;
+ delete = () => {
+ this.props.deleteDoc(this.props.document);
+ }
+
+
+ @action
+ remove = (document: Document) => {
+ var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+ if (children && children !== FieldWaiting) {
+ children.Data.splice(children.Data.indexOf(document), 1);
+ }
+ }
+
+ renderBullet(type: BulletType) {
+ let onClicked = action(() => this.collapsed = !this.collapsed);
+
+ switch (type) {
+ case BulletType.Collapsed:
+ return <div className="bullet" onClick={onClicked}>&#9654;</div>
+ case BulletType.Collapsible:
+ return <div className="bullet" onClick={onClicked}>&#9660;</div>
+ case BulletType.List:
+ return <div className="bullet">&mdash;</div>
+ }
+ }
+
/**
- * Renders a single child document. If this child is a collection, it will call renderTreeView again. Otherwise, it will just append a list element.
- * @param childDocument The document to render.
+ * Renders the EditableView title element for placement into the tree.
*/
- renderChild(childDocument: Document) {
+ renderTitle() {
+ let title = this.props.document.GetT<TextField>(KeyStore.Title, TextField);
+
+ // if the title hasn't loaded, immediately return the div
+ if (!title || title === "<Waiting>") {
+ return <div key={this.props.document.Id}></div>;
+ }
+
+ return <div className="docContainer"> <EditableView contents={title.Data}
+ height={36} GetValue={() => {
+ let title = this.props.document.GetT<TextField>(KeyStore.Title, TextField);
+ if (title && title !== "<Waiting>")
+ return title.Data;
+ return "";
+ }} SetValue={(value: string) => {
+ this.props.document.SetData(KeyStore.Title, value, TextField);
+ return true;
+ }} />
+ <div className="delete-button" onClick={this.delete}>x</div>
+ </div >
+ }
+
+ render() {
+ var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+
let reference = React.createRef<HTMLDivElement>();
+ let onItemDown = setupDrag(reference, () => this.props.document);
+ let titleElement = this.renderTitle();
- var children = childDocument.GetT<ListField<Document>>(KeyStore.Data, ListField);
- let title = childDocument.GetT<TextField>(KeyStore.Title, TextField);
- let onItemDown = setupDrag(reference, () => childDocument);
+ // check if this document is a collection
+ if (children && children !== FieldWaiting) {
+ let subView;
- if (title && title != FieldWaiting) {
- let subView = !children || this.collapsed || children === FieldWaiting ? (null) :
- <ul>
- <TreeView document={childDocument} />
- </ul>;
- return <div className="treeViewItem-container" onPointerDown={onItemDown} ref={reference}>
- <li className={!children ? "leaf" : this.collapsed ? "collapsed" : "uncollapsed"}
- onClick={action(() => this.collapsed = !this.collapsed)} >
- {title.Data}
- {subView}
+ // if uncollapsed, then add the children elements
+ if (!this.collapsed) {
+ // render all children elements
+ let childrenElement = (children.Data.map(value =>
+ <TreeView document={value} deleteDoc={this.remove} />)
+ )
+ subView =
+ <li key={this.props.document.Id} >
+ {this.renderBullet(BulletType.Collapsible)}
+ {titleElement}
+ <ul key={this.props.document.Id}>
+ {childrenElement}
+ </ul>
+ </li>
+ } else {
+ subView = <li key={this.props.document.Id}>
+ {this.renderBullet(BulletType.Collapsed)}
+ {titleElement}
</li>
+ }
+
+ return <div className="treeViewItem-container" onPointerDown={onItemDown} ref={reference}>
+ {subView}
</div>
}
- return (null);
- }
- render() {
- var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
- return !children || children === FieldWaiting ? (null) :
- (children.Data.map(value =>
- <div key={value.Id}>
- {this.renderChild(value)}
- </div>)
- )
+ // otherwise this is a normal leaf node
+ else {
+ return <li key={this.props.document.Id}>
+ {this.renderBullet(BulletType.List)}
+ {titleElement}
+ </li>;
+ }
}
}
@@ -67,21 +135,42 @@ class TreeView extends React.Component<TreeViewProps> {
@observer
export class CollectionTreeView extends CollectionViewBase {
+ @action
+ remove = (document: Document) => {
+ var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+ if (children && children !== FieldWaiting) {
+ children.Data.splice(children.Data.indexOf(document), 1);
+ }
+ }
+
render() {
let titleStr = "";
let title = this.props.Document.GetT<TextField>(KeyStore.Title, TextField);
if (title && title !== FieldWaiting) {
titleStr = title.Data;
}
+
+ var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+ let childrenElement = !children || children === FieldWaiting ? (null) :
+ (children.Data.map(value =>
+ <TreeView document={value} key={value.Id} deleteDoc={this.remove} />)
+ )
+
return (
- <div className="collectionTreeView-dropTarget" onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} >
- <h3>{titleStr}</h3>
+ <div id="body" className="collectionTreeView-dropTarget" onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}>
+ <h3>
+ <EditableView contents={titleStr}
+ height={72} GetValue={() => {
+ return this.props.Document.Title;
+ }} SetValue={(value: string) => {
+ this.props.Document.SetData(KeyStore.Title, value, TextField);
+ return true;
+ }} />
+ </h3>
<ul className="no-indent">
- <TreeView
- document={this.props.Document}
- />
+ {childrenElement}
</ul>
- </div>
+ </div >
);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f938d2237..1dbc3c3e3 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable } from "mobx";
+import { action } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { ListField } from "../../../fields/ListField";
@@ -30,7 +30,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
public static LayoutString(fieldKey: string = "DataKey") {
return `<CollectionView Document={Document}
ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
- isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} />`;
+ isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
}
public active = () => {
var isSelected = this.props.isSelected();
@@ -89,29 +89,43 @@ export class CollectionView extends React.Component<CollectionViewProps> {
Document.SetData(KeyStore.ViewType, type, NumberField);
}
+ specificContextMenu = (e: React.MouseEvent): void => {
+ ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) })
+ ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) })
+ ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) })
+ ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
+ }
render() {
let viewType = this.collectionViewType;
-
+ let subView: JSX.Element;
switch (viewType) {
case CollectionViewType.Freeform:
- return (<CollectionFreeFormView {...this.props}
+ subView = (<CollectionFreeFormView {...this.props}
addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
- CollectionView={this} />);
+ CollectionView={this} />)
+ break;
case CollectionViewType.Schema:
- return (<CollectionSchemaView {...this.props}
+ subView = (<CollectionSchemaView {...this.props}
addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
CollectionView={this} />)
+ break;
case CollectionViewType.Docking:
- return (<CollectionDockingView {...this.props}
+ subView = (<CollectionDockingView {...this.props}
addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
CollectionView={this} />)
+ break;
case CollectionViewType.Tree:
- return (<CollectionTreeView {...this.props}
+ subView = (<CollectionTreeView {...this.props}
addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
CollectionView={this} />)
+ break;
default:
- return <div></div>
+ subView = <div></div>
+ break;
}
+ return (<div onContextMenu={this.specificContextMenu}>
+ {subView}
+ </div>)
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 7067724c8..0a3b965f2 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -1,16 +1,16 @@
-import { action, computed } from "mobx";
+import { action } from "mobx";
import { Document } from "../../../fields/Document";
import { ListField } from "../../../fields/ListField";
import React = require("react");
import { KeyStore } from "../../../fields/KeyStore";
-import { Opt, FieldWaiting } from "../../../fields/Field";
+import { FieldWaiting } from "../../../fields/Field";
import { undoBatch } from "../../util/UndoManager";
import { DragManager } from "../../util/DragManager";
import { DocumentView } from "../nodes/DocumentView";
import { Documents, DocumentOptions } from "../../documents/Documents";
import { Key } from "../../../fields/Key";
import { Transform } from "../../util/Transform";
-
+import { CollectionView } from "./CollectionView";
export interface CollectionViewProps {
fieldKey: Key;
@@ -22,12 +22,13 @@ export interface CollectionViewProps {
bindings: any;
panelWidth: () => number;
panelHeight: () => number;
+ focus: (doc: Document) => void;
}
export interface SubCollectionViewProps extends CollectionViewProps {
active: () => boolean;
addDocument: (doc: Document) => void;
removeDocument: (doc: Document) => boolean;
- CollectionView: any;
+ CollectionView: CollectionView;
}
export class CollectionViewBase extends React.Component<SubCollectionViewProps> {
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 9edad1f64..50dc5a619 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -69,7 +69,6 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
}
render() {
- console.log(this.transform);
return (
<div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
transformOrigin: "left top",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e2b3f9833..b23fdf72f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -21,22 +21,20 @@ import { WebBox } from "../nodes/WebBox";
import "./DocumentView.scss";
import React = require("react");
import { PresentationView } from "../PresentationView";
-import { CollectionViewProps } from "../collections/CollectionViewBase";
-const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
+const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView>;
-
Document: Document;
AddDocument?: (doc: Document) => void;
RemoveDocument?: (doc: Document) => boolean;
ScreenToLocalTransform: () => Transform;
isTopMost: boolean;
- //tfs: This shouldn't be necessary I don't think
ContentScaling: () => number;
PanelWidth: () => number;
PanelHeight: () => number;
+ focus: (doc: Document) => void;
SelectOnLoad: boolean;
}
export interface JsxArgs extends DocumentViewProps {
@@ -83,20 +81,16 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
-
private _mainCont = React.createRef<HTMLDivElement>();
private _documentBindings: any = null;
private _downX: number = 0;
private _downY: number = 0;
-
@computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); }
@computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; }
@computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
@computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
@computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
-
screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
-
onPointerDown = (e: React.PointerEvent): void => {
this._downX = e.clientX;
this._downY = e.clientY;
@@ -116,7 +110,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
}
-
onPointerMove = (e: PointerEvent): void => {
if (e.cancelBubble) {
return;
@@ -141,7 +134,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
e.stopPropagation();
e.preventDefault();
}
-
onPointerUp = (e: PointerEvent): void => {
document.removeEventListener("pointermove", this.onPointerMove)
document.removeEventListener("pointerup", this.onPointerUp)
@@ -188,19 +180,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked })
+ ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) })
ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) })
- ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) })
- ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) })
- ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) })
- ContextMenu.Instance.addItem({
- description: "center", event: () => {
- if (this.props.ContainingCollectionView) {
- let doc = this.props.ContainingCollectionView.props.Document;
- doc.SetNumber(KeyStore.PanX, this.props.Document.GetNumber(KeyStore.X, 0) + (this.props.Document.GetNumber(KeyStore.Width, 0) / 2))
- doc.SetNumber(KeyStore.PanY, this.props.Document.GetNumber(KeyStore.Y, 0) + (this.props.Document.GetNumber(KeyStore.Height, 0) / 2))
- }
- }
- })
//ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
if (!this.topMost) {
@@ -213,7 +194,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
SelectionManager.SelectDoc(this, e.ctrlKey);
}
-
@computed get mainContent() {
return <JsxParser
components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox }}
@@ -224,27 +204,34 @@ export class DocumentView extends React.Component<DocumentViewProps> {
/>
}
+ isSelected = () => {
+ return SelectionManager.IsSelected(this);
+ }
+
+ select = (ctrlPressed: boolean) => {
+ SelectionManager.SelectDoc(this, ctrlPressed)
+ }
+
render() {
- if (!this.props.Document)
- return <div></div>
+ if (!this.props.Document) return <div></div>
let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField);
if (!lkeys || lkeys === "<Waiting>") {
return <p>Error loading layout keys</p>;
}
this._documentBindings = {
...this.props,
- isSelected: () => SelectionManager.IsSelected(this),
- select: (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed)
+ isSelected: this.isSelected,
+ select: this.select,
+ focus: this.props.focus
};
for (const key of this.layoutKeys) {
- this._documentBindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
+ this._documentBindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
}
for (const key of this.layoutFields) {
let field = this.props.Document.Get(key);
this._documentBindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
}
this._documentBindings.bindings = this._documentBindings;
-
var scaling = this.props.ContentScaling();
var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
@@ -254,13 +241,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
transformOrigin: "left top",
- transform: `scale(${scaling},${scaling})`
+ transform: `scale(${scaling} , ${scaling})`
}}
onContextMenu={this.onContextMenu}
- onPointerDown={this.onPointerDown}
- >
+ onPointerDown={this.onPointerDown} >
{this.mainContent}
</div>
)
}
-}
+} \ No newline at end of file
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index f372258f8..9e63006d1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,7 +1,7 @@
import React = require("react")
import { observer } from "mobx-react";
import { computed } from "mobx";
-import { Field, Opt, FieldWaiting, FieldValue } from "../../../fields/Field";
+import { Field, FieldWaiting, FieldValue } from "../../../fields/Field";
import { Document } from "../../../fields/Document";
import { TextField } from "../../../fields/TextField";
import { NumberField } from "../../../fields/NumberField";
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e65615af4..04eb2052d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -10,6 +10,7 @@ import "./FormattedTextBox.scss";
import React = require("react")
import { RichTextField } from "../../../fields/RichTextField";
import { FieldViewProps, FieldView } from "./FieldView";
+import { ContextMenu } from "../../views/ContextMenu";
@@ -112,12 +113,36 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
e.stopPropagation();
}
}
+
+ //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
+ textCapability = (e: React.MouseEvent): void => {
+ }
+
+ specificContextMenu = (e: React.MouseEvent): void => {
+ ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability });
+ // ContextMenu.Instance.addItem({
+ // description: "Submenu",
+ // items: [
+ // {
+ // description: "item 1", event:
+ // },
+ // {
+ // description: "item 2", event:
+ // }
+ // ]
+ // })
+ // e.stopPropagation()
+
+ }
+
onPointerWheel = (e: React.WheelEvent): void => {
e.stopPropagation();
}
+
render() {
return (<div className="formattedTextBox-cont"
onPointerDown={this.onPointerDown}
+ onContextMenu={this.specificContextMenu}
onWheel={this.onPointerWheel}
ref={this._ref} />)
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e206bf8d5..8c44395f4 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -7,6 +7,7 @@ import { ImageField } from '../../../fields/ImageField';
import { FieldViewProps, FieldView } from './FieldView';
import { FieldWaiting } from '../../../fields/Field';
import { observer } from "mobx-react"
+import { ContextMenu } from "../../views/ContextMenu";
import { observable, action } from 'mobx';
import { KeyStore } from '../../../fields/KeyStore';
@@ -88,13 +89,21 @@ export class ImageBox extends React.Component<FieldViewProps> {
}
}
+ //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
+ imageCapability = (e: React.MouseEvent): void => {
+ }
+
+ specificContextMenu = (e: React.MouseEvent): void => {
+ ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability });
+ }
+
render() {
let field = this.props.doc.Get(this.props.fieldKey);
let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif";
let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1);
return (
- <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} >
+ <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} onContextMenu={this.specificContextMenu}>
<img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
{this.lightbox(path)}
</div>)