From 5cd64622f14ede408d3baca4a10d155b60392e46 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 13 Apr 2023 22:22:07 -0400 Subject: lots of changes to get rid of ContainingCollectionDoc and ContainingCollectionView props. --- src/client/views/collections/CollectionView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index bc25ad43a..53fbcc3cc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent +
{this.showIsTagged()} {this.renderSubView(this.collectionViewType, props)}
-- cgit v1.2.3-70-g09d2 From 650cc00d18c97f89aef77f50703aa9b525dd0368 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 14 Apr 2023 11:12:49 -0400 Subject: got rid of CollectionView prop. fixed DocFocusOrOpen to toggle targets and zoom correctly. --- src/client/util/DocumentManager.ts | 12 +++++++----- .../util/Import & Export/DirectoryImportBox.tsx | 2 +- src/client/util/LinkFollower.ts | 2 +- src/client/views/MainView.tsx | 1 - src/client/views/PropertiesDocBacklinksSelector.tsx | 2 +- src/client/views/PropertiesDocContextSelector.tsx | 21 +-------------------- src/client/views/SidebarAnnos.tsx | 1 - src/client/views/StyleProvider.tsx | 4 ++-- src/client/views/TemplateMenu.tsx | 1 - src/client/views/collections/CollectionMenu.tsx | 1 - .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 6 +++--- src/client/views/collections/CollectionTreeView.tsx | 6 +++--- src/client/views/collections/CollectionView.tsx | 1 - src/client/views/collections/TabDocView.tsx | 1 - src/client/views/collections/TreeView.tsx | 6 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++++---- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 14 +++++++------- src/client/views/nodes/ImageBox.tsx | 1 - src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 1 - src/client/views/nodes/PDFBox.tsx | 1 - src/client/views/nodes/ScreenshotBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 2 -- src/client/views/nodes/WebBox.tsx | 1 - .../views/nodes/formattedText/FormattedTextBox.tsx | 1 - src/client/views/pdf/PDFViewer.tsx | 1 - 29 files changed, 39 insertions(+), 69 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ad89e8653..e01457b4f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -227,6 +227,7 @@ export class DocumentManager { let rootContextView = docViewPath.shift(); await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined }))); if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden; + else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) MainView.addDocTabFunc(rootContextView.rootDoc, options.openLocation); }; // shows a document by first: @@ -246,10 +247,9 @@ export class DocumentManager { const viewIndex = docContextPath.findIndex(doc => this.getDocumentView(doc)); if (viewIndex !== -1) return res(this.getDocumentView(docContextPath[viewIndex])!); options.didMove = true; - docContextPath.some(doc => TabDocView.Activate(doc)) || MainView.addDocTabFunc(docContextPath[0], options.openLocation as OpenWhere); + docContextPath.some(doc => TabDocView.Activate(doc)) || MainView.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight); this.AddViewRenderedCb(docContextPath[0], dv => res(dv)); }); - docContextPath.shift(); const childViewIterator = async (docView: DocumentView) => { const innerDoc = docContextPath.shift(); @@ -297,15 +297,17 @@ export class DocumentManager { } } } -export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, openLocation: OpenWhere.addRight }, containingDoc?: Doc) { +export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) { DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc)); } else { - const showDoc = Doc.BestAlias(DocCast((containingDoc ?? doc.context) !== Doc.MyFilesystem ? containingDoc ?? doc.context : undefined, doc)); - DocumentManager.Instance.showDocument(showDoc, { ...options, toggleTarget: undefined }, () => DocumentManager.Instance.showDocument(doc, options)).then(() => { + const container = DocCast(containingDoc ?? doc.context); + const showDoc = !Doc.IsSystem(container) ? container : doc; + options.toggleTarget = undefined; + DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); dv && Doc.linkFollowHighlight(dv.rootDoc); diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 76b1323c4..b9bb22564 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -157,7 +157,7 @@ export class DirectoryImportBox extends React.Component { x: NumCast(doc.x), y: NumCast(doc.y) + offset, }; - const parent = _.nth(this.props.docViewPath(), -2); // last element of path is this box's document view, 2nd to last is any collection or other document that may contain it. + const parent = this.props.DocumentView?.().props.docViewPath().lastElement(); if (parent?.rootDoc.type === DocumentType.COL) { let importContainer: Doc; if (docs.length < 50) { diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index d4d7c66f5..ba2edb65c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -75,7 +75,7 @@ export class LinkFollower { zoomTime: NumCast(sourceDoc.followLinkTransitionTime, 500), zoomScale: Cast(sourceDoc.followLinkZoomScale, 'number', null), easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, - openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox), + openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox) as OpenWhere, effect: sourceDoc, zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), }; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0384d925e..ccc9a7215 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -883,7 +883,6 @@ export class MainView extends React.Component { isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} - CollectionView={undefined} addDocument={this.addButtonDoc} addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 00c3400cb..935d551c6 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -25,7 +25,7 @@ export class PropertiesDocBacklinksSelector extends React.Component { if (!this.props.DocView) return; col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col; - if (col._viewType === CollectionViewType.Freeform) { - col._panX = NumCast(target.x) + NumCast(target._width) / 2; - col._panY = NumCast(target.y) + NumCast(target._height) / 2; - } - col.hidden = false; - //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere); - setTimeout( - () => - this.props.DocView && - DocFocusOrOpen( - Doc.GetProto(this.props.DocView.props.Document), - { - // - willZoomCentered: true, - openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere, - }, - col - ), - 100 - ); + DocFocusOrOpen(Doc.GetProto(this.props.DocView.props.Document), undefined, col); }; render() { diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 2d2b0f83e..b0aab968e 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -243,7 +243,6 @@ export class SidebarAnnos extends React.Component { removeDocument={this.removeDocument} moveDocument={this.moveDocument} addDocument={this.addDocument} - CollectionView={undefined} ScreenToLocalTransform={this.screenToLocalTransform} renderDepth={this.props.renderDepth + 1} viewType={CollectionViewType.Stacking} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 739d6d819..5f16e0ebd 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -5,7 +5,7 @@ import { Shadows } from 'browndash-components'; import { action, runInAction } from 'mobx'; import { extname } from 'path'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; -import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types'; import { DashColor, lightOrDark, Utils } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager'; @@ -383,7 +383,7 @@ export function DashboardStyleProvider(doc: Opt, props: Opt {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => { - DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc); + DocFocusOrOpen(doc, { toggleTarget: true, willZoomCentered: true, zoomScale: 0 }, DocCast(doc?.context ?? doc?.annotationOn)); })} ); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index c5a501aa6..1c816aa05 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -113,7 +113,6 @@ export class TemplateMenu extends React.Component { {templateMenu} { isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={returnFalse} - CollectionView={undefined} addDocument={returnFalse} addDocTab={returnFalse} pinToPres={emptyFunction} diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 80e81bc1c..99d4d0bee 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -162,7 +162,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @action - moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => { + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => { return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; }; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 67f5dc9f4..bdad325d5 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -230,7 +230,7 @@ export class CollectionStackingView extends CollectionSubView this.props.isAnyChildContentActive(); @action - moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => { + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; }; createRef = (ele: HTMLDivElement | null) => { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 132ed6fb6..5581ac8fe 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -19,7 +19,6 @@ import { DocComponent } from '../DocComponent'; import React = require('react'); export interface SubCollectionViewProps extends CollectionViewProps { - CollectionView: Opt; isAnyChildContentActive: () => boolean; } @@ -201,8 +200,9 @@ export function CollectionSubView(moreProps?: X) { } } - addDocument = (doc: Doc | Doc[]) => this.props.addDocument?.(doc) || false; - + 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 protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 92932fb61..f81c17a7b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -374,10 +374,10 @@ export class CollectionTreeView extends CollectionSubView this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1)); - addAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; - remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; + addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; + remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => - this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false; + this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false; @observable _headerHeight = 0; @computed get content() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 53fbcc3cc..d7a889362 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -276,7 +276,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent {
boolean; panelWidth: () => number; panelHeight: () => number; - addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; + addDocument: (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => boolean; removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined; moveDocument: DragManager.MoveFunction; isContentActive: (outsideReaction?: boolean) => boolean; @@ -373,7 +373,7 @@ export class TreeView extends React.Component { dropping: boolean = false; dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) { - const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before); + const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, undefined, before); const localAdd = (doc: Doc | Doc[]) => { const innerAdd = (doc: Doc) => { const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField; @@ -1186,7 +1186,7 @@ export class TreeView extends React.Component { }; const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined); - const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); + const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); const childLayout = Doc.Layout(pair.layout); const rowHeight = () => { const aspect = Doc.NativeAspect(childLayout); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a3f5e73fb..33fc2ddf3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -311,7 +311,7 @@ export class CollectionFreeFormView extends CollectionSubView boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: OpenWhere) => boolean; filterAddDocument?: (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) - addDocument?: (doc: Doc | Doc[]) => boolean; - removeDocument?: (doc: Doc | Doc[]) => boolean; - moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean; pinToPres: (document: Doc, pinProps: PinProps) => void; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 22ecaa299..7c98aa6e4 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -478,7 +478,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent <> diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index b144c9318..7a7d4fe37 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -963,7 +963,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent { renderDepth={this.props.renderDepth + 1} isAnnotationOverlay={true} fieldKey={this.props.fieldKey + '-annotations'} - CollectionView={undefined} getScrollHeight={this.getScrollHeight} setPreviewCursor={this.setPreviewCursor} setBrushViewer={this.setBrushViewer} -- cgit v1.2.3-70-g09d2 From 8127616d06b4db2b29de0b13068810fd19e77b5e Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 17 Apr 2023 09:26:45 -0400 Subject: minor cleanup of CollectionView --- src/client/views/collections/CollectionView.tsx | 90 +++++++------------------ 1 file changed, 25 insertions(+), 65 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index d7a889362..cfb9310b6 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -99,18 +99,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - 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.rootDoc[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) : ; - //this.isContentActive(); - }; - screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth())); // prettier-ignore private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => { @@ -138,26 +126,25 @@ export class CollectionView extends ViewBoxAnnotatableComponent Doc, addExtras: boolean) { - const subItems: ContextMenuProps[] = []; - subItems.push({ description: 'Freeform', event: () => func(CollectionViewType.Freeform), icon: 'signature' }); - if (addExtras && CollectionView._safeMode) { - ContextMenu.Instance.addItem({ description: 'Test Freeform', event: () => func(CollectionViewType.Invalid), icon: 'project-diagram' }); - } - subItems.push({ description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' }); - subItems.push({ description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' }); - subItems.push({ description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' }); - subItems.push({ description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' }); - subItems.push({ description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' }); - subItems.push({ description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' }); - subItems.push({ description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' }); - subItems.push({ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' }); - subItems.push({ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' }); - !Doc.noviceMode && subItems.push({ description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' }); - !Doc.noviceMode && subItems.push({ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' }); - subItems.push({ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' }); - + setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc) { if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { + // prettier-ignore + const subItems: ContextMenuProps[] = [ + { description: 'Freeform', event: () => func(CollectionViewType.Freeform), icon: 'signature' }, + { description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' }, + { description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' }, + { description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' }, + { description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' }, + { description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' }, + { description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' }, + { description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' }, + { description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' }, + { description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' }, + { description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' }, + { description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' }, + { description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' }, + ]; + const existingVm = ContextMenu.Instance.findByDescription(category); const catItems = existingVm && 'subitems' in existingVm ? existingVm.subitems : []; catItems.push({ description: 'Add a Perspective...', addDivider: true, noexpand: true, subitems: subItems, icon: 'eye' }); @@ -169,16 +156,12 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const newRendition = Doc.MakeAlias(this.rootDoc); - newRendition._viewType = vtype; - this.props.addDocTab(newRendition, OpenWhere.addRight); - return newRendition; - }, - false - ); + this.setupViewTypes('UI Controls...', vtype => { + const newRendition = Doc.MakeAlias(this.rootDoc); + newRendition._viewType = vtype; + this.props.addDocTab(newRendition, OpenWhere.addRight); + return newRendition; + }); const options = cm.findByDescription('Options...'); const optionItems = options && 'subitems' in options ? options.subitems : []; @@ -191,24 +174,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' }); - // if (!Doc.noviceMode && false) { - // optionItems.push({ - // description: 'Create Branch', - // event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight), - // icon: 'project-diagram', - // }); - // optionItems.push({ - // description: 'Pull Master', - // event: () => BranchTask(this.rootDoc, 'pull'), - // icon: 'project-diagram', - // }); - // optionItems.push({ - // description: 'Merge Branches', - // event: () => BranchTask(this.rootDoc, 'merge'), - // icon: 'project-diagram', - // }); - // } - !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' }); if (!Doc.noviceMode && !this.rootDoc.annotationOn) { @@ -253,10 +218,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles); childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle); childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); - @computed get childLayoutString() { - return StrCast(this.rootDoc.childLayoutString, this.props.childLayoutString); - } - isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive(); render() { @@ -273,7 +234,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent - {this.showIsTagged()} {this.renderSubView(this.collectionViewType, props)}
); -- cgit v1.2.3-70-g09d2 From f83e5d34794ef675d4627ecef2ed7042b17b1b06 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 18 Apr 2023 10:05:01 -0400 Subject: cleaning up zip/unzip of files --- src/client/views/collections/CollectionView.tsx | 13 ++- src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 6 +- src/fields/Doc.ts | 128 +++++++++------------ src/server/ApiManagers/UploadManager.ts | 9 +- 5 files changed, 67 insertions(+), 91 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index cfb9310b6..790aa765d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -156,12 +156,13 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const newRendition = Doc.MakeAlias(this.rootDoc); - newRendition._viewType = vtype; - this.props.addDocTab(newRendition, OpenWhere.addRight); - return newRendition; - }); + !Doc.noviceMode && + this.setupViewTypes('UI Controls...', vtype => { + const newRendition = Doc.MakeAlias(this.rootDoc); + newRendition._viewType = vtype; + this.props.addDocTab(newRendition, OpenWhere.addRight); + return newRendition; + }); const options = cm.findByDescription('Options...'); const optionItems = options && 'subitems' in options ? options.subitems : []; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7107707d1..6686f142f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -693,7 +693,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) { + if (!Doc.IsSystem(this.rootDoc) && this.rootDoc.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.rootDoc._viewType as any)) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index c43206629..72e8aedac 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -101,11 +101,7 @@ export class DashFieldViewInternal extends React.Component { - dashDoc instanceof Doc && (this._dashDoc = dashDoc); - }) - ); + DocServer.GetRefField(this.props.docId).then(action(dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc))); } else { this._dashDoc = this.props.tbox.rootDoc; } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 6c808c145..c5af45262 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -705,7 +705,7 @@ export namespace Doc { if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; const copy = new Doc(undefined, true); cloneMap.set(doc[Id], copy); - const filter = [...exclusions, ...Cast(doc.cloneFieldFilter, listSpec('string'), [])]; + const filter = [...exclusions, ...StrListCast(doc.cloneFieldFilter)]; await Promise.all( Object.keys(doc).map(async key => { if (filter.includes(key)) return; @@ -725,15 +725,13 @@ export namespace Doc { const docidsearch = new RegExp('(' + DocsInTextFieldIds.map(exp => '(' + exp + ')').join('|') + ')":"([a-z-A-Z0-9_]*)"', 'g'); const rawdocids = field.Data.match(docidsearch); const docids = rawdocids?.map((str: string) => - DocsInTextFieldIds.reduce((output, exp) => { - return output.replace(new RegExp(`${exp}":`, 'g'), ''); - }, str) + DocsInTextFieldIds.reduce((output, exp) => output.replace(new RegExp(`${exp}":`, 'g'), ''), str) .replace(/"/g, '') .trim() ); const results = docids && (await DocServer.GetRefFields(docids)); const docs = results && Array.from(Object.keys(results)).map(key => DocCast(results[key])); - docs && docs.map(doc => Doc.makeClone(doc, cloneMap, linkMap, rtfs, exclusions, cloneLinks)); + docs?.map(doc => doc && Doc.makeClone(doc, cloneMap, linkMap, rtfs, exclusions, cloneLinks)); rtfs.push({ copy, key, field }); } } @@ -741,7 +739,7 @@ export namespace Doc { }; const docAtKey = doc[key]; if (docAtKey instanceof Doc) { - if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || key === 'annotationOn' || key === 'proto' || ((key === 'anchor1' || key === 'anchor2') && doc.author === Doc.CurrentUserEmail))) { + if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || ['context', 'annotationOn', 'proto'].includes(key) || ((key === 'anchor1' || key === 'anchor2') && doc.author === Doc.CurrentUserEmail))) { assignKey(await Doc.makeClone(docAtKey, cloneMap, linkMap, rtfs, exclusions, cloneLinks)); } else { assignKey(docAtKey); @@ -749,8 +747,7 @@ export namespace Doc { } else if (field instanceof RefField) { assignKey(field); } else if (cfield instanceof ComputedField) { - assignKey(cfield[Copy]()); - // ComputedField.MakeFunction(cfield.script.originalScript)); + assignKey(cfield[Copy]()); // ComputedField.MakeFunction(cfield.script.originalScript)); } else if (field instanceof ObjectField) { await copyObjectField(field); } else if (field instanceof Promise) { @@ -804,8 +801,6 @@ export namespace Doc { const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf'], cloneLinks); const repaired = new Set(); const linkedDocs = Array.from(linkMap.values()); - const clonedDocs = [...Array.from(cloneMap.values()), ...linkedDocs]; - clonedDocs.map(clone => Doc.repairClone(clone, cloneMap, repaired)); linkedDocs.map((link: Doc) => LinkManager.Instance.addLink(link, true)); rtfMap.map(({ copy, key, field }) => { const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { @@ -816,20 +811,16 @@ export namespace Doc { const mapped = cloneMap.get(id); return href + (mapped ? mapped[Id] : id); }; - const regex = `(${Doc.localServerPath()})([^"]*)`; - const re = new RegExp(regex, 'g'); + const re = new RegExp(`(${Doc.localServerPath()})([^"]*)`, 'g'); const docidsearch = new RegExp('(' + DocsInTextFieldIds.map(exp => `"${exp}":`).join('|') + ')"([^"]+)"', 'g'); copy[key] = new RichTextField(field.Data.replace(docidsearch, replacer).replace(re, replacer2), field.Text); }); + const clonedDocs = [...Array.from(cloneMap.values()), ...linkedDocs]; + clonedDocs.map(clone => Doc.repairClone(clone, cloneMap, repaired)); return { clone: copy, map: cloneMap, linkMap }; } - export async function Zip(doc: Doc) { - // const a = document.createElement("a"); - // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); - // a.href = url; - // a.download = `DocExport-${this.props.Document[Id]}.zip`; - // a.click(); + export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') { const { clone, map, linkMap } = await Doc.MakeClone(doc); clone.LINKS = new List(Array.from(linkMap.values())); const proms = [] as string[]; @@ -837,76 +828,61 @@ export namespace Doc { if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined; else if (value instanceof Doc) { if (key !== 'field' && Number.isNaN(Number(key))) { - const __fields = value[FieldsSym](); - return { id: value[Id], __type: 'Doc', fields: __fields }; - } else { - return { fieldId: value[Id], __type: 'proxy' }; + return { id: value[Id], __type: 'Doc', fields: value[FieldsSym]() }; } - } else if (value instanceof ScriptField) return { script: value.script, __type: 'script' }; - else if (value instanceof RichTextField) return { Data: value.Data, Text: value.Text, __type: 'RichTextField' }; - else if (value instanceof ImageField) { + return { fieldId: value[Id], __type: 'proxy' }; + } else if (value instanceof ImageField) { const extension = value.url.href.replace(/.*\./, ''); proms.push(value.url.href.replace('.' + extension, '_o.' + extension)); return { url: value.url.href, __type: 'image' }; } else if (value instanceof PdfField) { proms.push(value.url.href); return { url: value.url.href, __type: 'pdf' }; - } else if (value instanceof AudioField) return { url: value.url.href, __type: 'audio' }; - else if (value instanceof VideoField) return { url: value.url.href, __type: 'video' }; + } else if (value instanceof AudioField) { + proms.push(value.url.href); + return { url: value.url.href, __type: 'audio' }; + } else if (value instanceof VideoField) { + proms.push(value.url.href); + return { url: value.url.href, __type: 'video' }; + } else if (value instanceof ScriptField) return { script: value.script, __type: 'script' }; + else if (value instanceof RichTextField) return { Data: value.Data, Text: value.Text, __type: 'RichTextField' }; else if (value instanceof WebField) return { url: value.url.href, __type: 'web' }; else if (value instanceof MapField) return { url: value.url.href, __type: 'map' }; else if (value instanceof DateField) return { date: value.toString(), __type: 'date' }; else if (value instanceof ProxyField) return { fieldId: value.fieldId, __type: 'proxy' }; else if (value instanceof Array && key !== 'fields') return { fields: value, __type: 'list' }; else if (value instanceof ComputedField) return { script: value.script, __type: 'computed' }; - else return value; + return value; } const docs: { [id: string]: any } = {}; Array.from(map.entries()).forEach(f => (docs[f[0]] = f[1])); - const docString = JSON.stringify({ id: clone[Id], docs }, decycle(replacer)); - - let generateZIP = (proms: string[]) => { - var zip = new JSZip(); - var count = 0; - var zipFilename = 'dashExport.zip'; - - proms - .filter(url => url.startsWith(window.location.origin)) - .forEach((url, i) => { - var filename = proms[i].replace(window.location.origin + '/', '').replace(/\//g, '%%%'); - // loading a file and add it in a zip file - JSZipUtils.getBinaryContent(url, function (err: any, data: any) { - if (err) { - throw err; // or handle the error - } - zip.file(filename, data, { binary: true }); - count++; - if (count == proms.length) { - zip.file('doc.json', docString); - zip.generateAsync({ type: 'blob' }).then(function (content) { - saveAs(content, zipFilename); - }); - } - }); - }); - }; - generateZIP(proms); - const zip = new JSZip(); - - zip.file('doc.json', docString); - - // // Generate a directory within the Zip file structure - // var img = zip.folder("images"); - - // // Add a file to the directory, in this case an image with data URI as contents - // img.file("smile.gif", imgData, {base64: true}); + const jsonDocs = JSON.stringify({ id: clone[Id], docs }, decycle(replacer)); - // Generate the zip file asynchronously - zip.generateAsync({ type: 'blob' }).then((content: any) => { - // Force down of the Zip file - saveAs(content, doc.title + '.zip'); // glr: Possibly change the name of the document to match the title? - }); + const zip = new JSZip(); + var count = 0; + proms + .filter(url => url.startsWith(window.location.origin)) + .forEach((url, i) => { + // loading a file and add it in a zip file + JSZipUtils.getBinaryContent(url, (err: any, data: any) => { + if (err) throw err; // or handle the error + // // Generate a directory within the Zip file structure + // const assets = zip.folder("assets"); + // assets.file(filename, data, {binary: true}); + const assetPathOnServer = proms[i].replace(window.location.origin + '/', '').replace(/\//g, '%%%'); + zip.file(assetPathOnServer, data, { binary: true }); + if (++count == proms.length) { + zip.file('doc.json', jsonDocs); + zip.generateAsync({ type: 'blob' }).then(content => saveAs(content, zipFilename)); + // const a = document.createElement("a"); + // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); + // a.href = url; + // a.download = `DocExport-${this.props.Document[Id]}.zip`; + // a.click(); + } + }); + }); } const _pendingMap: Map = new Map(); @@ -963,7 +939,7 @@ export namespace Doc { // otherwise, it just returns the childDoc export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt, childDoc: Doc) { if (!childDoc || childDoc instanceof Promise || !Doc.GetProto(childDoc)) { - console.log('No, no, no!'); + console.log('Warning: GetLayoutDataDocPair childDoc not defined'); return { layout: childDoc, data: childDoc }; } const resolvedDataDoc = Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc; @@ -1553,15 +1529,19 @@ export namespace Doc { } } - export async function importDocument(file: File) { + /// + // imports a previously exported zip file which contains a set of documents and their assets (eg, images, videos) + // the 'remap' parameter determines whether the ids of the documents loaded should be kept as they were, or remapped to new ids + // If they are not remapped, loading the file will overwrite any existing documents with those ids + // + export async function importDocument(file: File, remap = false) { const upload = Utils.prepend('/uploadDoc'); const formData = new FormData(); if (file) { formData.append('file', file); - formData.append('remap', 'true'); + formData.append('remap', remap.toString()); const response = await fetch(upload, { method: 'POST', body: formData }); const json = await response.json(); - console.log(json); if (json !== 'error') { await DocServer.GetRefFields(json.docids as string[]); const doc = DocCast(await DocServer.GetRefField(json.id)); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 6e28268a9..2cc2ac46c 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -184,9 +184,8 @@ export default class UploadManager extends ApiManager { if (id.endsWith('Proto')) return id; if (id in ids) { return ids[id]; - } else { - return (ids[id] = v4()); } + return (ids[id] = v4()); }; const mapFn = (doc: any) => { if (doc.id) { @@ -266,7 +265,7 @@ export default class UploadManager extends ApiManager { await Promise.all( docs.map( (doc: any) => - new Promise(res => { + new Promise(res => Database.Instance.replace( doc.id, doc, @@ -275,8 +274,8 @@ export default class UploadManager extends ApiManager { res(); }, true - ); - }) + ) + ) ) ); } catch (e) { -- cgit v1.2.3-70-g09d2