aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authorHannah Chow <hannah_chow@brown.edu>2019-03-11 17:11:43 -0400
committerHannah Chow <hannah_chow@brown.edu>2019-03-11 17:11:43 -0400
commit281b4e05a7fbd6b038782d9708839bf7edcf398d (patch)
treed91d9d4b45571b35c6b84d31de8af0487c4aaa2e /src/client/views/nodes
parentfe4f37c9986e0a6500d63b46e2238b0e0efb102b (diff)
parent618e66a5a070f1aac9224bd3f44b76a5ac314bfa (diff)
uhhhh
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DocumentView.tsx122
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/LinkBox.scss39
-rw-r--r--src/client/views/nodes/LinkBox.tsx89
-rw-r--r--src/client/views/nodes/LinkEditor.scss29
-rw-r--r--src/client/views/nodes/LinkEditor.tsx58
-rw-r--r--src/client/views/nodes/LinkMenu.scss20
-rw-r--r--src/client/views/nodes/LinkMenu.tsx54
-rw-r--r--src/client/views/nodes/WebBox.scss1
9 files changed, 395 insertions, 19 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9a0c1e6a4..1db16aca6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, IReactionDisposer, runInAction, reaction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { Field, FieldWaiting, Opt } from "../../../fields/Field";
@@ -24,6 +24,8 @@ import { WebBox } from "../nodes/WebBox";
import { PDFBox } from "../nodes/PDFBox";
import "./DocumentView.scss";
import React = require("react");
+import { TextField } from "../../../fields/TextField";
+import { DocumentManager } from "../../util/DocumentManager";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -88,6 +90,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
private _documentBindings: any = null;
private _downX: number = 0;
private _downY: number = 0;
+ private _reactionDisposer: Opt<IReactionDisposer>;
@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>"); }
@@ -97,16 +100,21 @@ export class DocumentView extends React.Component<DocumentViewProps> {
onPointerDown = (e: React.PointerEvent): void => {
this._downX = e.clientX;
this._downY = e.clientY;
+<<<<<<< HEAD
if (e.shiftKey && e.buttons === 1) {
CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e);
+=======
+ if (e.shiftKey && e.buttons === 2) {
+ if (this.props.isTopMost) {
+ this.startDragging(e.pageX, e.pageY);
+ }
+ else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e);
+>>>>>>> 618e66a5a070f1aac9224bd3f44b76a5ac314bfa
e.stopPropagation();
} else {
if (this.active && !e.isDefaultPrevented()) {
e.stopPropagation();
- if (e.buttons === 2) {
- e.preventDefault();
- }
document.removeEventListener("pointermove", this.onPointerMove)
document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp)
@@ -114,25 +122,74 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
}
+
+ private dropDisposer?: DragManager.DragDropDisposer;
+ protected createDropTarget = (ele: HTMLDivElement) => {
+
+ }
+
+ componentDidMount() {
+ if (this._mainCont.current) {
+ this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+ }
+ runInAction(() => {
+ DocumentManager.Instance.DocumentViews.push(this);
+ })
+ this._reactionDisposer = reaction(
+ () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(),
+ () => {
+ if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.indexOf(this.props.Document.Id) != -1)
+ SelectionManager.SelectDoc(this, true);
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.dropDisposer) {
+ this.dropDisposer();
+ }
+ if (this._mainCont.current) {
+ this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.dropDisposer) {
+ this.dropDisposer();
+ }
+ runInAction(() => {
+ DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
+
+ })
+ if (this._reactionDisposer) {
+ this._reactionDisposer();
+ }
+ }
+
+ startDragging(x: number, y: number) {
+ if (this._mainCont.current) {
+ const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ let dragData: { [id: string]: any } = {};
+ dragData["documentView"] = this;
+ dragData["xOffset"] = x - left;
+ dragData["yOffset"] = y - top;
+ DragManager.StartDrag(this._mainCont.current, dragData, {
+ handlers: {
+ dragComplete: action(() => { }),
+ },
+ hideSource: true
+ })
+ }
+ }
+
onPointerMove = (e: PointerEvent): void => {
if (e.cancelBubble) {
return;
}
if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
document.removeEventListener("pointermove", this.onPointerMove)
- document.removeEventListener("pointerup", this.onPointerUp)
- if (this._mainCont.current != null && !this.topMost) {
- const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- let dragData: { [id: string]: any } = {};
- dragData["documentView"] = this;
- dragData["xOffset"] = e.x - left;
- dragData["yOffset"] = e.y - top;
- DragManager.StartDrag(this._mainCont.current, dragData, {
- handlers: {
- dragComplete: action(() => { }),
- },
- hideSource: true
- })
+ document.removeEventListener("pointerup", this.onPointerUp);
+ if (!this.topMost || e.buttons == 2) {
+ this.startDragging(e.x, e.y);
}
}
e.stopPropagation();
@@ -173,6 +230,34 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
@action
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ console.log("drop");
+ const sourceDocView: DocumentView = de.data["linkSourceDoc"];
+ if (!sourceDocView) {
+ return;
+ }
+ let sourceDoc: Document = sourceDocView.props.Document;
+ let destDoc: Document = this.props.Document;
+ if (this.props.isTopMost) {
+ return;
+ }
+ let linkDoc: Document = new Document();
+
+ linkDoc.Set(KeyStore.Title, new TextField("New Link"));
+ linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
+ linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+
+ sourceDoc.GetOrCreateAsync(KeyStore.LinkedToDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) });
+ linkDoc.Set(KeyStore.LinkedToDocs, destDoc);
+ destDoc.GetOrCreateAsync(KeyStore.LinkedFromDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) });
+ linkDoc.Set(KeyStore.LinkedFromDocs, sourceDoc);
+
+
+
+ e.stopPropagation();
+ }
+
+ @action
onContextMenu = (e: React.MouseEvent): void => {
e.stopPropagation();
let moved = Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3;
@@ -197,7 +282,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
SelectionManager.SelectDoc(this, e.ctrlKey);
}
- @computed get mainContent() {
+
+ get mainContent() {
return <JsxParser
components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, WebBox, KeyValueBox, VideoBox, AudioBox, PDFBox }}
bindings={this._documentBindings}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index f5d5597a7..521b0324e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -69,7 +69,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
};
let field = this.props.doc.GetT(this.props.fieldKey, RichTextField);
- if (field && field != FieldWaiting) {
+ if (field && field != FieldWaiting && field.Data) {
state = EditorState.fromJSON(config, JSON.parse(field.Data));
} else {
state = EditorState.create(config);
diff --git a/src/client/views/nodes/LinkBox.scss b/src/client/views/nodes/LinkBox.scss
new file mode 100644
index 000000000..00e5ebb3d
--- /dev/null
+++ b/src/client/views/nodes/LinkBox.scss
@@ -0,0 +1,39 @@
+.link-container {
+ width: 100%;
+ height: 30px;
+ display: flex;
+ flex-direction: row;
+ border-top: 0.5px solid #bababa;
+}
+
+.info-container {
+ width: 60%;
+ padding-top: 5px;
+ padding-left: 5px;
+ display: flex;
+ flex-direction: column
+}
+
+.link-name {
+ font-size: 11px;
+}
+
+.doc-name {
+ font-size: 8px;
+}
+
+.button-container {
+ width: 40%;
+ display: flex;
+ flex-direction: row;
+}
+
+.button {
+ height: 15px;
+ width: 15px;
+ margin: 8px 5px;
+ border-radius: 50%;
+ opacity: 0.6;
+ pointer-events: auto;
+ background-color: #2B6091;
+} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
new file mode 100644
index 000000000..69df676ff
--- /dev/null
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -0,0 +1,89 @@
+import { observable, computed, action } from "mobx";
+import React = require("react");
+import { SelectionManager } from "../../util/SelectionManager";
+import { observer } from "mobx-react";
+import './LinkBox.scss'
+import { KeyStore } from '../../../fields/KeyStore'
+import { props } from "bluebird";
+import { DocumentView } from "./DocumentView";
+import { Document } from "../../../fields/Document";
+import { ListField } from "../../../fields/ListField";
+import { DocumentManager } from "../../util/DocumentManager";
+import { LinkEditor } from "./LinkEditor";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
+
+interface Props {
+ linkDoc: Document;
+ linkName: String;
+ pairedDoc: Document;
+ type: String;
+ showEditor: () => void
+}
+
+@observer
+export class LinkBox extends React.Component<Props> {
+
+ onViewButtonPressed = (e: React.PointerEvent): void => {
+ console.log("view down");
+ e.stopPropagation();
+ let docView = DocumentManager.Instance.getDocumentView(this.props.pairedDoc);
+ if (docView) {
+ docView.props.focus(this.props.pairedDoc);
+ } else {
+ CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc)
+ }
+ }
+
+ onEditButtonPressed = (e: React.PointerEvent): void => {
+ console.log("edit down");
+ e.stopPropagation();
+
+ this.props.showEditor();
+ }
+
+ onDeleteButtonPressed = (e: React.PointerEvent): void => {
+ console.log("delete down");
+ e.stopPropagation();
+ this.props.linkDoc.GetTAsync(KeyStore.LinkedFromDocs, Document, field => {
+ if (field) {
+ field.GetTAsync<ListField<Document>>(KeyStore.LinkedToDocs, ListField, field => {
+ if (field) {
+ field.Data.splice(field.Data.indexOf(this.props.linkDoc));
+ }
+ })
+ }
+ });
+ this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => {
+ if (field) {
+ field.GetTAsync<ListField<Document>>(KeyStore.LinkedFromDocs, ListField, field => {
+ if (field) {
+ field.Data.splice(field.Data.indexOf(this.props.linkDoc));
+ }
+ })
+ }
+ });
+ }
+
+ render() {
+
+ return (
+ //<LinkEditor linkBox={this} linkDoc={this.props.linkDoc} />
+ <div className="link-container">
+ <div className="info-container" onPointerDown={this.onViewButtonPressed}>
+ <div className="link-name">
+ <p>{this.props.linkName}</p>
+ </div>
+ <div className="doc-name">
+ <p>{this.props.type}{this.props.pairedDoc.Title}</p>
+ </div>
+ </div>
+
+ <div className="button-container">
+ <div className="button" onPointerDown={this.onViewButtonPressed}></div>
+ <div className="button" onPointerDown={this.onEditButtonPressed}></div>
+ <div className="button" onPointerDown={this.onDeleteButtonPressed}></div>
+ </div>
+ </div>
+ )
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkEditor.scss b/src/client/views/nodes/LinkEditor.scss
new file mode 100644
index 000000000..cb191dc8c
--- /dev/null
+++ b/src/client/views/nodes/LinkEditor.scss
@@ -0,0 +1,29 @@
+.edit-container {
+ width: 100%;
+ height: auto;
+ display: flex;
+ flex-direction: column;
+}
+
+.name-input {
+ margin-bottom: 10px;
+ padding: 5px;
+ font-size: 12px;
+}
+
+.description-input {
+ font-size: 12px;
+ padding: 5px;
+ margin-bottom: 10px;
+}
+
+.save-button {
+ width: 50px;
+ height: 20px;
+ background-color: #2B6091;
+ margin: 0 auto;
+ color: white;
+ text-align: center;
+ line-height: 20px;
+ font-size: 12px;
+} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
new file mode 100644
index 000000000..3f7b4bf2d
--- /dev/null
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -0,0 +1,58 @@
+import { observable, computed, action } from "mobx";
+import React = require("react");
+import { SelectionManager } from "../../util/SelectionManager";
+import { observer } from "mobx-react";
+import './LinkEditor.scss'
+import { KeyStore } from '../../../fields/KeyStore'
+import { props } from "bluebird";
+import { DocumentView } from "./DocumentView";
+import { Document } from "../../../fields/Document";
+import { TextField } from "../../../fields/TextField";
+import { link } from "fs";
+
+interface Props {
+ linkDoc: Document;
+ showLinks: () => void;
+}
+
+@observer
+export class LinkEditor extends React.Component<Props> {
+
+ @observable private _nameInput: string = this.props.linkDoc.GetText(KeyStore.Title, "");
+ @observable private _descriptionInput: string = this.props.linkDoc.GetText(KeyStore.LinkDescription, "");
+
+
+ onSaveButtonPressed = (e: React.PointerEvent): void => {
+ console.log("view down");
+ e.stopPropagation();
+
+ this.props.linkDoc.SetData(KeyStore.Title, this._nameInput, TextField);
+ this.props.linkDoc.SetData(KeyStore.LinkDescription, this._descriptionInput, TextField);
+
+ this.props.showLinks();
+ }
+
+
+
+ render() {
+
+ return (
+ <div className="edit-container">
+ <input onChange={this.onNameChanged} className="name-input" type="text" value={this._nameInput} placeholder="Name . . ."></input>
+ <textarea onChange={this.onDescriptionChanged} className="description-input" value={this._descriptionInput} placeholder="Description . . ."></textarea>
+ <div className="save-button" onPointerDown={this.onSaveButtonPressed}>SAVE</div>
+ </div>
+
+ )
+ }
+
+ @action
+ onNameChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._nameInput = e.target.value;
+ }
+
+ @action
+ onDescriptionChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+ this._descriptionInput = e.target.value;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkMenu.scss b/src/client/views/nodes/LinkMenu.scss
new file mode 100644
index 000000000..a120ab2a7
--- /dev/null
+++ b/src/client/views/nodes/LinkMenu.scss
@@ -0,0 +1,20 @@
+#linkMenu-container {
+ width: 100%;
+ height: auto;
+ display: flex;
+ flex-direction: column;
+}
+
+#linkMenu-searchBar {
+ width: 100%;
+ padding: 5px;
+ margin-bottom: 10px;
+ font-size: 12px;
+}
+
+#linkMenu-list {
+ margin-top: 5px;
+ width: 100%;
+ height: 100px;
+ overflow-y: scroll;
+} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
new file mode 100644
index 000000000..5c6b06d00
--- /dev/null
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -0,0 +1,54 @@
+import { action, observable } from "mobx";
+import { observer } from "mobx-react";
+import { Document } from "../../../fields/Document";
+import { FieldWaiting } from "../../../fields/Field";
+import { Key } from "../../../fields/Key";
+import { KeyStore } from '../../../fields/KeyStore';
+import { ListField } from "../../../fields/ListField";
+import { DocumentView } from "./DocumentView";
+import { LinkBox } from "./LinkBox";
+import { LinkEditor } from "./LinkEditor";
+import './LinkMenu.scss';
+import React = require("react");
+
+interface Props {
+ docView: DocumentView;
+ changeFlyout: () => void
+}
+
+@observer
+export class LinkMenu extends React.Component<Props> {
+
+ @observable private _editingLink?: Document;
+
+ renderLinkItems(links: Document[], key: Key, type: string) {
+ return links.map(link => {
+ let doc = link.GetT(key, Document);
+ if (doc && doc != FieldWaiting) {
+ return <LinkBox key={doc.Id} linkDoc={link} linkName={link.Title} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={type} />
+ }
+ })
+ }
+
+ render() {
+ //get list of links from document
+ let linkFrom: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedFromDocs, ListField, []);
+ let linkTo: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []);
+ if (this._editingLink === undefined) {
+ return (
+ <div id="linkMenu-container">
+ <input id="linkMenu-searchBar" type="text" placeholder="Search..."></input>
+ <div id="linkMenu-list">
+ {this.renderLinkItems(linkTo, KeyStore.LinkedToDocs, "Source: ")}
+ {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Destination: ")}
+ </div>
+ </div>
+ )
+ } else {
+ return (
+ <LinkEditor linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)}></LinkEditor>
+ )
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index e72b3c4da..a535b2638 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -4,6 +4,7 @@
position: absolute;
width: 100%;
height: 100%;
+ overflow: scroll;
}
.webBox-button {