diff options
| author | Melissa Zhang <mzhang19096@gmail.com> | 2020-05-15 19:10:07 -0700 |
|---|---|---|
| committer | Melissa Zhang <mzhang19096@gmail.com> | 2020-05-15 19:10:07 -0700 |
| commit | 253d5efbbafe4a44c350fef7dda6d553a70a94c9 (patch) | |
| tree | b43a55e1efddc86e25df4bb7d90a99f3c7b52a17 /src/client/views/collections/CollectionView.tsx | |
| parent | 36c01920e3874e1484222a7012745b581405f67d (diff) | |
| parent | 08b6bf8b51ab631c8cfe9c3e12bfb0ae2dd7b4c7 (diff) | |
merge with master
Diffstat (limited to 'src/client/views/collections/CollectionView.tsx')
| -rw-r--r-- | src/client/views/collections/CollectionView.tsx | 120 |
1 files changed, 69 insertions, 51 deletions
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 801704673..3b2e5e4fc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -7,17 +7,15 @@ import { observer } from "mobx-react"; import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app -import { DateField } from '../../../new_fields/DateField'; -import { DataSym, Doc, DocListCast, Field, Opt } from '../../../new_fields/Doc'; -import { List } from '../../../new_fields/List'; -import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; -import { ImageField } from '../../../new_fields/URLField'; -import { TraceMobx } from '../../../new_fields/util'; +import { DateField } from '../../../fields/DateField'; +import { DataSym, Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; +import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../fields/Types'; +import { ImageField } from '../../../fields/URLField'; +import { TraceMobx } from '../../../fields/util'; import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; -import { DocumentManager } from '../../util/DocumentManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { ScriptBox } from '../ScriptBox'; @@ -37,15 +35,14 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { listSpec } from '../../../new_fields/Schema'; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; +import { Id } from '../../../fields/FieldSymbols'; +import { listSpec } from '../../../fields/Schema'; import { Docs } from '../../documents/Documents'; -import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; +import { ScriptField, ComputedField } from '../../../fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; -import { ObjectField } from '../../../new_fields/ObjectField'; +import { ObjectField } from '../../../fields/ObjectField'; import CollectionMapView from './CollectionMapView'; -import { Transform } from 'prosemirror-transform'; import { CollectionPileView } from './CollectionPileView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; @@ -71,18 +68,25 @@ export enum CollectionViewType { Map = "map", Pile = "pileup" } +export interface CollectionViewCustomProps { + filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + childLayoutTemplate?: () => Opt<Doc>; // specify a layout Doc template to use for children of the collection + childLayoutString?: string; // specify a layout string to use for children of the collection +} export interface CollectionRenderProps { - addDocument: (document: Doc) => boolean; - removeDocument: (document: Doc) => boolean; - moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + addDocument: (document: Doc | Doc[]) => boolean; + removeDocument: (document: Doc | Doc[]) => boolean; + moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; active: () => boolean; whenActiveChanged: (isActive: boolean) => void; PanelWidth: () => number; + ChildLayoutTemplate?: () => Doc; + ChildLayoutString?: string; } @observer -export class CollectionView extends Touchable<FieldViewProps> { +export class CollectionView extends Touchable<FieldViewProps & CollectionViewCustomProps> { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } private _isChildActive = false; //TODO should this be observable? @@ -112,31 +116,33 @@ export class CollectionView extends Touchable<FieldViewProps> { whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive); @action.bound - addDocument(doc: Doc): boolean { + addDocument = (doc: Doc | Doc[]): boolean => { + if (doc instanceof Doc) { + if (this.props.filterAddDocument?.(doc) === false) { + return false; + } + } + const docs = doc instanceof Doc ? [doc] : doc; const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there - // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); - doc.context = this.props.Document; - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); - Doc.GetProto(doc).lastOpened = new DateField; + const added = docs.filter(d => !docList.includes(d)); + if (added.length) { + added.map(doc => doc.context = this.props.Document); + added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); + targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } return true; } @action.bound - removeDocument(doc: Doc): boolean { + removeDocument = (doc: any): boolean => { + const docs = doc instanceof Doc ? [doc] : doc as Doc[]; const targetDataDoc = this.props.Document[DataSym]; - const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); - docView && SelectionManager.DeselectDoc(docView); const value = DocListCast(targetDataDoc[this.props.fieldKey]); - let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); - index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); - - doc.context = undefined; - ContextMenu.Instance?.clearItems(); - if (index !== -1) { - value.splice(index, 1); - targetDataDoc[this.props.fieldKey] = new List<Doc>(value); + const result = value.filter(v => !docs.includes(v)); + if (result.length !== value.length) { + targetDataDoc[this.props.fieldKey] = new List<Doc>(result); return true; } return false; @@ -147,7 +153,7 @@ export class CollectionView extends Touchable<FieldViewProps> { // otherwise, the document being moved must be able to be removed from its container before // moving it into the target. @action.bound - moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean { + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } @@ -155,10 +161,14 @@ export class CollectionView extends Touchable<FieldViewProps> { } showIsTagged = () => { - const children = DocListCast(this.props.Document[this.props.fieldKey]); - const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); - const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); - return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />; + return (null); + // this section would display an icon in the bototm right of a collection to indicate that all + // photos had been processed through Google's content analysis API and Google's tags had been + // assigned to the documents googlePhotosTags field. + // const children = DocListCast(this.props.Document[this.props.fieldKey]); + // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); + // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); + // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />; } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { @@ -190,8 +200,8 @@ export class CollectionView extends Touchable<FieldViewProps> { private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip const chrome = this.props.Document._chromeStatus === "disabled" || this.props.Document._chromeStatus === "replaced" || type === CollectionViewType.Docking ? (null) : - <CollectionViewBaseChrome CollectionView={this} key="chrome" PanelWidth={this.bodyPanelWidth} type={type} collapse={this.collapse} />; - return [chrome, this.SubViewHelper(type, renderProps)]; + <CollectionViewBaseChrome key="chrome" CollectionView={this} PanelWidth={this.bodyPanelWidth} type={type} collapse={this.collapse} />; + return <>{chrome} {this.SubViewHelper(type, renderProps)}</>; } @@ -224,7 +234,6 @@ export class CollectionView extends Touchable<FieldViewProps> { 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 - this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); this.setupViewTypes("Add a Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; @@ -238,8 +247,8 @@ export class CollectionView extends Touchable<FieldViewProps> { if (this.props.Document.childLayout instanceof Doc) { layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" }); } - if (this.props.Document.childDetailView instanceof Doc) { - layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailView as Doc, "onRight"), icon: "project-diagram" }); + if (this.props.Document.childClickedOpenTemplateView instanceof Doc) { + layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); @@ -247,15 +256,20 @@ export class CollectionView extends Touchable<FieldViewProps> { const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }]; - DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick => - funcs.push({ key: "onChildClick", name: StrCast(childClick.title), script: ScriptCast(childClick.script) })); + const funcs = [ + { key: "onChildClick", name: "On Child Clicked" }, + { key: "onChildDoubleClick", name: "On Child Double Clicked" }]; funcs.map(func => onClicks.push({ description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => { - func.script && (this.props.Document[func.key] = ObjectField.MakeCopy(func.script)); ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }); } })); + DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick => + onClicks.push({ + description: `Set child ${childClick.title}`, + icon: "edit", + event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), + })); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); const more = ContextMenu.Instance.findByDescription("More..."); @@ -462,6 +476,8 @@ export class CollectionView extends Touchable<FieldViewProps> { </div> </div>; } + childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); + childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString); render() { TraceMobx(); @@ -471,7 +487,9 @@ export class CollectionView extends Touchable<FieldViewProps> { moveDocument: this.moveDocument, active: this.active, whenActiveChanged: this.whenActiveChanged, - PanelWidth: this.bodyPanelWidth + PanelWidth: this.bodyPanelWidth, + ChildLayoutTemplate: this.childLayoutTemplate, + ChildLayoutString: this.childLayoutString, }; return (<div className={"collectionView"} style={{ @@ -481,7 +499,7 @@ export class CollectionView extends Touchable<FieldViewProps> { }} onContextMenu={this.onContextMenu}> {this.showIsTagged()} - <div style={{ width: `calc(100% - ${this.facetWidth()}px)` }}> + <div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}> {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)} </div> {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => |
