aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2021-04-04 13:38:55 -0400
committerusodhi <61431818+usodhi@users.noreply.github.com>2021-04-04 13:38:55 -0400
commit15c1c952c50bb2de972c614e46c5f33c2b2952cc (patch)
treee8d7330336b80939e82749290c22ef5a05b01224 /src/client/views/collections
parent479dff344ff2cf92ace9c68c3ce6d03e6e6dce22 (diff)
parentee17752109ba1238d645a4df7cee1cf60855f8df (diff)
merging
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx3
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx1
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx8
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx29
-rw-r--r--src/client/views/collections/CollectionMapView.tsx2
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx3
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx19
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx16
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx12
-rw-r--r--src/client/views/collections/CollectionSubView.tsx14
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx198
-rw-r--r--src/client/views/collections/CollectionView.tsx200
-rw-r--r--src/client/views/collections/SchemaTable.tsx17
-rw-r--r--src/client/views/collections/TabDocView.tsx11
-rw-r--r--src/client/views/collections/TreeView.scss7
-rw-r--r--src/client/views/collections/TreeView.tsx341
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx34
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx15
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx5
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx4
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx4
23 files changed, 395 insertions, 552 deletions
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index f0b9b5240..b2ae441d6 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -54,7 +54,6 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
PanelHeight={this.panelHeight}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
bringToFront={returnFalse}
- parentActive={this.props.active}
/>;
};
@@ -127,7 +126,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
}
@computed get buttons() {
- if (!this.props.active()) return null;
+ if (!this.props.isContentActive()) return null;
return <div className="arrow-buttons" >
<div key="back" className="carousel3DView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
onClick={(e) => this.onArrowClick(e, -1)}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index f400ac5a2..cc90b9134 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -58,7 +58,6 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
PanelHeight={this.panelHeight}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
bringToFront={returnFalse}
- parentActive={this.props.active}
/>
</div>
<div className="collectionCarouselView-caption" key="caption"
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 7e89cf55d..388f9a909 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -353,7 +353,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
if (clone) {
const cloned = (await Doc.MakeClone(doc));
Array.from(cloned.map.entries()).map(entry => json = json.replace(entry[0], entry[1][Id]));
- Doc.SetInPlace(cloned.clone, "dockingConfig", json, true);
+ Doc.GetProto(cloned.clone).dockingConfig = json;
return cloned.clone;
}
const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
@@ -363,7 +363,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
const origtabdocs = DocListCast(origtab.data);
const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true) : Doc.MakeAlias(origtab);
const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc));
- newtabdocs.length && Doc.SetInPlace(newtab, "data", new List<Doc>(newtabdocs), true);
+ newtabdocs.length && (Doc.GetProto(newtab).data = new List<Doc>(newtabdocs));
json = json.replace(origtab[Id], newtab[Id]);
return newtab;
});
@@ -437,9 +437,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
}
render() {
- return <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} ref={this._containerRef}>
- {this.props.renderDepth > 0 ? "Nested dashboards can't be rendered" : (null)}
- </div>;
+ return <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} ref={this._containerRef} />;
}
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index ead0ce6c4..e0b90304b 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -7,12 +7,13 @@ import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { makeInterface } from '../../../fields/Schema';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnTrue, Utils, emptyPath, returnEmptyDoclist } from '../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, Utils } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
import { Transform } from '../../util/Transform';
import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
import { DocumentView } from '../nodes/DocumentView';
import { LinkDescriptionPopup } from '../nodes/LinkDescriptionPopup';
+import { StyleProp } from '../StyleProvider';
import "./CollectionLinearView.scss";
import { CollectionSubView } from './CollectionSubView';
import { CollectionViewType } from './CollectionView';
@@ -37,14 +38,13 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
}
componentDidMount() {
- // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported).
- this._widthDisposer = reaction(() => 5 + (this.props.Document.linearViewIsExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10),
- width => this.childDocs.length && (this.props.Document._width = width),
+ 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.props.Document.selectedIndex),
+ () => NumCast(this.layoutDoc.selectedIndex),
(i) => runInAction(() => {
this._selectedIndex = i;
let selected: any = undefined;
@@ -71,7 +71,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
}
}
- dimension = () => NumCast(this.props.Document._height); // 2 * the padding
+ dimension = () => NumCast(this.rootDoc._height); // 2 * the padding
getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
if (!ele.current) return Transform.Identity();
const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current);
@@ -109,21 +109,21 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
render() {
const guid = Utils.GenerateGuid();
const flexDir: any = StrCast(this.Document.flexDirection);
- const backgroundColor = StrCast(this.props.Document.backgroundColor, "black");
- const color = StrCast(this.props.Document.color, "white");
+ const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+ const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const menuOpener = <label htmlFor={`${guid}`} style={{ pointerEvents: "all", cursor: "pointer", background: backgroundColor === color ? "black" : backgroundColor, }}
onPointerDown={e => e.stopPropagation()} >
- <p>{BoolCast(this.props.Document.linearViewIsExpanded) ? "–" : "+"}</p>
+ <p>{BoolCast(this.layoutDoc.linearViewIsExpanded) ? "–" : "+"}</p>
</label>;
return <div className="collectionLinearView-outer">
<div className="collectionLinearView" ref={this.createDashEventsTarget} >
- <Tooltip title={<><div className="dash-tooltip">{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close menu" : "Open menu"}</div></>} placement="top">
+ <Tooltip title={<><div className="dash-tooltip">{BoolCast(this.layoutDoc.linearViewIsExpanded) ? "Close menu" : "Open menu"}</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)} />
+ <input id={`${guid}`} type="checkbox" checked={BoolCast(this.layoutDoc.linearViewIsExpanded)} ref={this.addMenuToggle}
+ onChange={action(() => this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
<div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
{this.childLayoutPairs.map((pair, ind) => {
@@ -140,6 +140,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
<DocumentView
Document={pair.layout}
DataDoc={pair.data}
+ isContentActive={returnFalse}
+ isDocumentActive={returnTrue}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
@@ -154,8 +156,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
styleProvider={this.props.styleProvider}
layerProvider={this.props.layerProvider}
docViewPath={returnEmptyDoclist}
- parentActive={returnTrue}
- whenActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
bringToFront={emptyFunction}
docFilters={this.props.docFilters}
docRangeFilters={this.props.docRangeFilters}
diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 92288c1f2..2d7569d45 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -208,7 +208,7 @@ export class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMap
render() {
const { childLayoutPairs } = this;
- const { Document, fieldKey, active, google } = this.props;
+ const { Document, fieldKey, isContentActive: active, google } = this.props;
const mapLoc = this.getLocation(this.rootDoc, `${fieldKey}-mapCenter`, false);
let center = mapLoc;
if (center === undefined) {
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index ba701b2a4..a94e706eb 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -281,7 +281,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this.props.parent.columnWidth}px`, ""),
}}>
{this.props.parent.children(this.props.docList)}
- {this.props.showHandle && this.props.parent.props.active() ? this.props.parent.columnDragger : (null)}
+ {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : (null)}
</div>
</div>;
}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index aaf243567..623e05b33 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -341,8 +341,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
}
@computed get viewModes() {
- const excludedViewTypes = Doc.UserDoc().noviceMode ? [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Stacking, CollectionViewType.Map, CollectionViewType.Linear] :
- [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear];
+ const excludedViewTypes = [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear];
const isPres: boolean = (this.document && this.document.type === DocumentType.PRES);
return isPres ? (null) : (<div className="collectionViewBaseChrome-viewModes" >
<Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a265045b8..b33c437a9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -328,7 +328,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action
onWheel(e: React.WheelEvent) {
const scale = this.props.ScreenToLocalTransform().Scale;
- this.props.active(true) && e.stopPropagation();
+ this.props.isContentActive(true) && e.stopPropagation();
}
@computed get renderMenuContent() {
@@ -410,6 +410,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
rootSelected={this.rootSelected}
PanelWidth={this.previewWidth}
PanelHeight={this.previewHeight}
+ isContentActive={returnTrue}
+ isDocumentActive={returnFalse}
ScreenToLocalTransform={this.getPreviewTransform}
docFilters={this.docFilters}
docRangeFilters={this.docRangeFilters}
@@ -422,8 +424,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
moveDocument={this.props.moveDocument}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}
@@ -445,7 +446,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
renderDepth={this.props.renderDepth}
moveDocument={this.props.moveDocument}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- active={this.props.active}
+ active={this.props.isContentActive}
onDrop={this.onExternalDrop}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
@@ -534,11 +535,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
this.columns = columns;
}
- onZoomMenu = (e: React.WheelEvent) => this.props.active(true) && e.stopPropagation();
+ onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
render() {
TraceMobx();
- if (!this.props.active()) setTimeout(() => this.closeHeader(), 0);
+ if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
const menuContent = this.renderMenuContent;
const menu = <div className="collectionSchema-header-menu"
onWheel={e => this.onZoomMenu(e)}
@@ -554,21 +555,21 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
return <div className={"collectionSchemaView" + (this.props.Document._searchDoc ? "-searchContainer" : "-container")}
style={{
overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
- pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
+ pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined,
width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
onContextMenu={this.onSpecificMenu}
onPointerDown={this.onPointerDown}
- onWheel={e => this.props.active(true) && e.stopPropagation()}
+ onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
onDrop={e => this.onExternalDrop(e, {})}
ref={this.createTarget}>
{this.schemaTable}
</div>
{this.dividerDragger}
{!this.previewWidth() ? (null) : this.previewPanel}
- {this._headerOpen && this.props.active() ? menu : null}
+ {this._headerOpen && this.props.isContentActive() ? menu : null}
</div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index c0cebf021..6a1242f20 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -32,10 +32,10 @@ export type CollectionStackedTimelineProps = {
playFrom: (seekTimeInSeconds: number, endTime?: number) => void;
playing: () => boolean;
setTime: (time: number) => void;
- isChildActive: () => boolean;
startTag: string;
endTag: string;
mediaPath: string;
+ dictationKey: string;
};
@observer
@@ -114,7 +114,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
onPointerDownTimeline = (e: React.PointerEvent): void => {
const rect = this._timeline?.getBoundingClientRect();
const clientX = e.clientX;
- if (rect && this.props.active()) {
+ if (rect && this.props.isContentActive()) {
const wasPlaying = this.props.playing();
if (wasPlaying) this.props.Pause();
const wasSelecting = CollectionStackedTimeline.SelectingRegion === this;
@@ -145,7 +145,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
e.shiftKey && CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime);
!wasPlaying && doubleTap && this.props.Play();
},
- this.props.isSelected(true) || this.props.isChildActive(), undefined,
+ this.props.isSelected(true) || this.props.isContentActive(), undefined,
() => !wasPlaying && this.props.setTime((clientX - rect.x) / rect.width * this.duration));
}
}
@@ -238,18 +238,19 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
timelineContentHeight = () => this.props.PanelHeight() * 2 / 3;
dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight());
@computed get renderDictation() {
- const dictation = Cast(this.dataDoc[this.props.fieldKey.replace("annotations", "dictation")], Doc, null);
+ const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
return !dictation ? (null) : <div style={{ position: "absolute", height: this.dictationHeight(), top: this.timelineContentHeight(), background: "tan" }}>
<DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
Document={dictation}
PanelHeight={this.dictationHeight}
isAnnotationOverlay={true}
+ isDocumentActive={returnFalse}
select={emptyFunction}
scaling={returnOne}
xMargin={25}
yMargin={10}
ScreenToLocalTransform={this.dictationScreenToLocalTransform}
- whenActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
removeDocument={returnFalse}
moveDocument={returnFalse}
addDocument={returnFalse}
@@ -274,7 +275,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
const overlaps: { anchorStartTime: number, anchorEndTime: number, level: number }[] = [];
const drawAnchors = this.childDocs.map(anchor => ({ level: this.getLevel(anchor, overlaps), anchor }));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
- const isActive = this.props.isChildActive() || this.props.isSelected(false);
+ const isActive = this.props.isContentActive() || this.props.isSelected(false);
return <div className="collectionStackedTimeline" ref={(timeline: HTMLDivElement | null) => this._timeline = timeline}
onClick={e => isActive && StopEvent(e)} onPointerDown={e => isActive && this.onPointerDownTimeline(e)}>
{drawAnchors.map(d => {
@@ -323,7 +324,6 @@ interface StackedTimelineAnchorProps {
toTimeline: (screen_delta: number, width: number) => number;
playLink: (linkDoc: Doc) => void;
setTime: (time: number) => void;
- isChildActive: () => boolean;
startTag: string;
endTag: string;
renderDepth: number;
@@ -395,11 +395,11 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={undefined}
LayoutTemplateString={LabelBox.LayoutString("data")}
+ isDocumentActive={returnFalse}
PanelWidth={() => width}
PanelHeight={() => height}
ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-x, -y)}
focus={focusFunc}
- parentActive={out => this.props.isSelected(out) || this.props.isChildActive()}
rootSelected={returnFalse}
onClick={script}
onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 23c63561c..cc5a41c72 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -196,7 +196,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
});
}
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
if (property === StyleProp.Opacity && doc) {
if (this.props.childOpacity) {
return this.props.childOpacity();
@@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
}
return this.props.styleProvider?.(doc, props, property);
}
+ isContentActive = () => this.props.isSelected() || this.props.isContentActive();
getDisplayDoc(doc: Doc, width: () => number) {
const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
const height = () => this.getDocHeight(doc);
@@ -224,6 +225,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
layerProvider={this.props.layerProvider}
docViewPath={this.props.docViewPath}
fitWidth={this.props.childFitWidth}
+ isContentActive={returnFalse}
+ isDocumentActive={this.isContentActive}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
freezeDimensions={this.props.childFreezeDimensions}
@@ -248,8 +251,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.addDocTab}
bringToFront={returnFalse}
scriptContext={this.props.scriptContext}
@@ -534,14 +536,14 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
<div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
ref={this.createRef}
style={{
- overflowY: this.props.active() ? "auto" : "hidden",
+ overflowY: this.props.isContentActive() ? "auto" : "hidden",
background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
pointerEvents: this.backgroundEvents ? "all" : undefined
}}
onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
- onWheel={e => this.props.active(true) && e.stopPropagation()} >
+ onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} >
{this.renderedSections}
{!this.showAddAGroup ? (null) :
<div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 28f4f76be..79fab8b62 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -442,25 +442,23 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
});
}
}
- this.slowLoadDocuments(files, options, generatedDocuments, text, completed, e.clientX, e.clientY, addDocument);
- batch.end();
+ this.slowLoadDocuments(files, options, generatedDocuments, text, completed, e.clientX, e.clientY, addDocument).then(batch.end);
}
slowLoadDocuments = async (files: File[], options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: (() => void) | undefined, clientX: number, clientY: number, addDocument: (doc: Doc | Doc[]) => boolean) => {
- runInAction(() => CollectionSubViewLoader.Waiting = "block");
const disposer = OverlayView.Instance.addElement(
<ReactLoading type={"spinningBubbles"} color={"green"} height={250} width={250} />, { x: clientX - 125, y: clientY - 125 });
generatedDocuments.push(...await DocUtils.uploadFilesToDocs(files, options));
if (generatedDocuments.length) {
const set = generatedDocuments.length > 1 && generatedDocuments.map(d => DocUtils.iconify(d));
if (set) {
- UndoManager.RunInBatch(() => addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!), "drop");
+ addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!);
} else {
- UndoManager.RunInBatch(() => generatedDocuments.forEach(addDocument), "drop");
+ generatedDocuments.forEach(addDocument);
}
completed?.();
} else {
if (text && !text.includes("https://")) {
- UndoManager.RunInBatch(() => addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop");
+ addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 }));
} else {
alert("Document upload failed - possibly an unsupported file type.");
}
@@ -472,10 +470,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
return CollectionSubView;
}
-export class CollectionSubViewLoader {
- @observable public static Waiting = "none";
-}
-
import { DragManager, dropActionType } from "../../util/DragManager";
import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 0702febae..f41043179 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -136,7 +136,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
}
@computed get contents() {
- return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.active() ? undefined : "none" }}
+ return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : "none" }}
onClick={this.contentsDown}>
<CollectionFreeFormView {...this.props}
engineProps={{ pivotField: this.pivotField, docFilters: this.docFilters, docRangeFilters: this.docRangeFilters }}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f5eb534aa..37600fa4d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -27,6 +27,8 @@ import { TreeView } from "./TreeView";
import React = require("react");
export type collectionTreeViewProps = {
+ treeViewExpandedView?: "fields" | "layout" | "links" | "data";
+ treeViewOpen?: boolean;
treeViewHideTitle?: boolean;
treeViewHideHeaderFields?: boolean;
treeViewSkipFields?: string[]; // prevents specific fields from being displayed (see LinkBox)
@@ -38,12 +40,19 @@ export type collectionTreeViewProps = {
export class
CollectionTreeView extends CollectionSubView<Document, Partial<collectionTreeViewProps>>(Document) {
private treedropDisposer?: DragManager.DragDropDisposer;
- private _isChildActive = false;
private _mainEle?: HTMLDivElement;
- public _uniqueId = Utils.GenerateGuid();
-
- @computed get doc() { TraceMobx(); return this.props.Document; }
+ MainEle = () => this._mainEle;
+ @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() { return this.props.childDocuments || this.childDocs; }
+ @computed get outlineMode() { return this.doc.treeViewType === "outline"; }
+ @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
+
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.treedropDisposer?.();
+ }
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this.treedropDisposer?.();
@@ -53,19 +62,13 @@ export class
protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
const dragData = de.complete.docDragData;
if (dragData) {
- if (targetAction && !dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d))) {
- dragData.dropAction = targetAction;
- } else dragData.dropAction = this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction;
+ const isInTree = () => dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d));
+ dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction;
}
}
- componentWillUnmount() {
- super.componentWillUnmount();
- this.treedropDisposer?.();
- }
-
- @undoBatch
- remove = action((doc: Doc | Doc[]): boolean => {
+ @action
+ remove = (doc: Doc | Doc[]): boolean => {
const docs = doc instanceof Doc ? [doc] : doc;
const targetDataDoc = this.doc[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
@@ -83,27 +86,24 @@ export class
return true;
}
return false;
- });
+ }
+
@action
- addDoc = (doc: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
+ addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
const doAddDoc = (doc: Doc | Doc[]) =>
- (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) =>
- flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false), true);
- if (this.doc.resolvedDataDoc instanceof Promise) {
- this.doc.resolvedDataDoc.then((resolved: any) => doAddDoc(doc));
- } else if (relativeTo === undefined) {
- this.props.addDocument?.(doc);
- } else {
- doAddDoc(doc);
- (doc instanceof Doc ? [doc] : doc).forEach(d => d.context = this.props.Document);
- }
- return true;
+ (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
+ const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before);
+ res && (doc.context = this.props.Document);
+ return res;
+ }, 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.UserDoc().noviceMode) {
const layoutItems: ContextMenuProps[] = [];
- layoutItems.push({ description: (this.doc.treeViewPreventOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.doc.treeViewPreventOpen = !this.doc.treeViewPreventOpen, icon: "paint-brush" });
+ 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" });
@@ -113,50 +113,30 @@ export class
!existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
}
}
- outerXf = () => Utils.GetScreenTransform(this._mainEle!);
onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {});
- @computed get renderClearButton() {
- return !this.doc.allowClear ? (null) : <div key="toolbar">
- <button className="toolbar-button round-button" title="Empty" onClick={undoBatch(action(() => Doc.GetProto(this.doc)[this.props.fieldKey] = undefined))}>
- <FontAwesomeIcon icon={"trash"} size="sm" />
- </button>
- </div >;
- }
-
@undoBatch
- makeTextCollection = action((childDocs: Doc[]) => {
- Doc.SetInPlace(this.doc, "editTitle", undefined, false);
- const bullet = TreeView.makeTextBullet();
- bullet.context = this.doc;
- this.addDoc(bullet, childDocs.length ? childDocs[0] : undefined, true);
- });
+ makeTextCollection = (childDocs: Doc[]) => {
+ this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true);
+ }
editableTitle = (childDocs: Doc[]) => {
- return !this.dataDoc ? (null) : <EditableView
- contents={this.dataDoc.title}
- editing={false}
- display={"block"}
- maxHeight={72}
- height={"auto"}
- GetValue={() => StrCast(this.dataDoc.title)}
- SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => {
- if (enter) {
- switch (this.props.Document.treeViewType) {
- case "outline": this.makeTextCollection(childDocs); break;
- case "fileSystem": break;
- }
- }
- return Doc.SetInPlace(this.dataDoc, "title", value, false);
- })} />;
+ return !this.dataDoc ? (null) :
+ <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 === "outline") this.makeTextCollection(childDocs);
+ this.dataDoc.title = value;
+ return true;
+ })} />;
}
-
- rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.props.PanelWidth() - 20);
- rtfOutlineHeight = () => Math.min(this.layoutDoc?.[HeightSym](), (StrCast(this.layoutDoc?._fontSize) ? Number(StrCast(this.layoutDoc?._fontSize, "32px").replace("px", "")) : NumCast(this.layoutDoc?._fontSize)) * 2);
- titleTransform = () => this.props.ScreenToLocalTransform().translate(-NumCast(this.doc._xPadding, 10), -NumCast(this.doc._yPadding, 20));
documentTitle = (childDocs: Doc[]) => {
- return <div style={{ display: "inline-block", width: "100%", height: this.rtfOutlineHeight() }} key={this.doc[Id]}
+ return <div style={{ display: "inline-block", width: "100%", height: this.documentTitleHeight() }} key={this.doc[Id]}
onKeyDown={e => {
e.stopPropagation();
e.key === "Enter" && this.makeTextCollection(childDocs);
@@ -166,15 +146,15 @@ export class
DataDoc={undefined}
LayoutTemplateString={FormattedTextBox.LayoutString("text")}
renderDepth={this.props.renderDepth + 1}
+ isContentActive={this.isContentActive}
rootSelected={returnTrue}
- //dontRegisterView={true}
docViewPath={this.props.docViewPath}
styleProvider={this.props.styleProvider}
layerProvider={this.props.layerProvider}
- PanelWidth={this.rtfWidth}
- PanelHeight={this.rtfOutlineHeight}
- NativeWidth={this.rtfWidth}
- NativeHeight={this.rtfOutlineHeight}
+ PanelWidth={this.documentTitleWidth}
+ PanelHeight={this.documentTitleHeight}
+ NativeWidth={this.documentTitleWidth}
+ NativeHeight={this.documentTitleHeight}
focus={this.props.focus}
ScreenToLocalTransform={this.titleTransform}
docFilters={returnEmptyFilter}
@@ -185,54 +165,77 @@ export class
addDocument={this.props.addDocument}
moveDocument={returnFalse}
removeDocument={returnFalse}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}
/>
</div>;
}
- @computed get treeViewtruncateTitleWidth() { return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); }
- truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
- @computed get outlineMode() { return this.doc.treeViewType === "outline"; }
- @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
- onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
- whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
- active = (outsideReaction: boolean | undefined) => this.props.active(outsideReaction) || this._isChildActive;
- panelWidth = () => this.props.PanelWidth() - 20; // bcz: 20 is the 10 + 10 for the left and right padding.
- @computed get treeChildren() {
- TraceMobx();
- return this.props.childDocuments || this.childDocs;
- }
@computed get treeViewElements() {
TraceMobx();
const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false;
- return TreeView.GetChildElements(this.treeChildren, this, this.doc, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
- moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, returnTrue, this.props.ScreenToLocalTransform,
- this.outerXf, this.active, this.panelWidth, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields),
- BoolCast(this.doc.treeViewPreventOpen), [], this.props.onCheckedClick,
- this.onChildClick, this.props.treeViewSkipFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null), this);
+ return TreeView.GetChildElements(
+ this.treeChildren,
+ this,
+ this,
+ this.doc,
+ this.props.DataDoc,
+ this.props.ContainingCollectionDoc,
+ undefined,
+ addDoc,
+ this.remove,
+ moveDoc,
+ dropAction,
+ this.props.addDocTab,
+ this.props.styleProvider,
+ this.props.ScreenToLocalTransform,
+ this.props.isContentActive,
+ this.panelWidth,
+ this.props.renderDepth,
+ () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields),
+ [],
+ this.props.onCheckedClick,
+ this.onChildClick,
+ this.props.treeViewSkipFields,
+ true,
+ this.props.whenChildContentsActiveChanged,
+ this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null));
}
@computed get titleBar() {
const hideTitle = this.props.treeViewHideTitle || this.doc.treeViewHideTitle;
return hideTitle ? (null) : (this.doc.treeViewType === "outline" ? this.documentTitle : this.editableTitle)(this.treeChildren);
}
+
+ @computed get renderClearButton() {
+ return !this.doc.treeViewShowClearButton ? (null) : <div key="toolbar">
+ <button className="toolbar-button round-button" title="Empty" onClick={undoBatch(action(() => Doc.GetProto(this.doc)[this.props.fieldKey] = undefined))}>
+ <FontAwesomeIcon icon={"trash"} size="sm" />
+ </button>
+ </div >;
+ }
+
+ paddingX = () => NumCast(this.doc._xPadding, 15);
+ documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth());
+ documentTitleHeight = () => Math.min(this.layoutDoc?.[HeightSym](), (StrCast(this.layoutDoc?._fontSize) ? Number(StrCast(this.layoutDoc?._fontSize, "32px").replace("px", "")) : NumCast(this.layoutDoc?._fontSize)) * 2);
+ titleTransform = () => this.props.ScreenToLocalTransform().translate(-NumCast(this.doc._xPadding, 10), -NumCast(this.doc._yPadding, 20));
+ truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
+ onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
+ panelWidth = () => this.props.PanelWidth() - 2 * this.paddingX();
+ isContentActive = () => this.props.isContentActive() || this.props.isSelected();
render() {
TraceMobx();
- if (!(this.doc instanceof Doc)) return (null);
- const background = this.props.treeViewHideTitle && this.props.treeViewHideHeaderFields ? "#9F9F9F" : this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
- const paddingX = `${NumCast(this.doc._xPadding, 15)}px`;
- const paddingTop = `${NumCast(this.doc._yPadding, 20)}px`;
- const pointerEvents = !this.props.active() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
+ const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
+ const paddingTop = () => `${NumCast(this.doc._yPadding, 20)}px`;
+ const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined;
- return !this.treeChildren ? (null) : (
+ return !(this.doc instanceof Doc) || !this.treeChildren ? (null) :
<div className="collectionTreeView-container" onContextMenu={this.onContextMenu}>
<div className="collectionTreeView-dropTarget"
- style={{ background, paddingLeft: paddingX, paddingRight: paddingX, paddingTop, pointerEvents }}
- onWheel={(e) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
+ style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingTop: paddingTop(), pointerEvents: pointerEvents() }}
+ onWheel={e => e.stopPropagation()}
onDrop={this.onTreeDrop}
ref={this.createTreeDropTarget}>
{this.titleBar}
@@ -241,7 +244,6 @@ export class
{this.treeViewElements}
</ul>
</div >
- </div>
- );
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1e693f594..91f159d8e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -2,26 +2,23 @@ import { action, computed, observable } from 'mobx';
import { observer } from "mobx-react";
import * as React from 'react';
import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
-import { DateField } from '../../../fields/DateField';
-import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
-import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
+import { makeInterface } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { Cast, ScriptCast, StrCast, DateCast } from '../../../fields/Types';
-import { denormalizeEmail, distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
-import { returnFalse } from '../../../Utils';
-import { Docs, DocUtils } from '../../documents/Documents';
-import { BranchTask, BranchCreate } from '../../documents/Gitlike';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { DocUtils } from '../../documents/Documents';
+import { BranchCreate, BranchTask } from '../../documents/Gitlike';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { InteractionUtils } from '../../util/InteractionUtils';
-import { UndoManager } from '../../util/UndoManager';
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
-import { Touchable } from '../Touchable';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
import { CollectionDockingView } from "./CollectionDockingView";
@@ -66,8 +63,6 @@ export enum CollectionViewType {
export interface CollectionViewProps extends FieldViewProps {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
layoutEngine?: () => string;
- parentActive: (outsideReaction: boolean) => boolean;
- filterAddDocument?: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
// property overrides for child documents
@@ -84,19 +79,20 @@ export interface CollectionViewProps extends FieldViewProps {
childClickScript?: ScriptField;
childDoubleClickScript?: ScriptField;
}
+
+type CollectionDocument = makeInterface<[typeof documentSchema]>;
+const CollectionDocument = makeInterface(documentSchema);
@observer
-export class CollectionView extends Touchable<CollectionViewProps> {
+export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument, "") {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
- _isChildActive = false; //TODO should this be observable?
- @observable private _curLightboxImg = 0;
@observable private static _safeMode = false;
public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
get collectionViewType(): CollectionViewType | undefined {
- const viewField = StrCast(this.props.Document._viewType);
+ const viewField = StrCast(this.layoutDoc._viewType);
if (CollectionView._safeMode) {
switch (viewField) {
case CollectionViewType.Freeform:
@@ -107,133 +103,16 @@ export class CollectionView extends Touchable<CollectionViewProps> {
return viewField as any as CollectionViewType;
}
- active = (outsideReaction?: boolean) => {
- return this.props.renderDepth === 0 ||
- this.props.isSelected(outsideReaction) ||
- this.props.rootSelected(outsideReaction) ||
- (this.props.layerProvider?.(this.props.Document) !== false && (this.props.Document.forceActive || this.props.Document._isGroup)) ||
- this._isChildActive ?
- true :
- false;
- }
-
- whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
-
- /**
- * Applies the collection/dashboard's current filter attributes to the doc being added
- */
- addFilterAttributes = (doc: Doc) => {
- Cast((FilterBox._filterScope === "Current Collection" ? this.props.Document : CurrentUserUtils.ActiveDashboard)._docFilters, listSpec("string"))?.forEach(attribute => {
- if (attribute.charAt(0).toUpperCase() === attribute.charAt(0)) {
- const fields = attribute.split(':');
- if (fields[2] === "check") doc[DataSym][fields[0]] = fields[1];
- else if (fields[2] === "x" && doc[DataSym][fields[0]] === fields[1]) doc[DataSym][fields[0]] = undefined;
- }
- });
- }
-
- @action.bound
- addDocument = (doc: Doc | Doc[]): boolean => {
- if (this.props.filterAddDocument?.(doc) === false) {
- return false;
- }
-
- const docs = doc instanceof Doc ? [doc] : doc;
-
- if (docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) return false;
- const targetDataDoc = this.props.Document[DataSym];
- const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
- const added = docs.filter(d => !docList.includes(d));
- const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
-
- if (added.length) {
- if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
- return false;
- }
- else {
- if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym])) {
- added.forEach(d => {
- for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
- if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true);
- //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true);
- //else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
- }
- });
- }
-
- if (effectiveAcl === AclAddonly) {
- added.map(doc => {
- this.props.layerProvider?.(doc, true);// assigns layer values to the newly added document... testing the utility of this
- Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
- doc.context = this.props.Document;
- });
- }
- else {
- added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document
- DocUtils.LeavePushpin(doc);
- doc._stayInCollection = undefined;
- doc.context = this.props.Document;
- this.addFilterAttributes(doc); //
- });
- added.map(doc => this.props.layerProvider?.(doc, true));// assigns layer values to the newly added document... testing the utility of this
- (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
- targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
- }
- }
- }
- return true;
- }
-
- @action.bound
- removeDocument = (doc: any): boolean => {
- const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
- const indocs = doc instanceof Doc ? [doc] : doc as Doc[];
- const docs = indocs.filter(doc => effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin);
- if (docs.length) {
- const targetDataDoc = this.props.Document[DataSym];
- const value = DocListCast(targetDataDoc[this.props.fieldKey]);
- const toRemove = value.filter(v => docs.includes(v));
- if (toRemove.length !== 0) {
- const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc;
- toRemove.forEach(doc => {
- const ind = (targetDataDoc[this.props.fieldKey] as List<Doc>).indexOf(doc);
- if (ind !== -1) {
- Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
- doc.context = undefined;
- recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
- }
- });
- return true;
- }
- }
- return false;
- }
-
- // this is called with the document that was dragged and the collection to move it into.
- // if the target collection is the same as this collection, then the move will be allowed.
- // otherwise, the document being moved must be able to be removed from its container before
- // moving it into the target.
- @action.bound
- moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
- if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
- return true;
- }
- const first = doc instanceof Doc ? doc : doc[0];
- if (!first?._stayInCollection && addDocument !== returnFalse) {
- return UndoManager.RunInTempBatch(() => this.removeDocument(doc) && addDocument(doc));
- }
- return false;
- }
-
showIsTagged = () => {
return (null);
// this section would display an icon in the bototm right of a collection to indicate that all
// photos had been processed through Google's content analysis API and Google's tags had been
// assigned to the documents googlePhotosTags field.
- // const children = DocListCast(this.props.Document[this.props.fieldKey]);
+ // const children = DocListCast(this.rootDoc[this.props.fieldKey]);
// const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
// const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
// return !allTagged ? (null) : <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());
@@ -268,7 +147,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
}
subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" });
subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
- !Doc.UserDoc().noviceMode && subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" });
subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
@@ -279,7 +157,7 @@ export class CollectionView extends Touchable<CollectionViewProps> {
!Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" });
- if (!Doc.IsSystem(this.props.Document) && !this.props.Document.annotationOn) {
+ if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.annotationOn) {
const existingVm = ContextMenu.Instance.findByDescription(category);
const catItems = existingVm && "subitems" in existingVm ? existingVm.subitems : [];
catItems.push({ description: "Add a Perspective...", addDivider: true, noexpand: true, subitems: subItems, icon: "eye" });
@@ -289,9 +167,9 @@ export class CollectionView extends Touchable<CollectionViewProps> {
onContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
- if (cm && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+ if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
this.setupViewTypes("UI Controls...", vtype => {
- const newRendition = Doc.MakeAlias(this.props.Document);
+ const newRendition = Doc.MakeAlias(this.rootDoc);
newRendition._viewType = vtype;
this.props.addDocTab(newRendition, "add:right");
return newRendition;
@@ -299,34 +177,34 @@ export class CollectionView extends Touchable<CollectionViewProps> {
const options = cm.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
- !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
- if (this.props.Document.childLayout instanceof Doc) {
- optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "add:right"), icon: "project-diagram" });
+ !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null;
+ if (this.rootDoc.childLayout instanceof Doc) {
+ optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" });
}
- if (this.props.Document.childClickedOpenTemplateView instanceof Doc) {
- optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" });
+ if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) {
+ optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" });
}
- !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
+ !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" });
optionItems.push({
- description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.props.Document), "add:right"), icon: "project-diagram"
+ description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram"
});
optionItems.push({
- description: "Pull Master", event: () => BranchTask(this.props.Document, "pull"), icon: "project-diagram"
+ description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram"
});
optionItems.push({
- description: "Merge Branches", event: () => BranchTask(this.props.Document, "merge"), icon: "project-diagram"
+ description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram"
});
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" });
- if (!Doc.UserDoc().noviceMode && !this.props.Document.annotationOn) {
+ if (!Doc.UserDoc().noviceMode && !this.rootDoc.annotationOn) {
const existingOnClick = cm.findByDescription("OnClick...");
const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
const funcs = [{ key: "onChildClick", name: "On Child Clicked" }, { key: "onChildDoubleClick", name: "On Child Double Clicked" }];
funcs.map(func => onClicks.push({
description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => {
- const alias = Doc.MakeAlias(this.props.Document);
+ const alias = Doc.MakeAlias(this.rootDoc);
DocUtils.makeCustomViewClicked(alias, undefined, func.key);
this.props.addDocTab(alias, "add:right");
}
@@ -335,15 +213,15 @@ export class CollectionView extends Touchable<CollectionViewProps> {
onClicks.push({
description: `Set child ${childClick.title}`,
icon: "edit",
- event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
+ event: () => Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
}));
- !Doc.IsSystem(this.props.Document) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
+ !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
}
if (!Doc.UserDoc().noviceMode) {
const more = cm.findByDescription("More...");
const moreItems = more && "subitems" in more ? more.subitems : [];
- moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) });
+ moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) });
!more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
}
}
@@ -351,28 +229,26 @@ export class CollectionView extends Touchable<CollectionViewProps> {
bodyPanelWidth = () => this.props.PanelWidth();
- childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
- @computed get childLayoutString() { return StrCast(this.props.Document.childLayoutString); }
+ childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
+ @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); }
render() {
TraceMobx();
const props: SubCollectionViewProps = {
...this.props,
addDocument: this.addDocument,
- removeDocument: this.removeDocument,
moveDocument: this.moveDocument,
- active: this.active,
- whenActiveChanged: this.whenActiveChanged,
- parentActive: this.props.parentActive,
+ removeDocument: this.removeDocument,
+ isContentActive: this.isContentActive,
PanelWidth: this.bodyPanelWidth,
PanelHeight: this.props.PanelHeight,
+ ScreenToLocalTransform: this.screenToLocalTransform,
childLayoutTemplate: this.childLayoutTemplate,
childLayoutString: this.childLayoutString,
- ScreenToLocalTransform: this.screenToLocalTransform,
CollectionView: this,
};
return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
- style={{ pointerEvents: this.props.layerProvider?.(this.props.Document) === false ? "none" : undefined }}>
+ style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}>
{this.showIsTagged()}
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
</div>);
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 4005c751e..0c69ee030 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -15,7 +15,7 @@ import { ComputedField } from "../../../fields/ScriptField";
import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
import { ImageField } from "../../../fields/URLField";
import { GetEffectiveAcl } from "../../../fields/util";
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils";
import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -559,15 +559,15 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
{this.reactTable}
- {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>}
+ {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
{!this._showDoc ? (null) :
- <div className="collectionSchemaView-documentPreview"
+ <div className="collectionSchemaView-documentPreview" ref="overlay"
style={{
position: "absolute", width: 150, height: 150,
background: "dimGray", display: "block", top: 0, left: 0,
transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`
- }}
- ref="overlay"><DocumentView
+ }} >
+ <DocumentView
Document={this._showDoc}
DataDoc={this._showDataDoc}
styleProvider={DefaultStyleProvider}
@@ -576,7 +576,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
freezeDimensions={true}
focus={DocUtils.DefaultFocus}
renderDepth={this.props.renderDepth}
- rootSelected={() => false}
+ rootSelected={returnFalse}
+ isContentActive={returnTrue}
+ isDocumentActive={returnFalse}
PanelWidth={() => 150}
PanelHeight={() => 150}
ScreenToLocalTransform={this.getPreviewTransform}
@@ -586,8 +588,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
moveDocument={this.props.moveDocument}
- parentActive={this.props.active}
- whenActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f333c4077..f6aecbb14 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -309,6 +309,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
+ isContentActive={returnTrue}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
layerProvider={this.layerProvider}
@@ -322,8 +323,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
ScreenToLocalTransform={this.ScreenToLocalTransform}
dontCenter={"y"}
rootSelected={returnTrue}
- parentActive={this.active}
- whenActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
focus={this.focusFunc}
docViewPath={returnEmptyDoclist}
bringToFront={emptyFunction}
@@ -368,7 +368,7 @@ interface TabMinimapViewProps {
}
@observer
export class TabMinimapView extends React.Component<TabMinimapViewProps> {
- static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+ static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
if (doc) {
switch (property.split(":")[0]) {
default: return DefaultStyleProvider(doc, props, property);
@@ -417,12 +417,11 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
CollectionView={undefined}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
- parentActive={returnFalse}
docViewPath={returnEmptyDoclist}
childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
noOverlay={true} // don't render overlay Docs since they won't scale
setHeight={returnFalse}
- active={returnTrue}
+ isContentActive={returnTrue}
select={emptyFunction}
dropAction={undefined}
isSelected={returnFalse}
@@ -437,7 +436,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
PanelHeight={this.returnMiniSize}
ScreenToLocalTransform={Transform.Identity}
renderDepth={0}
- whenActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
focus={DocUtils.DefaultFocus}
styleProvider={TabMinimapView.miniStyleProvider}
layerProvider={undefined}
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 2f74a49bb..5b0c04f33 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -13,14 +13,15 @@
.treeView-container-active {
.bullet-outline {
position: relative;
- width: 15px;
+ width: $TREE_BULLET_WIDTH;
color: $intermediate-color;
transform: scale(0.5);
- display: inline-block;
+ display: inline-flex;
+ align-items: center;
}
.treeView-bulletIcons {
- width: 15px;
+ width: $TREE_BULLET_WIDTH;
.treeView-expandIcon {
display: none;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 1d14c63c7..94a19a673 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction, trace, reaction, IReactionDisposer } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -22,7 +22,6 @@ import { undoBatch, UndoManager } from '../../util/UndoManager';
import { EditableView } from "../EditableView";
import { TREE_BULLET_WIDTH } from '../globalCssVariables.scss';
import { DocumentView, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import { KeyValueBox } from '../nodes/KeyValueBox';
@@ -32,43 +31,35 @@ import { CollectionTreeView } from './CollectionTreeView';
import { CollectionView, CollectionViewType } from './CollectionView';
import "./TreeView.scss";
import React = require("react");
-import { ContextMenu } from '../ContextMenu';
-import { ContextMenuProps } from '../ContextMenuItem';
-import { SharingManager } from '../../util/SharingManager';
export interface TreeViewProps {
+ treeView: CollectionTreeView;
+ parentTreeView: TreeView | CollectionTreeView | undefined;
+ prevSibling?: Doc;
document: Doc;
dataDoc?: Doc;
- containingCollection: Doc;
- prevSibling?: Doc;
+ containerCollection: Doc;
renderDepth: number;
dropAction: dropActionType;
addDocTab: (doc: Doc, where: string) => boolean;
- pinToPres: (document: Doc) => void;
panelWidth: () => number;
panelHeight: () => number;
addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined;
moveDocument: DragManager.MoveFunction;
+ isContentActive: (outsideReaction?: boolean) => boolean;
+ whenChildContentsActiveChanged: (isActive: boolean) => void;
indentDocument?: (editTitle: boolean) => void;
outdentDocument?: (editTitle: boolean) => void;
ScreenToLocalTransform: () => Transform;
dontRegisterView?: boolean;
styleProvider?: StyleProviderFunc | undefined;
- layerProvider?: undefined | ((doc: Doc, assign?: boolean) => boolean);
- outerXf: () => { translateX: number, translateY: number };
- treeView: CollectionTreeView;
- parentKey: string;
- active: (outsideReaction?: boolean) => boolean;
treeViewHideHeaderFields: () => boolean;
- treeViewPreventOpen: boolean;
renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
onCheckedClick?: () => ScriptField;
onChildClick?: () => ScriptField;
skipFields?: string[];
firstLevel: boolean;
- whenActiveChanged: (isActive: boolean) => void;
- parentTreeView: TreeView | CollectionTreeView | undefined;
}
const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
@@ -79,49 +70,52 @@ const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("p
*
* special fields:
* treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden
- * treeViewPreventOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
* treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
*/
export class TreeView extends React.Component<TreeViewProps> {
static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
static _openTitleScript: Opt<ScriptField | undefined>;
static _openLevelScript: Opt<ScriptField | undefined>;
- private _editTitleScript: (() => ScriptField) | undefined;
- private _openScript: (() => ScriptField) | undefined;
- private _header?: React.RefObject<HTMLDivElement> = React.createRef();
- private _treedropDisposer?: DragManager.DragDropDisposer;
+ private _header: React.RefObject<HTMLDivElement> = React.createRef();
private _tref = React.createRef<HTMLDivElement>();
private _docRef: Opt<DocumentView>;
- private _editMaxWidth: number | string = 0;
private _selDisposer: Opt<IReactionDisposer>;
+ private _editTitleScript: (() => ScriptField) | undefined;
+ private _openScript: (() => ScriptField) | undefined;
+ private _treedropDisposer?: DragManager.DragDropDisposer;
+ get treeViewOpenIsTransient() { return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsPrototype(this.doc); }
set treeViewOpen(c: boolean) {
- if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c;
- else this.doc.treeViewOpen = this._overrideTreeViewOpen = c;
+ if (this.treeViewOpenIsTransient) this._transientOpenState = c;
+ else {
+ this.doc.treeViewOpen = c;
+ this._transientOpenState = false;
+ }
}
- @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
+ @observable _transientOpenState = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
@observable _editTitle: boolean = false;
@observable _dref: DocumentView | undefined | null;
get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
- get treeViewLockExpandedView() { return this.doc.treeViewLockExpandedView; }
- get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.props.treeView.fileSysMode ? (this.doc.isFolder ? "data" : "aliases") : Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields"); }
- get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.props.treeView.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
-
- @computed get doc() { TraceMobx(); return this.props.document; }
- @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._overrideTreeViewOpen; }
- @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.treeViewDefaultExpandedView); }
- @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
+ get defaultExpandedView() {
+ return this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") :
+ this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
+ }
+
+ @computed get doc() { return this.props.document; }
+ @computed get treeViewOpen() { return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._transientOpenState; }
+ @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.defaultExpandedView); }
+ @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
@computed get dataDoc() { return this.doc[DataSym]; }
@computed get layoutDoc() { return Doc.Layout(this.doc); }
- @computed get fieldKey() { TraceMobx(); const splits = StrCast(Doc.LayoutField(this.doc)).split("fieldKey={\'"); return splits.length > 1 ? splits[1].split("\'")[0] : "data"; }
- @computed get childDocs() { TraceMobx(); return this.childDocList(this.fieldKey); }
+ @computed get fieldKey() { return Doc.LayoutFieldKey(this.doc); }
+ @computed get childDocs() { return this.childDocList(this.fieldKey); }
@computed get childLinks() { return this.childDocList("links"); }
@computed get childAliases() { return this.childDocList("aliases"); }
@computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
- @computed get selected() { return SelectionManager.Views().length && SelectionManager.Views()[0].props.Document === this.props.document; }
+ @computed get selected() { return SelectionManager.Views().lastElement()?.props.Document === this.props.document; }
childDocList(field: string) {
- const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
+ const layout = Cast(Doc.LayoutField(this.doc), Doc, null);
return (this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
(layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
DocListCastOrNull(this.doc[field]); // otherwise use the document's data field
@@ -184,9 +178,9 @@ export class TreeView extends React.Component<TreeViewProps> {
document.removeEventListener("pointermove", this.onDragMove, true);
}
onPointerEnter = (e: React.PointerEvent): void => {
- this.props.active(true) && Doc.BrushDoc(this.dataDoc);
+ this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
- this._header!.current!.className = "treeView-header";
+ this._header.current!.className = "treeView-header";
document.removeEventListener("pointermove", this.onDragMove, true);
document.removeEventListener("pointerup", this.onDragUp, true);
document.addEventListener("pointermove", this.onDragMove, true);
@@ -195,8 +189,8 @@ export class TreeView extends React.Component<TreeViewProps> {
}
onPointerLeave = (e: React.PointerEvent): void => {
Doc.UnBrushDoc(this.dataDoc);
- if (this._header?.current?.className !== "treeView-header-editing") {
- this._header!.current!.className = "treeView-header";
+ if (this._header.current?.className !== "treeView-header-editing") {
+ this._header.current!.className = "treeView-header";
}
document.removeEventListener("pointerup", this.onDragUp, true);
document.removeEventListener("pointermove", this.onDragMove, true);
@@ -204,13 +198,13 @@ export class TreeView extends React.Component<TreeViewProps> {
onDragMove = (e: PointerEvent): void => {
Doc.UnBrushDoc(this.dataDoc);
const pt = [e.clientX, e.clientY];
- const rect = this._header!.current!.getBoundingClientRect();
+ const rect = this._header.current!.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
- this._header!.current!.className = "treeView-header";
- if (inside) this._header!.current!.className += " treeView-header-inside";
- else if (before) this._header!.current!.className += " treeView-header-above";
- else if (!before) this._header!.current!.className += " treeView-header-below";
+ this._header.current!.className = "treeView-header";
+ if (inside) this._header.current!.className += " treeView-header-inside";
+ else if (before) this._header.current!.className += " treeView-header-above";
+ else if (!before) this._header.current!.className += " treeView-header-below";
e.stopPropagation();
}
@@ -218,6 +212,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const bullet = Docs.Create.TextDocument("-text-", {
layout: CollectionView.LayoutString("data"),
title: "-title-", "sidebarColor": "transparent", "sidebarViewType": CollectionViewType.Freeform,
+ treeViewExpandedViewLock: true, treeViewExpandedView: "data",
_viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: "outline",
x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, backgroundColor: "transparent", _width: 1000, _height: 10
});
@@ -229,18 +224,14 @@ export class TreeView extends React.Component<TreeViewProps> {
makeTextCollection = () => {
const bullet = TreeView.makeTextBullet();
- const added = this.props.addDocument(bullet);
TreeView._editTitleOnLoad = { id: bullet[Id], parent: this };
- bullet.context = this.props.treeView.Document;
- return added;
+ return this.props.addDocument(bullet);
}
makeFolder = () => {
const folder = Docs.Create.TreeDocument([], { title: "-folder-", _stayInCollection: true, isFolder: true });
- const added = this.props.addDocument(folder);
- folder.context = this.props.treeView.Document;
TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
- return added;
+ return this.props.addDocument(folder);
}
preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
@@ -251,7 +242,7 @@ export class TreeView extends React.Component<TreeViewProps> {
@undoBatch
treeDrop = (e: Event, de: DragManager.DropEvent) => {
const pt = [de.x, de.y];
- const rect = this._header!.current!.getBoundingClientRect();
+ const rect = this._header.current!.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
if (de.complete.linkDragData) {
@@ -265,7 +256,7 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
if (docDragData.draggedDocuments[0] === this.doc) return true;
const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before);
- const canAdd = !StrCast((inside ? this.props.document : this.props.containingCollection)?.freezeChildren).includes("add") || docDragData.treeViewDoc === this.props.treeView.props.Document;
+ const canAdd = !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes("add") || docDragData.treeViewDoc === this.props.treeView.props.Document;
const localAdd = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) && ((doc.context = this.doc.context) || true) ? true : false;
const addDoc = !inside ? parentAddDoc :
(doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean);
@@ -279,7 +270,7 @@ export class TreeView extends React.Component<TreeViewProps> {
refTransform = (ref: HTMLDivElement | undefined | null) => {
if (!ref) return this.props.ScreenToLocalTransform();
const { scale, translateX, translateY } = Utils.GetScreenTransform(ref);
- const outerXf = this.props.outerXf();
+ const outerXf = Utils.GetScreenTransform(this.props.treeView.MainEle());
const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
}
@@ -299,9 +290,9 @@ export class TreeView extends React.Component<TreeViewProps> {
if (aspect) return this.docWidth() / (aspect || 1);
return layoutDoc._fitWidth ?
(!Doc.NativeHeight(this.doc) ?
- NumCast(this.props.containingCollection._height)
+ NumCast(this.props.containerCollection._height)
:
- Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc)) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containingCollection._height))
+ Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc)) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height))
))
:
(layoutDoc[HeightSym]() || 50);
@@ -328,10 +319,10 @@ export class TreeView extends React.Component<TreeViewProps> {
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents),
- this.props.treeView, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
- this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.layerProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
- this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this);
+ this.props.treeView, this, doc, undefined, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
+ this.props.dropAction, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.isContentActive,
+ this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
+ [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged, this.props.dontRegisterView);
} else {
contentElement = <EditableView key="editableView"
contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -378,18 +369,17 @@ export class TreeView extends React.Component<TreeViewProps> {
TraceMobx();
const expandKey = this.treeViewExpandedView;
if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) {
- const key = expandKey === "annotations" ? this.fieldKey + "-annotations" : expandKey;
+ const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey;
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
// if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
// then the modification would be done here
- const ordering = StrCast(this.doc[this.fieldKey + "-sortCriteria"]);
+ const ordering = StrCast(this.doc.treeViewSortCriterion);
if (ordering === "Z") {
const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
- doc.zIndex = addBefore ? (before ? NumCast(addBefore.zIndex) - 0.5 : NumCast(addBefore.zIndex) + 0.5) : 1000;
+ doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
docs.push(doc);
- docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1);
- docs.forEach((d, i) => d.zIndex = i);
+ docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1).forEach((d, i) => d.zIndex = i);
}
const added = Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
added && (doc.context = this.doc.context);
@@ -397,24 +387,23 @@ export class TreeView extends React.Component<TreeViewProps> {
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
- const sortKey = `${this.fieldKey}-sortCriteria`;
let downX = 0, downY = 0;
const sortings = ["up", "down", "Z", undefined];
- const curSort = Math.max(0, sortings.indexOf(Cast(this.doc[sortKey], "string", null)));
+ const curSort = Math.max(0, sortings.indexOf(Cast(this.doc.treeViewSortCriterion, "string", null)));
return <ul key={expandKey + "more"} title={"sort: " + sortings[curSort]} className={this.doc.treeViewHideTitle ? "no-indent" : ""}
onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
onClick={(e) => {
- if (this.props.active() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
- !this.props.treeView.outlineMode && (this.doc[sortKey] = sortings[(curSort + 1) % sortings.length]);
+ if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
+ !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]);
e.stopPropagation();
}
}}>
{!docs ? (null) :
- TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc,
- this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
- StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.layerProvider, this.props.ScreenToLocalTransform,
- this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this)}
+ TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc,
+ this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
+ StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
+ this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
+ [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged, this.props.dontRegisterView)}
</ul >;
} else if (this.treeViewExpandedView === "fields") {
return <ul key={this.doc[Id] + this.doc.title}>
@@ -433,7 +422,7 @@ export class TreeView extends React.Component<TreeViewProps> {
if (this.onCheckedClick) {
this.onCheckedClick?.script.run({
this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
- heading: this.props.containingCollection.title,
+ heading: this.props.containerCollection.title,
checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? "remove" : "check",
containingTreeView: this.props.treeView.props.Document,
}, console.log);
@@ -470,47 +459,49 @@ export class TreeView extends React.Component<TreeViewProps> {
}
</div>;
}
+
+ @action
+ expandNextviewType = () => {
+ if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeViewExpandedViewLock) {
+ const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.doc.treeViewExpandedView)) + 1) % modes.length];
+ const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" : "";
+ const links = () => DocListCast(this.doc.links).length ? "links" : "";
+ const children = () => this.childDocs ? this.fieldKey : "";
+ this.doc.treeViewExpandedView = next(this.props.treeView.fileSysMode ?
+ (Doc.UserDoc().noviceMode ? ["layout", "aliases"] : ["layout", "aliases", "fields"]) :
+ (Doc.UserDoc().noviceMode ? [children(), "layout"] : [children(), "fields", "layout", links(), annos()]).filter(mode => mode));
+ }
+ this.treeViewOpen = true;
+ }
+
@computed get headerElements() {
- return (Doc.IsSystem(this.doc) && Doc.UserDoc().noviceMode) || this.props.treeViewHideHeaderFields() ? (null) :
- <>
+ return this.props.treeViewHideHeaderFields() || Doc.IsSystem(this.doc) ? (null)
+ : <>
<FontAwesomeIcon key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />
- <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
- onPointerDown={action(() => {
- if (this.props.treeView.fileSysMode) {
- this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "aliases" :
- this.treeViewExpandedView === "aliases" && !Doc.UserDoc().noviceMode ? "fields" : "layout";
- } else if (this.treeViewOpen) {
- this.doc.treeViewExpandedView = this.treeViewLockExpandedView ? this.doc.treeViewExpandedView :
- this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields") :
- this.treeViewExpandedView === "fields" && this.layoutDoc ? "layout" :
- this.treeViewExpandedView === "layout" && DocListCast(this.doc.links).length ? "links" :
- (this.treeViewExpandedView === "links" || this.treeViewExpandedView === "layout") && DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" :
- this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields");
- }
- this.treeViewOpen = true;
- })}>
- {this.treeViewExpandedView}
- </span>
+ {this.doc.treeViewExpandedViewLock ? (null) :
+ <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}>
+ {this.treeViewExpandedView}
+ </span>}
</>;
}
showContextMenu = (e: React.MouseEvent) => simulateMouseClick(this._docRef?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
- contextMenuItems = () => this.doc.isFolder ?
- [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] : Doc.IsSystem(this.doc) ? [] :
- this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
- [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }] :
- [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }]
+ contextMenuItems = () => Doc.IsSystem(this.doc) ? [] : this.doc.isFolder ?
+ [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] :
+ this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
+ [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }] :
+ [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }]
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document);
ignoreEvent = (e: any) => {
- if (this.props.active(true)) {
+ if (this.props.isContentActive(true)) {
e.stopPropagation();
e.preventDefault();
}
}
- titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+ titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
switch (property.split(":")[0]) {
@@ -524,9 +515,10 @@ export class TreeView extends React.Component<TreeViewProps> {
{StrCast(doc?.title)}
</div>;
case StyleProp.Decorations: return (null);
+ default: return this.props?.treeView?.props.styleProvider?.(doc, props, property);
}
}
- embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+ embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
if (property.startsWith(StyleProp.Decorations)) return (null);
return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
}
@@ -542,6 +534,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
}
}
+ titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - treeBulletWidth()));
/**
* Renders the EditableView title element for placement into the tree.
@@ -582,8 +575,10 @@ export class TreeView extends React.Component<TreeViewProps> {
Document={this.doc}
DataDoc={undefined}
scriptContext={this}
+ hideDecorationTitle={this.props.treeView.outlineMode}
+ hideResizeHandles={this.props.treeView.outlineMode}
styleProvider={this.titleStyleProvider}
- layerProvider={this.props.layerProvider}
+ layerProvider={returnTrue}
docViewPath={returnEmptyDoclist}
treeViewDoc={this.props.treeView.props.Document}
addDocument={undefined}
@@ -597,17 +592,19 @@ export class TreeView extends React.Component<TreeViewProps> {
removeDocument={this.props.removeDoc}
ScreenToLocalTransform={this.getTransform}
NativeHeight={() => 18}
- NativeWidth={this.props.treeView.truncateTitleWidth}
- PanelWidth={this.props.treeView.truncateTitleWidth}
+ NativeWidth={this.titleWidth}
+ PanelWidth={this.titleWidth}
PanelHeight={() => 18}
contextMenuItems={this.contextMenuItems}
renderDepth={1}
- focus={returnTrue}
- parentActive={returnTrue}
- whenActiveChanged={this.props.whenActiveChanged}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={this.props.isContentActive}
+ focus={this.refocus}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
bringToFront={emptyFunction}
- cantBrush={this.props.treeView.props.cantBrush}
- dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews)}
+ disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+ hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
+ dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
docFilters={returnEmptyFilter}
docRangeFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -621,22 +618,21 @@ export class TreeView extends React.Component<TreeViewProps> {
fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? "bold" : undefined,
textDecoration: Doc.GetT(this.doc, "title", "string", true) ? "underline" : undefined,
outline: this.doc === CurrentUserUtils.ActiveDashboard ? "dashed 1px #06123232" : undefined,
- pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined
+ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined
}} >
{view}
</div >
<div className={"right-buttons-container"}>
- {this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations)} {/* hide and lock buttons */}
+ {this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""))} {/* hide and lock buttons */}
{this.headerElements}
</div>
</>;
}
- renderBulletHeader = (contents: JSX.Element) => {
+ renderBulletHeader = (contents: JSX.Element, editing: boolean) => {
return <>
- <div className={`treeView-header` + (this._editMaxWidth ? "-editing" : "")} key="titleheader"
+ <div className={`treeView-header` + (editing ? "-editing" : "")} key="titleheader"
ref={this._header}
- style={{ maxWidth: this._editMaxWidth }}
onClick={this.ignoreEvent}
onPointerDown={this.ignoreEvent}
onPointerEnter={this.onPointerEnter}
@@ -647,13 +643,6 @@ export class TreeView extends React.Component<TreeViewProps> {
</>;
}
- // renders the text version of a document as the header (e.g., useful for Slide views where the "")
- @computed get renderTitleAsHeader() {
- return <>
- {this.renderBullet}
- {this.renderTitle}
- </>;
- }
renderEmbeddedDocument = (asText: boolean) => {
const layout = StrCast(Doc.LayoutField(this.layoutDoc));
@@ -667,34 +656,47 @@ export class TreeView extends React.Component<TreeViewProps> {
PanelHeight={panelHeight}
NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined}
NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined}
- fitContentsToDoc={returnTrue}
- hideTitle={asText}
LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined}
- focus={asText ? this.refocus : returnFalse}
- dontRegisterView={asText ? undefined : this.props.dontRegisterView}
+ isContentActive={asText ? this.props.isContentActive : returnFalse}
+ isDocumentActive={asText ? this.props.isContentActive : returnFalse}
+ styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
+ hideTitle={asText}
+ fitContentsToDoc={returnTrue}
+ hideDecorationTitle={this.props.treeView.outlineMode}
+ hideResizeHandles={this.props.treeView.outlineMode}
+ focus={this.refocus}
+ hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
+ dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
ScreenToLocalTransform={this.docTransform}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
- styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
- layerProvider={this.props.layerProvider}
+ layerProvider={returnTrue}
docViewPath={this.props.treeView.props.docViewPath}
docFilters={returnEmptyFilter}
docRangeFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionDoc={this.props.containingCollection}
+ ContainingCollectionDoc={this.props.containerCollection}
ContainingCollectionView={undefined}
addDocument={this.props.addDocument}
moveDocument={this.move}
removeDocument={this.props.removeDoc}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres}
- cantBrush={this.props.treeView.props.cantBrush}
+ pinToPres={this.props.treeView.props.pinToPres}
+ disableDocBrushing={this.props.treeView.props.disableDocBrushing}
bringToFront={returnFalse}
/>;
}
+ // renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views.
+ @computed get renderTitleAsHeader() {
+ return <>
+ {this.renderBullet}
+ {this.renderTitle}
+ </>;
+ }
+
+ // renders the document in the header field instead of a text proxy.
@computed get renderDocumentAsHeader() {
return <>
{this.renderBullet}
@@ -712,29 +714,18 @@ export class TreeView extends React.Component<TreeViewProps> {
render() {
TraceMobx();
- if (this.props.renderedIds.indexOf(this.doc[Id]) !== -1) return "<" + this.doc.title + ">";
- if (this._editTitle) { // find containing CollectionTreeView and set our maximum width so the containing tree view won't have to scroll
- let par: any = this._header?.current;
- while (par && par.className !== "collectionTreeView-dropTarget") par = par.parentNode;
- if (par) {
- const par_rect = (par as HTMLElement).getBoundingClientRect();
- const my_recct = this._docRef?.ContentDiv?.getBoundingClientRect();
- this._editMaxWidth = Math.max(100, par_rect.right - (my_recct?.left || 0));
- }
- }
- else this._editMaxWidth = "";
-
const hideTitle = this.doc.treeViewHideHeader || this.props.treeView.outlineMode;
- return <div className={`treeView-container${this._dref?.contentsActive() ? "-active" : ""}`}
- ref={this.createTreeDropTarget}
- onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}
- onKeyDown={this.onKeyDown}>
- <li className="collection-child">
- {hideTitle && this.doc.type !== DocumentType.RTF ?
- this.renderEmbeddedDocument(false) :
- this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader : this.renderTitleAsHeader)}
- </li>
- </div>;
+ return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
+ <div className={`treeView-container${this.props.isContentActive() ? "-active" : ""}`}
+ ref={this.createTreeDropTarget}
+ onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()}
+ onKeyDown={this.onKeyDown}>
+ <li className="collection-child">
+ {hideTitle && this.doc.type !== DocumentType.RTF ?
+ this.renderEmbeddedDocument(false) :
+ this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader : this.renderTitleAsHeader, this._editTitle)}
+ </li>
+ </div>;
}
public static sortDocs(childDocs: Doc[], criterion: string | undefined) {
@@ -768,45 +759,40 @@ export class TreeView extends React.Component<TreeViewProps> {
public static GetChildElements(
childDocs: Doc[],
treeView: CollectionTreeView,
- containingCollection: Doc,
+ parentTreeView: CollectionTreeView | TreeView | undefined,
+ conainerCollection: Doc,
dataDoc: Doc | undefined,
- key: string,
parentCollectionDoc: Doc | undefined,
- parentPrevSibling: Doc | undefined,
+ containerPrevSibling: Doc | undefined,
add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean,
remove: undefined | ((doc: Doc | Doc[]) => boolean),
move: DragManager.MoveFunction,
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => boolean,
- pinToPres: (document: Doc) => void,
styleProvider: undefined | StyleProviderFunc,
- layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean),
screenToLocalXf: () => Transform,
- outerXf: () => { translateX: number, translateY: number },
- active: (outsideReaction?: boolean) => boolean,
+ isContentActive: (outsideReaction?: boolean) => boolean,
panelWidth: () => number,
renderDepth: number,
treeViewHideHeaderFields: () => boolean,
- treeViewPreventOpen: boolean,
renderedIds: string[],
onCheckedClick: undefined | (() => ScriptField),
onChildClick: undefined | (() => ScriptField),
skipFields: string[] | undefined,
firstLevel: boolean,
- whenActiveChanged: (isActive: boolean) => void,
+ whenChildContentsActiveChanged: (isActive: boolean) => void,
dontRegisterView: boolean | undefined,
- parentTreeView: CollectionTreeView | TreeView | undefined
) {
- const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
+ const viewSpecScript = Cast(conainerCollection.viewSpecScript, ScriptField);
if (viewSpecScript) {
childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
}
- const docs = TreeView.sortDocs(childDocs, StrCast(containingCollection?.[key + "-sortCriteria"]));
+ const docs = TreeView.sortDocs(childDocs, StrCast(conainerCollection.treeViewSortCriterion));
const rowWidth = () => panelWidth() - treeBulletWidth();
const treeViewRefs = new Map<Doc, TreeView | undefined>();
return docs.filter(child => child instanceof Doc).map((child, i) => {
- const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, child);
+ const pair = Doc.GetLayoutDataDocPair(conainerCollection, dataDoc, child);
if (!pair.layout || pair.data instanceof Promise) {
return (null);
}
@@ -823,7 +809,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
};
const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
- const outdent = parentCollectionDoc?._viewType !== CollectionViewType.Tree ? undefined : ((editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, parentPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined));
+ const outdent = parentCollectionDoc?._viewType !== CollectionViewType.Tree ? undefined : ((editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined));
const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
const childLayout = Doc.Layout(pair.layout);
const rowHeight = () => {
@@ -833,7 +819,7 @@ export class TreeView extends React.Component<TreeViewProps> {
return <TreeView key={child[Id]} ref={r => treeViewRefs.set(child, r ? r : undefined)}
document={pair.layout}
dataDoc={pair.data}
- containingCollection={containingCollection}
+ containerCollection={conainerCollection}
prevSibling={docs[i]}
treeView={treeView}
indentDocument={indent}
@@ -841,27 +827,22 @@ export class TreeView extends React.Component<TreeViewProps> {
onCheckedClick={onCheckedClick}
onChildClick={onChildClick}
renderDepth={renderDepth}
- removeDoc={StrCast(containingCollection.freezeChildren).includes("remove") ? undefined : remove}
+ removeDoc={StrCast(conainerCollection.freezeChildren).includes("remove") ? undefined : remove}
addDocument={addDocument}
styleProvider={styleProvider}
- layerProvider={layerProvider}
panelWidth={rowWidth}
panelHeight={rowHeight}
dontRegisterView={dontRegisterView}
moveDocument={move}
dropAction={dropAction}
addDocTab={addDocTab}
- pinToPres={pinToPres}
ScreenToLocalTransform={screenToLocalXf}
- outerXf={outerXf}
- parentKey={key}
- active={active}
+ isContentActive={isContentActive}
treeViewHideHeaderFields={treeViewHideHeaderFields}
- treeViewPreventOpen={treeViewPreventOpen}
renderedIds={renderedIds}
skipFields={skipFields}
firstLevel={firstLevel}
- whenActiveChanged={whenActiveChanged}
+ whenChildContentsActiveChanged={whenChildContentsActiveChanged}
parentTreeView={parentTreeView} />;
});
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f0d99611a..c623ce653 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -36,7 +36,6 @@ import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveIn
import { LightboxView } from "../../LightboxView";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
-import { FieldViewProps } from "../../nodes/FieldView";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
import { PresBox } from "../../nodes/PresBox";
@@ -67,7 +66,6 @@ export const panZoomSchema = createSchema({
type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>;
const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema);
export type collectionFreeformViewProps = {
- parentActive: (outsideReaction: boolean) => boolean;
annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
viewDefDivClick?: ScriptField;
childPointerEvents?: boolean;
@@ -117,7 +115,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
@computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
- @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); }
+ @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); }
@computed get fitToContentVals() {
return {
bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -152,7 +150,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getKeyFrameEditing = () => this._keyframeEditing;
onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
- parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false;
elementFunc = () => this._layoutElements;
shrinkWrap = () => {
const vals = this.fitToContentVals;
@@ -422,7 +419,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
}
- getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => {
+ getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
if (property !== StyleProp.BackgroundColor) return styleProp;
const cluster = NumCast(doc?.cluster);
@@ -459,7 +456,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return;
}
this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
- if (e.button === 0 && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+ if (e.button === 0 && !e.altKey && !e.ctrlKey && this.props.isContentActive(true)) {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);
@@ -484,7 +481,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const pt = me.changedTouches[0];
if (pt) {
this._hitCluster = this.pickCluster(this.getTransform().transformPoint(pt.clientX, pt.clientY));
- if (!e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+ if (!e.shiftKey && !e.altKey && !e.ctrlKey && this.props.isContentActive(true)) {
this.removeMoveListeners();
this.addMoveListeners();
this.removeEndListeners();
@@ -625,8 +622,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onClick = (e: React.MouseEvent) => {
if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
- if (e.shiftKey && Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click
- this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+ if (e.shiftKey) {
+ if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click
+ this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+ }
e.stopPropagation();
e.preventDefault();
}
@@ -647,7 +646,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (this.props.Document._isGroup) return; // groups don't pan when dragged -- instead let the event go through to allow the group itself to drag
if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return;
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
- if (this.props.active(true)) e.stopPropagation();
+ if (this.props.isContentActive(true)) e.stopPropagation();
} else if (!e.cancelBubble) {
if (CurrentUserUtils.SelectedTool === InkTool.None) {
if (this.tryDragCluster(e, this._hitCluster)) {
@@ -735,7 +734,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
- if (!e.nativeEvent.cancelBubble && this.props.active(true)) {
+ if (!e.nativeEvent.cancelBubble && this.props.isContentActive(true)) {
// const pt1: React.Touch | null = e.targetTouches.item(0);
// const pt2: React.Touch | null = e.targetTouches.item(1);
// // if (!pt1 || !pt2) return;
@@ -819,7 +818,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
e.stopPropagation();
}
- else if (this.props.active(true) && !this.Document._isGroup) {
+ else if (this.props.isContentActive(true) && !this.Document._isGroup) {
e.stopPropagation();
e.preventDefault();
this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
@@ -1007,6 +1006,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
};
}
+ isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+
getChildDocView(entry: PoolData) {
const childLayout = entry.pair.layout;
const childData = entry.pair.data;
@@ -1030,14 +1031,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
docFilters={this.freeformDocFilters}
docRangeFilters={this.freeformRangeDocFilters}
searchFilterDocs={this.searchFilterDocs}
+ isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
+ isDocumentActive={this.isContentActive}
focus={this.focusDocument}
addDocTab={this.addDocTab}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
moveDocument={this.props.moveDocument}
pinToPres={this.props.pinToPres}
- whenActiveChanged={this.props.whenActiveChanged}
- parentActive={this.parentActive}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
docViewPath={this.props.docViewPath}
styleProvider={this.getClusterColor}
layerProvider={this.props.layerProvider}
@@ -1444,7 +1446,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getTransform={this.getTransform}
isAnnotationOverlay={this.isAnnotationOverlay}>
<div ref={this._marqueeRef}>
- {this.layoutDoc["_backgroundGrid-show"] && (!SnappingManager.GetIsDragging() || !Doc.UserDoc().showSnapLines) ? this.backgroundGrid : (null)}
+ {this.layoutDoc["_backgroundGrid-show"] ? this.backgroundGrid : (null)}
<CollectionFreeFormViewPannableContents
isAnnotationOverlay={this.isAnnotationOverlay}
transform={this.contentTransform}
@@ -1488,7 +1490,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
width: `${100 / (this.contentScaling || 1)}%`,
height: this.isAnnotationOverlay && this.Document.scrollHeight ? this.Document.scrollHeight : `${100 / (this.contentScaling || 1)}%`// : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
}}>
- {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ?
+ {this.Document._freeformLOD && !this.props.isContentActive() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ?
this.placeholder : this.marqueeView}
{this.props.noOverlay ? (null) : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index af391a078..d14b68fa7 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -132,18 +132,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
});
})();
e.stopPropagation();
- } else if (e.key === "f" && e.ctrlKey) {
- e.preventDefault();
- const root = Docs.Create.TreeDocument([], { title: "folder", _stayInCollection: true, isFolder: true });
- const folder = Docs.Create.TreeDocument([root], { title: "root", isFolder: true, treeViewType: "fileSystem", treeViewTruncateTitleWidth: 150 });
- Doc.GetProto(folder).isFolder = true;
- folder.x = x;
- folder.y = y;
- folder._width = 200;
- folder._height = 300;
- this.props.addDocument?.(folder);
- //setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false));
- e.stopPropagation();
} else if (e.key === "b" && e.ctrlKey) {
// e.preventDefault();
// navigator.clipboard.readText().then(text => {
@@ -167,7 +155,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : "";
FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
- this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0, this.props.isAnnotationOverlay ? this.props.Document : undefined));
+ this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0));
e.stopPropagation();
}
}
@@ -366,6 +354,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
newCollection._width = this.Bounds.width;
newCollection._height = this.Bounds.height;
newCollection._isGroup = makeGroup;
+ newCollection.forceActive = makeGroup;
newCollection.x = this.Bounds.left;
newCollection.y = this.Bounds.top;
selected.forEach(d => d.context = newCollection);
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index e2feff5ed..b0030471d 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -171,7 +171,6 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
ScreenToLocalTransform={dxf}
onClick={this.onChildClickHandler}
renderDepth={this.props.renderDepth + 1}
- parentActive={this.props.active}
dontCenter={"y"}
/>;
}
@@ -296,7 +295,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
* Handles text document creation on double click.
*/
onPointerDown = (e: React.PointerEvent) => {
- if (this.props.active(true)) {
+ if (this.props.isContentActive(true)) {
setupMoveUpEvents(this, e, returnFalse, returnFalse,
(e: PointerEvent, doubleTap?: boolean) => {
if (doubleTap) {
@@ -316,7 +315,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
render() {
return (
<div className="collectionGridView-contents" ref={this.createDashEventsTarget}
- style={{ pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined }}
+ style={{ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined }}
onContextMenu={this.onContextMenu}
onPointerDown={this.onPointerDown}
onDrop={this.onExternalDrop}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 0c0dbef9f..8b5c02b75 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -223,6 +223,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
LayoutTemplateString={this.props.childLayoutString}
freezeDimensions={this.props.childFreezeDimensions}
renderDepth={this.props.renderDepth + 1}
+ isContentActive={returnFalse}
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
@@ -239,8 +240,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 0a1000a20..2c5e40d02 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -232,6 +232,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
ScreenToLocalTransform={dxf}
focus={this.props.focus}
docFilters={this.docFilters}
+ isContentActive={returnFalse}
docRangeFilters={this.docRangeFilters}
searchFilterDocs={this.searchFilterDocs}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
@@ -239,8 +240,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
- parentActive={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
addDocTab={this.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}