aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx657
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx321
-rw-r--r--src/client/views/collections/CollectionView.tsx266
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx34
-rw-r--r--src/client/views/collections/collectionGrid/Grid.tsx17
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx291
6 files changed, 878 insertions, 708 deletions
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 37589974b..7d40cab8c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,37 +1,36 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { CursorProperty } from "csstype";
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
-import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
-import { Docs, DocUtils } from "../../documents/Documents";
-import { DragManager, dropActionType } from "../../util/DragManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { EditableView } from "../EditableView";
-import { LightboxView } from "../LightboxView";
-import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView";
-import { StyleProp } from "../StyleProvider";
-import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
-import "./CollectionStackingView.scss";
-import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
-import { CollectionSubView } from "./CollectionSubView";
-import { CollectionViewType } from "./CollectionView";
-import { FieldViewProps } from "../nodes/FieldView";
-import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
-const _global = (window /* browser */ || global /* node */) as any;
-
+import React = require('react');
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { CursorProperty } from 'csstype';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { listSpec } from '../../../fields/Schema';
+import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
+import { Docs, DocUtils } from '../../documents/Documents';
+import { DragManager, dropActionType } from '../../util/DragManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { Transform } from '../../util/Transform';
+import { undoBatch } from '../../util/UndoManager';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { EditableView } from '../EditableView';
+import { LightboxView } from '../LightboxView';
+import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
+import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView';
+import { StyleProp } from '../StyleProvider';
+import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
+import './CollectionStackingView.scss';
+import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
+import { CollectionSubView } from './CollectionSubView';
+import { CollectionViewType } from './CollectionView';
+import { FieldViewProps } from '../nodes/FieldView';
+import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+const _global = (window /* browser */ || global) /* node */ as any;
export type collectionStackingViewProps = {
chromeHidden?: boolean;
@@ -46,27 +45,50 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
_draggerRef = React.createRef<HTMLDivElement>();
_pivotFieldDisposer?: IReactionDisposer;
_autoHeightDisposer?: IReactionDisposer;
- _docXfs: { height: () => number, width: () => number, stackedDocTransform: () => Transform }[] = [];
+ _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
_columnStart: number = 0;
@observable _heightMap = new Map<string, number>();
- @observable _cursor: CursorProperty = "grab";
+ @observable _cursor: CursorProperty = 'grab';
@observable _scroll = 0; // used to force the document decoration to update when scrolling
- @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); }
- @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); }
- @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); }
- @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); }
- @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); }
- @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
- @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
- @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
- @computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking; }
- @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
- @computed get showAddAGroup() { return this.pivotField && !this.chromeHidden; }
+ @computed get chromeHidden() {
+ return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
+ }
+ @computed get columnHeaders() {
+ return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null);
+ }
+ @computed get pivotField() {
+ return StrCast(this.layoutDoc._pivotField);
+ }
+ @computed get filteredChildren() {
+ return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout);
+ }
+ @computed get headerMargin() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
+ }
+ @computed get xMargin() {
+ return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, 0.05 * this.props.PanelWidth()));
+ }
+ @computed get yMargin() {
+ return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5);
+ } // 2 * this.gridGap)); }
+ @computed get gridGap() {
+ return NumCast(this.layoutDoc._gridGap, 10);
+ }
+ @computed get isStackingView() {
+ return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking;
+ }
+ @computed get numGroupColumns() {
+ return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1;
+ }
+ @computed get showAddAGroup() {
+ return this.pivotField && !this.chromeHidden;
+ }
@computed get columnWidth() {
- return Math.min(this.props.PanelWidth() - 2 * this.xMargin,
- this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
+ return Math.min(this.props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
+ }
+ @computed get NodeWidth() {
+ return this.props.PanelWidth() - this.gridGap;
}
- @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
constructor(props: any) {
super(props);
@@ -84,21 +106,23 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const width = () => this.getDocWidth(d);
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
- return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} style={style} >
- {this.getDisplayDoc(d, width)}
- </div>;
+ return (
+ <div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
+ {this.getDisplayDoc(d, width)}
+ </div>
+ );
});
- }
+ };
@action
setDocHeight = (key: string, sectionHeight: number) => {
this._heightMap.set(key, sectionHeight);
- }
+ };
get Sections() {
if (!this.pivotField || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
if (this.columnHeaders === undefined) {
- setTimeout(() => this.layoutDoc._columnHeaders = new List<SchemaHeaderField>(), 0);
+ setTimeout(() => (this.layoutDoc._columnHeaders = new List<SchemaHeaderField>()), 0);
return new Map<SchemaHeaderField, Doc[]>();
}
const columnHeaders = Array.from(this.columnHeaders);
@@ -114,8 +138,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`));
if (existingHeader) {
fields.get(existingHeader)!.push(d);
- }
- else {
+ } else {
const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`);
fields.set(newSchemaHeader, [d]);
columnHeaders.push(newSchemaHeader);
@@ -124,13 +147,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
});
// remove all empty columns if hideHeadings is set
if (this.layoutDoc._columnsHideIfEmpty) {
- Array.from(fields.keys()).filter(key => !fields.get(key)!.length).map(header => {
- fields.delete(header);
- columnHeaders.splice(columnHeaders.indexOf(header), 1);
- changed = true;
- });
+ Array.from(fields.keys())
+ .filter(key => !fields.get(key)!.length)
+ .map(header => {
+ fields.delete(header);
+ columnHeaders.splice(columnHeaders.indexOf(header), 1);
+ changed = true;
+ });
}
- changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0);
+ changed &&
+ setTimeout(
+ action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)),
+ 0
+ );
return fields;
}
@@ -140,13 +169,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
() => this.pivotField,
- () => this.layoutDoc._columnHeaders = new List()
+ () => (this.layoutDoc._columnHeaders = new List())
+ );
+ this._autoHeightDisposer = reaction(
+ () => this.layoutDoc._autoHeight,
+ autoHeight =>
+ autoHeight &&
+ this.props.setHeight?.(
+ Math.min(
+ NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
+ this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0))
+ )
+ )
);
- this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight,
- autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
- this.headerMargin + (this.isStackingView ?
- Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) :
- this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)))));
}
componentWillUnmount() {
@@ -158,45 +193,50 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
@action
moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => {
return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
- }
+ };
createRef = (ele: HTMLDivElement | null) => {
this._masonryGridRef = ele;
this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
- }
+ };
- @computed get onChildClickHandler() { return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
- @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
+ @computed get onChildClickHandler() {
+ return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
+ }
+ @computed get onChildDoubleClickHandler() {
+ return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
+ }
addDocTab = (doc: Doc, where: string) => {
- if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+ if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
return true;
}
return this.props.addDocTab(doc, where);
- }
+ };
scrollToBottom = () => {
smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight);
- }
+ };
focusDocument = (doc: Doc, options?: DocFocusOptions) => {
Doc.BrushDoc(doc);
let focusSpeed = 0;
- const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]);
+ const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
if (Math.floor(localTop[1]) !== 0) {
- smoothScroll(focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ smoothScroll((focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
}
}
const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
this.props.focus(this.rootDoc, {
- willZoom: options?.willZoom, scale: options?.scale, afterFocus: (didFocus: boolean) =>
- new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed))
+ willZoom: options?.willZoom,
+ scale: options?.scale,
+ afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
});
- }
+ };
styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
if (property === StyleProp.Opacity && doc) {
@@ -208,85 +248,88 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
}
return this.props.styleProvider?.(doc, props, property);
- }
+ };
@undoBatch
@action
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
const docView = fieldProps.DocumentView?.();
- if (docView && ["Enter"].includes(e.key) && e.ctrlKey) {
+ if (docView && ['Enter'].includes(e.key) && e.ctrlKey) {
e.stopPropagation?.();
- const below = !e.altKey && e.key !== "Tab";
+ const below = !e.altKey && e.key !== 'Tab';
const layoutKey = StrCast(docView.LayoutFieldKey);
const newDoc = Doc.MakeCopy(docView.rootDoc, true);
const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) {
+ if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) {
newDoc[layoutKey] = docView.rootDoc[layoutKey];
}
Doc.GetProto(newDoc).text = undefined;
FormattedTextBox.SelectOnLoad = newDoc[Id];
return this.addDocument?.(newDoc);
}
- }
+ };
isContentActive = () => this.props.isSelected() || this.props.isContentActive();
- isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined;
+ isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined);
getDisplayDoc(doc: Doc, width: () => number) {
- const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
+ const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
const height = () => this.getDocHeight(doc);
let dref: Opt<DocumentView>;
const stackedDocTransform = () => this.getDocTransform(doc, dref);
this._docXfs.push({ stackedDocTransform, width, height });
- return <DocumentView ref={r => dref = r || undefined}
- Document={doc}
- DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
- renderDepth={this.props.renderDepth + 1}
- PanelWidth={width}
- PanelHeight={height}
- styleProvider={this.styleProvider}
- docViewPath={this.props.docViewPath}
- fitWidth={this.props.childFitWidth}
- isContentActive={this.isChildContentActive}
- onKey={this.onKeyDown}
- isDocumentActive={this.isContentActive}
- LayoutTemplate={this.props.childLayoutTemplate}
- LayoutTemplateString={this.props.childLayoutString}
- NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
- NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
- dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
- dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
- rootSelected={this.rootSelected}
- showTitle={this.props.childShowTitle}
- dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
- ScreenToLocalTransform={stackedDocTransform}
- focus={this.focusDocument}
- docFilters={this.childDocFilters}
- hideDecorationTitle={this.props.childHideDecorationTitle?.()}
- hideResizeHandles={this.props.childHideResizeHandles?.()}
- hideTitle={this.props.childHideTitle?.()}
- docRangeFilters={this.childDocRangeFilters}
- searchFilterDocs={this.searchFilterDocs}
- ContainingCollectionDoc={this.props.CollectionView?.props.Document}
- ContainingCollectionView={this.props.CollectionView}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- removeDocument={this.props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
- bringToFront={returnFalse}
- scriptContext={this.props.scriptContext}
- pinToPres={this.props.pinToPres}
- />;
+ return (
+ <DocumentView
+ ref={r => (dref = r || undefined)}
+ Document={doc}
+ DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
+ renderDepth={this.props.renderDepth + 1}
+ PanelWidth={width}
+ PanelHeight={height}
+ styleProvider={this.styleProvider}
+ docViewPath={this.props.docViewPath}
+ fitWidth={this.props.childFitWidth}
+ isContentActive={this.isChildContentActive}
+ onKey={this.onKeyDown}
+ isDocumentActive={this.isContentActive}
+ LayoutTemplate={this.props.childLayoutTemplate}
+ LayoutTemplateString={this.props.childLayoutString}
+ NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
+ dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined}
+ dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
+ rootSelected={this.rootSelected}
+ showTitle={this.props.childShowTitle}
+ dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ onClick={this.onChildClickHandler}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={stackedDocTransform}
+ focus={this.focusDocument}
+ docFilters={this.childDocFilters}
+ hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+ hideResizeHandles={this.props.childHideResizeHandles?.()}
+ hideTitle={this.props.childHideTitle?.()}
+ docRangeFilters={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+ addDocTab={this.addDocTab}
+ bringToFront={returnFalse}
+ scriptContext={this.props.scriptContext}
+ pinToPres={this.props.pinToPres}
+ />
+ );
}
getDocTransform(doc: Doc, dref?: DocumentView) {
const y = this._scroll; // required for document decorations to update when the text box container is scrolled
const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
- // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
- return new Transform(- translateX + (dref?.centeringX || 0), - translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
+ // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
+ return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
}
getDocWidth(d?: Doc) {
if (!d) return 0;
@@ -300,37 +343,42 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
getDocHeight(d?: Doc) {
if (!d || d.hidden) return 0;
const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
- const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
- const maxHeight = (lim => lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1));
+ const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS ? undefined : this.props.DataDoc;
+ const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0);
const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0);
if (nw && nh) {
const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
- return Math.min(
- maxHeight,
- docWid * nh / nw);
+ return Math.min(maxHeight, (docWid * nh) / nw);
}
const childHeight = NumCast(childLayoutDoc._height);
- const panelHeight = (childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
+ const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
return Math.min(childHeight, maxHeight, panelHeight);
}
columnDividerDown = (e: React.PointerEvent) => {
- runInAction(() => this._cursor = "grabbing");
- setupMoveUpEvents(this, e, this.onDividerMove, action(() => this._cursor = "grab"), emptyFunction);
- }
+ runInAction(() => (this._cursor = 'grabbing'));
+ setupMoveUpEvents(
+ this,
+ e,
+ this.onDividerMove,
+ action(() => (this._cursor = 'grab')),
+ emptyFunction
+ );
+ };
@action
onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
this.layoutDoc._columnWidth = Math.max(10, this.columnWidth + delta[0]);
return false;
- }
+ };
@computed get columnDragger() {
- return <div className="collectionStackingView-columnDragger" onPointerDown={this.columnDividerDown} ref={this._draggerRef}
- style={{ cursor: this._cursor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }} >
- <FontAwesomeIcon icon={"arrows-alt-h"} />
- </div>;
+ return (
+ <div className="collectionStackingView-columnDragger" onPointerDown={this.columnDividerDown} ref={this._draggerRef} style={{ cursor: this._cursor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }}>
+ <FontAwesomeIcon icon={'arrows-alt-h'} />
+ </div>
+ );
}
@undoBatch
@@ -341,7 +389,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
let dropAfter = 0;
if (de.complete.docDragData) {
this._docXfs.map((cd, i) => {
- const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
+ const pos = cd
+ .stackedDocTransform()
+ .inverse()
+ .transformPoint(-2 * this.gridGap, -2 * this.gridGap);
const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height());
if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) {
dropInd = i;
@@ -358,21 +409,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
DragManager.docsBeingDragged = [];
if (docs && newDocs.length) {
const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
- const offset = newDocs.reduce((off, ndoc) => this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0);
+ const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0);
newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1));
docs.splice(insertInd - offset, 0, ...newDocs);
}
}
- }
- else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
- const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, _fitWidth: true, title: "dropped annotation" });
+ } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
+ const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' });
this.props.addDocument?.(source);
- de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, 'doc annotation', ''); // TODODO this is where in text links get passed
e.stopPropagation();
- }
- else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+ } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
return false;
- }
+ };
@undoBatch
internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) {
@@ -390,7 +439,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const where = [e.clientX, e.clientY];
let targInd = -1;
this._docXfs.map((cd, i) => {
- const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
+ const pos = cd
+ .stackedDocTransform()
+ .inverse()
+ .transformPoint(-2 * this.gridGap, -2 * this.gridGap);
const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height());
if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
targInd = i;
@@ -406,98 +458,103 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
}
});
- }
+ };
headings = () => Array.from(this.Sections);
refList: any[] = [];
sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
const key = this.pivotField;
- let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
+ let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined;
if (this.pivotField) {
const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
type = types[0];
}
}
- return <CollectionStackingViewFieldColumn
- unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
- observeHeight={ref => {
- if (ref) {
- this.refList.push(ref);
- this.observer = new _global.ResizeObserver(action((entries: any) => {
- if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
- const height = this.headerMargin +
- Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
- Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
- if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
- this.props.setHeight?.(height);
- }
- }
- }));
- this.observer.observe(ref);
- }
- }}
- addDocument={this.addDocument}
- chromeHidden={this.chromeHidden}
- columnHeaders={this.columnHeaders}
- Document={this.props.Document}
- DataDoc={this.props.DataDoc}
- renderChildren={this.children}
- columnWidth={this.columnWidth}
- numGroupColumns={this.numGroupColumns}
- gridGap={this.gridGap}
- pivotField={this.pivotField}
- key={heading?.heading ?? ""}
- headings={this.headings}
- heading={heading?.heading ?? ""}
- headingObject={heading}
- docList={docList}
- yMargin={this.yMargin}
- type={type}
- createDropTarget={this.createDashEventsTarget}
- screenToLocalTransform={this.props.ScreenToLocalTransform}
- />;
- }
+ return (
+ <CollectionStackingViewFieldColumn
+ unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
+ observeHeight={ref => {
+ if (ref) {
+ this.refList.push(ref);
+ this.observer = new _global.ResizeObserver(
+ action((entries: any) => {
+ if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+ const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
+ if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
+ this.props.setHeight?.(height);
+ }
+ }
+ })
+ );
+ this.observer.observe(ref);
+ }
+ }}
+ addDocument={this.addDocument}
+ chromeHidden={this.chromeHidden}
+ columnHeaders={this.columnHeaders}
+ Document={this.props.Document}
+ DataDoc={this.props.DataDoc}
+ renderChildren={this.children}
+ columnWidth={this.columnWidth}
+ numGroupColumns={this.numGroupColumns}
+ gridGap={this.gridGap}
+ pivotField={this.pivotField}
+ key={heading?.heading ?? ''}
+ headings={this.headings}
+ heading={heading?.heading ?? ''}
+ headingObject={heading}
+ docList={docList}
+ yMargin={this.yMargin}
+ type={type}
+ createDropTarget={this.createDashEventsTarget}
+ screenToLocalTransform={this.props.ScreenToLocalTransform}
+ />
+ );
+ };
sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => {
const key = this.pivotField;
- let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
+ let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined;
const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]);
if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
type = types[0];
}
- const rows = () => !this.isStackingView ? 1 : Math.max(1, Math.min(docList.length,
- Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
- return <CollectionMasonryViewFieldRow
- showHandle={first}
- Document={this.props.Document}
- chromeHidden={this.chromeHidden}
- pivotField={this.pivotField}
- unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)}
- observeHeight={(ref) => {
- if (ref) {
- this.refList.push(ref);
- this.observer = new _global.ResizeObserver(action((entries: any) => {
- if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
- const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
- this.props.setHeight?.(this.headerMargin + height);
- }
- }));
- this.observer.observe(ref);
- }
- }}
- key={heading ? heading.heading : ""}
- rows={rows}
- headings={this.headings}
- heading={heading ? heading.heading : ""}
- headingObject={heading}
- docList={docList}
- parent={this}
- type={type}
- createDropTarget={this.createDashEventsTarget}
- screenToLocalTransform={this.props.ScreenToLocalTransform}
- setDocHeight={this.setDocHeight}
- />;
- }
+ const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
+ return (
+ <CollectionMasonryViewFieldRow
+ showHandle={first}
+ Document={this.props.Document}
+ chromeHidden={this.chromeHidden}
+ pivotField={this.pivotField}
+ unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
+ observeHeight={ref => {
+ if (ref) {
+ this.refList.push(ref);
+ this.observer = new _global.ResizeObserver(
+ action((entries: any) => {
+ if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+ const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0);
+ this.props.setHeight?.(this.headerMargin + height);
+ }
+ })
+ );
+ this.observer.observe(ref);
+ }
+ }}
+ key={heading ? heading.heading : ''}
+ rows={rows}
+ headings={this.headings}
+ heading={heading ? heading.heading : ''}
+ headingObject={heading}
+ docList={docList}
+ parent={this}
+ type={type}
+ createDropTarget={this.createDashEventsTarget}
+ screenToLocalTransform={this.props.ScreenToLocalTransform}
+ setDocHeight={this.setDocHeight}
+ />
+ );
+ };
@action
addGroup = (value: string) => {
@@ -507,25 +564,25 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return true;
}
return false;
- }
+ };
sortFunc = (a: [SchemaHeaderField, Doc[]], b: [SchemaHeaderField, Doc[]]): 1 | -1 => {
- const descending = StrCast(this.layoutDoc._columnsSort) === "descending";
+ const descending = StrCast(this.layoutDoc._columnsSort) === 'descending';
const firstEntry = descending ? b : a;
const secondEntry = descending ? a : b;
return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1;
- }
+ };
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
if (!e.isPropagationStopped()) {
const subItems: ContextMenuProps[] = [];
- subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" });
- subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
- subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" });
- ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
+ subItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' });
+ subItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' });
+ subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' });
+ ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' });
}
- }
+ };
@computed get renderedSections() {
TraceMobx();
@@ -534,7 +591,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const entries = Array.from(this.Sections.entries());
sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries;
}
- return sections.map((section, i) => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0));
+ return sections.map((section, i) => (this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0)));
}
@computed get buttonMenu() {
@@ -544,85 +601,90 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const width: number = NumCast(menuDoc._width, 30);
const height: number = NumCast(menuDoc._height, 30);
console.log(menuDoc.title, width, height);
- return (<div className="buttonMenu-docBtn"
- style={{ width: width, height: height }}>
- <DocumentView
- Document={menuDoc}
- DataDoc={menuDoc}
- isContentActive={this.props.isContentActive}
- isDocumentActive={returnTrue}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
- pinToPres={emptyFunction}
- rootSelected={this.props.isSelected}
- removeDocument={this.props.removeDocument}
- ScreenToLocalTransform={Transform.Identity}
- PanelWidth={() => 35}
- PanelHeight={() => 35}
- renderDepth={this.props.renderDepth}
- focus={emptyFunction}
- styleProvider={this.props.styleProvider}
- docViewPath={returnEmptyDoclist}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- />
- </div>
+ return (
+ <div className="buttonMenu-docBtn" style={{ width: width, height: height }}>
+ <DocumentView
+ Document={menuDoc}
+ DataDoc={menuDoc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={() => 35}
+ PanelHeight={() => 35}
+ renderDepth={this.props.renderDepth}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>
);
}
}
+ @computed get nativeWidth() {
+ return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc);
+ }
+ @computed get nativeHeight() {
+ return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc);
+ }
- @computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); }
- @computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); }
-
- @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
+ @computed get scaling() {
+ return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight;
+ }
- @computed get backgroundEvents() { return SnappingManager.GetIsDragging(); }
+ @computed get backgroundEvents() {
+ return SnappingManager.GetIsDragging();
+ }
observer: any;
render() {
TraceMobx();
const editableViewProps = {
- GetValue: () => "",
+ GetValue: () => '',
SetValue: this.addGroup,
- contents: "+ ADD A GROUP"
+ contents: '+ ADD A GROUP',
};
const buttonMenu = this.rootDoc.buttonMenu;
const noviceExplainer = this.rootDoc.explainer;
return (
<>
- {buttonMenu || noviceExplainer ? <div className="documentButtonMenu">
- {buttonMenu ? this.buttonMenu : null}
- {Doc.noviceMode && noviceExplainer ?
- <div className="documentExplanation">
- {noviceExplainer}
- </div>
- : null
- }
- </div> : null}
- <div className="collectionStackingMasonry-cont" >
- <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
+ {buttonMenu || noviceExplainer ? (
+ <div className="documentButtonMenu">
+ {buttonMenu ? this.buttonMenu : null}
+ {Doc.noviceMode && noviceExplainer ? <div className="documentExplanation">{StrCast(noviceExplainer)}</div> : null}
+ </div>
+ ) : null}
+ <div className="collectionStackingMasonry-cont">
+ <div
+ className={this.isStackingView ? 'collectionStackingView' : 'collectionMasonryView'}
ref={this.createRef}
style={{
- overflowY: this.props.isContentActive() ? "auto" : "hidden",
+ overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
- pointerEvents: this.backgroundEvents ? "all" : undefined
+ pointerEvents: this.backgroundEvents ? 'all' : undefined,
}}
- onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
+ onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
- onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} >
+ onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
{this.renderedSections}
- {!this.showAddAGroup ? (null) :
- <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
- style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
+ {!this.showAddAGroup ? null : (
+ <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
<EditableView {...editableViewProps} />
- </div>}
+ </div>
+ )}
{/* {this.chromeHidden || !this.props.isSelected() ? (null) :
<Switch
onChange={this.onToggle}
@@ -634,7 +696,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
</div>
</div>
</>
-
);
}
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ba72fb7b9..f5b9162d3 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,5 +1,5 @@
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
+import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
@@ -11,27 +11,27 @@ import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnF
import { DocUtils } from '../../documents/Documents';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DocumentManager } from '../../util/DocumentManager';
-import { DragManager, dropActionType } from "../../util/DragManager";
+import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { EditableView } from "../EditableView";
+import { EditableView } from '../EditableView';
import { DocumentView } from '../nodes/DocumentView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormView } from './collectionFreeForm';
-import { CollectionSubView } from "./CollectionSubView";
-import "./CollectionTreeView.scss";
-import { TreeView } from "./TreeView";
-import React = require("react");
-import { FieldViewProps } from "../nodes/FieldView";
-const _global = (window /* browser */ || global /* node */) as any;
+import { CollectionSubView } from './CollectionSubView';
+import './CollectionTreeView.scss';
+import { TreeView } from './TreeView';
+import React = require('react');
+import { FieldViewProps } from '../nodes/FieldView';
+const _global = (window /* browser */ || global) /* node */ as any;
export type collectionTreeViewProps = {
- treeViewExpandedView?: "fields" | "layout" | "links" | "data";
+ treeViewExpandedView?: 'fields' | 'layout' | 'links' | 'data';
treeViewOpen?: boolean;
treeViewHideTitle?: boolean;
treeViewHideHeaderFields?: boolean;
@@ -45,9 +45,9 @@ export type collectionTreeViewProps = {
};
export enum TreeViewType {
- outline = "outline",
- fileSystem = "fileSystem",
- default = "default"
+ outline = 'outline',
+ fileSystem = 'fileSystem',
+ default = 'default',
}
@observer
@@ -61,13 +61,28 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
private observer: any; // observer for monitoring tree view items.
private static expandViewLabelSize = 20;
- @computed get doc() { return this.props.Document; }
- @computed get dataDoc() { return this.props.DataDoc || this.doc; }
- @computed get treeViewtruncateTitleWidth() { return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); }
- @computed get treeChildren() { TraceMobx(); return this.props.childDocuments || this.childDocs; }
- @computed get outlineMode() { return this.doc.treeViewType === TreeViewType.outline; }
- @computed get fileSysMode() { return this.doc.treeViewType === TreeViewType.fileSystem; }
- @computed get dashboardMode() { return this.doc === CurrentUserUtils.MyDashboards; }
+ @computed get doc() {
+ return this.props.Document;
+ }
+ @computed get dataDoc() {
+ return this.props.DataDoc || this.doc;
+ }
+ @computed get treeViewtruncateTitleWidth() {
+ return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth());
+ }
+ @computed get treeChildren() {
+ TraceMobx();
+ return this.props.childDocuments || this.childDocs;
+ }
+ @computed get outlineMode() {
+ return this.doc.treeViewType === TreeViewType.outline;
+ }
+ @computed get fileSysMode() {
+ return this.doc.treeViewType === TreeViewType.fileSystem;
+ }
+ @computed get dashboardMode() {
+ return this.doc === CurrentUserUtils.MyDashboards;
+ }
@observable _explainerHeight = 0; // height of the description of the tree view
@@ -75,11 +90,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
// these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
@observable _isAnyChildContentActive = false;
- whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
- isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.ActiveTool !== InkTool.None ||
- (this.props.isContentActive?.() || this.props.Document.forceActive ||
- this.props.isSelected(outsideReaction) || this._isAnyChildContentActive ||
- this.props.rootSelected(outsideReaction)) ? true : false)
+ whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
+ isContentActive = (outsideReaction?: boolean) =>
+ CurrentUserUtils.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction)
+ ? true
+ : false;
componentWillUnmount() {
this._isDisposing = true;
@@ -89,47 +104,51 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
}
componentDidMount() {
- this._disposers.autoheight = reaction(() => this.rootDoc.autoHeight,
+ this._disposers.autoheight = reaction(
+ () => this.rootDoc.autoHeight,
auto => auto && this.computeHeight(),
- { fireImmediately: true });
+ { fireImmediately: true }
+ );
}
computeHeight = () => {
if (!this._isDisposing) {
- const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace("px", ""));
- const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), this.marginBot());
+ const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', ''));
+ const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot());
this.layoutDoc._autoHeightMargins = bodyHeight;
this.props.setHeight?.(bodyHeight + titleHeight);
}
- }
+ };
unobserveHeight = (ref: any) => {
this.refList.delete(ref);
this.rootDoc.autoHeight && this.computeHeight();
- }
+ };
observeHeight = (ref: any) => {
if (ref) {
this.refList.add(ref);
- this.observer = new _global.ResizeObserver(action((entries: any) => {
- if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) {
- this.computeHeight();
- }
- }));
+ this.observer = new _global.ResizeObserver(
+ action((entries: any) => {
+ if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) {
+ this.computeHeight();
+ }
+ })
+ );
this.rootDoc.autoHeight && this.computeHeight();
this.observer.observe(ref);
}
- }
+ };
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- if (this._mainEle = ele) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
- }
+ if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
+ };
protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
const dragData = de.complete.docDragData;
if (dragData) {
const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d));
- dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction;
+ dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction;
}
- }
+ };
@action
remove = (doc: Doc | Doc[]): boolean => {
@@ -149,7 +168,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
return true;
}
return false;
- }
+ };
@action
addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
@@ -161,81 +180,85 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
}, true);
if (this.doc.resolvedDataDoc instanceof Promise) return false;
return relativeTo === undefined ? this.props.addDocument?.(docs) || false : doAddDoc(docs);
- }
+ };
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
if (!Doc.noviceMode) {
const layoutItems: ContextMenuProps[] = [];
- layoutItems.push({ description: "Make tree state " + (this.doc.treeViewOpenIsTransient ? "persistent" : "transient"), event: () => this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient, icon: "paint-brush" });
- layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields, icon: "paint-brush" });
- layoutItems.push({ description: (this.doc.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle, icon: "paint-brush" });
- ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
- const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
- const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
- onClicks.push({ description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" });
- !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
+ layoutItems.push({ description: 'Make tree state ' + (this.doc.treeViewOpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient), icon: 'paint-brush' });
+ layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields), icon: 'paint-brush' });
+ layoutItems.push({ description: (this.doc.treeViewHideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle), icon: 'paint-brush' });
+ ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
+ const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...');
+ const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
+ onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' });
+ !existingOnClick && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
}
- }
+ };
onTreeDrop = (e: React.DragEvent, addDocs?: (docs: Doc[]) => void) => this.onExternalDrop(e, {}, addDocs);
@undoBatch
makeTextCollection = (childDocs: Doc[]) => {
this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true);
- }
+ };
get editableTitle() {
- return <EditableView
- contents={this.dataDoc.title}
- display={"block"}
- maxHeight={72}
- height={"auto"}
- GetValue={() => StrCast(this.dataDoc.title)}
- SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => {
- if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren);
- this.dataDoc.title = value;
- return true;
- })} />;
+ return (
+ <EditableView
+ contents={this.dataDoc.title}
+ display={'block'}
+ maxHeight={72}
+ height={'auto'}
+ GetValue={() => StrCast(this.dataDoc.title)}
+ SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => {
+ if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren);
+ this.dataDoc.title = value;
+ return true;
+ })}
+ />
+ );
}
-
onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- if (this.outlineMode && e.key === "Enter") {
+ if (this.outlineMode && e.key === 'Enter') {
e.stopPropagation();
this.makeTextCollection(this.treeChildren);
return true;
}
- }
+ };
get documentTitle() {
- return <FormattedTextBox
- {...this.props}
- fieldKey={"text"}
- renderDepth={this.props.renderDepth + 1}
- isContentActive={this.isContentActive}
- isDocumentActive={this.isContentActive}
- rootSelected={returnTrue}
- forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not autoHeight
- PanelWidth={this.documentTitleWidth}
- PanelHeight={this.documentTitleHeight}
- scaling={returnOne}
- onKey={this.onKey}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionDoc={this.doc}
- ContainingCollectionView={this.props.CollectionView}
- addDocument={returnFalse}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- bringToFront={returnFalse}
- />;
+ return (
+ <FormattedTextBox
+ {...this.props}
+ fieldKey={'text'}
+ renderDepth={this.props.renderDepth + 1}
+ isContentActive={this.isContentActive}
+ isDocumentActive={this.isContentActive}
+ rootSelected={returnTrue}
+ forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not autoHeight
+ PanelWidth={this.documentTitleWidth}
+ PanelHeight={this.documentTitleHeight}
+ scaling={returnOne}
+ onKey={this.onKey}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionDoc={this.doc}
+ ContainingCollectionView={this.props.CollectionView}
+ addDocument={returnFalse}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ bringToFront={returnFalse}
+ />
+ );
}
childContextMenuItems = () => {
const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
const icons = StrListCast(this.doc.childContextMenuIcons);
return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
- }
+ };
@computed get treeViewElements() {
TraceMobx();
const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
@@ -266,36 +289,34 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
this.props.treeViewSkipFields,
true,
this.whenChildContentsActiveChanged,
- this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null),
+ this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, 'boolean', null),
this.observeHeight,
this.unobserveHeight,
this.childContextMenuItems(),
//TODO: [AL] add these
this.props.AddToMap,
this.props.RemFromMap,
- this.props.hierarchyIndex,
+ this.props.hierarchyIndex
);
}
@computed get titleBar() {
- return this.dataDoc === null ? (null) :
- <div className="collectionTreeView-titleBar" key={this.doc[Id]}
- style={!this.outlineMode ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}}
- ref={r => this._titleRef = r}>
+ return this.dataDoc === null ? null : (
+ <div className="collectionTreeView-titleBar" key={this.doc[Id]} style={!this.outlineMode ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}} ref={r => (this._titleRef = r)}>
{this.outlineMode ? this.documentTitle : this.editableTitle}
- </div>;
+ </div>
+ );
}
@computed get noviceExplainer() {
- return !Doc.noviceMode || !this.rootDoc.explainer ? (null) :
- <div className="documentExplanation"> {this.rootDoc.explainer} </div>;
+ return !Doc.noviceMode || !this.rootDoc.explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.explainer)} </div>;
}
return35 = () => 35;
@computed get buttonMenu() {
const menuDoc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
// To create a multibutton menu add a CollectionLinearView
- return !menuDoc ? null :
- (<div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
+ return !menuDoc ? null : (
+ <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
<DocumentView
Document={menuDoc}
DataDoc={menuDoc}
@@ -322,11 +343,16 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
/>
- </div>);
+ </div>
+ );
}
- @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); }
- @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); }
+ @computed get nativeWidth() {
+ return Doc.NativeWidth(this.Document, undefined, true);
+ }
+ @computed get nativeHeight() {
+ return Doc.NativeHeight(this.Document, undefined, true);
+ }
@computed get contentScaling() {
const nw = this.nativeWidth;
@@ -347,68 +373,73 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
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;
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.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false;
contentFunc = () => {
const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
- const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined;
- const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? (null) : this.titleBar;
+ const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined);
+ const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar;
return [
- <div className="collectionTreeView-contents" key="tree" style={{
- ...(!titleBar ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
- overflow: "auto",
- height: "100%"//this.layoutDoc._autoHeight ? "max-content" : "100%"
- }} >
+ <div
+ className="collectionTreeView-contents"
+ key="tree"
+ style={{
+ ...(!titleBar ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
+ overflow: 'auto',
+ height: '100%', //this.layoutDoc._autoHeight ? "max-content" : "100%"
+ }}>
{titleBar}
- <div className="collectionTreeView-container"
+ <div
+ className="collectionTreeView-container"
style={{
- transform: this.outlineMode ? `scale(${this.contentScaling})` : "",
+ transform: this.outlineMode ? `scale(${this.contentScaling})` : '',
paddingLeft: `${this.marginX()}px`,
- width: this.outlineMode ? `calc(${100 / this.contentScaling}%)` : ""
+ width: this.outlineMode ? `calc(${100 / this.contentScaling}%)` : '',
}}
onContextMenu={this.onContextMenu}>
- {!this.buttonMenu && !this.noviceExplainer ? (null) :
+ {!this.buttonMenu && !this.noviceExplainer ? null : (
<div className="documentButtonMenu" ref={action((r: HTMLDivElement) => r && (this._explainerHeight = r.getBoundingClientRect().height))}>
{this.buttonMenu}
{this.noviceExplainer}
</div>
- }
- <div className="collectionTreeView-dropTarget"
+ )}
+ <div
+ className="collectionTreeView-dropTarget"
style={{
background: background(),
height: `calc(100% - ${this._explainerHeight}px)`,
- pointerEvents: pointerEvents()
+ pointerEvents: pointerEvents(),
}}
onWheel={e => e.stopPropagation()}
onDrop={this.onTreeDrop}
ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}>
- <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} >
- {this.treeViewElements}
- </ul>
- </div >
+ <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul>
+ </div>
</div>
- </div>
+ </div>,
];
- }
+ };
render() {
TraceMobx();
- return !(this.doc instanceof Doc) || !this.treeChildren ? (null) :
- this.doc.treeViewHasOverlay ?
- <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
- isAnnotationOverlay={true}
- isAnnotationOverlayScrollable={true}
- childDocumentsActive={this.props.isDocumentActive}
- fieldKey={this.props.fieldKey + "-annotations"}
- dropAction={"move"}
- select={emptyFunction}
- addDocument={this.addAnnotationDocument}
- removeDocument={this.remAnnotationDocument}
- moveDocument={this.moveAnnotationDocument}
- bringToFront={emptyFunction}
- renderDepth={this.props.renderDepth + 1} >
- {this.contentFunc}
- </CollectionFreeFormView> :
- this.contentFunc();
+ return !(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? (
+ <CollectionFreeFormView
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+ isAnnotationOverlay={true}
+ isAnnotationOverlayScrollable={true}
+ childDocumentsActive={this.props.isDocumentActive}
+ fieldKey={this.props.fieldKey + '-annotations'}
+ dropAction={'move'}
+ select={emptyFunction}
+ addDocument={this.addAnnotationDocument}
+ removeDocument={this.remAnnotationDocument}
+ moveDocument={this.moveAnnotationDocument}
+ bringToFront={emptyFunction}
+ renderDepth={this.props.renderDepth + 1}>
+ {this.contentFunc}
+ </CollectionFreeFormView>
+ ) : (
+ this.contentFunc()
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2ae0c01ef..d788f9a77 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,5 +1,5 @@
import { computed, observable, runInAction } from 'mobx';
-import { observer } from "mobx-react";
+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 { Doc, DocListCast } from '../../../fields/Doc';
@@ -14,66 +14,65 @@ import { BranchCreate, BranchTask } from '../../documents/Gitlike';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { InteractionUtils } from '../../util/InteractionUtils';
-import { ContextMenu } from "../ContextMenu";
+import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
-import { CollectionDockingView } from "./CollectionDockingView";
+import { CollectionDockingView } from './CollectionDockingView';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import { CollectionGridView } from './collectionGrid/CollectionGridView';
import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionPileView } from './CollectionPileView';
-import { CollectionSchemaView } from "./collectionSchema/CollectionSchemaView";
+import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
import { CollectionStackingView } from './CollectionStackingView';
import { SubCollectionViewProps } from './CollectionSubView';
import { CollectionTimeView } from './CollectionTimeView';
-import { CollectionTreeView } from "./CollectionTreeView";
+import { CollectionTreeView } from './CollectionTreeView';
import './CollectionView.scss';
export const COLLECTION_BORDER_WIDTH = 2;
const path = require('path');
export enum CollectionViewType {
- Invalid = "invalid",
- Freeform = "freeform",
- Schema = "schema",
- Docking = "docking",
+ Invalid = 'invalid',
+ Freeform = 'freeform',
+ Schema = 'schema',
+ Docking = 'docking',
Tree = 'tree',
- Stacking = "stacking",
- Masonry = "masonry",
- Multicolumn = "multicolumn",
- Multirow = "multirow",
- Time = "time",
- Carousel = "carousel",
- Carousel3D = "3D Carousel",
- Linear = "linear",
+ Stacking = 'stacking',
+ Masonry = 'masonry',
+ Multicolumn = 'multicolumn',
+ Multirow = 'multirow',
+ Time = 'time',
+ Carousel = 'carousel',
+ Carousel3D = '3D Carousel',
+ Linear = 'linear',
//Staff = "staff",
- Map = "map",
- Grid = "grid",
- Pile = "pileup",
- StackedTimeline = "stacked timeline"
+ Map = 'map',
+ Grid = 'grid',
+ Pile = 'pileup',
+ StackedTimeline = 'stacked timeline',
}
-export interface CollectionViewProps extends FieldViewProps {
- isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
+interface CollectionViewProps_ extends FieldViewProps {
+ isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently)
layoutEngine?: () => string;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
// property overrides for child documents
- children?: never | (() => JSX.Element[]) | React.ReactNode;
childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
- childDocumentsActive?: () => boolean;// whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
+ childDocumentsActive?: () => boolean; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
childFitWidth?: (child: Doc) => boolean;
childShowTitle?: () => string;
childOpacity?: () => number;
- childContextMenuItems?: () => { script: ScriptField, label: string }[];
+ childContextMenuItems?: () => { script: ScriptField; label: string }[];
childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children
childHideDecorationTitle?: () => boolean;
childHideResizeHandles?: () => boolean;
- childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection
+ childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection
childLayoutString?: string;
childIgnoreNativeSize?: boolean;
childClickScript?: ScriptField;
@@ -81,20 +80,25 @@ export interface CollectionViewProps extends FieldViewProps {
//TODO: [AL] add these fields
AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
- hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views)
+ hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views)
}
+export interface CollectionViewProps extends React.PropsWithChildren<CollectionViewProps_> {}
@observer
export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() {
- public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
+ public static LayoutString(fieldStr: string) {
+ return FieldView.LayoutString(CollectionView, fieldStr);
+ }
@observable private static _safeMode = false;
- public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
+ public static SetSafeMode(safeMode: boolean) {
+ this._safeMode = safeMode;
+ }
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
constructor(props: any) {
super(props);
- runInAction(() => this._annotationKeySuffix = returnEmptyString);
+ runInAction(() => (this._annotationKeySuffix = returnEmptyString));
}
get collectionViewType(): CollectionViewType | undefined {
@@ -102,15 +106,17 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
if (CollectionView._safeMode) {
switch (viewField) {
case CollectionViewType.Freeform:
- case CollectionViewType.Schema: return CollectionViewType.Tree;
- case CollectionViewType.Invalid: return CollectionViewType.Freeform;
+ case CollectionViewType.Schema:
+ return CollectionViewType.Tree;
+ case CollectionViewType.Invalid:
+ return CollectionViewType.Freeform;
}
}
return viewField as any as CollectionViewType;
}
showIsTagged = () => {
- return (null);
+ 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.
@@ -119,136 +125,171 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
// const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
// return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
//this.isContentActive();
- }
+ };
- screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
+ screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()));
private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => {
TraceMobx();
if (type === undefined) return null;
switch (type) {
default:
- case CollectionViewType.Freeform: return <CollectionFreeFormView key="collview" {...props} />;
- case CollectionViewType.Schema: return <CollectionSchemaView key="collview" {...props} />;
- case CollectionViewType.Docking: return <CollectionDockingView key="collview" {...props} />;
- case CollectionViewType.Tree: return <CollectionTreeView key="collview" {...props} />;
- case CollectionViewType.Multicolumn: return <CollectionMulticolumnView key="collview" {...props} />;
- case CollectionViewType.Multirow: return <CollectionMultirowView key="collview" {...props} />;
- case CollectionViewType.Linear: return <CollectionLinearView key="collview" {...props} />;
- case CollectionViewType.Pile: return <CollectionPileView key="collview" {...props} />;
- case CollectionViewType.Carousel: return <CollectionCarouselView key="collview" {...props} />;
- case CollectionViewType.Carousel3D: return <CollectionCarousel3DView key="collview" {...props} />;
- case CollectionViewType.Stacking: return <CollectionStackingView key="collview" {...props} />;
- case CollectionViewType.Masonry: return <CollectionStackingView key="collview" {...props} />;
- case CollectionViewType.Time: return <CollectionTimeView key="collview" {...props} />;
- case CollectionViewType.Grid: return <CollectionGridView key="collview" {...props} />;
+ case CollectionViewType.Freeform:
+ return <CollectionFreeFormView key="collview" {...props} />;
+ case CollectionViewType.Schema:
+ return <CollectionSchemaView key="collview" {...props} />;
+ case CollectionViewType.Docking:
+ return <CollectionDockingView key="collview" {...props} />;
+ case CollectionViewType.Tree:
+ return <CollectionTreeView key="collview" {...props} />;
+ case CollectionViewType.Multicolumn:
+ return <CollectionMulticolumnView key="collview" {...props} />;
+ case CollectionViewType.Multirow:
+ return <CollectionMultirowView key="collview" {...props} />;
+ case CollectionViewType.Linear:
+ return <CollectionLinearView key="collview" {...props} />;
+ case CollectionViewType.Pile:
+ return <CollectionPileView key="collview" {...props} />;
+ case CollectionViewType.Carousel:
+ return <CollectionCarouselView key="collview" {...props} />;
+ case CollectionViewType.Carousel3D:
+ return <CollectionCarousel3DView key="collview" {...props} />;
+ case CollectionViewType.Stacking:
+ return <CollectionStackingView key="collview" {...props} />;
+ case CollectionViewType.Masonry:
+ return <CollectionStackingView key="collview" {...props} />;
+ case CollectionViewType.Time:
+ return <CollectionTimeView key="collview" {...props} />;
+ case CollectionViewType.Grid:
+ return <CollectionGridView key="collview" {...props} />;
//case CollectionViewType.Staff: return <CollectionStaffView key="collview" {...props} />;
}
- }
+ };
setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) {
const subItems: ContextMenuProps[] = [];
- subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" });
+ 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" });
+ 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: "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" });
+ 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: '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' });
if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !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" });
- !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: catItems, icon: "eye" });
+ const catItems = existingVm && 'subitems' in existingVm ? existingVm.subitems : [];
+ catItems.push({ description: 'Add a Perspective...', addDivider: true, noexpand: true, subitems: subItems, icon: 'eye' });
+ !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: catItems, icon: 'eye' });
}
}
onContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
if (e.nativeEvent.cancelBubble) return; // nested calls to React to render can cause the same event to trigger in the outer view even if the inner view has handled it. This avoid CollectionDockingView menu options from being added when the event has been handled by a sub-document.
- 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.rootDoc);
- newRendition._viewType = vtype;
- this.props.addDocTab(newRendition, "add:right");
- return newRendition;
- }, false);
+ 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.rootDoc);
+ newRendition._viewType = vtype;
+ this.props.addDocTab(newRendition, 'add:right');
+ return newRendition;
+ },
+ false
+ );
- const options = cm.findByDescription("Options...");
- const optionItems = options && "subitems" in options ? options.subitems : [];
- !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null;
+ const options = cm.findByDescription('Options...');
+ const optionItems = options && 'subitems' in options ? options.subitems : [];
+ !Doc.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" });
+ optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout 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" });
+ optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, 'add:right'), icon: 'project-diagram' });
}
- !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" });
+ !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' });
if (!Doc.noviceMode) {
optionItems.push({
- description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "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.rootDoc, "pull"), icon: "project-diagram"
+ description: 'Pull Master',
+ event: () => BranchTask(this.rootDoc, 'pull'),
+ icon: 'project-diagram',
});
optionItems.push({
- description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram"
+ description: 'Merge Branches',
+ event: () => BranchTask(this.rootDoc, 'merge'),
+ icon: 'project-diagram',
});
}
if (this.Document._viewType === CollectionViewType.Docking) {
- optionItems.push({ description: "Create Dashboard", event: () => CurrentUserUtils.createNewDashboard(), icon: "project-diagram" });
+ optionItems.push({ description: 'Create Dashboard', event: () => CurrentUserUtils.createNewDashboard(), icon: 'project-diagram' });
}
- !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" });
+ !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
if (!Doc.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.rootDoc);
- DocUtils.makeCustomViewClicked(alias, undefined, func.key);
- this.props.addDocTab(alias, "add:right");
- }
- }));
- DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick =>
+ 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.rootDoc);
+ DocUtils.makeCustomViewClicked(alias, undefined, func.key);
+ this.props.addDocTab(alias, 'add:right');
+ },
+ })
+ );
+ DocListCast(Cast(Doc.UserDoc()['clickFuncs-child'], Doc, null).data).forEach(childClick =>
onClicks.push({
description: `Set child ${childClick.title}`,
- icon: "edit",
- event: () => Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
- }));
- !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
+ icon: 'edit',
+ event: () => (Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))),
+ })
+ );
+ !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
}
if (!Doc.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.rootDoc) });
- !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
+ 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.rootDoc) });
+ !more && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'hand-point-right' });
}
}
- }
+ };
bodyPanelWidth = () => this.props.PanelWidth();
childHideResizeHandles = () => 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); }
+ @computed get childLayoutString() {
+ return StrCast(this.rootDoc.childLayoutString);
+ }
isContentActive = (outsideReaction?: boolean) => {
return this.props.isContentActive();
- }
+ };
render() {
TraceMobx();
const props: SubCollectionViewProps = {
@@ -268,10 +309,11 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
childHideDecorationTitle: this.childHideDecorationTitle,
CollectionView: this,
};
- return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
- style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? "none" : undefined }}>
- {this.showIsTagged()}
- {this.renderSubView(this.collectionViewType, props)}
- </div>);
+ return (
+ <div className={'collectionView'} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+ {this.showIsTagged()}
+ {this.renderSubView(this.collectionViewType, props)}
+ </div>
+ );
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index dacbb3508..8720c9097 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,25 +1,23 @@
-import { computed } from "mobx";
-import { observer } from "mobx-react";
-import { Id } from "../../../../fields/FieldSymbols";
-import { DocumentManager } from "../../../util/DocumentManager";
-import "./CollectionFreeFormLinksView.scss";
-import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
-import React = require("react");
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
+import { Id } from '../../../../fields/FieldSymbols';
+import { DocumentManager } from '../../../util/DocumentManager';
+import './CollectionFreeFormLinksView.scss';
+import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView';
+import React = require('react');
@observer
-export class CollectionFreeFormLinksView extends React.Component {
+export class CollectionFreeFormLinksView extends React.Component<React.PropsWithChildren<{}>> {
@computed get uniqueConnections() {
- return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c =>
- <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />
- );
+ return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />);
}
render() {
- return <div className="collectionfreeformlinksview-container">
- <svg className="collectionfreeformlinksview-svgCanvas">
- {this.uniqueConnections}
- </svg>
- {this.props.children}
- </div>;
+ return (
+ <div className="collectionfreeformlinksview-container">
+ <svg className="collectionfreeformlinksview-svgCanvas">{this.uniqueConnections}</svg>
+ {this.props.children}
+ </div>
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx
index 3d2ed0cf9..3d1d87aa0 100644
--- a/src/client/views/collections/collectionGrid/Grid.tsx
+++ b/src/client/views/collections/collectionGrid/Grid.tsx
@@ -1,14 +1,13 @@
import * as React from 'react';
-import { observer } from "mobx-react";
+import { observer } from 'mobx-react';
-import "../../../../../node_modules/react-grid-layout/css/styles.css";
-import "../../../../../node_modules/react-resizable/css/styles.css";
+import '../../../../../node_modules/react-grid-layout/css/styles.css';
+import '../../../../../node_modules/react-resizable/css/styles.css';
import * as GridLayout from 'react-grid-layout';
import { Layout } from 'react-grid-layout';
export { Layout } from 'react-grid-layout';
-
interface GridProps {
width: number;
nodeList: JSX.Element[] | null;
@@ -29,9 +28,10 @@ interface GridProps {
@observer
export default class Grid extends React.Component<GridProps> {
render() {
- const compactType = this.props.compactType === "vertical" || this.props.compactType === "horizontal" ? this.props.compactType : null;
+ const compactType = this.props.compactType === 'vertical' || this.props.compactType === 'horizontal' ? this.props.compactType : null;
return (
- <GridLayout className="layout"
+ <GridLayout
+ className="layout"
layout={this.props.layout}
cols={this.props.numCols}
rowHeight={this.props.rowHeight}
@@ -43,9 +43,8 @@ export default class Grid extends React.Component<GridProps> {
useCSSTransforms={true}
onLayoutChange={this.props.setLayout}
preventCollision={this.props.preventCollision}
- transformScale={1 / this.props.transformScale} // still doesn't work :(
- margin={[this.props.margin, this.props.margin]}
- >
+ transformScale={1 / this.props.transformScale} // still doesn't work :( ??
+ margin={[this.props.margin, this.props.margin]}>
{this.props.nodeList}
</GridLayout>
);
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c31267e87..8adfdc70b 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -9,7 +9,7 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types
import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
import { DocUtils } from '../../../documents/Documents';
import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
-import { DocumentManager } from "../../../util/DocumentManager";
+import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
import { Colors, Shadows } from '../../global/globalEnums';
@@ -21,13 +21,12 @@ import { StyleProp } from '../../StyleProvider';
import { CollectionStackedTimeline } from '../CollectionStackedTimeline';
import { CollectionSubView } from '../CollectionSubView';
import { CollectionViewType } from '../CollectionView';
-import "./CollectionLinearView.scss";
-
+import './CollectionLinearView.scss';
/**
- * CollectionLinearView is the class for rendering the horizontal collection
+ * CollectionLinearView is the class for rendering the horizontal collection
* of documents, it useful for horizontal menus. It can either be expandable
- * or not using the linearViewExpandable field.
+ * or not using the linearViewExpandable field.
* It is used in the following locations:
* - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx)
* - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx)
@@ -48,45 +47,47 @@ export class CollectionLinearView extends CollectionSubView() {
}
componentDidMount() {
- this._widthDisposer = reaction(() => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * (this.rootDoc[HeightSym]()) : 10),
+ this._widthDisposer = reaction(
+ () => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * this.rootDoc[HeightSym]() : 10),
width => this.childDocs.length && (this.layoutDoc._width = width),
{ fireImmediately: true }
);
this._selectedDisposer = reaction(
() => NumCast(this.layoutDoc.selectedIndex),
- (i) => runInAction(() => {
- this._selectedIndex = i;
- let selected: any = undefined;
- this.childLayoutPairs.map(async (pair, ind) => {
- const isSelected = this._selectedIndex === ind;
- if (isSelected) {
- selected = pair;
- }
- else {
- ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
+ i =>
+ runInAction(() => {
+ this._selectedIndex = i;
+ let selected: any = undefined;
+ this.childLayoutPairs.map(async (pair, ind) => {
+ const isSelected = this._selectedIndex === ind;
+ if (isSelected) {
+ selected = pair;
+ } else {
+ ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
+ }
+ });
+ if (selected && selected.layout) {
+ ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
}
- });
- if (selected && selected.layout) {
- ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
- }
- }),
+ }),
{ fireImmediately: true }
);
}
- protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view
+ protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
+ //used for stacking and masonry view
this._dropDisposer && this._dropDisposer();
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
- }
+ };
dimension = () => NumCast(this.rootDoc._height); // 2 * the padding
getTransform = (ele: Opt<HTMLDivElement>) => {
if (!ele) return Transform.Identity();
const { scale, translateX, translateY } = Utils.GetScreenTransform(ele);
return new Transform(-translateX, -translateY, 1);
- }
+ };
@action
exitLongLinks = () => {
@@ -99,28 +100,27 @@ export class CollectionLinearView extends CollectionSubView() {
}
DocumentLinksButton.StartLink = undefined;
DocumentLinksButton.StartLinkView = undefined;
- }
+ };
@action
changeDescriptionSetting = () => {
if (LinkDescriptionPopup.showDescriptions) {
- if (LinkDescriptionPopup.showDescriptions === "ON") {
- LinkDescriptionPopup.showDescriptions = "OFF";
+ if (LinkDescriptionPopup.showDescriptions === 'ON') {
+ LinkDescriptionPopup.showDescriptions = 'OFF';
LinkDescriptionPopup.descriptionPopup = false;
} else {
- LinkDescriptionPopup.showDescriptions = "ON";
+ LinkDescriptionPopup.showDescriptions = 'ON';
}
} else {
- LinkDescriptionPopup.showDescriptions = "OFF";
+ LinkDescriptionPopup.showDescriptions = 'OFF';
LinkDescriptionPopup.descriptionPopup = false;
}
- }
+ };
myContextMenu = (e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
- }
-
+ };
getDisplayDoc = (doc: Doc, preview: boolean = false) => {
const nested = doc._viewType === CollectionViewType.Linear;
@@ -129,44 +129,50 @@ export class CollectionLinearView extends CollectionSubView() {
let dref: Opt<HTMLDivElement>;
const docXf = () => this.getTransform(dref);
// const scalable = pair.layout.onClick || pair.layout.onDragStart;
- return hidden ? (null) : <div className={preview ? "preview" : `collectionLinearView-docBtn`} key={doc[Id]} ref={r => dref = r || undefined}
- style={{
- pointerEvents: "all",
- width: nested ? undefined : NumCast(doc._width),
- height: nested ? undefined : NumCast(doc._height),
- marginLeft: !nested ? 2.5 : 0,
- marginRight: !nested ? 2.5 : 0,
- // width: NumCast(pair.layout._width),
- // height: NumCast(pair.layout._height),
- }} >
- <DocumentView
- Document={doc}
- isContentActive={this.props.isContentActive}
- isDocumentActive={returnTrue}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
- pinToPres={emptyFunction}
- rootSelected={this.props.isSelected}
- removeDocument={this.props.removeDocument}
- ScreenToLocalTransform={docXf}
- PanelWidth={nested ? doc[WidthSym] : this.dimension}
- PanelHeight={nested || doc._height ? doc[HeightSym] : this.dimension}
- renderDepth={this.props.renderDepth + 1}
- dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)}
- focus={emptyFunction}
- styleProvider={this.props.styleProvider}
- docViewPath={returnEmptyDoclist}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- hideResizeHandles={true} />
- </div>;
- }
+ return hidden ? null : (
+ <div
+ className={preview ? 'preview' : `collectionLinearView-docBtn`}
+ key={doc[Id]}
+ ref={r => (dref = r || undefined)}
+ style={{
+ pointerEvents: 'all',
+ width: nested ? undefined : NumCast(doc._width),
+ height: nested ? undefined : NumCast(doc._height),
+ marginLeft: !nested ? 2.5 : 0,
+ marginRight: !nested ? 2.5 : 0,
+ // width: NumCast(pair.layout._width),
+ // height: NumCast(pair.layout._height),
+ }}>
+ <DocumentView
+ Document={doc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={docXf}
+ PanelWidth={nested ? doc[WidthSym] : this.dimension}
+ PanelHeight={nested || doc._height ? doc[HeightSym] : this.dimension}
+ renderDepth={this.props.renderDepth + 1}
+ dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ hideResizeHandles={true}
+ />
+ </div>
+ );
+ };
render() {
const guid = Utils.GenerateGuid(); // Generate a unique ID to use as the label
@@ -178,66 +184,99 @@ export class CollectionLinearView extends CollectionSubView() {
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const icon: string = StrCast(this.props.Document.icon); // Menu opener toggle
- const menuOpener = <label htmlFor={`${guid}`}
- style={{
- boxShadow: floating ? Shadows.STANDARD_SHADOW : undefined,
- color: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.BLACK,
- backgroundColor: backgroundColor === color ? "black" : BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.LIGHT_GRAY
- }}
- onPointerDown={e => e.stopPropagation()} >
- <div className="collectionLinearView-menuOpener">
- {BoolCast(this.layoutDoc.linearViewIsExpanded) ? icon ? icon : <FontAwesomeIcon icon={"minus"} /> : icon ? icon : <FontAwesomeIcon icon={"plus"} />}
- </div>
- </label>;
-
- return <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : "transparent" }}>
- <div className="collectionLinearView" ref={this.createDashEventsTarget}
- onContextMenu={this.myContextMenu} >
- {!expandable ? (null) : <Tooltip title={<><div className="dash-tooltip">{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close" : "Open"}</div></>} placement="top">
- {menuOpener}
- </Tooltip>}
- <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
- onChange={action(() => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
-
- <div className="collectionLinearView-content"
- style={{
- height: this.dimension(),
- flexDirection: flexDir,
- gap: flexGap
- }}>
- {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
- </div>
- {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null :
- <span className="bottomPopup-background" style={{ pointerEvents: "all" }}
- onPointerDown={e => e.stopPropagation()} >
- <span className="bottomPopup-text" >
- Creating link from: <b>{DocumentLinksButton.AnnotationId ? "Annotation in " : " "} {StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...'}</b>
- </span>
+ const menuOpener = (
+ <label
+ htmlFor={`${guid}`}
+ style={{
+ boxShadow: floating ? Shadows.STANDARD_SHADOW : undefined,
+ color: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.BLACK,
+ backgroundColor: backgroundColor === color ? 'black' : BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.LIGHT_GRAY,
+ }}
+ onPointerDown={e => e.stopPropagation()}>
+ <div className="collectionLinearView-menuOpener">{BoolCast(this.layoutDoc.linearViewIsExpanded) ? icon ? icon : <FontAwesomeIcon icon={'minus'} /> : icon ? icon : <FontAwesomeIcon icon={'plus'} />}</div>
+ </label>
+ );
- <Tooltip title={<><div className="dash-tooltip">{"Toggle description pop-up"} </div></>} placement="top">
- <span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
- Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"}
- </span>
+ return (
+ <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : 'transparent' }}>
+ <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu}>
+ {!expandable ? null : (
+ <Tooltip
+ title={
+ <>
+ <div className="dash-tooltip">{BoolCast(this.props.Document.linearViewIsExpanded) ? 'Close' : 'Open'}</div>
+ </>
+ }
+ placement="top">
+ {menuOpener}
</Tooltip>
+ )}
+ <input
+ id={`${guid}`}
+ type="checkbox"
+ checked={BoolCast(this.props.Document.linearViewIsExpanded)}
+ ref={this.addMenuToggle}
+ onChange={action(() => (this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked))}
+ />
- <Tooltip title={<><div className="dash-tooltip">Exit linking mode</div></>} placement="top">
- <span className="bottomPopup-exit" onClick={this.exitLongLinks}>
- Stop
+ <div
+ className="collectionLinearView-content"
+ style={{
+ height: this.dimension(),
+ flexDirection: flexDir,
+ gap: flexGap,
+ }}>
+ {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+ </div>
+ {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : (
+ <span className="bottomPopup-background" style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()}>
+ <span className="bottomPopup-text">
+ Creating link from:{' '}
+ <b>
+ {(DocumentLinksButton.AnnotationId ? 'Annotation in ' : ' ') +
+ (StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...')}
+ </b>
</span>
- </Tooltip>
- </span>}
- {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? (null) :
- <span className="bottomPopup-background">
- <span className="bottomPopup-text">
- Currently playing:
- {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) =>
- <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}>
- {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")}
- </span>)}
- </span>
- </span>}
+ <Tooltip
+ title={
+ <>
+ <div className="dash-tooltip">{'Toggle description pop-up'} </div>
+ </>
+ }
+ placement="top">
+ <span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
+ Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'}
+ </span>
+ </Tooltip>
+
+ <Tooltip
+ title={
+ <>
+ <div className="dash-tooltip">Exit linking mode</div>
+ </>
+ }
+ placement="top">
+ <span className="bottomPopup-exit" onClick={this.exitLongLinks}>
+ Stop
+ </span>
+ </Tooltip>
+ </span>
+ )}
+ {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : (
+ <span className="bottomPopup-background">
+ <span className="bottomPopup-text">
+ Currently playing:
+ {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => (
+ <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}>
+ {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '' : ',')}
+ </span>
+ ))}
+ </span>
+ </span>
+ )}
+ </div>
</div>
- </div>;
+ );
}
-} \ No newline at end of file
+}