aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionBaseView.tsx
diff options
context:
space:
mode:
authorlaurawilsonri <laura_wilson@brown.edu>2019-04-11 14:12:49 -0400
committerlaurawilsonri <laura_wilson@brown.edu>2019-04-11 14:12:49 -0400
commitc392a9322c1df269cfd823dd82d07d991fe065c0 (patch)
treefdd44c511bd179984dc3dc18b92745751c86bfc5 /src/client/views/collections/CollectionBaseView.tsx
parent15514b0f3d685764d1bd7ebeac9cdee1f778e184 (diff)
parent50be8cb7a93110821c972c679567ddb6aae8bc6f (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into richTextEditor
Diffstat (limited to 'src/client/views/collections/CollectionBaseView.tsx')
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
new file mode 100644
index 000000000..4380c8194
--- /dev/null
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -0,0 +1,187 @@
+import { action } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Document } from '../../../fields/Document';
+import { Field, FieldValue, FieldWaiting } from '../../../fields/Field';
+import { KeyStore } from '../../../fields/KeyStore';
+import { ListField } from '../../../fields/ListField';
+import { NumberField } from '../../../fields/NumberField';
+import { ContextMenu } from '../ContextMenu';
+import { FieldViewProps } from '../nodes/FieldView';
+
+export enum CollectionViewType {
+ Invalid,
+ Freeform,
+ Schema,
+ Docking,
+ Tree,
+}
+
+export interface CollectionRenderProps {
+ addDocument: (document: Document, allowDuplicates?: boolean) => boolean;
+ removeDocument: (document: Document) => boolean;
+ moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
+ active: () => boolean;
+ onActiveChanged: (isActive: boolean) => void;
+}
+
+export interface CollectionViewProps extends FieldViewProps {
+ onContextMenu?: (e: React.MouseEvent) => void;
+ children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null;
+ className?: string;
+ contentRef?: React.Ref<HTMLDivElement>;
+}
+
+export const COLLECTION_BORDER_WIDTH = 1;
+
+@observer
+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 topMost = this.props.isTopMost;
+ return isSelected || this._isChildActive || topMost;
+ }
+
+ //TODO should this be observable?
+ private _isChildActive = false;
+ onActiveChanged = (isActive: boolean) => {
+ this._isChildActive = isActive;
+ this.props.onActiveChanged(isActive);
+ }
+
+ createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
+ let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
+ for (const doc of data) {
+ if (this.createsCycle(doc, containerDocument)) {
+ return true;
+ }
+ }
+ let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
+ for (const annot of annots) {
+ if (this.createsCycle(annot, containerDocument)) {
+ return true;
+ }
+ }
+ for (let containerProto: FieldValue<Document> = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) {
+ if (containerProto.Id === documentToAdd.Id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @action.bound
+ addDocument(doc: Document, allowDuplicates: boolean = false): 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)) {
+ const field = new ListField([doc]);
+ // const script = CompileScript(`
+ // if(added) {
+ // console.log("added " + field.Title);
+ // } else {
+ // console.log("removed " + field.Title);
+ // }
+ // `, {
+ // addReturn: false,
+ // params: {
+ // field: Document.name,
+ // added: "boolean"
+ // }
+ // });
+ // if (script.compiled) {
+ // field.addScript(new ScriptField(script));
+ // }
+ props.Document.SetOnPrototype(props.fieldKey, field);
+ }
+ 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;
+ }
+
+ @action.bound
+ moveDocument(doc: Document, targetCollection: Document, addDocument: (doc: Document) => boolean): boolean {
+ if (this.props.Document === targetCollection) {
+ return true;
+ }
+ if (this.removeDocument(doc)) {
+ return addDocument(doc);
+ }
+ return false;
+ }
+
+ render() {
+ const props: CollectionRenderProps = {
+ addDocument: this.addDocument,
+ removeDocument: this.removeDocument,
+ moveDocument: this.moveDocument,
+ active: this.active,
+ onActiveChanged: this.onActiveChanged,
+ };
+ return (
+ <div className={this.props.className || "collectionView-cont"} onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}>
+ {this.props.children(this.collectionViewType, props)}
+ </div>
+ );
+ }
+
+} \ No newline at end of file