diff options
Diffstat (limited to 'src/client/views/collections')
10 files changed, 105 insertions, 80 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index c8c840085..c9f640c4a 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -19,16 +19,21 @@ export enum CollectionViewType { } export interface CollectionRenderProps { - addDocument: (document: Document, allowDuplicates: boolean) => void; + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; active: () => boolean; } export interface CollectionViewProps extends FieldViewProps { onContextMenu?: (e: React.MouseEvent) => void; - children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | null; + children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null; + className?: string; + contentRef?: React.Ref<HTMLDivElement>; } +export const COLLECTION_BORDER_WIDTH = 1; + export class CollectionBaseView extends React.Component<CollectionViewProps> { get collectionViewType(): CollectionViewType { let Document = this.props.Document; @@ -44,7 +49,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { active = (): boolean => { var isSelected = this.props.isSelected(); - var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == self); + var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this); var topMost = this.props.isTopMost; return isSelected || childSelected || topMost; } @@ -68,7 +73,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { } @action.bound - addDocument(doc: Document, allowDuplicates: boolean): boolean { + 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)); @@ -123,14 +128,27 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { return false } + @action.bound + moveDocument(doc: Document, targetCollection: Document, addDocument: (doc: Document) => void): boolean { + if (this.props.Document === targetCollection) { + return false; + } + if (this.removeDocument(doc)) { + addDocument(doc); + return true; + } + return false; + } + render() { const props: CollectionRenderProps = { addDocument: this.addDocument, removeDocument: this.removeDocument, + moveDocument: this.moveDocument, active: this.active } return ( - <div className="collectionView-cont" onContextMenu={this.props.onContextMenu}> + <div className={this.props.className || "collectionView-cont"} onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}> {this.props.children(this.collectionViewType, props)} </div> ) diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c67354139..bb34340fb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -8,12 +8,12 @@ import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import Measure from "react-measure"; import { FieldId, Opt, Field } from "../../../fields/Field"; -import { Utils } from "../../../Utils"; +import { Utils, returnTrue } from "../../../Utils"; import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; -import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionViewBase"; import { ServerUtils } from "../../../server/ServerUtil"; @@ -310,14 +310,15 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { var content = <div className="collectionDockingView-content" ref={this._mainCont}> <DocumentView key={this._document.Id} Document={this._document} - AddDocument={undefined} - RemoveDocument={undefined} + addDocument={undefined} + removeDocument={undefined} ContentScaling={this._contentScaling} PanelWidth={this._nativeWidth} PanelHeight={this._nativeHeight} ScreenToLocalTransform={this.ScreenToLocalTransform} isTopMost={true} selectOnLoad={false} + parentActive={returnTrue} focus={(doc: Document) => { }} ContainingCollectionView={undefined} /> </div> diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 6bb3bacc7..14ed70b8c 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -1,23 +1,20 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import "./CollectionPDFView.scss" import React = require("react"); -import { FieldId } from "../../../fields/Field"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; +import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; @observer export class CollectionPDFView extends React.Component<CollectionViewProps> { public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionPDFView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionPDFView, fieldKey); } private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } @@ -35,26 +32,27 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> { ); } - // "inherited" CollectionView API starts here... - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); } } - render() { + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; return ( - <div className="collectionPdfView-cont" onContextMenu={this.specificContextMenu}> - <CollectionFreeFormView {...CollectionView.SubViewProps(this)} /> + <> + <CollectionFreeFormView {...props} /> {this.props.isSelected() ? this.uIButtons : (null)} - </div> + </> + ) + } + + render() { + return ( + <CollectionBaseView {...this.props} className="collectionPdfView-cont" onContextMenu={this.onContextMenu}> + {this.subView} + </CollectionBaseView> ) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 0c7e28691..0eacd38b0 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -22,9 +22,11 @@ import { EditableView } from "../EditableView"; import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import { TextField } from "../../../fields/TextField"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; +import { emptyFunction, returnFalse } from "../../../Utils"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -79,6 +81,9 @@ export class CollectionSchemaView extends CollectionViewBase { select: () => { }, isTopMost: false, selectOnLoad: false, + ScreenToLocalTransform: Transform.Identity, + focus: emptyFunction, + active: returnFalse } let contents = ( <FieldView {...props} /> @@ -295,15 +300,16 @@ export class CollectionSchemaView extends CollectionViewBase { {({ measureRef }) => <div className="collectionSchemaView-content" ref={measureRef}> {doc instanceof Document ? <DocumentView Document={doc} - AddDocument={this.props.addDocument} RemoveDocument={this.props.removeDocument} + addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} isTopMost={false} selectOnLoad={false} ScreenToLocalTransform={this.getPreviewTransform} ContentScaling={this.getContentScaling} PanelWidth={this.getPanelWidth} PanelHeight={this.getPanelHeight} - ContainingCollectionView={this.props.CollectionView} + ContainingCollectionView={undefined} focus={this.focusDocument} + parentActive={this.props.active} /> : null} <input value={this.previewScript} onChange={this.onPreviewScriptChange} style={{ position: 'absolute', bottom: '0px' }} /> diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70790af18..6f9ba40d2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,9 +10,10 @@ import { ListField } from "../../../fields/ListField"; import { setupDrag } from "../../util/DragManager"; import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import React = require("react") +import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; export interface TreeViewProps { diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 1f0143d87..7cb461b4d 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -3,12 +3,14 @@ import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; +import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; import "./CollectionVideoView.scss" -import { CollectionFreeFormView } from "./CollectionFreeFormView"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; @observer @@ -20,9 +22,7 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { @observable _isPlaying: boolean = false; public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionVideoView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); @@ -102,26 +102,27 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { } - // "inherited" CollectionView API starts here... - - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); } } + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; + return ( + <> + <CollectionFreeFormView {...props} /> + {this.props.isSelected() ? this.uIButtons : (null)} + </> + ) + } + render() { trace(); - return (<div className="collectionVideoView-cont" ref={this.mainCont} onContextMenu={this.specificContextMenu}> - <CollectionFreeFormView {...CollectionView.SubViewProps(this)} /> - {this.props.isSelected() ? this.uIButtons : (null)} - </div>) + return ( + <CollectionBaseView {...this.props} className="collectionVideoView-cont" contentRef={this.mainCont} onContextMenu={this.onContextMenu}> + {this.subView} + </CollectionBaseView>) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 51cc99595..d440dcff9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -12,7 +12,7 @@ export class CollectionView extends React.Component<FieldViewProps> { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - let props = { ...renderProps, ...this.props }; + let props = { ...this.props, ...renderProps }; switch (type) { case CollectionViewType.Freeform: return (<CollectionFreeFormView {...props} />) case CollectionViewType.Schema: return (<CollectionSchemaView {...props} />) @@ -34,7 +34,7 @@ export class CollectionView extends React.Component<FieldViewProps> { return ( <CollectionBaseView {...this.props} onContextMenu={this.onContextMenu}> {this.SubView} - </CollectionBaseView> > + </CollectionBaseView> ) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index ca4f3b12f..4a0b2312e 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -20,6 +20,9 @@ import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; export interface CollectionViewProps extends FieldViewProps { + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; } export interface SubCollectionViewProps extends CollectionViewProps { @@ -72,8 +75,8 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> de.data.draggedDocument.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); } let added = this.props.addDocument(de.data.droppedDocument, false); - if (added && de.data.removeDocument && !de.data.aliasOnDrop) { - de.data.removeDocument(this.props.CollectionView); + if (added && de.data.moveDocument && !de.data.aliasOnDrop) { + de.data.moveDocument(this.props.Document, this.props.addDocument); } e.stopPropagation(); return added; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 19382e66f..f664f4e65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,21 +1,8 @@ -import { action, computed, observable } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; -import { TextField } from "../../../../fields/TextField"; -import { DragManager } from "../../../util/DragManager"; -import { Transform } from "../../../util/Transform"; -import { undoBatch } from "../../../util/UndoManager"; -import { InkingCanvas } from "../../InkingCanvas"; -import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; -import { CollectionViewBase, CollectionViewProps, CursorEntry } from "../CollectionViewBase"; -import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; +import { CollectionViewProps, CursorEntry } from "../CollectionViewBase"; import "./CollectionFreeFormView.scss"; -import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 51ab85b71..144d121db 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -11,7 +11,7 @@ import { InkingCanvas } from "../../InkingCanvas"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "../CollectionBaseView"; import { CollectionViewBase } from "../CollectionViewBase"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import "./CollectionFreeFormView.scss"; @@ -20,6 +20,8 @@ import React = require("react"); import v5 = require("uuid/v5"); import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import { PreviewCursor } from "./PreviewCursor"; +import { DocumentManager } from "../../../util/DocumentManager"; +import { SelectionManager } from "../../../util/SelectionManager"; @observer export class CollectionFreeFormView extends CollectionViewBase { @@ -39,8 +41,13 @@ export class CollectionFreeFormView extends CollectionViewBase { } public selectDocuments = (docs: Document[]) => { - this.props.CollectionView.SelectedDocs.length = 0; - docs.map(d => this.props.CollectionView.SelectedDocs.push(d.Id)); + SelectionManager.DeselectAll; + docs.map(doc => { + const dv = DocumentManager.Instance.getDocumentView(doc); + if (dv) { + SelectionManager.SelectDoc(dv, true); + } + }) } public getActiveDocuments = () => { @@ -59,6 +66,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @observable private _lastX: number = 0; @observable private _lastY: number = 0; + private outerElement?: HTMLDivElement; + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @@ -66,8 +75,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); } - @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this.props.panelWidth() / 2 : 0; } // shift so pan position is at center of window for non-overlay collections - @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this.props.panelHeight() / 2 : 0; }// shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) && this.outerElement ? this.outerElement.clientWidth / 2 : 0; } // shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) && this.outerElement ? this.outerElement.clientHeight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections @undoBatch @action @@ -227,16 +236,17 @@ export class CollectionFreeFormView extends CollectionViewBase { getDocumentViewProps(document: Document): DocumentViewProps { return { Document: document, - AddDocument: this.props.addDocument, - RemoveDocument: this.props.removeDocument, + addDocument: this.props.addDocument, + removeDocument: this.props.removeDocument, ScreenToLocalTransform: this.getTransform, isTopMost: false, selectOnLoad: document.Id == this._selectOnLoaded, PanelWidth: document.Width, PanelHeight: document.Height, ContentScaling: this.noScaling, - ContainingCollectionView: this.props.CollectionView, - focus: this.focusDocument + ContainingCollectionView: undefined, + focus: this.focusDocument, + parentActive: this.props.active, } } @@ -266,7 +276,7 @@ export class CollectionFreeFormView extends CollectionViewBase { getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) - getLocalTransform = (): Transform => Transform.Identity.scale(1 / this.scale).translate(this.panX, this.panY); + getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; |
