diff options
Diffstat (limited to 'src/client/views/collections/CollectionSubView.tsx')
| -rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 40b2f9644..fd53e12da 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, makeObservable, observable, override, runInAction, untracked } from 'mobx'; import * as rp from 'request-promise'; import CursorField from '../../../fields/CursorField'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; @@ -35,6 +35,17 @@ export function CollectionSubView<X>(moreProps?: X) { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; + @override _props: X & SubCollectionViewProps; + + constructor(props: any) { + super(props); + this._props = props; + makeObservable(this); + } + componentDidUpdate() { + // untracked(() => (this._props = this.props)); + } + @observable _focusFilters: Opt<string[]>; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it @observable _focusRangeFilters: Opt<string[]>; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it protected createDashEventsTarget = (ele: HTMLDivElement | null) => { @@ -55,29 +66,29 @@ export function CollectionSubView<X>(moreProps?: X) { this.gestureDisposer?.(); } - @computed get dataDoc() { - return this.props.TemplateDataDocument instanceof Doc && this.props.Document.isTemplateForField - ? Doc.GetProto(this.props.TemplateDataDocument) - : this.props.Document.resolvedDataDoc - ? this.props.Document - : Doc.GetProto(this.props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + get dataDoc() { + return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField + ? Doc.GetProto(this._props.TemplateDataDocument) + : this._props.Document.resolvedDataDoc + ? this._props.Document + : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } // this returns whether either the collection is selected, or the template that it is part of is selected - rootSelected = () => this.props.isSelected() || BoolCast(this.props.TemplateDataDocument && this.props.rootSelected?.()); + rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); - // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. + // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. // When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @computed get dataField() { - return this.dataDoc[this.props.fieldKey]; // this used to be 'layoutDoc', but then template fields will get ignored since the template is not a proto of the layout. hopefully nothing depending on the previous code. + return this.dataDoc[this._props.fieldKey]; // this used to be 'layoutDoc', but then template fields will get ignored since the template is not a proto of the layout. hopefully nothing depending on the previous code. } @computed get childLayoutPairs(): { layout: Doc; data: Doc }[] { - const { Document, TemplateDataDocument } = this.props; + const { Document, TemplateDataDocument } = this._props; const validPairs = this.childDocs - .map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc)) + .map(doc => Doc.GetLayoutDataDocPair(Document, !this._props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc)) .filter(pair => { // filter out any documents that have a proto that we don't have permissions to return !pair.layout?.hidden && pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate)); @@ -87,14 +98,14 @@ export function CollectionSubView<X>(moreProps?: X) { @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } - collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters); - collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._childFiltersByRanges, listSpec('string'), []); + collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters); + collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []); // child filters apply to the descendants of the documents in this collection - childDocFilters = () => [...(this.props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()]; + childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()]; // unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack - unrecursiveDocFilters = () => [...(this.props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])]; - childDocRangeFilters = () => [...(this.props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()]; - searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs); + unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])]; + childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()]; + searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); let rawdocs: (Doc | Promise<Doc>)[] = []; @@ -108,27 +119,27 @@ export function CollectionSubView<X>(moreProps?: X) { // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc. // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection. // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image. - const templateRoot = this.props.TemplateDataDocument; - rawdocs = templateRoot && !this.props.isAnnotationOverlay ? [Doc.GetProto(templateRoot)] : []; + const templateRoot = this._props.TemplateDataDocument; + rawdocs = templateRoot && !this._props.isAnnotationOverlay ? [Doc.GetProto(templateRoot)] : []; } - const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc); + const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this._props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc); const childDocFilters = this.childDocFilters(); const childFiltersByRanges = this.childDocRangeFilters(); const searchDocs = this.searchFilterDocs(); - if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { + if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one } const docsforFilter: Doc[] = []; childDocs.forEach(d => { // dragging facets - const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter)); + const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter)); if (dragged && SnappingManager.GetCanEmbed() && DragManager.docsBeingDragged.includes(d)) return false; - let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0; + let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0; if (notFiltered) { - notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.props.Document).length > 0; + notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0; const fieldKey = Doc.LayoutFieldKey(d); const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name); const data = d[annos ? fieldKey + '_annotations' : fieldKey]; @@ -161,7 +172,7 @@ export function CollectionSubView<X>(moreProps?: X) { @action protected async setCursorPosition(position: [number, number]) { let ind; - const doc = this.props.Document; + const doc = this._props.Document; const id = Doc.UserDoc()[Id]; const email = Doc.CurrentUserEmail; const pos = { x: position[0], y: position[1] }; @@ -197,23 +208,23 @@ export function CollectionSubView<X>(moreProps?: X) { const dropAction = this.layoutDoc.dropAction as dropActionType; // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding. // so we check if our collection has a dropAction set on it and if so, we use that instead. - if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) { + if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) { de.complete.docDragData.dropAction = dropAction; } e.stopPropagation(); } } - addDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.addDocument?.(doc, annotationKey) || false; - removeDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.removeDocument?.(doc, annotationKey) || false; - moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string) => this.props.moveDocument?.(doc, targetCollection, addDocument); - @action + addDocument = (doc: Doc | Doc[], annotationKey?: string) => this._props.addDocument?.(doc, annotationKey) || false; + removeDocument = (doc: Doc | Doc[], annotationKey?: string) => this._props.removeDocument?.(doc, annotationKey) || false; + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string) => this._props.moveDocument?.(doc, targetCollection, addDocument); + protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; if (docDragData) { let added = undefined; const dropAction = docDragData.dropAction || docDragData.userDropAction; - const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]); + const targetDocments = DocListCast(this.dataDoc[this._props.fieldKey]); const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop)); if ((!dropAction || dropAction === 'inSame' || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) { @@ -236,13 +247,13 @@ export function CollectionSubView<X>(moreProps?: X) { added = this.addDocument(docDragData.droppedDocuments); !added && alert('You cannot perform this move'); } - added === false && !this.props.isAnnotationOverlay && e.preventDefault(); + added === false && !this._props.isAnnotationOverlay && e.preventDefault(); added === true && e.stopPropagation(); return added ? true : false; } else if (de.complete.annoDragData) { const dropCreator = de.complete.annoDragData.dropDocCreator; de.complete.annoDragData.dropDocCreator = () => { - const dropped = dropCreator(this.props.isAnnotationOverlay ? this.Document : undefined); + const dropped = dropCreator(this._props.isAnnotationOverlay ? this.Document : undefined); this.addDocument(dropped); return dropped; }; @@ -252,7 +263,6 @@ export function CollectionSubView<X>(moreProps?: X) { } @undoBatch - @action protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) { if (e.ctrlKey) { e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl @@ -463,15 +473,15 @@ export function CollectionSubView<X>(moreProps?: X) { } if (generatedDocuments.length) { // Creating a dash document - const isFreeformView = this.props.Document._type_collection === CollectionViewType.Freeform; + const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform; const set = !isFreeformView ? generatedDocuments : generatedDocuments.length > 1 - ? generatedDocuments.map(d => { - DocUtils.iconify(d); - return d; - }) - : []; + ? generatedDocuments.map(d => { + DocUtils.iconify(d); + return d; + }) + : []; if (completed) completed(set); else { if (isFreeformView && generatedDocuments.length > 1) { |
