From fa6aa3f3d13cade1cd46d954dbfee6f8566bcc86 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 29 Mar 2021 13:20:14 -0400 Subject: initial changes to cleanup pointer events. --- src/client/views/nodes/DocumentContentsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/DocumentContentsView.tsx') diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 2f7923574..553cfcdf7 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -158,7 +158,7 @@ export class DocumentContentsView extends React.Component obj.active = this.props.parentActive).omit, + ...OmitKeys(this.props, [...docOnlyProps], "").omit, RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, -- cgit v1.2.3-70-g09d2 From 7db0fe589afa3281894afb0a0d3bd6b9983c9d33 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 29 Mar 2021 19:04:08 -0400 Subject: still cleaning up all the active/selection code. --- src/client/documents/Documents.ts | 5 +- src/client/util/DragManager.ts | 7 +- src/client/views/DocComponent.tsx | 58 +++++-- src/client/views/MainView.tsx | 8 +- src/client/views/SidebarAnnos.tsx | 4 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionCarousel3DView.tsx | 2 +- src/client/views/collections/CollectionMapView.tsx | 2 +- .../collections/CollectionMasonryViewFieldRow.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 14 +- .../collections/CollectionStackedTimeline.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 190 +++++---------------- src/client/views/collections/TabDocView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 4 +- src/client/views/nodes/AudioBox.tsx | 14 +- src/client/views/nodes/ComparisonBox.tsx | 6 +- src/client/views/nodes/DocumentContentsView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 17 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FilterBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 8 +- src/client/views/nodes/KeyValuePair.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 16 +- src/client/views/nodes/PresBox.tsx | 3 +- src/client/views/nodes/ScreenshotBox.tsx | 8 +- src/client/views/nodes/ScriptingBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 20 +-- src/client/views/nodes/WebBox.tsx | 16 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 14 +- src/client/views/pdf/PDFViewer.tsx | 12 +- src/fields/util.ts | 2 +- 36 files changed, 206 insertions(+), 271 deletions(-) (limited to 'src/client/views/nodes/DocumentContentsView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9406b374e..81fb204de 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1322,7 +1322,10 @@ export namespace DocUtils { export function LeavePushpin(doc: Doc) { if (doc.isPushpin) return undefined; const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null); - const hasContextAnchor = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); + const hasContextAnchor = DocListCast(doc.links). + some(l => + (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || + (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { const pushpin = Docs.Create.FontIconDocument({ title: "pushpin", label: "", annotationOn: Cast(doc.annotationOn, Doc, null), isPushpin: true, diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 38d0ecaa6..abf1af669 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -379,7 +379,12 @@ export namespace DragManager { if (docsBeingDragged.length) { const pdfBox = dragElement.getElementsByTagName("canvas"); const pdfBoxSrc = ele.getElementsByTagName("canvas"); - Array.from(pdfBox).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); + Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => { + const context = pb.getContext('2d')!; + console.log(getComputedStyle(pb).width); + console.log(getComputedStyle(pdfBoxSrc[i]).width); + context.drawImage(pdfBoxSrc[i], 0, 0); + }); } [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele => ele.hasAttribute("style") && ((ele as any).style.pointerEvents = "none")); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 3f6715560..5c0fe6b97 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -10,6 +10,8 @@ import { ScriptField } from '../../fields/ScriptField'; import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DocUtils } from '../documents/Documents'; +import { returnFalse } from '../../Utils'; +import { UndoManager } from '../util/UndoManager'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -34,7 +36,7 @@ export function DocComponent

(schemaCtor: (doc: D return Component; } -/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. AudioBox, FormattedTextBox) +/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. InkingStroke, ColorBox) interface ViewBoxBaseProps { Document: Doc; DataDoc?: Doc; @@ -74,22 +76,23 @@ export interface ViewBoxAnnotatableProps { Document: Doc; DataDoc?: Doc; fieldKey: string; - layerProvider?: (doc: Doc) => boolean; - active: () => 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) + layerProvider?: (doc: Doc, assign?: boolean) => boolean; + isContentActive: () => boolean; select: (isCtrlPressed: boolean) => void; whenChildContentsActiveChanged: (isActive: boolean) => void; isSelected: (outsideReaction?: boolean) => boolean; rootSelected: (outsideReaction?: boolean) => boolean; renderDepth: number; + isAnnotationOverlay?: boolean; } -export function ViewBoxAnnotatableComponent

(schemaCtor: (doc: Doc) => T) { +export function ViewBoxAnnotatableComponent

(schemaCtor: (doc: Doc) => T, _annotationKey: string = "annotations") { class Component extends Touchable

{ - @observable _annotationKey: string = "annotations"; + @observable _annotationKey: string = _annotationKey; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } - // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @@ -125,7 +128,7 @@ export function ViewBoxAnnotatableComponent

boolean, annotationKey?: string): boolean { - return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc, annotationKey, true) ? addDocument(doc) : false; + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string): boolean => { + if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { + return true; + } + const first = doc instanceof Doc ? doc : doc[0]; + if (!first?._stayInCollection && addDocument !== returnFalse) { + return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc)); + } + return false; } @action.bound addDocument(doc: Doc | Doc[], annotationKey?: string): boolean { const docs = doc instanceof Doc ? [doc] : doc; - docs.map(doc => doc.context = Doc.GetProto(doc).annotationOn = this.props.Document); + if (this.props.filterAddDocument?.(docs) === false || + docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) { + return false; + } const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]); const added = docs.filter(d => !docList.includes(d)); @@ -187,10 +202,21 @@ export function ViewBoxAnnotatableComponent

Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc)); + added.map(doc => { + this.props.layerProvider?.(doc, true); + Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); + doc.context = this.props.Document; + if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document; + }); } else { - added.map(doc => doc.context = this.props.Document); + added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document + this.props.layerProvider?.(doc, true); + DocUtils.LeavePushpin(doc); + doc._stayInCollection = undefined; + doc.context = this.props.Document; + if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document; + }); const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List; if (annoDocs) annoDocs.push(...added); else targetDataDoc[annotationKey ?? this.annotationKey] = new List(added); @@ -202,10 +228,10 @@ export function ViewBoxAnnotatableComponent

this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); - active = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool === InkTool.None && + isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool === InkTool.None && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction)) ? true : false) annotationsActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None || - (this.props.layerProvider?.(this.props.Document) === false && this.props.active()) || + (this.props.layerProvider?.(this.props.Document) !== false && this.props.isContentActive?.()) || (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0) ? true : false) } return Component; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index bb6a091cb..83949eba2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -485,7 +485,7 @@ export class MainView extends React.Component { rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} - active={returnFalse} + isContentActive={returnFalse} isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} @@ -547,7 +547,7 @@ export class MainView extends React.Component { fieldKey="data" dropAction="move" isSelected={returnTrue} - active={returnTrue} + isContentActive={returnTrue} select={returnTrue} setHeight={returnFalse} addDocument={undefined} @@ -593,7 +593,7 @@ export class MainView extends React.Component { pinToPres={returnFalse} ScreenToLocalTransform={Transform.Identity} bringToFront={returnFalse} - active={returnFalse} + isContentActive={returnFalse} whenChildContentsActiveChanged={returnFalse} focus={returnFalse} docViewPath={returnEmptyDoclist} @@ -665,7 +665,7 @@ export class MainView extends React.Component { pinToPres={returnFalse} ScreenToLocalTransform={Transform.Identity} bringToFront={returnFalse} - active={returnFalse} + isContentActive={returnFalse} whenChildContentsActiveChanged={returnFalse} focus={returnFalse} PanelWidth={() => 500} diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index d3216bc94..4514e3ebb 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -98,7 +98,7 @@ export class SidebarAnnos extends React.Component { }; return !this.props.layoutDoc._showSidebar ? (null) :

{ scaleField={this.sidebarKey() + "-scale"} isAnnotationOverlay={false} select={emptyFunction} - active={this.props.annotationsActive} + isContentActive={this.props.annotationsActive} scaling={returnOne} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} childHideDecorationTitle={returnTrue} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 34b0e4d99..5491a81e6 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -141,7 +141,7 @@ export class TemplateMenu extends React.Component { onCheckedClick={this.scriptField} onChildClick={this.scriptField} dropAction={undefined} - active={returnTrue} + isContentActive={returnTrue} bringToFront={emptyFunction} focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 452c79f88..b2ae441d6 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -126,7 +126,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume } @computed get buttons() { - if (!this.props.active()) return null; + if (!this.props.isContentActive()) return null; return
this.onArrowClick(e, -1)} diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 92288c1f2..2d7569d45 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -208,7 +208,7 @@ export class CollectionMapView extends CollectionSubView list + ` ${this.props.parent.columnWidth}px`, ""), }}> {this.props.parent.children(this.props.docList)} - {this.props.showHandle && this.props.parent.props.active() ? this.props.parent.columnDragger : (null)} + {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : (null)}
; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index dc2880a48..d49403d8e 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -328,7 +328,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @action onWheel(e: React.WheelEvent) { const scale = this.props.ScreenToLocalTransform().Scale; - this.props.active(true) && e.stopPropagation(); + this.props.isContentActive(true) && e.stopPropagation(); } @computed get renderMenuContent() { @@ -444,7 +444,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { renderDepth={this.props.renderDepth} moveDocument={this.props.moveDocument} ScreenToLocalTransform={this.props.ScreenToLocalTransform} - active={this.props.active} + active={this.props.isContentActive} onDrop={this.onExternalDrop} addDocTab={this.props.addDocTab} pinToPres={this.props.pinToPres} @@ -533,11 +533,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { this.columns = columns; } - onZoomMenu = (e: React.WheelEvent) => this.props.active(true) && e.stopPropagation(); + onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation(); render() { TraceMobx(); - if (!this.props.active()) setTimeout(() => this.closeHeader(), 0); + if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0); const menuContent = this.renderMenuContent; const menu =
this.onZoomMenu(e)} @@ -553,21 +553,21 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { return
this.props.active(true) && e.stopPropagation()} + onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}> {this.schemaTable}
{this.dividerDragger} {!this.previewWidth() ? (null) : this.previewPanel} - {this._headerOpen && this.props.active() ? menu : null} + {this._headerOpen && this.props.isContentActive() ? menu : null}
; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 304643d52..d6aca6f00 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -114,7 +114,7 @@ export class CollectionStackedTimeline extends CollectionSubView { const rect = this._timeline?.getBoundingClientRect(); const clientX = e.clientX; - if (rect && this.props.active()) { + if (rect && this.props.isContentActive()) { const wasPlaying = this.props.playing(); if (wasPlaying) this.props.Pause(); const wasSelecting = CollectionStackedTimeline.SelectingRegion === this; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 3087aeb81..4dab9d94a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -533,14 +533,14 @@ export class CollectionStackingView extends CollectionSubView this._scroll = e.currentTarget.scrollTop)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} - onWheel={e => this.props.active(true) && e.stopPropagation()} > + onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > {this.renderedSections} {!this.showAddAGroup ? (null) :
doc) { } @computed get contents() { - return
this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); whenChildContentsActiveChanged = (isActive: boolean) => { this.props.whenChildContentsActiveChanged(this._isChildActive = isActive); }; - active = (outsideReaction: boolean | undefined) => this.props.active(outsideReaction) || this._isChildActive; + active = (outsideReaction: boolean | undefined) => this.props.isContentActive(outsideReaction) || this._isChildActive; panelWidth = () => this.props.PanelWidth() - 20; // bcz: 20 is the 10 + 10 for the left and right padding. @computed get treeChildren() { TraceMobx(); @@ -224,7 +224,7 @@ export class CollectionTreeView extends CollectionSubView diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index f8c846f7f..28099a995 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -2,26 +2,23 @@ import { action, computed, observable } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app -import { DateField } from '../../../fields/DateField'; -import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; -import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; +import { makeInterface } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { Cast, ScriptCast, StrCast, DateCast } from '../../../fields/Types'; -import { denormalizeEmail, distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; -import { returnFalse } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; -import { BranchTask, BranchCreate } from '../../documents/Gitlike'; -import { DocumentType } from '../../documents/DocumentTypes'; +import { Cast, ScriptCast, StrCast } from '../../../fields/Types'; +import { TraceMobx } from '../../../fields/util'; +import { DocUtils } from '../../documents/Documents'; +import { BranchCreate, BranchTask } from '../../documents/Gitlike'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { InteractionUtils } from '../../util/InteractionUtils'; -import { UndoManager } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; -import { Touchable } from '../Touchable'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from "./CollectionDockingView"; @@ -64,7 +61,6 @@ export enum CollectionViewType { export interface CollectionViewProps extends FieldViewProps { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) layoutEngine?: () => string; - 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) setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; // property overrides for child documents @@ -81,19 +77,20 @@ export interface CollectionViewProps extends FieldViewProps { childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; } + +type CollectionDocument = makeInterface<[typeof documentSchema]>; +const CollectionDocument = makeInterface(documentSchema); @observer -export class CollectionView extends Touchable { +export class CollectionView extends ViewBoxAnnotatableComponent(CollectionDocument, "") { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } - _isChildActive = false; //TODO should this be observable? - @observable private _curLightboxImg = 0; @observable private static _safeMode = false; public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; } protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; get collectionViewType(): CollectionViewType | undefined { - const viewField = StrCast(this.props.Document._viewType); + const viewField = StrCast(this.layoutDoc._viewType); if (CollectionView._safeMode) { switch (viewField) { case CollectionViewType.Freeform: @@ -104,121 +101,24 @@ export class CollectionView extends Touchable { return viewField as any as CollectionViewType; } - active = (outsideReaction?: boolean) => { - return this.props.renderDepth === 0 || - this.props.isSelected(outsideReaction) || - this.props.rootSelected(outsideReaction) || - (this.props.layerProvider?.(this.props.Document) !== false && (this.props.Document.forceActive || this.props.Document._isGroup)) || - this._isChildActive ? - true : - false; - } - - whenChildContentsActiveChanged = (isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive); - - @action.bound - addDocument = (doc: Doc | Doc[]): boolean => { - if (this.props.filterAddDocument?.(doc) === false) { - return false; - } - - const docs = doc instanceof Doc ? [doc] : doc; - - if (docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) return false; - const targetDataDoc = this.props.Document[DataSym]; - const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - const added = docs.filter(d => !docList.includes(d)); - const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); - - if (added.length) { - if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) { - return false; - } - else { - if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym])) { - added.forEach(d => { - for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); - //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); - //else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); - } - }); - } - - if (effectiveAcl === AclAddonly) { - added.map(doc => { - this.props.layerProvider?.(doc, true);// assigns layer values to the newly added document... testing the utility of this - Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); - doc.context = this.props.Document; - }); - } - else { - added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document - DocUtils.LeavePushpin(doc); - doc._stayInCollection = undefined; - doc.context = this.props.Document; - }); - added.map(doc => this.props.layerProvider?.(doc, true));// assigns layer values to the newly added document... testing the utility of this - (targetDataDoc[this.props.fieldKey] as List).push(...added); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); - } - } - } - return true; - } - - @action.bound - removeDocument = (doc: any): boolean => { - const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); - const indocs = doc instanceof Doc ? [doc] : doc as Doc[]; - const docs = indocs.filter(doc => effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin); - if (docs.length) { - const targetDataDoc = this.props.Document[DataSym]; - const value = DocListCast(targetDataDoc[this.props.fieldKey]); - const toRemove = value.filter(v => docs.includes(v)); - if (toRemove.length !== 0) { - const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc; - toRemove.forEach(doc => { - const ind = (targetDataDoc[this.props.fieldKey] as List).indexOf(doc); - if (ind !== -1) { - Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc); - doc.context = undefined; - recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true); - } - }); - return true; - } - } - return false; - } - - // this is called with the document that was dragged and the collection to move it into. - // if the target collection is the same as this collection, then the move will be allowed. - // 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 | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { - if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { - return true; - } - const first = doc instanceof Doc ? doc : doc[0]; - if (!first?._stayInCollection && addDocument !== returnFalse) { - return UndoManager.RunInTempBatch(() => this.removeDocument(doc) && addDocument(doc)); - } - return false; - } - showIsTagged = () => { 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 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) : ; } + isContentActive = (outsideReaction?: boolean) => { + return this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction) || + (this.props.layerProvider?.(this.rootDoc) !== false && (this.rootDoc.forceActive || this.rootDoc._isGroup)) + ? + true : false; + } + screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()); private SubView = (type: CollectionViewType, props: SubCollectionViewProps) => { TraceMobx(); @@ -251,7 +151,6 @@ export class CollectionView extends Touchable { } subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" }); subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" }); - !Doc.UserDoc().noviceMode && subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" }); subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking)._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" }); @@ -262,7 +161,7 @@ export class CollectionView extends Touchable { !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); - if (!Doc.IsSystem(this.props.Document) && !this.props.Document.annotationOn) { + if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.annotationOn) { 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" }); @@ -272,9 +171,9 @@ export class CollectionView extends Touchable { onContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; - if (cm && !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 + if (cm && !e.isPropagationStopped() && this.rootDoc[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("UI Controls...", vtype => { - const newRendition = Doc.MakeAlias(this.props.Document); + const newRendition = Doc.MakeAlias(this.rootDoc); newRendition._viewType = vtype; this.props.addDocTab(newRendition, "add:right"); return newRendition; @@ -282,34 +181,34 @@ export class CollectionView extends Touchable { const options = cm.findByDescription("Options..."); const optionItems = options && "subitems" in options ? options.subitems : []; - !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null; - if (this.props.Document.childLayout instanceof Doc) { - optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "add:right"), icon: "project-diagram" }); + !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; + if (this.rootDoc.childLayout instanceof Doc) { + optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" }); } - if (this.props.Document.childClickedOpenTemplateView instanceof Doc) { - optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" }); + if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { + optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" }); } - !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); + !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); optionItems.push({ - description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.props.Document), "add:right"), icon: "project-diagram" + description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram" }); optionItems.push({ - description: "Pull Master", event: () => BranchTask(this.props.Document, "pull"), icon: "project-diagram" + description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram" }); optionItems.push({ - description: "Merge Branches", event: () => BranchTask(this.props.Document, "merge"), icon: "project-diagram" + description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram" }); !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" }); - if (!Doc.UserDoc().noviceMode && !this.props.Document.annotationOn) { + if (!Doc.UserDoc().noviceMode && !this.rootDoc.annotationOn) { const existingOnClick = cm.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; 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) => { - const alias = Doc.MakeAlias(this.props.Document); + const alias = Doc.MakeAlias(this.rootDoc); DocUtils.makeCustomViewClicked(alias, undefined, func.key); this.props.addDocTab(alias, "add:right"); } @@ -318,15 +217,15 @@ export class CollectionView extends Touchable { onClicks.push({ description: `Set child ${childClick.title}`, icon: "edit", - event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), + event: () => Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), })); - !Doc.IsSystem(this.props.Document) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); + !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); } if (!Doc.UserDoc().noviceMode) { const more = cm.findByDescription("More..."); const moreItems = more && "subitems" in more ? more.subitems : []; - moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) }); + moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); } } @@ -334,27 +233,26 @@ export class CollectionView extends Touchable { bodyPanelWidth = () => this.props.PanelWidth(); - childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); - @computed get childLayoutString() { return StrCast(this.props.Document.childLayoutString); } + childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); + @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); } render() { TraceMobx(); const props: SubCollectionViewProps = { ...this.props, addDocument: this.addDocument, - removeDocument: this.removeDocument, moveDocument: this.moveDocument, - active: this.active, - whenChildContentsActiveChanged: this.whenChildContentsActiveChanged, + removeDocument: this.removeDocument, + isContentActive: this.isContentActive, PanelWidth: this.bodyPanelWidth, PanelHeight: this.props.PanelHeight, + ScreenToLocalTransform: this.screenToLocalTransform, childLayoutTemplate: this.childLayoutTemplate, childLayoutString: this.childLayoutString, - ScreenToLocalTransform: this.screenToLocalTransform, CollectionView: this, }; return (
+ style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}> {this.showIsTagged()} {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index dcd874089..ec3f3090b 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -420,7 +420,7 @@ export class TabMinimapView extends React.Component { childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. noOverlay={true} // don't render overlay Docs since they won't scale setHeight={returnFalse} - active={returnTrue} + isContentActive={returnTrue} select={emptyFunction} dropAction={undefined} isSelected={returnFalse} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index eca655099..b74bca5d3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -116,7 +116,7 @@ export class CollectionFreeFormView extends CollectionSubView ele.bounds && !ele.bounds.z).map(ele => ele.ele); } @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); } - @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); } + @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); } @computed get fitToContentVals() { return { bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 }, @@ -457,7 +457,7 @@ export class CollectionFreeFormView extends CollectionSubView) => { - if (!e.nativeEvent.cancelBubble && this.props.active(true)) { + if (!e.nativeEvent.cancelBubble && this.props.isContentActive(true)) { // const pt1: React.Touch | null = e.targetTouches.item(0); // const pt2: React.Touch | null = e.targetTouches.item(1); // // if (!pt1 || !pt2) return; @@ -817,7 +817,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.active()} + isDocumentActive={() => this.props.isContentActive()} dontRegisterView={this.props.dontRegisterView} pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" : (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined} @@ -1486,7 +1486,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? + {this.Document._freeformLOD && !this.props.isContentActive() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} {this.props.noOverlay ? (null) : } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index af391a078..d7a0d3f34 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -167,7 +167,7 @@ export class MarqueeView extends React.Component { - if (this.props.active(true)) { + if (this.props.isContentActive(true)) { setupMoveUpEvents(this, e, returnFalse, returnFalse, (e: PointerEvent, doubleTap?: boolean) => { if (doubleTap) { @@ -315,7 +315,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { render() { return (
; const AudioDocument = makeInterface(documentSchema); @observer -export class AudioBox extends ViewBoxAnnotatableComponent(AudioDocument) { +export class AudioBox extends ViewBoxAnnotatableComponent(AudioDocument, "annotations") { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); } public static Enabled = false; static playheadWidth = 30; // width of playhead @@ -63,7 +63,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent) { + constructor(props: Readonly) { super(props); AudioBox.Instance = this; @@ -267,7 +267,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent + return ; @@ -337,7 +337,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent}
: -
+
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index d71bb1397..0a9d7e809 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -9,7 +9,7 @@ import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; -import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import "./ComparisonBox.scss"; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; @@ -21,7 +21,7 @@ type ComparisonDocument = makeInterface<[typeof comparisonSchema, typeof documen const ComparisonDocument = makeInterface(comparisonSchema, documentSchema); @observer -export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument) { +export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument, "annotations") { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; @@ -102,7 +102,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent +
{displayBox("after", 1, this.props.PanelWidth() - 3)}
{displayBox("before", 0, 0)} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 553cfcdf7..b53827371 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -40,6 +40,7 @@ import React = require("react"); import { TraceMobx, GetEffectiveAcl } from "../../../fields/util"; import { ScriptField } from "../../../fields/ScriptField"; import XRegExp = require("xregexp"); +import { DocumentType } from "../../documents/DocumentTypes"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 19ed417c0..e4f1ac8ed 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -110,6 +110,7 @@ export interface DocumentViewSharedProps { whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: string) => boolean; + filterAddDocument?: (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; @@ -130,7 +131,8 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings treeViewDoc?: Doc; - documentActive?: () => boolean; // whether a document should handle pointer events + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive?: () => boolean | undefined; // whether a document should handle pointer events contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents radialMenu?: String[]; LayoutTemplateString?: string; @@ -175,7 +177,6 @@ export class DocumentViewInternal extends DocComponent; // needs to be accessed from DocumentView wrapper class private get topMost() { return this.props.renderDepth === 0; } - private get active() { return this.props.documentActive?.() || this.props.isSelected(true); } public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive public get ContentDiv() { return this._mainCont.current; } public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); } @@ -279,7 +280,7 @@ export class DocumentViewInternal extends DocComponent) => { - if (e.cancelBubble && this.active) { + if (e.cancelBubble && this.props.isDocumentActive?.()) { this.removeMoveListeners(); } - else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { const touch = me.touchEvent.changedTouches.item(0); if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -510,7 +511,7 @@ export class DocumentViewInternal extends DocComponent 0))) { - if ((this.active || this.layoutDoc.onDragStart) && + if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { @@ -527,10 +528,10 @@ export class DocumentViewInternal extends DocComponent { if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return; - if (e.cancelBubble && this.active) { + if (e.cancelBubble && this.props.isDocumentActive?.()) { document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) } - else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 97f53aac0..0fc7a752f 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -18,8 +18,8 @@ export interface FieldViewProps extends DocumentViewSharedProps { fieldKey: string; scrollOverflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further - active: (outsideReaction?: boolean) => boolean; select: (isCtrlPressed: boolean) => void; + isContentActive: (outsideReaction?: boolean) => boolean; isSelected: (outsideReaction?: boolean) => boolean; scaling?: () => number; setHeight: (height: number) => void; diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 39db6f46c..bf5a6b7d2 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -215,7 +215,7 @@ export class FilterBox extends ViewBoxBaseComponent(ImageDocument) { +export class ImageBox extends ViewBoxAnnotatableComponent(ImageDocument, "annotations") { protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject = React.createRef(); @@ -319,7 +319,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.active(true)) this._marqueeing = [e.clientX, e.clientY]; + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY]; } @action finishMarquee = () => { @@ -358,7 +358,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent {this.contentFunc} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index e03293332..881cbf2bb 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -72,7 +72,7 @@ export class KeyValuePair extends React.Component { dropAction: "alias", bringToFront: emptyFunction, renderDepth: 1, - active: returnFalse, + isContentActive: returnFalse, whenChildContentsActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index cef294692..3eaa6e0f4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -16,7 +16,7 @@ import { undoBatch } from '../../util/UndoManager'; import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { PDFViewer } from "../pdf/PDFViewer"; import { SidebarAnnos } from '../SidebarAnnos'; import { FieldView, FieldViewProps } from './FieldView'; @@ -28,7 +28,7 @@ type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, t const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @observer -export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument) { +export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument, "annotations") { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } private _searchString: string = ""; private _initialScrollTarget: Opt; @@ -171,9 +171,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent; const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; const curPage = this.Document._curPage || 1; - return !this.active() ? (null) : + return !this.isContentActive() ? (null) :
[KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true} - onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}> + onPointerDown={e => e.stopPropagation()} style={{ display: this.isContentActive() ? "flex" : "none" }}>
e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}> @@ -221,7 +221,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent
{this.props.Document.title} @@ -240,7 +240,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent {this.settingsPanel()}
; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 21ab0a2e0..57c88d411 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -713,8 +713,7 @@ export class PresBox extends ViewBoxBaseComponent whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive)); // For dragging documents into the presentation trail - addDocumentFilter = (doc: Doc | Doc[]) => { - const docs = doc instanceof Doc ? [doc] : doc; + addDocumentFilter = (docs: Doc[]) => { docs.forEach((doc, i) => { if (doc.presentationTargetDoc) return true; if (doc.type === DocumentType.LABEL) { diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 48fc0834f..b4e7c6243 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -19,7 +19,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./ScreenshotBox.scss"; import { VideoBox } from "./VideoBox"; @@ -33,7 +33,7 @@ type ScreenshotDocument = makeInterface<[typeof documentSchema]>; const ScreenshotDocument = makeInterface(documentSchema); @observer -export class ScreenshotBox extends ViewBoxAnnotatableComponent(ScreenshotDocument) { +export class ScreenshotBox extends ViewBoxAnnotatableComponent(ScreenshotDocument, "annotations") { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } private _videoRef = React.createRef(); private _audioRec: any; @@ -159,7 +159,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent(ScriptingDocument) { +export class ScriptingBox extends ViewBoxAnnotatableComponent(ScriptingDocument, "annotations") { private dropDisposer?: DragManager.DragDropDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 0b0f8afd1..f26a4fdbd 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -19,7 +19,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; import { StyleProp } from "../StyleProvider"; @@ -32,7 +32,7 @@ type VideoDocument = makeInterface<[typeof documentSchema]>; const VideoDocument = makeInterface(documentSchema); @observer -export class VideoBox extends ViewBoxAnnotatableComponent(VideoDocument) { +export class VideoBox extends ViewBoxAnnotatableComponent(VideoDocument, "annotations") { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } static _youtubeIframeCounter: number = 0; static Instance: VideoBox; @@ -63,7 +63,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent) { + constructor(props: Readonly) { super(props); VideoBox.Instance = this; } @@ -309,7 +309,7 @@ export class VideoBox extends ViewBoxAnnotatableComponentLoading
: -
+