diff options
author | laurawilsonri <laura_wilson@brown.edu> | 2019-04-11 14:12:49 -0400 |
---|---|---|
committer | laurawilsonri <laura_wilson@brown.edu> | 2019-04-11 14:12:49 -0400 |
commit | c392a9322c1df269cfd823dd82d07d991fe065c0 (patch) | |
tree | fdd44c511bd179984dc3dc18b92745751c86bfc5 /src/client/views/collections/CollectionBaseView.tsx | |
parent | 15514b0f3d685764d1bd7ebeac9cdee1f778e184 (diff) | |
parent | 50be8cb7a93110821c972c679567ddb6aae8bc6f (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.tsx | 187 |
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 |