aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-04-02 13:00:00 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-04-02 13:00:00 -0400
commitadecb4a47cac3c2f92d11d8f500d4decf70a06d1 (patch)
tree9a2de6465a4241327e99833a7e1bfbb8ff069966
parent1cdb04707301bc51b3ed6dd1c15c79a7b989b7f7 (diff)
More work on collection refactor
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx139
-rw-r--r--src/client/views/collections/CollectionView.tsx178
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx15
-rw-r--r--src/client/views/nodes/FieldView.tsx5
4 files changed, 174 insertions, 163 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
new file mode 100644
index 000000000..c8c840085
--- /dev/null
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -0,0 +1,139 @@
+import * as React from 'react';
+import { FieldViewProps } from '../nodes/FieldView';
+import { KeyStore } from '../../../fields/KeyStore';
+import { NumberField } from '../../../fields/NumberField';
+import { FieldWaiting, Field } from '../../../fields/Field';
+import { ContextMenu } from '../ContextMenu';
+import { SelectionManager } from '../../util/SelectionManager';
+import { Document } from '../../../fields/Document';
+import { ListField } from '../../../fields/ListField';
+import { action } from 'mobx';
+import { Transform } from '../../util/Transform';
+
+export enum CollectionViewType {
+ Invalid,
+ Freeform,
+ Schema,
+ Docking,
+ Tree,
+}
+
+export interface CollectionRenderProps {
+ addDocument: (document: Document, allowDuplicates: boolean) => void;
+ removeDocument: (document: Document) => boolean;
+ active: () => boolean;
+}
+
+export interface CollectionViewProps extends FieldViewProps {
+ onContextMenu?: (e: React.MouseEvent) => void;
+ children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | null;
+}
+
+export class CollectionBaseView extends React.Component<CollectionViewProps> {
+ get collectionViewType(): CollectionViewType {
+ let Document = this.props.Document;
+ let viewField = Document.GetT(KeyStore.ViewType, NumberField);
+ if (viewField === FieldWaiting) {
+ return CollectionViewType.Invalid;
+ } else if (viewField) {
+ return viewField.Data;
+ } else {
+ return CollectionViewType.Freeform;
+ }
+ }
+
+ active = (): boolean => {
+ var isSelected = this.props.isSelected();
+ var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == self);
+ var topMost = this.props.isTopMost;
+ return isSelected || childSelected || topMost;
+ }
+
+ createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
+ let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
+ for (let i = 0; i < data.length; i++) {
+ if (this.createsCycle(data[i], containerDocument))
+ return true;
+ }
+ let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
+ for (let i = 0; i < annots.length; i++) {
+ if (this.createsCycle(annots[i], containerDocument))
+ return true;
+ }
+ for (let containerProto: any = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) {
+ if (containerProto.Id == documentToAdd.Id)
+ return true;
+ }
+ return false;
+ }
+
+ @action.bound
+ addDocument(doc: Document, allowDuplicates: boolean): boolean {
+ let props = this.props;
+ var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
+ doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
+ if (curPage >= 0) {
+ doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
+ }
+ if (props.Document.Get(props.fieldKey) instanceof Field) {
+ //TODO This won't create the field if it doesn't already exist
+ const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
+ if (!this.createsCycle(doc, props.Document)) {
+ if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
+ value.push(doc);
+ }
+ else
+ return false;
+ } else {
+ let proto = props.Document.GetPrototype();
+ if (!proto || proto == FieldWaiting || !this.createsCycle(proto, doc)) {
+ props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
+ }
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @action.bound
+ removeDocument(doc: Document): boolean {
+ const props = this.props;
+ //TODO This won't create the field if it doesn't already exist
+ const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
+ let index = -1;
+ for (let i = 0; i < value.length; i++) {
+ if (value[i].Id == doc.Id) {
+ index = i;
+ break;
+ }
+ }
+ doc.GetTAsync(KeyStore.AnnotationOn, Document).then((annotationOn) => {
+ if (annotationOn == props.Document) {
+ doc.Set(KeyStore.AnnotationOn, undefined, true);
+ }
+ })
+
+ if (index !== -1) {
+ value.splice(index, 1)
+
+ SelectionManager.DeselectAll()
+ ContextMenu.Instance.clearItems()
+ return true;
+ }
+ return false
+ }
+
+ render() {
+ const props: CollectionRenderProps = {
+ addDocument: this.addDocument,
+ removeDocument: this.removeDocument,
+ active: this.active
+ }
+ return (
+ <div className="collectionView-cont" onContextMenu={this.props.onContextMenu}>
+ {this.props.children(this.collectionViewType, props)}
+ </div>
+ )
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index e6351618c..51cc99595 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,137 +1,28 @@
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Document } from "../../../fields/Document";
-import { ListField } from "../../../fields/ListField";
-import { SelectionManager } from "../../util/SelectionManager";
-import { ContextMenu } from "../ContextMenu";
-import React = require("react");
-import { KeyStore } from "../../../fields/KeyStore";
-import { NumberField } from "../../../fields/NumberField";
-import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import { CollectionDockingView } from "./CollectionDockingView";
-import { CollectionSchemaView } from "./CollectionSchemaView";
-import { CollectionViewProps, SubCollectionViewProps } from "./CollectionViewBase";
-import { CollectionTreeView } from "./CollectionTreeView";
-import { Field, FieldId, FieldWaiting } from "../../../fields/Field";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-
-export enum CollectionViewType {
- Invalid,
- Freeform,
- Schema,
- Docking,
- Tree
-}
-
-export const COLLECTION_BORDER_WIDTH = 1;
-
-@observer
-export class CollectionView extends React.Component<CollectionViewProps> {
-
- public static LayoutString(fieldKey: string = "DataKey") {
- return `<${CollectionView.name} Document={Document}
- ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
- isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
- }
-
- @observable
- public SelectedDocs: FieldId[] = [];
- public active: () => boolean = () => CollectionView.Active(this);
- addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); }
- removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
-
- public static Active(self: CollectionView): boolean {
- var isSelected = self.props.isSelected();
- var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == self);
- var topMost = self.props.isTopMost;
- return isSelected || childSelected || topMost;
- }
-
- static createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
- let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
- for (let i = 0; i < data.length; i++) {
- if (CollectionView.createsCycle(data[i], containerDocument))
- return true;
- }
- let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
- for (let i = 0; i < annots.length; i++) {
- if (CollectionView.createsCycle(annots[i], containerDocument))
- return true;
- }
- for (let containerProto: any = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) {
- if (containerProto.Id == documentToAdd.Id)
- return true;
- }
- return false;
- }
-
- @action
- public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean): boolean {
- var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
- doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
- if (curPage >= 0) {
- doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
- }
- if (props.Document.Get(props.fieldKey) instanceof Field) {
- //TODO This won't create the field if it doesn't already exist
- const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
- if (!CollectionView.createsCycle(doc, props.Document)) {
- if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
- value.push(doc);
- }
- else
- return false;
- } else {
- let proto = props.Document.GetPrototype();
- if (!proto || proto == FieldWaiting || !CollectionView.createsCycle(proto, doc)) {
- props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
- }
- else
- return false;
- }
- return true;
- }
-
- @action
- public static RemoveDocument(props: CollectionViewProps, doc: Document): boolean {
- //TODO This won't create the field if it doesn't already exist
- const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
- let index = -1;
- for (let i = 0; i < value.length; i++) {
- if (value[i].Id == doc.Id) {
- index = i;
- break;
- }
- }
- doc.GetTAsync(KeyStore.AnnotationOn, Document).then((annotationOn) => {
- if (annotationOn == props.Document) {
- doc.Set(KeyStore.AnnotationOn, undefined, true);
- }
- })
-
- if (index !== -1) {
- value.splice(index, 1)
-
- SelectionManager.DeselectAll()
- ContextMenu.Instance.clearItems()
- return true;
- }
- return false
- }
-
- get collectionViewType(): CollectionViewType {
- let Document = this.props.Document;
- let viewField = Document.GetT(KeyStore.ViewType, NumberField);
- if (viewField === FieldWaiting) {
- return CollectionViewType.Invalid;
- } else if (viewField) {
- return viewField.Data;
- } else {
- return CollectionViewType.Freeform;
+import * as React from 'react'
+import { FieldViewProps, FieldView } from '../nodes/FieldView';
+import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView';
+import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+import { CollectionSchemaView } from './CollectionSchemaView';
+import { CollectionDockingView } from './CollectionDockingView';
+import { CollectionTreeView } from './CollectionTreeView';
+import { ContextMenu } from '../ContextMenu';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { KeyStore } from '../../../fields/KeyStore';
+export class CollectionView extends React.Component<FieldViewProps> {
+ public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) }
+
+ private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
+ let props = { ...renderProps, ...this.props };
+ switch (type) {
+ case CollectionViewType.Freeform: return (<CollectionFreeFormView {...props} />)
+ case CollectionViewType.Schema: return (<CollectionSchemaView {...props} />)
+ case CollectionViewType.Docking: return (<CollectionDockingView {...props} />)
+ case CollectionViewType.Tree: return (<CollectionTreeView {...props} />)
}
+ return (null);
}
- specificContextMenu = (e: React.MouseEvent): void => {
+ onContextMenu = (e: React.MouseEvent): void => {
if (!e.isPropagationStopped() && this.props.Document.Id != CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
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) })
@@ -139,24 +30,11 @@ export class CollectionView extends React.Component<CollectionViewProps> {
}
}
- public static SubViewProps(self: CollectionView): SubCollectionViewProps {
- return { ...self.props, addDocument: self.addDocument, removeDocument: self.removeDocument, active: self.active, CollectionView: self }
- }
-
- private get SubView() {
- let subProps = CollectionView.SubViewProps(this);
- switch (this.collectionViewType) {
- case CollectionViewType.Freeform: return (<CollectionFreeFormView {...subProps} />)
- case CollectionViewType.Schema: return (<CollectionSchemaView {...subProps} />)
- case CollectionViewType.Docking: return (<CollectionDockingView {...subProps} />)
- case CollectionViewType.Tree: return (<CollectionTreeView {...subProps} />)
- }
- return (null);
- }
-
render() {
- return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}>
- {this.SubView}
- </div>)
+ return (
+ <CollectionBaseView {...this.props} onContextMenu={this.onContextMenu}>
+ {this.SubView}
+ </CollectionBaseView> >
+ )
}
-}
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index c5a6c53b3..ca4f3b12f 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -20,17 +20,9 @@ import { Server } from "../../Server";
import { FieldViewProps } from "../nodes/FieldView";
export interface CollectionViewProps extends FieldViewProps {
- ScreenToLocalTransform: () => Transform;
- panelWidth: () => number;
- panelHeight: () => number;
- focus: (doc: Document) => void;
}
export interface SubCollectionViewProps extends CollectionViewProps {
- active: () => boolean;
- addDocument: (doc: Document, allowDuplicates: boolean) => boolean;
- removeDocument: (doc: Document) => boolean;
- CollectionView: CollectionView;
}
export type CursorEntry = TupleField<[string, string], [number, number]>;
@@ -127,8 +119,6 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
@action
protected onDrop(e: React.DragEvent, options: DocumentOptions): void {
- let that = this;
-
let html = e.dataTransfer.getData("text/html");
let text = e.dataTransfer.getData("text/plain");
@@ -151,7 +141,6 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
let item = e.dataTransfer.items[i];
if (item.kind === "string" && item.type.indexOf("uri") != -1) {
e.dataTransfer.items[i].getAsString(action((s: string) => {
- let document: Document;
request.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s), (err, res, body) => {
let type = res.headers["content-type"];
if (type) {
@@ -184,11 +173,11 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
runInAction(() => {
let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 })
- let docs = that.props.Document.GetT(KeyStore.Data, ListField);
+ let docs = this.props.Document.GetT(KeyStore.Data, ListField);
if (docs != FieldWaiting) {
if (!docs) {
docs = new ListField<Document>();
- that.props.Document.Set(KeyStore.Data, docs)
+ this.props.Document.Set(KeyStore.Data, docs)
}
if (doc) {
docs.Data.push(doc);
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 43688989b..2a7d3175f 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -33,6 +33,11 @@ export interface FieldViewProps {
select: (isCtrlPressed: boolean) => void;
isTopMost: boolean;
selectOnLoad: boolean;
+ addDocument: (document: Document, allowDuplicates: boolean) => boolean;
+ removeDocument: (document: Document) => boolean;
+ ScreenToLocalTransform: () => Transform;
+ active: () => boolean;
+ focus: (doc: Document) => void;
}
@observer