aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx36
-rw-r--r--src/client/views/collections/CollectionMenu.tsx11
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx19
-rw-r--r--src/client/views/collections/CollectionPileView.tsx145
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx35
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx19
-rw-r--r--src/client/views/collections/CollectionSubView.tsx4
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx353
-rw-r--r--src/client/views/collections/CollectionTreeView.scss3
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx13
-rw-r--r--src/client/views/collections/TabDocView.tsx99
-rw-r--r--src/client/views/collections/TreeView.scss3
-rw-r--r--src/client/views/collections/TreeView.tsx32
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss9
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx86
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss50
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx230
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx19
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx5
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx19
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx17
-rw-r--r--src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx10
-rw-r--r--src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx3
-rw-r--r--src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx9
27 files changed, 632 insertions, 610 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 92319d080..ffc004df6 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -25,6 +25,7 @@ import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import { TabDocView } from './TabDocView';
import React = require('react');
+import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
@@ -142,7 +143,7 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
@action
- public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean {
+ public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean): boolean {
const instance = CollectionDockingView.Instance;
if (!instance) return false;
const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
@@ -164,7 +165,7 @@ export class CollectionDockingView extends CollectionSubView() {
}
@undoBatch
- public static ToggleSplit(doc: Doc, location: string, stack?: any, panelName?: string) {
+ public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string) {
return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1
? CollectionDockingView.CloseSplit(doc)
: CollectionDockingView.AddSplit(doc, location, stack, panelName);
@@ -175,7 +176,7 @@ export class CollectionDockingView extends CollectionSubView() {
//
@undoBatch
@action
- public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
+ public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string) {
if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
if (!CollectionDockingView.Instance) return false;
const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
@@ -190,7 +191,7 @@ export class CollectionDockingView extends CollectionSubView() {
if (!pullSide && stack) {
stack.addChild(docContentConfig, undefined);
- stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]);
+ setTimeout(() => stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]));
} else {
const newContentItem = () => {
const newItem = glayRoot.layoutManager.createContentItem({ type: 'stack', content: [docContentConfig] }, instance._goldenLayout);
@@ -208,14 +209,15 @@ export class CollectionDockingView extends CollectionSubView() {
// if row
switch (pullSide) {
default:
- case 'right':
+ case OpenWhereMod.none:
+ case OpenWhereMod.right:
glayRoot.contentItems[0].addChild(newContentItem());
break;
- case 'left':
+ case OpenWhereMod.left:
glayRoot.contentItems[0].addChild(newContentItem(), 0);
break;
- case 'top':
- case 'bottom':
+ case OpenWhereMod.top:
+ case OpenWhereMod.bottom:
// if not going in a row layout, must add already existing content into column
const rowlayout = glayRoot.contentItems[0];
const newColumn = rowlayout.layoutManager.createContentItem({ type: 'column' }, instance._goldenLayout);
@@ -387,6 +389,7 @@ export class CollectionDockingView extends CollectionSubView() {
const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
if (!className.includes('lm_close') && !className.includes('lm_maximise')) {
this._flush = UndoManager.StartBatch('golden layout edit');
+ DocServer.UPDATE_SERVER_CACHE();
}
}
}
@@ -452,7 +455,7 @@ export class CollectionDockingView extends CollectionSubView() {
.map(id => DocServer.GetCachedRefField(id))
.filter(f => f)
.map(f => f as Doc);
- const changesMade = this.props.Document.dockcingConfig !== json;
+ const changesMade = this.props.Document.dockingConfig !== json;
if (changesMade && !this._flush) {
UndoManager.RunInBatch(() => {
this.props.Document.dockingConfig = json;
@@ -496,7 +499,7 @@ export class CollectionDockingView extends CollectionSubView() {
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
});
this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
- CollectionDockingView.AddSplit(docToAdd, '', stack);
+ CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
}
});
@@ -507,7 +510,12 @@ export class CollectionDockingView extends CollectionSubView() {
action(() => {
//if (confirm('really close this?')) {
if ((!stack.parent.isRoot && !stack.parent.parent.isRoot) || stack.parent.contentItems.length > 1) {
+ const batch = UndoManager.StartBatch('close stack');
stack.remove();
+ setTimeout(() => {
+ this.stateChanged();
+ batch.end();
+ });
} else {
alert('cant delete the last stack');
}
@@ -534,7 +542,7 @@ export class CollectionDockingView extends CollectionSubView() {
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
});
this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
- CollectionDockingView.AddSplit(docToAdd, '', stack);
+ CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
}
})
);
@@ -563,14 +571,14 @@ export class CollectionDockingView extends CollectionSubView() {
ScriptingGlobals.add(
function openInLightbox(doc: any) {
- LightboxView.AddDocTab(doc, 'lightbox');
+ LightboxView.AddDocTab(doc, OpenWhere.lightbox);
},
'opens up document in a lightbox',
'(doc: any)'
);
ScriptingGlobals.add(
function openOnRight(doc: any) {
- return CollectionDockingView.AddSplit(doc, 'right');
+ return CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
},
'opens up document in tab on right side of the screen',
'(doc: any)'
@@ -583,5 +591,5 @@ ScriptingGlobals.add(
'(doc: any)'
);
ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) {
- CollectionDockingView.ReplaceTab(doc, 'right', undefined, shiftKey);
+ CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, shiftKey);
});
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index db81f28f6..e2594b6ae 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -31,7 +31,7 @@ import { Colors } from '../global/globalEnums';
import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../InkingStroke';
import { LightboxView } from '../LightboxView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
-import { DocumentView } from '../nodes/DocumentView';
+import { DocumentView, OpenWhereMod } from '../nodes/DocumentView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import { DefaultStyleProvider } from '../StyleProvider';
@@ -569,7 +569,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
startRecording = () => {
const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
//Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
- CollectionDockingView.AddSplit(doc, 'right');
+ CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
};
@computed
@@ -733,11 +733,12 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
doc._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
}
- CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
+ CollectionFreeFormDocumentView.updateKeyframe(undefined, childDocs, currentFrame || 0);
doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
}
}
+ _keyTimer: NodeJS.Timeout | undefined;
@undoBatch
@action
nextKeyframe = (): void => {
@@ -746,7 +747,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
- CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
+ this._keyTimer = CollectionFreeFormDocumentView.updateKeyframe(this._keyTimer, this.childDocs, currentFrame || 0);
this.document._currentFrame = Math.max(0, (currentFrame || 0) + 1);
this.document.lastFrame = Math.max(NumCast(this.document._currentFrame), NumCast(this.document.lastFrame));
};
@@ -758,7 +759,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
- CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
+ this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, this.childDocs.slice());
this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
};
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index b0f64ed60..26c73438c 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -19,7 +19,7 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { LightboxView } from '../LightboxView';
-import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
@@ -180,16 +180,8 @@ export class CollectionNoteTakingView extends CollectionSubView() {
return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
}
- addDocTab = (doc: Doc, where: string) => {
- if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
- return true;
- }
- return this.props.addDocTab(doc, where);
- };
-
scrollToBottom = () => {
- smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight);
+ smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight, 'ease');
};
// let's dive in and get the actual document we want to drag/move around
@@ -201,13 +193,12 @@ export class CollectionNoteTakingView extends CollectionSubView() {
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
if (Math.floor(localTop[1]) !== 0) {
- smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
}
}
const endFocus = async (moved: boolean) => (options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing);
this.props.focus(this.rootDoc, {
- willZoom: options?.willZoom,
- scale: options?.scale,
+ ...options,
afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
});
};
@@ -274,7 +265,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
removeDocument={this.props.removeDocument}
contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
+ addDocTab={this.props.addDocTab}
bringToFront={returnFalse}
scriptContext={this.props.scriptContext}
pinToPres={this.props.pinToPres}
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 4489601db..ba90ed8cd 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -1,33 +1,37 @@
-import { action, computed, IReactionDisposer, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, HeightSym, WidthSym } from "../../../fields/Doc";
-import { NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils";
-import { DocUtils } from "../../documents/Documents";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import "./CollectionPileView.scss";
-import { CollectionSubView } from "./CollectionSubView";
-import React = require("react");
-import { ScriptField } from "../../../fields/ScriptField";
+import { action, computed, IReactionDisposer, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { NumCast, StrCast } from '../../../fields/Types';
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
+import { DocUtils } from '../../documents/Documents';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+import './CollectionPileView.scss';
+import { CollectionSubView } from './CollectionSubView';
+import React = require('react');
+import { ScriptField } from '../../../fields/ScriptField';
+import { OpenWhere } from '../nodes/DocumentView';
+import { computePassLayout, computeStarburstLayout } from './collectionFreeForm';
@observer
export class CollectionPileView extends CollectionSubView() {
- _originalChrome: any = "";
+ _originalChrome: any = '';
_disposers: { [name: string]: IReactionDisposer } = {};
componentDidMount() {
- if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") {
- this.Document._pileLayoutEngine = "pass";
+ if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) {
+ this.Document._pileLayoutEngine = computePassLayout.name;
}
this._originalChrome = this.layoutDoc._chromeHidden;
this.layoutDoc._chromeHidden = true;
- // pileups are designed to go away when they are empty.
- this._disposers.selected = reaction(() => this.childDocs.length,
- (num) => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document));
+ // pileups are designed to go away when they are empty.
+ this._disposers.selected = reaction(
+ () => this.childDocs.length,
+ num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document)
+ );
}
componentWillUnmount() {
this.layoutDoc._chromeHidden = this._originalChrome;
@@ -38,37 +42,41 @@ export class CollectionPileView extends CollectionSubView() {
@undoBatch
addPileDoc = (doc: Doc | Doc[]) => {
- (doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d));
+ (doc instanceof Doc ? [doc] : doc).map(d => DocUtils.iconify(d));
return this.props.addDocument?.(doc) || false;
- }
+ };
@undoBatch
removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
- (doc instanceof Doc ? [doc] : doc).map(undoBatch((d) => Doc.deiconifyView(d)));
+ (doc instanceof Doc ? [doc] : doc).map(undoBatch(d => Doc.deiconifyView(d)));
return this.props.moveDocument?.(doc, targetCollection, addDoc) || false;
- }
+ };
toggleIcon = () => {
- return ScriptField.MakeScript("documentView.iconify()", { documentView: "any" });
- }
+ return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' });
+ };
// returns the contents of the pileup in a CollectionFreeFormView
@computed get contents() {
- const isStarburst = this.layoutEngine() === "starburst";
- return <div className="collectionPileView-innards"
- style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : "none" }} >
- <CollectionFreeFormView {...this.props}
- layoutEngine={this.layoutEngine}
- childDocumentsActive={isStarburst ? returnTrue : undefined}
- addDocument={this.addPileDoc}
- childClickScript={this.toggleIcon()}
- moveDocument={this.removePileDoc} />
- </div>;
+ const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
+ return (
+ <div className="collectionPileView-innards" style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : 'none' }}>
+ <CollectionFreeFormView
+ {...this.props}
+ layoutEngine={this.layoutEngine}
+ childDocumentsActive={isStarburst ? returnTrue : undefined}
+ addDocument={this.addPileDoc}
+ childCanEmbedOnDrag={true}
+ childClickScript={this.toggleIcon()}
+ moveDocument={this.removePileDoc}
+ />
+ </div>
+ );
}
// toggles the pileup between starburst to compact
toggleStarburst = action(() => {
- if (this.layoutEngine() === 'starburst') {
+ if (this.layoutEngine() === computeStarburstLayout.name) {
const defaultSize = 110;
this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
@@ -77,12 +85,12 @@ export class CollectionPileView extends CollectionSubView() {
DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
this.layoutDoc._panX = 0;
this.layoutDoc._panY = -10;
- this.props.Document._pileLayoutEngine = 'pass';
+ this.props.Document._pileLayoutEngine = computePassLayout.name;
} else {
const defaultSize = 25;
!this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 250);
!this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5);
- if (this.layoutEngine() === 'pass') {
+ if (this.layoutEngine() === computePassLayout.name) {
this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2;
this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2;
this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym]();
@@ -90,7 +98,7 @@ export class CollectionPileView extends CollectionSubView() {
}
this.layoutDoc._panX = this.layoutDoc._panY = 0;
this.layoutDoc._width = this.layoutDoc._height = defaultSize;
- this.props.Document._pileLayoutEngine = 'starburst';
+ this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
}
});
@@ -99,27 +107,35 @@ export class CollectionPileView extends CollectionSubView() {
pointerDown = (e: React.PointerEvent) => {
let dist = 0;
SnappingManager.SetIsDragging(true);
- setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
- if (this.layoutEngine() === "pass" && this.childDocs.length && e.shiftKey) {
- dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
- if (dist > 100) {
- if (!this._undoBatch) {
- this._undoBatch = UndoManager.StartBatch("layout pile");
+ setupMoveUpEvents(
+ this,
+ e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ if (this.layoutEngine() === 'pass' && this.childDocs.length && e.shiftKey) {
+ dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
+ if (dist > 100) {
+ if (!this._undoBatch) {
+ this._undoBatch = UndoManager.StartBatch('layout pile');
+ }
+ const doc = this.childDocs[0];
+ doc.x = e.clientX;
+ doc.y = e.clientY;
+ this.props.addDocTab(doc, OpenWhere.inParentFromScreen) && (this.props.removeDocument?.(doc) || false);
+ dist = 0;
}
- const doc = this.childDocs[0];
- doc.x = e.clientX;
- doc.y = e.clientY;
- this.props.addDocTab(doc, "inParent") && (this.props.removeDocument?.(doc) || false);
- dist = 0;
}
- }
- return false;
- }, () => {
- this._undoBatch?.end();
- this._undoBatch = undefined;
- SnappingManager.SetIsDragging(false);
- }, emptyFunction, e.shiftKey && this.layoutEngine() === "pass", this.layoutEngine() === "pass" && e.shiftKey); // this sets _doubleTap
- }
+ return false;
+ },
+ () => {
+ this._undoBatch?.end();
+ this._undoBatch = undefined;
+ SnappingManager.SetIsDragging(false);
+ },
+ emptyFunction,
+ e.shiftKey && this.layoutEngine() === computePassLayout.name,
+ this.layoutEngine() === computePassLayout.name && e.shiftKey
+ ); // this sets _doubleTap
+ };
// onClick for toggling the pileup view
@undoBatch
@@ -130,12 +146,13 @@ export class CollectionPileView extends CollectionSubView() {
this.toggleStarburst();
e.stopPropagation();
}
- }
+ };
render() {
- return <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown}
- style={{ width: this.props.PanelWidth(), height: "100%" }}>
- {this.contents}
- </div>;
+ return (
+ <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown} style={{ width: this.props.PanelWidth(), height: '100%' }}>
+ {this.contents}
+ </div>
+ );
}
}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 7bf798656..e9bf03208 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -8,6 +8,7 @@ import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { Cast, NumCast } from '../../../fields/Types';
+import { ImageField } from '../../../fields/URLField';
import { emptyFunction, formatTime, OmitKeys, returnFalse, returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -23,13 +24,10 @@ import { AudioWaveform } from '../AudioWaveform';
import { CollectionSubView } from '../collections/CollectionSubView';
import { Colors } from '../global/globalEnums';
import { LightboxView } from '../LightboxView';
-import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, DocumentViewSharedProps } from '../nodes/DocumentView';
+import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { LabelBox } from '../nodes/LabelBox';
-import './CollectionStackedTimeline.scss';
import { VideoBox } from '../nodes/VideoBox';
-import { ImageField } from '../../../fields/URLField';
-import { StyleProp } from '../StyleProvider';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import './CollectionStackedTimeline.scss';
export type CollectionStackedTimelineProps = {
Play: () => void;
@@ -610,7 +608,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
height={height}
toTimeline={this.toTimeline}
layoutDoc={this.layoutDoc}
- // isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+ isDocumentActive={this.isContentActive}
currentTimecode={this.currentTimecode}
_timeline={this._timeline}
stackedTimeline={this}
@@ -702,7 +700,7 @@ interface StackedTimelineAnchorProps {
endTag: string;
renderDepth: number;
layoutDoc: Doc;
- isDocumentActive?: () => boolean;
+ isDocumentActive?: () => boolean | undefined;
ScreenToLocalTransform: () => Transform;
_timeline: HTMLDivElement | null;
focus: DocFocusFunc;
@@ -748,7 +746,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
time < NumCast(this.props.mark[this.props.endTag]) &&
this._lastTimecode < NumCast(this.props.mark[this.props.startTag]) - 1e-5
) {
- LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false, true);
+ LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false);
}
this._lastTimecode = time;
}
@@ -806,25 +804,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
return [resetTitle];
};
- innerStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
- if (property === StyleProp.Decorations && doc && NumCast(doc.timecodeToHide) - NumCast(doc.timecodeToShow) < 0.0002) {
- return (
- <div className="styleProvider-lock">
- <FontAwesomeIcon
- icon={'camera'}
- style={{ color: 'red' }}
- onClick={e => {
- LinkFollower.FollowLink(undefined, doc, props as DocumentViewSharedProps, e.altKey);
- e.stopPropagation();
- }}
- size="lg"
- />
- </div>
- );
- }
- return this.props.styleProvider?.(doc, props, property);
- };
-
// renders anchor LabelBox
renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
const anchor = observable({ view: undefined as any });
@@ -841,7 +820,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
ref={action((r: DocumentView | null) => (anchor.view = r))}
Document={mark}
DataDoc={undefined}
- styleProvider={this.innerStyleProvider}
+ styleProvider={this.props.styleProvider}
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={undefined}
LayoutTemplateString={LabelBox.LayoutStringWithTitle('data', this.computeTitle())}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 175051d5c..acf59b5da 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -22,7 +22,7 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
import { LightboxView } from '../LightboxView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
-import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
@@ -241,16 +241,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
}
- addDocTab = (doc: Doc, where: string) => {
- if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
- return true;
- }
- return this.props.addDocTab(doc, where);
- };
-
scrollToBottom = () => {
- smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight);
+ smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight, 'ease');
};
// let's dive in and get the actual document we want to drag/move around
@@ -263,13 +255,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
if (Math.floor(localTop[1]) !== 0) {
- smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
}
}
const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
this.props.focus(this.rootDoc, {
- willZoom: options?.willZoom,
- scale: options?.scale,
+ ...options,
afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
});
};
@@ -361,7 +352,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
removeDocument={this.props.removeDocument}
contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
+ addDocTab={this.props.addDocTab}
bringToFront={returnFalse}
scriptContext={this.props.scriptContext}
pinToPres={this.props.pinToPres}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7bc273d7d..d2074219a 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -111,7 +111,7 @@ export function CollectionSubView<X>(moreProps?: X) {
rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : [];
}
- const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate).map(d => d as Doc);
+ const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.unrendered)).map(d => d as Doc);
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
@@ -172,8 +172,6 @@ export function CollectionSubView<X>(moreProps?: X) {
// The following conditional detects a recurring bug we've seen on the server
if (proto[Id] === Docs.Prototypes.get(DocumentType.COL)[Id]) {
alert('COLLECTION PROTO CURSOR ISSUE DETECTED! Check console for more info...');
- console.log(doc);
- console.log(proto);
throw new Error(`AHA! You were trying to set a cursor on a collection's proto, which is the original collection proto! Look at the two previously printed lines for document values!`);
}
let cursors = Cast(proto.cursors, listSpec(CursorField));
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 3dd9d2d84..a1466bcd0 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,32 +1,32 @@
-import { toUpper } from "lodash";
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, Opt, StrListCast } from "../../../fields/Doc";
-import { List } from "../../../fields/List";
-import { ObjectField } from "../../../fields/ObjectField";
-import { RichTextField } from "../../../fields/RichTextField";
-import { listSpec } from "../../../fields/Schema";
-import { ComputedField, ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentManager } from "../../util/DocumentManager";
-import { ScriptingGlobals } from "../../util/ScriptingGlobals";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { EditableView } from "../EditableView";
-import { ViewSpecPrefix } from "../nodes/DocumentView";
-import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
-import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import { CollectionSubView } from "./CollectionSubView";
-import "./CollectionTimeView.scss";
-import React = require("react");
+import { toUpper } from 'lodash';
+import { action, computed, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { RichTextField } from '../../../fields/RichTextField';
+import { listSpec } from '../../../fields/Schema';
+import { ComputedField, ScriptField } from '../../../fields/ScriptField';
+import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { EditableView } from '../EditableView';
+import { ViewSpecPrefix } from '../nodes/DocumentView';
+import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
+import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+import { CollectionSubView } from './CollectionSubView';
+import './CollectionTimeView.scss';
+import React = require('react');
@observer
export class CollectionTimeView extends CollectionSubView() {
_changing = false;
- @observable _layoutEngine = "pivot";
+ @observable _layoutEngine = computePivotLayout.name;
@observable _collapsed: boolean = false;
@observable _childClickedScript: Opt<ScriptField>;
@observable _viewDefDivClick: Opt<ScriptField>;
@@ -35,7 +35,7 @@ export class CollectionTimeView extends CollectionSubView() {
getAnchor = () => {
const anchor = Docs.Create.HTMLAnchorDocument([], {
title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any,
- annotationOn: this.rootDoc
+ annotationOn: this.rootDoc,
});
// save view spec information for anchor
@@ -43,81 +43,103 @@ export class CollectionTimeView extends CollectionSubView() {
proto.pivotField = this.pivotField;
proto.docFilters = ObjectField.MakeCopy(this.layoutDoc._docFilters as ObjectField) || new List<string>([]);
proto.docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField) || new List<string>([]);
- proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType;
+ proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType;
// store anchor in annotations list of document (not technically needed since these anchors are never drawn)
- if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) {
- Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor);
+ if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
+ Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
} else {
- this.dataDoc[this.props.fieldKey + "-annotations"] = new List<Doc>([anchor]);
+ this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
}
return anchor;
- }
+ };
async componentDidMount() {
this.props.setContentView?.(this);
//const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), "");
- ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
+ ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; useRightSplit(alias, shiftKey); ";
runInAction(() => {
- this._childClickedScript = ScriptField.MakeScript("openInLightbox(self)", { this: Doc.name });
- this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" });
+ this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name });
+ this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
});
}
- get pivotField() { return this._focusPivotField || StrCast(this.layoutDoc._pivotField); }
+ get pivotField() {
+ return this._focusPivotField || StrCast(this.layoutDoc._pivotField);
+ }
@action
setViewSpec = (anchor: Doc, preview: boolean) => {
- if (preview) { // if in preview, then override document's fields with view spec
+ if (preview) {
+ // if in preview, then override document's fields with view spec
this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters);
this._focusPivotField = StrCast(anchor.pivotField);
- } else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec
+ } else if (anchor.pivotField !== undefined) {
+ // otherwise set document's fields based on anchor view spec
this.layoutDoc._prevFilterIndex = 1;
this.layoutDoc._pivotField = StrCast(anchor.pivotField);
this.layoutDoc._docFilters = new List<string>(StrListCast(anchor.docFilters));
this.layoutDoc._docRangeFilters = new List<string>(StrListCast(anchor.docRangeFilters));
}
return 0;
- }
+ };
layoutEngine = () => this._layoutEngine;
- toggleVisibility = action(() => this._collapsed = !this._collapsed);
+ toggleVisibility = action(() => (this._collapsed = !this._collapsed));
onMinDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
- const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0));
- const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10));
- this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth();
- this.props.Document[this.props.fieldKey + "-timelineSpan"] = undefined;
- return false;
- }), returnFalse, emptyFunction);
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ action((e: PointerEvent, down: number[], delta: number[]) => {
+ const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0));
+ const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10));
+ this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth();
+ this.props.Document[this.props.fieldKey + '-timelineSpan'] = undefined;
+ return false;
+ }),
+ returnFalse,
+ emptyFunction
+ );
+ };
onMaxDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
- const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0));
- const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10));
- this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth();
- return false;
- }), returnFalse, emptyFunction);
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ action((e: PointerEvent, down: number[], delta: number[]) => {
+ const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0));
+ const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10));
+ this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth();
+ return false;
+ }),
+ returnFalse,
+ emptyFunction
+ );
+ };
onMidDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
- const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0));
- const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10));
- this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth();
- this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth();
- return false;
- }), returnFalse, emptyFunction);
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ action((e: PointerEvent, down: number[], delta: number[]) => {
+ const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0));
+ const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10));
+ this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth();
+ this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth();
+ return false;
+ }),
+ returnFalse,
+ emptyFunction
+ );
+ };
goTo = (prevFilterIndex: number) => {
- this.layoutDoc._pivotField = this.layoutDoc["_prevPivotFields" + prevFilterIndex];
- this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocFilter" + prevFilterIndex] as ObjectField);
- this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
+ this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
+ this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
+ this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
this.layoutDoc._prevFilterIndex = prevFilterIndex;
- }
+ };
@action
contentsDown = (e: React.MouseEvent) => {
@@ -127,37 +149,58 @@ export class CollectionTimeView extends CollectionSubView() {
} else {
this.layoutDoc._docFilters = new List([]);
}
- }
+ };
dontScaleFilter = (doc: Doc) => doc.type === DocumentType.RTF;
@computed get contents() {
- 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.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
- fitContentsToBox={returnTrue}
- childClickScript={this._childClickedScript}
- viewDefDivClick={this._viewDefDivClick}
- //dontScaleFilter={this.dontScaleFilter}
- layoutEngine={this.layoutEngine} />
- </div>;
+ 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.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
+ fitContentsToBox={returnTrue}
+ childClickScript={this._childClickedScript}
+ viewDefDivClick={this._viewDefDivClick}
+ //dontScaleFilter={this.dontScaleFilter}
+ layoutEngine={this.layoutEngine}
+ />
+ </div>
+ );
}
public static SyncTimelineToPresentation(doc: Doc) {
const fieldKey = Doc.LayoutFieldKey(doc);
- doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)");
+ doc[fieldKey + '-timelineCur'] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)");
}
specificMenu = (e: React.MouseEvent) => {
const layoutItems: ContextMenuProps[] = [];
const doc = this.layoutDoc;
- layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline"; }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot"; }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" });
+ layoutItems.push({
+ description: 'Force Timeline',
+ event: () => {
+ doc._forceRenderEngine = computeTimelineLayout.name;
+ },
+ icon: 'compress-arrows-alt',
+ });
+ layoutItems.push({
+ description: 'Force Pivot',
+ event: () => {
+ doc._forceRenderEngine = computePivotLayout.name;
+ },
+ icon: 'compress-arrows-alt',
+ });
+ layoutItems.push({
+ description: 'Auto Time/Pivot layout',
+ event: () => {
+ doc._forceRenderEngine = undefined;
+ },
+ icon: 'compress-arrows-alt',
+ });
+ layoutItems.push({ description: 'Sync with presentation', event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: 'compress-arrows-alt' });
- ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
- }
+ ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
+ };
@computed get _allFacets() {
const facets = new Set<string>();
this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
@@ -169,37 +212,40 @@ export class CollectionTimeView extends CollectionSubView() {
const docItems: ContextMenuProps[] = [];
const keySet: Set<string> = new Set();
- this.childLayoutPairs.map(pair => this._allFacets.filter(fieldKey =>
- pair.layout[fieldKey] instanceof RichTextField ||
- typeof (pair.layout[fieldKey]) === "number" ||
- typeof (pair.layout[fieldKey]) === "boolean" ||
- typeof (pair.layout[fieldKey]) === "string").filter(fieldKey => fieldKey[0] !== "_" && (fieldKey[0] !== "#" || fieldKey === "#") && (fieldKey === "tags" || fieldKey[0] === toUpper(fieldKey)[0])).map(fieldKey => keySet.add(fieldKey)));
- Array.from(keySet).map(fieldKey =>
- docItems.push({ description: ":" + fieldKey, event: () => this.layoutDoc._pivotField = fieldKey, icon: "compress-arrows-alt" }));
- docItems.push({ description: ":default", event: () => this.layoutDoc._pivotField = undefined, icon: "compress-arrows-alt" });
- ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" });
+ this.childLayoutPairs.map(pair =>
+ this._allFacets
+ .filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof pair.layout[fieldKey] === 'number' || typeof pair.layout[fieldKey] === 'boolean' || typeof pair.layout[fieldKey] === 'string')
+ .filter(fieldKey => fieldKey[0] !== '_' && (fieldKey[0] !== '#' || fieldKey === '#') && (fieldKey === 'tags' || fieldKey[0] === toUpper(fieldKey)[0]))
+ .map(fieldKey => keySet.add(fieldKey))
+ );
+ Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' }));
+ docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' });
+ ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' });
const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
- ContextMenu.Instance.displayMenu(x, y, ":");
- }
+ ContextMenu.Instance.displayMenu(x, y, ':');
+ };
@computed get pivotKeyUI() {
- return <div className={"pivotKeyEntry"}>
- <EditableView
- GetValue={returnEmptyString}
- SetValue={(value: any) => {
- if (value?.length) {
- this.layoutDoc._pivotField = value;
- return true;
- }
- return false;
- }}
- toggle={this.toggleVisibility}
- background={"#f1efeb"} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
- contents={":" + StrCast(this.layoutDoc._pivotField)}
- showMenuOnLoad={true}
- display={"inline"}
- menuCallback={this.menuCallback} />
- </div>;
+ return (
+ <div className={'pivotKeyEntry'}>
+ <EditableView
+ GetValue={returnEmptyString}
+ SetValue={(value: any) => {
+ if (value?.length) {
+ this.layoutDoc._pivotField = value;
+ return true;
+ }
+ return false;
+ }}
+ toggle={this.toggleVisibility}
+ background={'#f1efeb'} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+ contents={':' + StrCast(this.layoutDoc._pivotField)}
+ showMenuOnLoad={true}
+ display={'inline'}
+ menuCallback={this.menuCallback}
+ />
+ </div>
+ );
}
render() {
@@ -211,55 +257,62 @@ export class CollectionTimeView extends CollectionSubView() {
}
});
const forceLayout = StrCast(this.layoutDoc._forceRenderEngine);
- const doTimeline = forceLayout ? (forceLayout === "timeline") : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6;
- if (doTimeline !== (this._layoutEngine === "timeline")) {
+ const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6;
+ if (doTimeline !== (this._layoutEngine === computeTimelineLayout.name)) {
if (!this._changing) {
this._changing = true;
- setTimeout(action(() => {
- this._layoutEngine = doTimeline ? "timeline" : "pivot";
- this._changing = false;
- }), 0);
+ setTimeout(
+ action(() => {
+ this._layoutEngine = doTimeline ? computeTimelineLayout.name : computePivotLayout.name;
+ this._changing = false;
+ }),
+ 0
+ );
}
}
- return <div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} onContextMenu={this.specificMenu}
- style={{ width: this.props.PanelWidth(), height: "100%" }}>
- {this.pivotKeyUI}
- {this.contents}
- {!this.props.isSelected() || !doTimeline ? (null) : <>
- <div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} />
- <div className="collectionTimeView-thumb-max collectionTimeView-thumb" key="mid" onPointerDown={this.onMaxDown} />
- <div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} />
- </>}
- </div>;
+ return (
+ <div className={'collectionTimeView' + (doTimeline ? '' : '-pivot')} onContextMenu={this.specificMenu} style={{ width: this.props.PanelWidth(), height: '100%' }}>
+ {this.pivotKeyUI}
+ {this.contents}
+ {!this.props.isSelected() || !doTimeline ? null : (
+ <>
+ <div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} />
+ <div className="collectionTimeView-thumb-max collectionTimeView-thumb" key="mid" onPointerDown={this.onMaxDown} />
+ <div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} />
+ </>
+ )}
+ </div>
+ );
}
}
ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
- const pivotField = StrCast(pivotDoc._pivotField) || "author";
+ const pivotField = StrCast(pivotDoc._pivotField) || 'author';
let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField));
- pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
- pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
- pivotDoc["_prevPivotFields" + prevFilterIndex] = pivotField;
+ pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
+ pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
+ pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
pivotDoc._prevFilterIndex = ++prevFilterIndex;
pivotDoc._docFilters = new List();
- setTimeout(action(() => {
- const filterVals = (bounds.payload as string[]);
- filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, "check"));
- const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc);
- if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) {
- if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
- pivotDoc._pivotField = filterVals[0];
+ setTimeout(
+ action(() => {
+ const filterVals = bounds.payload as string[];
+ filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check'));
+ const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc);
+ if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) {
+ if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
+ pivotDoc._pivotField = filterVals[0];
+ }
}
- }
- const newFilters = StrListCast(pivotDoc._docFilters);
- if (newFilters.length && originalFilter.length &&
- newFilters.lastElement() === originalFilter.lastElement()) {
- pivotDoc._prevFilterIndex = --prevFilterIndex;
- pivotDoc["_prevDocFilter" + prevFilterIndex] = undefined;
- pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = undefined;
- pivotDoc["_prevPivotFields" + prevFilterIndex] = undefined;
- }
- }));
-}); \ No newline at end of file
+ const newFilters = StrListCast(pivotDoc._docFilters);
+ if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
+ pivotDoc._prevFilterIndex = --prevFilterIndex;
+ pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
+ pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = undefined;
+ pivotDoc['_prevPivotFields' + prevFilterIndex] = undefined;
+ }
+ })
+ );
+});
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 3785b7d61..273b08247 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -67,7 +67,8 @@
font-style: italic;
font-size: 8pt;
margin-left: 3px;
- display: none;
+ opacity: 0;
+ pointer-events: none;
}
.collectionTreeView-contents {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 0ff89c5a7..1a265af4a 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -115,7 +115,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', ''));
const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6;
this.layoutDoc._autoHeightMargins = bodyHeight;
- this.props.setHeight?.(bodyHeight + titleHeight);
+ !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight);
}
};
unobserveHeight = (ref: any) => {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 9f63a11aa..a28b1ca19 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -16,6 +16,7 @@ import { InteractionUtils } from '../../util/InteractionUtils';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
@@ -42,6 +43,7 @@ interface CollectionViewProps_ extends FieldViewProps {
layoutEngine?: () => string;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => void;
+ ignoreUnrendered?: boolean;
// property overrides for child documents
childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
@@ -54,6 +56,7 @@ interface CollectionViewProps_ extends FieldViewProps {
childHideDecorationTitle?: () => boolean;
childHideResizeHandles?: () => boolean;
childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection
+ childCanEmbedOnDrag?: boolean;
childXPadding?: number;
childYPadding?: number;
childLayoutString?: string;
@@ -173,7 +176,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
vtype => {
const newRendition = Doc.MakeAlias(this.rootDoc);
newRendition._viewType = vtype;
- this.props.addDocTab(newRendition, 'add:right');
+ this.props.addDocTab(newRendition, OpenWhere.addRight);
return newRendition;
},
false
@@ -183,17 +186,17 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
const optionItems = options && 'subitems' in options ? options.subitems : [];
!Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.rootDoc.forceActive = !this.rootDoc.forceActive), icon: 'project-diagram' }) : null;
if (this.rootDoc.childLayout instanceof Doc) {
- optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, 'add:right'), icon: 'project-diagram' });
+ optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' });
}
if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) {
- optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, 'add:right'), icon: 'project-diagram' });
+ optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
}
!Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' });
if (!Doc.noviceMode && false) {
optionItems.push({
description: 'Create Branch',
- event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), 'add:right'),
+ event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight),
icon: 'project-diagram',
});
optionItems.push({
@@ -224,7 +227,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
event: (obj: any) => {
const alias = Doc.MakeAlias(this.rootDoc);
DocUtils.makeCustomViewClicked(alias, undefined, func.key);
- this.props.addDocTab(alias, 'add:right');
+ this.props.addDocTab(alias, OpenWhere.addRight);
},
})
);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 31ed5a83b..cd58319cb 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -11,7 +11,7 @@ import { List } from '../../../fields/List';
import { FieldId } from '../../../fields/RefField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { DocUtils } from '../../documents/Documents';
@@ -26,7 +26,7 @@ import { DashboardView } from '../DashboardView';
import { Colors, Shadows } from '../global/globalEnums';
import { LightboxView } from '../LightboxView';
import { MainView } from '../MainView';
-import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
import { DashFieldView } from '../nodes/formattedText/DashFieldView';
import { PinProps, PresBox, PresMovement } from '../nodes/trails';
import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
@@ -55,6 +55,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@computed get layoutDoc() {
return this._document && Doc.Layout(this._document);
}
+ @computed get tabBorderColor() {
+ const highlight = DefaultStyleProvider(this._document, undefined, StyleProp.Highlighting);
+ if (highlight?.highlightIndex >= Doc.DocBrushStatus.highlighted) return highlight.highlightColor;
+ return 'transparent';
+ }
@computed get tabColor() {
let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor)));
if (tabColor === 'transparent') return 'black';
@@ -147,17 +152,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
ReactDOM.createRoot(closeWrap).render(closeIcon);
tab.reactComponents = [iconWrap, closeWrap];
tab.element[0].prepend(iconWrap);
- tab._disposers.layerDisposer = reaction(
- () => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
- ({ layer, color }) => {
- // console.log("TabDocView: " + this.tabColor);
- // console.log("lightOrDark: " + lightOrDark(this.tabColor));
+ tab._disposers.color = reaction(
+ () => ({ color: this.tabColor, borderColor: this.tabBorderColor }),
+ coloring => {
const textColor = lightOrDark(this.tabColor); //not working with StyleProp.Color
titleEle.style.color = textColor;
- titleEle.style.backgroundColor = 'transparent';
+ titleEle.style.backgroundColor = coloring.borderColor;
iconWrap.style.color = textColor;
closeWrap.style.color = textColor;
- tab.element[0].style.background = !layer ? color : 'dimgrey';
+ tab.element[0].style.background = coloring.color;
},
{ fireImmediately: true }
);
@@ -193,11 +196,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
() => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc),
action(selected => {
if (selected) this._activated = true;
- const toggle = tab.element[0].children[1].children[0] as HTMLInputElement;
+ const toggle = tab.element[0].children[2].children[0] as HTMLInputElement;
selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), 'tab switch');
- // toggle.style.fontWeight = selected ? "bold" : "";
+ toggle.style.fontWeight = selected ? 'bold' : '';
// toggle.style.textTransform = selected ? "uppercase" : "";
- })
+ }),
+ { fireImmediately: true }
);
// highlight the tab when the tab document is brushed in any part of the UI
@@ -226,7 +230,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
* Adds a document to the presentation view
**/
@action
- public static PinDoc(docs: Doc | Doc[], pinProps?: PinProps) {
+ public static PinDoc(docs: Doc | Doc[], pinProps: PinProps) {
const docList = docs instanceof Doc ? [docs] : docs;
const batch = UndoManager.StartBatch('pinning doc');
@@ -243,8 +247,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
alert('Cannot pin presentation document to itself');
return;
}
- const pinDoc = Doc.MakeAlias(doc);
- pinDoc.presentationTargetDoc = doc;
+ const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.();
+ const pinDoc = Doc.MakeAlias(anchorDoc ?? doc);
+ pinDoc.presentationTargetDoc = anchorDoc ?? doc;
pinDoc.title = doc.title + ' - Slide';
pinDoc.data = new List<Doc>(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
@@ -268,7 +273,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.presStartTime = NumCast(doc.clipStart);
pinDoc.presEndTime = NumCast(doc.clipEnd, duration);
}
- PresBox.pinDocView(pinDoc, pinProps, doc);
+ PresBox.pinDocView(pinDoc, pinProps.pinDocContent ? { ...pinProps, pinData: PresBox.pinDataTypes(doc) } : pinProps, doc);
pinDoc.onClick = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)');
Doc.AddDocToList(curPres, 'data', pinDoc, presSelected);
//save position
@@ -277,6 +282,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.title = doc.title + ' (move)';
pinDoc.presMovement = PresMovement.Pan;
}
+ if (pinProps?.currentFrame !== undefined) {
+ pinDoc.presCurrentFrame = pinProps?.currentFrame;
+ pinDoc.title = doc.title + ' (move)';
+ pinDoc.presMovement = PresMovement.Pan;
+ }
if (pinDoc.isInkMask) {
pinDoc.presHideAfter = true;
pinDoc.presHideBefore = true;
@@ -293,8 +303,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
) {
const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []);
if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
- CollectionDockingView.AddSplit(curPres, 'right');
- setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
+ CollectionDockingView.AddSplit(curPres, OpenWhereMod.right);
+ setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), { willPan: true }, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
}
setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
@@ -340,31 +350,21 @@ export class TabDocView extends React.Component<TabDocViewProps> {
// "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name,
// "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
// inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
- addDocTab = (doc: Doc, location: string) => {
+ addDocTab = (doc: Doc, location: OpenWhere) => {
SelectionManager.DeselectAll();
- const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':');
- const locationParams = locationFields.length > 1 ? locationFields[1] : '';
- switch (locationFields[0]) {
- case 'dashboard':
- return DashboardView.openDashboard(doc);
- case 'close':
- return CollectionDockingView.CloseSplit(doc, locationParams);
- case 'fullScreen':
- return CollectionDockingView.OpenFullScreen(doc);
- case 'replace':
- return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
- // case "lightbox": {
- // // TabDocView.PinDoc(doc, { hidePresBox: true });
- // return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab);
- // }
- case 'lightbox':
- return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab);
- case 'toggle':
- return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack);
- case 'inPlace':
- case 'add':
- default:
- return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
+ const whereFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':');
+ const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none;
+ if (doc.dockingConfig) return DashboardView.openDashboard(doc);
+ // prettier-ignore
+ switch (whereFields[0]) {
+ case OpenWhere.inPlace: // fall through to lightbox
+ case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab);
+ case OpenWhere.dashboard: return DashboardView.openDashboard(doc);
+ case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc);
+ case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods);
+ case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack);
+ case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack);
+ case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, this.stack);
}
};
remDocTab = (doc: Doc | Doc[]) => {
@@ -382,17 +382,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@action
focusFunc = (doc: Doc, options: DocFocusOptions) => {
const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap;
- if (options?.willZoom !== false && shrinkwrap && this._document) {
- const focusSpeed = NumCast(this._document.focusSpeed, 500);
+ if (options?.willPanZoom !== false && shrinkwrap && this._document) {
+ const focusSpeed = options.zoomTime ?? 500;
shrinkwrap();
- this._document._viewTransition = `transform ${focusSpeed}ms`;
- setTimeout(
- action(() => {
- this._document!._viewTransition = undefined;
- options?.afterFocus?.(false);
- }),
- focusSpeed
- );
+ this._view?.setViewTransition('transform', focusSpeed, () => options?.afterFocus?.(false));
} else {
options?.afterFocus?.(false);
}
@@ -501,7 +494,7 @@ interface TabMinimapViewProps {
document: Doc;
hideMinimap: () => boolean;
tabView: () => DocumentView | undefined;
- addDocTab: (doc: Doc, where: string) => boolean;
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean;
PanelWidth: () => number;
PanelHeight: () => number;
background: () => string;
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 83fee013a..7eab03e1d 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -173,7 +173,8 @@
.treeView-header:hover {
.collectionTreeView-keyHeader {
- display: inherit;
+ opacity: unset;
+ pointer-events: unset;
}
.treeView-openRight {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ac8562d5a..bd326f917 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -22,7 +22,7 @@ import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
import { EditableView } from '../EditableView';
import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss';
-import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
@@ -44,7 +44,7 @@ export interface TreeViewProps {
containerCollection: Doc;
renderDepth: number;
dropAction: dropActionType;
- addDocTab: (doc: Doc, where: string) => boolean;
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean;
panelWidth: () => number;
panelHeight: () => number;
addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
@@ -236,7 +236,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const bestAlias =
docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
- this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), 'lightbox');
+ this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), OpenWhere.lightbox);
}
};
@@ -416,7 +416,6 @@ export class TreeView extends React.Component<TreeViewProps> {
})()
);
};
-
@computed get expandedField() {
const ids: { [key: string]: string } = {};
const rows: JSX.Element[] = [];
@@ -428,6 +427,8 @@ export class TreeView extends React.Component<TreeViewProps> {
const contents = doc[key];
let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+ let leftOffset = observable({ width: 0 });
+ const expandedWidth = () => this.props.panelWidth() - leftOffset.width;
if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
@@ -452,7 +453,7 @@ export class TreeView extends React.Component<TreeViewProps> {
this.titleStyleProvider,
this.props.ScreenToLocalTransform,
this.props.isContentActive,
- this.props.panelWidth,
+ expandedWidth,
this.props.renderDepth,
this.props.treeViewHideHeaderFields,
[...this.props.renderedIds, doc[Id]],
@@ -483,15 +484,21 @@ export class TreeView extends React.Component<TreeViewProps> {
);
}
rows.push(
- <div style={{ display: 'flex' }} key={key}>
- <span style={{ fontWeight: 'bold' }}>{key + ':'}</span>
- &nbsp;
+ <div style={{ display: 'flex', overflow: 'auto' }} key={key}>
+ <span
+ ref={action((r: any) => {
+ if (r) leftOffset.width = r.getBoundingClientRect().width;
+ })}
+ style={{ fontWeight: 'bold' }}>
+ {key + ':'}
+ &nbsp;
+ </span>
{contentElement}
</div>
);
}
rows.push(
- <div style={{ display: 'flex' }} key={'newKeyValue'}>
+ <div style={{ display: 'flex', overflow: 'auto' }} key={'newKeyValue'}>
<EditableView
key="editableView"
contents={'+key:value'}
@@ -692,6 +699,7 @@ export class TreeView extends React.Component<TreeViewProps> {
this.treeViewOpen = true;
};
+ @observable headerEleWidth = 0;
@computed get headerElements() {
return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
<>
@@ -822,7 +830,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
return false;
};
- titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - 3 * treeBulletWidth();
+ titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - this.headerEleWidth - treeBulletWidth();
return18 = () => 18;
/**
@@ -923,7 +931,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}}>
{view}
</div>
- <div className="treeView-rightButtons">
+ <div className="treeView-rightButtons" ref={action((r: any) => r && (this.headerEleWidth = r.getBoundingClientRect().width))}>
{buttons} {/* hide and lock buttons */}
{this.headerElements}
</div>
@@ -1101,7 +1109,7 @@ export class TreeView extends React.Component<TreeViewProps> {
remove: undefined | ((doc: Doc | Doc[]) => boolean),
move: DragManager.MoveFunction,
dropAction: dropActionType,
- addDocTab: (doc: Doc, where: string) => boolean,
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean,
styleProvider: undefined | StyleProviderFunc,
screenToLocalXf: () => Transform,
isContentActive: (outsideReaction?: boolean) => boolean,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 89cc22d07..7dd9cdb8b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -46,7 +46,7 @@ export interface PoolData {
export interface ViewDefResult {
ele: JSX.Element;
bounds?: ViewDefBounds;
- inkMask?: number; //sort elements into either the mask layer (which has a mixedBlendMode appropriate for transparent masks), or the regular documents layer; -1 = no mask, 0 = mask layer but stroke is transprent (hidden), >0 = mask layer and not hidden
+ inkMask?: number; //sort elements into either the mask layer (which has a mixedBlendMode appropriate for transparent masks), or the regular documents layer; -1 = no mask, 0 = mask layer but stroke is transparent (hidden, as in during a presentation when you want to smoothly animate it into being a mask), >0 = mask layer and not hidden
}
function toLabel(target: FieldResult<Field>) {
if (typeof target === 'number' || Number(target)) {
@@ -82,7 +82,7 @@ interface PivotColumn {
filters: string[];
}
-export function computerPassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
+export function computePassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const docMap = new Map<string, PoolData>();
childPairs.forEach(({ layout, data }, i) => {
docMap.set(layout[Id], {
@@ -97,7 +97,7 @@ export function computerPassLayout(poolData: Map<string, PoolData>, pivotDoc: Do
return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
}
-export function computerStarburstLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
+export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel
const docMap = new Map<string, PoolData>();
const docSize = mustFit ? panelDim[0] * 0.33 : 75; // assume an icon sized at 75
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
index 858719a08..b44acfce8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
@@ -5,15 +5,8 @@
transition: opacity 0.5s ease-in;
fill: transparent;
}
-.collectionfreeformlinkview-linkCircle {
- stroke: rgb(0,0,0);
- opacity: 0.5;
- pointer-events: all;
- cursor: pointer;
-}
.collectionfreeformlinkview-linkText {
- stroke: rgb(0,0,0);
- opacity: 0.5;
+ stroke: rgb(0, 0, 0);
pointer-events: all;
cursor: move;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index bf9de6760..4c8c65707 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
import { Doc, Field } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
-import { Cast, NumCast } from '../../../../fields/Types';
+import { Cast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
import { LinkManager } from '../../../util/LinkManager';
import { SelectionManager } from '../../../util/SelectionManager';
@@ -44,7 +44,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
this._start = Date.now();
this._timeout && clearTimeout(this._timeout);
this._timeout = setTimeout(this.timeout, 25);
- setTimeout(this.placeAnchors);
+ setTimeout(this.placeAnchors, 10); // when docs are dragged, their transforms will update before a render has been performed. placeanchors needs to come after a render to find things in the dom. a 0 timeout will still come before the render
}),
{ fireImmediately: true }
);
@@ -117,12 +117,16 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
return false;
},
emptyFunction,
- () => {
+ action(() => {
+ SelectionManager.DeselectAll();
+ SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true);
+ LinkManager.currentLink = this.props.LinkDocs[0];
+ this.toggleProperties();
// OverlayView.Instance.addElement(
// <LinkEditor sourceDoc={this.props.A.props.Document} linkDoc={this.props.LinkDocs[0]}
// showLinks={action(() => { })}
// />, { x: 300, y: 300 });
- }
+ })
);
};
@@ -163,15 +167,16 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
@action
toggleProperties = () => {
- if (SettingsManager.propertiesWidth > 0) {
- SettingsManager.propertiesWidth = 0;
- } else {
+ if ((SettingsManager.propertiesWidth ?? 0) < 100) {
SettingsManager.propertiesWidth = 250;
}
};
+ @action
onClickLine = () => {
+ SelectionManager.DeselectAll();
SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true);
+ LinkManager.currentLink = this.props.LinkDocs[0];
this.toggleProperties();
};
@@ -201,13 +206,13 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const clipped = aclipped || bclipped;
const pt1 = [aleft + a.width / 2, atop + a.height / 2];
const pt2 = [bleft + b.width / 2, btop + b.width / 2];
- const pt1vec = [(bDocBounds.left + bDocBounds.right) / 2 - pt1[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt1[1]];
- const pt2vec = [(aDocBounds.left + aDocBounds.right) / 2 - pt2[0], (aDocBounds.top + aDocBounds.bottom) / 2 - pt2[1]];
+ const pt2vec = [(bDocBounds.left + bDocBounds.right) / 2 - pt2[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt2[1]];
+ const pt1vec = [(aDocBounds.left + aDocBounds.right) / 2 - pt1[0], (aDocBounds.top + aDocBounds.bottom) / 2 - pt1[1]];
const pt1len = Math.sqrt(pt1vec[0] * pt1vec[0] + pt1vec[1] * pt1vec[1]);
const pt2len = Math.sqrt(pt2vec[0] * pt2vec[0] + pt2vec[1] * pt2vec[1]);
const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
- const pt1norm = clipped ? [0, 0] : [(pt1vec[0] / pt1len) * ptlen, (pt1vec[1] / pt1len) * ptlen];
- const pt2norm = clipped ? [0, 0] : [(pt2vec[0] / pt2len) * ptlen, (pt2vec[1] / pt2len) * ptlen];
+ const pt1norm = clipped ? [0, 0] : [-(pt1vec[0] / pt1len) * ptlen, -(pt1vec[1] / pt1len) * ptlen];
+ const pt2norm = clipped ? [0, 0] : [-(pt2vec[0] / pt2len) * ptlen, -(pt2vec[1] / pt2len) * ptlen];
const pt1normlen = Math.sqrt(pt1norm[0] * pt1norm[0] + pt1norm[1] * pt1norm[1]) || 1;
const pt2normlen = Math.sqrt(pt2norm[0] * pt2norm[0] + pt2norm[1] * pt2norm[1]) || 1;
const pt1normalized = [pt1norm[0] / pt1normlen, pt1norm[1] / pt1normlen];
@@ -217,51 +222,82 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].linkOffsetX);
const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].linkOffsetY);
- return { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1: [pt1[0] + pt1normalized[0] * 13, pt1[1] + pt1normalized[1] * 13], pt2: [pt2[0] + pt2normalized[0] * 13, pt2[1] + pt2normalized[1] * 13] };
+ return {
+ a,
+ b,
+ pt1norm,
+ pt2norm,
+ aActive,
+ bActive,
+ textX,
+ textY,
+ pt1: [pt1[0] + pt1normalized[0] * 13, pt1[1] + pt1normalized[1] * 13],
+ pt2: [pt2[0] + pt2normalized[0] * 13, pt2[1] + pt2normalized[1] * 13],
+ };
}
render() {
if (!this.renderData) return null;
+ const link = this.props.LinkDocs[0];
const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
- LinkManager.currentLink = this.props.LinkDocs[0];
- const linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field); //get string representing relationship
+ const linkRelationship = Field.toString(link?.linkRelationship as any as Field); //get string representing relationship
const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
const linkColorList = Doc.UserDoc().linkColorList as List<string>;
const linkRelationshipSizes = Doc.UserDoc().linkRelationshipSizes as List<number>;
const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
+ const linkDescription = Field.toString(link.description as any as Field);
const linkSize = currRelationshipIndex === -1 || currRelationshipIndex >= linkRelationshipSizes.length ? -1 : linkRelationshipSizes[currRelationshipIndex];
//access stroke color using index of the relationship in the color list (default black)
- const stroke = currRelationshipIndex === -1 || currRelationshipIndex >= linkColorList.length ? 'black' : linkColorList[currRelationshipIndex];
+ const stroke = currRelationshipIndex === -1 || currRelationshipIndex >= linkColorList.length ? StrCast(link._backgroundColor, 'black') : linkColorList[currRelationshipIndex];
// const hexStroke = this.rgbToHex(stroke)
//calculate stroke width/thickness based on the relative importance of the relationshipship (i.e. how many links the relationship has)
//thickness varies linearly from 3px to 12px for increasing link count
const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
- if (this.props.LinkDocs[0].displayArrow === undefined) {
- this.props.LinkDocs[0].displayArrow = false;
+ if (link.linkDisplayArrow === undefined) {
+ link.linkDisplayArrow = false;
}
- return this.props.LinkDocs[0].opacity === 0 || !a.width || !b.width || (!this.props.LinkDocs[0].linkDisplay && !aActive && !bActive) ? null : (
+ return link.opacity === 0 || !a.width || !b.width || (!link.linkDisplay && !aActive && !bActive) ? null : (
<>
<defs>
- <marker id="arrowhead" markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
- <polygon points="0 0, 3 1.5, 0 3" fill={Colors.DARK_GRAY} />
+ <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
+ <polygon points="0 0, 3 1.5, 0 3" fill={stroke} />
</marker>
+ <filter id="outline">
+ <feMorphology in="SourceAlpha" result="expanded" operator="dilate" radius="1" />
+ <feFlood floodColor={`${Colors.DARK_GRAY}`} />
+ <feComposite in2="expanded" operator="in" />
+ <feComposite in="SourceGraphic" />
+ </filter>
+ <filter x="0" y="0" width="1" height="1" id={`${link[Id] + 'background'}`}>
+ <feFlood floodColor={`${StrCast(link._backgroundColor, 'white')}`} result="bg" />
+ <feMerge>
+ <feMergeNode in="bg" />
+ <feMergeNode in="SourceGraphic" />
+ </feMerge>
+ </filter>
</defs>
<path
+ filter={LinkManager.currentLink === link ? 'url(#outline)' : ''}
+ fill="pink"
+ stroke="antiquewhite"
+ strokeWidth="4"
className="collectionfreeformlinkview-linkLine"
- style={{ pointerEvents: 'all', opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? Colors.MEDIUM_BLUE : stroke, strokeWidth }}
+ style={{ pointerEvents: 'all', opacity: this._opacity, stroke, strokeWidth }}
onClick={this.onClickLine}
d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
- markerEnd={this.props.LinkDocs[0].displayArrow ? 'url(#arrowhead)' : ''}
+ markerEnd={link.linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
/>
- {textX === undefined ? null : (
- <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
- {Field.toString(this.props.LinkDocs[0].description as any as Field)}
+ {textX === undefined || !linkDescription ? null : (
+ <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
+ <tspan>&nbsp;</tspan>
+ <tspan dy="2">{linkDescription}</tspan>
+ <tspan dy="2">&nbsp;</tspan>
</text>
)}
</>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index b8344dc0c..420e6a318 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -2,13 +2,13 @@ import { computed } from 'mobx';
import { observer } from 'mobx-react';
import { Id } from '../../../../fields/FieldSymbols';
import { DocumentManager } from '../../../util/DocumentManager';
+import { LightboxView } from '../../LightboxView';
import './CollectionFreeFormLinksView.scss';
import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView';
import React = require('react');
-import { LightboxView } from '../../LightboxView';
@observer
-export class CollectionFreeFormLinksView extends React.Component<React.PropsWithChildren<{}>> {
+export class CollectionFreeFormLinksView extends React.Component {
@computed get uniqueConnections() {
return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews))
.filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath)))
@@ -19,7 +19,6 @@ export class CollectionFreeFormLinksView extends React.Component<React.PropsWith
return (
<div className="collectionfreeformlinksview-container">
<svg className="collectionfreeformlinksview-svgCanvas">{this.uniqueConnections}</svg>
- {this.props.children}
</div>
);
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index d80fcdfc3..7a7ae3f40 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -96,37 +96,6 @@
border-color: #69a5db;
}
-.progressivizeButton {
- position: absolute;
- display: grid;
- grid-template-columns: auto 20px auto;
- transform: translate(-105%, 0);
- align-items: center;
- border: black solid 1px;
- border-radius: 3px;
- justify-content: center;
- width: 40;
- z-index: 30000;
- height: 20;
- overflow: hidden;
- background-color: #d5dce2;
- transition: all 1s;
-
- .progressivizeButton-prev:hover {
- color: #5a9edd;
- }
-
- .progressivizeButton-frame {
- justify-self: center;
- text-align: center;
- width: 15px;
- }
-
- .progressivizeButton-next:hover {
- color: #5a9edd;
- }
-}
-
.resizable {
background: rgba(0, 0, 0, 0.2);
width: 100px;
@@ -178,25 +147,6 @@
}
}
-.progressivizeMove-frame {
- width: 20px;
- border-radius: 2px;
- z-index: 100000;
- color: white;
- text-align: center;
- background-color: #5a9edd;
- transform: translate(-110%, 110%);
-}
-
-.progressivizeButton:hover {
- box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
-
- .progressivizeButton-frame {
- background-color: #5a9edd;
- color: white;
- }
-}
-
.collectionFreeform-customText {
position: absolute;
text-align: center;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ac3777aa6..dc0eb69f3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,5 @@
import { Bezier } from 'bezier-js';
+import { Colors } from 'browndash-components';
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
@@ -37,7 +38,7 @@ import { GestureOverlay } from '../../GestureOverlay';
import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
-import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView';
import { FieldViewProps } from '../../nodes/FieldView';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { PresBox } from '../../nodes/trails/PresBox';
@@ -47,7 +48,7 @@ import { StyleProp } from '../../StyleProvider';
import { CollectionSubView } from '../CollectionSubView';
import { TreeViewType } from '../CollectionTreeView';
import { TabDocView } from '../TabDocView';
-import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines';
+import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines';
import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors';
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
@@ -71,6 +72,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return 'CollectionFreeFormView(' + this.props.Document.title?.toString() + ')';
} // this makes mobx trace() statements more descriptive
+ @observable
+ public static ShowPresPaths = false;
+
private _lastNudge: any;
private _lastX: number = 0;
private _lastY: number = 0;
@@ -105,7 +109,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
@observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables
- @observable _viewTransition: number = 0; // sets the pan/zoom transform ease time- used by nudge(), focus() etc to smoothly zoom/pan. set to 0 to use document's transition time or default of 0
+ @observable _panZoomTransition: number = 0; // sets the pan/zoom transform ease time- used by nudge(), focus() etc to smoothly zoom/pan. set to 0 to use document's transition time or default of 0
@observable _hLines: number[] | undefined;
@observable _vLines: number[] | undefined;
@observable _firstRender = true; // this turns off rendering of the collection's content so that there's instant feedback when a tab is switched of what content will be shown.
@@ -118,6 +122,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
@observable _brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 }; // highlighted region of freeform canvas used by presentations to indicate a region
+ constructor(props: any) {
+ super(props);
+ this.props.setContentView?.(this);
+ }
+
@computed get views() {
const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask !== -1 && ele.inkMask !== undefined).map(ele => ele.ele);
const renderableEles = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && (ele.inkMask === -1 || ele.inkMask === undefined)).map(ele => ele.ele);
@@ -173,6 +182,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return this.getContainerTransform().translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY).transform(this.cachedGetLocalTransform);
}
+ _keyTimer: NodeJS.Timeout | undefined;
changeKeyFrame = (back = false) => {
const currentFrame = Cast(this.Document._currentFrame, 'number', null);
if (currentFrame === undefined) {
@@ -180,14 +190,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
if (back) {
- CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
+ this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, this.childDocs.slice());
this.Document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
} else {
- CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
+ this._keyTimer = CollectionFreeFormDocumentView.updateKeyframe(this._keyTimer, this.childDocs, currentFrame || 0);
this.Document._currentFrame = Math.max(0, (currentFrame || 0) + 1);
this.Document.lastFrame = Math.max(NumCast(this.Document._currentFrame), NumCast(this.Document.lastFrame));
}
};
+ @observable _keyframeEditing = false;
+ @action setKeyFrameEditing = (set: boolean) => (this._keyframeEditing = set);
+ getKeyFrameEditing = () => this._keyframeEditing;
onBrowseClickHandler = () => this.props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick);
onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
@@ -709,6 +722,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
pan = (e: PointerEvent | React.Touch | { clientX: number; clientY: number }): void => {
+ this.props.DocumentView?.().clearViewTransition();
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
this.setPan(NumCast(this.Document._panX) - dx, NumCast(this.Document._panY) - dy, 0, true);
this._lastX = e.clientX;
@@ -792,9 +806,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
p2: { x: currPointInkSpace.X, y: currPointInkSpace.Y },
});
const intersects = Array.from(new Set(rawIntersects as (number | string)[])); // convert to more manageable union array type
- if (intersects.length) {
- console.log();
- }
// return tuples of the inkingStroke intersected, and the t value of the intersection
intersections.push(...intersects.map(t => ({ inkView, t: +t + Math.floor(i / 4) }))); // convert string t's to numbers and add start of curve segment to convert from local t value to t value along complete curve
}
@@ -1008,7 +1019,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
e.stopPropagation();
e.preventDefault();
- switch (Doc.UserDoc().freeformScrollMode) {
+ switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) {
case freeformScrollMode.Pan:
// if shift is selected then zoom
if (e.ctrlKey) {
@@ -1021,8 +1032,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
} else if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) {
// things that can scroll vertically should do that instead of zooming
} else if (this.props.isContentActive(true) && !this.Document._isGroup) {
- const dx = e.deltaX;
- const dy = e.deltaY;
+ const dx = -e.deltaX;
+ const dy = -e.deltaY;
if (e.shiftKey) {
!this.props.isAnnotationOverlayScrollable && this.scrollPan({ deltaX: dy, deltaY: 0 });
} else {
@@ -1076,7 +1087,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
}
if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) {
- this._viewTransition = panTime;
+ this._panZoomTransition = panTime;
const scale = this.getLocalTransform().inverse().Scale;
const minScale = NumCast(this.rootDoc._viewScaleMin, 1);
const minPanX = NumCast(this.rootDoc._panXMin, 0);
@@ -1095,7 +1106,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.setPan(NumCast(this.layoutDoc._panX) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), NumCast(this.layoutDoc._panY) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), nudgeTime, true);
this._lastNudge && clearTimeout(this._lastNudge);
this._lastNudge = setTimeout(
- action(() => (this._viewTransition = 0)),
+ action(() => (this._panZoomTransition = 0)),
nudgeTime
);
return true;
@@ -1124,7 +1135,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
zoomSmoothlyAboutPt(docpt: number[], scale: number, transitionTime = 500) {
if (this.Document._isGroup) return;
- this._viewTransition = transitionTime;
+ this._panZoomTransition = transitionTime;
const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
this.layoutDoc[this.scaleFieldKey] = scale;
const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
@@ -1132,9 +1143,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const newpan = this.getTransform().transformDirection(scrDelta.x, scrDelta.y);
this.layoutDoc._panX = NumCast(this.layoutDoc._panX) - newpan[0];
this.layoutDoc._panY = NumCast(this.layoutDoc._panY) - newpan[1];
- return new Promise<number>(res => setTimeout(() => res(runInAction(() => (this._viewTransition = 0))), this._viewTransition)); // set transition to be smooth, then reset
+ return new Promise<number>(res => setTimeout(() => res(runInAction(() => (this._panZoomTransition = 0))), this._panZoomTransition)); // set transition to be smooth, then reset
}
+ _focusCount = 0;
focusDocument = (doc: Doc, options: DocFocusOptions) => {
const state = HistoryUtil.getState();
@@ -1154,14 +1166,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
// SelectionManager.DeselectAll();
// }
- if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined || this.props.Document.currentTimecode !== undefined) {
+ if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined || this.props.Document.currentTimecode !== undefined || doc.type === DocumentType.MARKER) {
this.props.focus(doc, options);
} else {
const xfToCollection = options?.docTransform ?? Transform.Identity();
- const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoom ? this.Document[this.scaleFieldKey] : undefined };
+ const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willPanZoom ? this.Document[this.scaleFieldKey] : undefined };
const newState = HistoryUtil.getState();
const cantTransform = (this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc;
- const { panX, panY, scale } = cantTransform ? savedState : this.calculatePanIntoView(doc, xfToCollection, options?.willZoom ? options?.scale || 0.75 : undefined);
+ const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willPanZoom) ? savedState : this.calculatePanIntoView(doc, xfToCollection, options?.willPanZoom ? options?.zoomScale || 0.75 : undefined);
if (!cantTransform) {
// only pan and zoom to focus on a document if the document is not an annotation in an annotation overlay collection
newState.initializers![this.Document[Id]] = { panX, panY };
@@ -1169,27 +1181,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
// focus on the document in the collection
const didMove = !cantTransform && !doc.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale);
- const focusSpeed = options?.instant ? 0 : didMove ? NumCast(doc.focusSpeed, 500) : 0;
+ const focusSpeed = options?.instant ? 0 : didMove ? options.zoomTime ?? 500 : 0;
// glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
if (didMove) {
- scale && (this.Document[this.scaleFieldKey] = scale);
+ options.zoomScale && scale && (this.Document[this.scaleFieldKey] = scale);
this.setPan(panX, panY, focusSpeed, true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
}
+ const focusCount = ++this._focusCount;
const startTime = Date.now();
// focus on this collection within its parent view. the parent view after focusing determines whether to reset the view change within the collection
const endFocus = async (moved: boolean) => {
doc.hidden && Doc.UnHighlightDoc(doc);
const resetView = options?.afterFocus ? await options?.afterFocus(moved) : ViewAdjustment.doNothing;
if (resetView) {
- const restoreState = (!LightboxView.LightboxDoc || LightboxView.LightboxDoc === this.props.Document) && savedState;
+ const restoreState = savedState;
if (typeof restoreState !== 'boolean') {
this.Document._panX = restoreState.panX;
this.Document._panY = restoreState.panY;
this.Document[this.scaleFieldKey] = restoreState.scale;
}
}
- runInAction(() => (this._viewTransition = 0));
+ this._focusCount === focusCount && didMove && runInAction(() => (this._panZoomTransition = 0));
return resetView;
};
const xf = !cantTransform
@@ -1269,7 +1282,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
pointerEvents = () => {
const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
- const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
+ const pointerEvents =
+ this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
return pointerEvents;
};
getChildDocView(entry: PoolData) {
@@ -1311,6 +1325,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
docViewPath={this.props.docViewPath}
styleProvider={this.getClusterColor}
+ canEmbedOnDrag={this.props.childCanEmbedOnDrag}
dataProvider={this.childDataProvider}
sizeProvider={this.childSizeProvider}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
@@ -1324,18 +1339,26 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
/>
);
}
- addDocTab = action((doc: Doc, where: string) => {
- if (where === 'inParent') {
- (doc instanceof Doc ? [doc] : doc).forEach(doc => {
- const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
- doc.x = pt[0];
- doc.y = pt[1];
- });
- return this.props.addDocument?.(doc) || false;
- }
- if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List<Doc>(doc as any as Doc[]);
- return true;
+ addDocTab = action((doc: Doc, where: OpenWhere) => {
+ switch (where) {
+ case OpenWhere.inParent:
+ return this.props.addDocument?.(doc) || false;
+ case OpenWhere.inParentFromScreen:
+ return (
+ this.props.addDocument?.(
+ (doc instanceof Doc ? [doc] : doc).map(doc => {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ return doc;
+ })
+ ) || false
+ );
+ case OpenWhere.inPlace:
+ if (this.layoutDoc.isInPlaceContainer) {
+ this.dataDoc[this.props.fieldKey] = new List<Doc>(doc instanceof Doc ? [doc] : doc);
+ return true;
+ }
}
return this.props.addDocTab(doc, where);
});
@@ -1353,7 +1376,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
z: Cast(z, 'number'),
color: Cast(color, 'string') ? StrCast(color) : this.props.styleProvider?.(childDoc, this.props, StyleProp.Color),
backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.props.styleProvider?.(childDoc, this.props, StyleProp.BackgroundColor),
- opacity: Cast(opacity, 'number') ?? this.props.styleProvider?.(childDoc, this.props, StyleProp.Opacity),
+ opacity: this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this.props.styleProvider?.(childDoc, this.props, StyleProp.Opacity),
zIndex: Cast(zIndex, 'number'),
width: Cast(childDocLayout._width, 'number'),
height: Cast(childDocLayout._height, 'number'),
@@ -1453,10 +1476,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const newPool = new Map<string, PoolData>();
// prettier-ignore
switch (this.layoutEngine) {
- case 'pass': return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) };
- case 'timeline': return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
- case 'pivot': return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) };
- case 'starburst': return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) };
+ case computePassLayout.name : return { newPool, computedElementData: this.doEngineLayout(newPool, computePassLayout) };
+ case computeTimelineLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
+ case computePivotLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) };
+ case computeStarburstLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeStarburstLayout) };
}
return { newPool, computedElementData: this.doFreeformLayout(newPool) };
}
@@ -1496,7 +1519,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
elements.push({
ele: this.getChildDocView(entry[1]),
bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica),
- inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity) : -1,
+ inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
})
);
@@ -1526,11 +1549,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return 0;
};
+ @action
+ scrollFocus = (anchor: Doc, options: DocFocusOptions) => {
+ const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500;
+ return PresBox.restoreTargetDocView(
+ this.props.DocumentView?.(), //
+ { pinDocLayout: BoolCast(anchor.presPinDocLayout) },
+ anchor,
+ focusSpeed,
+ {
+ pannable: anchor.presPinData ? true : false,
+ }
+ )
+ ? focusSpeed
+ : undefined;
+ }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
+
getAnchor = () => {
if (this.props.Document.annotationOn) {
return this.rootDoc;
}
- const anchor = Docs.Create.TextanchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc });
+ const anchor = Docs.Create.TextanchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), presTransition: 500, annotationOn: this.rootDoc });
+ PresBox.pinDocView(anchor, { pinData: { pannable: true } }, this.rootDoc);
const proto = Doc.GetProto(anchor);
proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType;
proto.docFilters = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List<string>([]);
@@ -1545,7 +1585,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
componentDidMount() {
super.componentDidMount?.();
- this.props.setContentView?.(this);
this.props.setBrushViewer?.(this.brushView);
setTimeout(
action(() => {
@@ -1568,12 +1607,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
r: cbounds.r - p[0] + c[0],
b: cbounds.b - p[1] + c[1],
};
- this.layoutDoc._width = pbounds.r - pbounds.x;
- this.layoutDoc._height = pbounds.b - pbounds.y;
- this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2;
- this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2;
- this.layoutDoc.x = pbounds.x;
- this.layoutDoc.y = pbounds.y;
+ if (Number.isFinite(pbounds.r - pbounds.x) && Number.isFinite(pbounds.b - pbounds.y)) {
+ this.layoutDoc._width = pbounds.r - pbounds.x;
+ this.layoutDoc._height = pbounds.b - pbounds.y;
+ this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2;
+ this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2;
+ this.layoutDoc.x = pbounds.x;
+ this.layoutDoc.y = pbounds.y;
+ }
}
},
{ fireImmediately: true }
@@ -1703,7 +1744,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
doc.x = scr?.[0];
doc.y = scr?.[1];
});
- this.props.addDocTab(childDocs as any as Doc, 'inParent');
+ this.props.addDocTab(childDocs as any as Doc, OpenWhere.inParentFromScreen);
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
};
@@ -1841,6 +1882,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
DragManager.SetSnapLines(horizLines, vertLines);
};
+ incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0;
+
incrementalRender = action(() => {
if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) {
const unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id]));
@@ -1866,6 +1909,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
}
+ showPresPaths = () => (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null);
+
@computed get marqueeView() {
TraceMobx();
return (
@@ -1912,10 +1957,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
isAnnotationOverlayScrollable={this.props.isAnnotationOverlayScrollable}
transform={this.contentTransform}
zoomScaling={this.zoomScaling}
- presPaths={BoolCast(this.Document.presPathView)}
- progressivize={BoolCast(this.Document.editProgressivize)}
+ presPaths={this.showPresPaths}
presPinView={BoolCast(this.Document.presPinView)}
- transition={this._viewTransition ? `transform ${this._viewTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', null)}
+ transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', null)}
viewDefDivClick={this.props.viewDefDivClick}>
{this.children}
</CollectionFreeFormViewPannableContents>
@@ -1987,19 +2031,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
{this._firstRender ? this.placeholder : this.marqueeView}
{this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
- {
- // uncomment to show snap lines
- <div className="snapLines" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none' }}>
- <svg style={{ width: '100%', height: '100%' }}>
- {this._hLines?.map(l => (
- <line x1="0" y1={l} x2="1000" y2={l} stroke="black" />
- ))}
- {this._vLines?.map(l => (
- <line y1="0" x1={l} y2="1000" x2={l} stroke="black" />
- ))}
- </svg>
- </div>
- }
+ {/* // uncomment to show snap lines */}
+ <div className="snapLines" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none' }}>
+ <svg style={{ width: '100%', height: '100%' }}>
+ {this._hLines?.map(l => (
+ <line x1="0" y1={l} x2="1000" y2={l} stroke="black" />
+ ))}
+ {this._vLines?.map(l => (
+ <line y1="0" x1={l} y2="1000" x2={l} stroke="black" />
+ ))}
+ </svg>
+ </div>
{this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ? (
<div
@@ -2041,8 +2083,7 @@ interface CollectionFreeFormViewPannableContentsProps {
viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
transition?: string;
- presPaths?: boolean;
- progressivize?: boolean;
+ presPaths: () => JSX.Element | null;
presPinView?: boolean;
isAnnotationOverlay: boolean | undefined;
isAnnotationOverlayScrollable: boolean | undefined;
@@ -2095,42 +2136,11 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
return true;
};
- // scale: NumCast(targetDoc._viewScale),
- @computed get zoomProgressivizeContainer() {
- const activeItem = PresBox.Instance.activeItem;
- // const targetDoc = PresBox.Instance.targetDoc;
- if (activeItem && activeItem.presPinView && activeItem.id) {
- const left = NumCast(activeItem.presPinViewX);
- const top = NumCast(activeItem.presPinViewY);
- const width = 100;
- const height = 100;
- return !this.props.presPinView ? null : (
- <div key="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width, height, top, left, position: 'absolute' }}>
- <div className="resizers" key={'resizer' + activeItem.id}>
- <div className="resizer top-left" onPointerDown={this.onPointerDown} />
- <div className="resizer top-right" onPointerDown={this.onPointerDown} />
- <div className="resizer bottom-left" onPointerDown={this.onPointerDown} />
- <div className="resizer bottom-right" onPointerDown={this.onPointerDown} />
- </div>
- </div>
- );
- }
- }
-
- @computed get zoomProgressivize() {
- return PresBox.Instance?.activeItem?.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : null;
- }
-
- @computed get progressivize() {
- return PresBox.Instance && this.props.progressivize ? PresBox.Instance.progressivizeChildDocs : null;
- }
-
@computed get presPaths() {
- const presPaths = 'presPaths' + (this.props.presPaths ? '' : '-hidden');
- return !PresBox.Instance || !this.props.presPaths ? null : (
+ return !this.props.presPaths() ? null : (
<>
- <div key="presorder">{PresBox.Instance.order}</div>
- <svg key="svg" className={presPaths}>
+ <div key="presorder">{PresBox.Instance?.order}</div>
+ <svg key="svg" className="presPaths">
<defs>
<marker id="markerSquare" markerWidth="3" markerHeight="3" refX="1.5" refY="1.5" orient="auto" overflow="visible">
<rect x="0" y="0" width="3" height="3" stroke="#69a6db" strokeWidth="1" fill="white" fillOpacity="0.8" />
@@ -2142,7 +2152,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
<path d="M2,2 L2,6 L6,4 L2,2 Z" stroke="#69a6db" strokeLinejoin="round" strokeWidth="1" fill="white" fillOpacity="0.8" />
</marker>
</defs>
- {PresBox.Instance.paths}
+ {this.props.presPaths()}
</svg>
</>
);
@@ -2182,8 +2192,6 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
/>
)}
{this.presPaths}
- {this.progressivize}
- {this.zoomProgressivize}
</div>
);
}
@@ -2252,7 +2260,7 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY: number) {
SelectionManager.DeselectAll();
dv.props.focus(dv.props.Document, {
- willZoom: true,
+ willPanZoom: true,
afterFocus: async didMove => {
if (!didMove) {
const selfFfview = dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
@@ -2272,6 +2280,14 @@ ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) {
ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) {
!readOnly && (SelectionManager.Views()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true);
});
+ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) {
+ const selView = SelectionManager.Views();
+ if (readOnly) return selView[0].ComponentView?.getKeyFrameEditing?.() ? Colors.MEDIUM_BLUE : 'transparent';
+ runInAction(() => selView[0].ComponentView?.setKeyFrameEditing?.(!selView[0].ComponentView?.getKeyFrameEditing?.()));
+});
ScriptingGlobals.add(function pinWithView(readOnly: boolean, pinDocContent: boolean) {
- !readOnly && SelectionManager.Views().forEach(view => TabDocView.PinDoc(view.rootDoc, { pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) }));
+ !readOnly &&
+ SelectionManager.Views().forEach(view =>
+ TabDocView.PinDoc(view.rootDoc, { currentFrame: Cast(view.rootDoc.currentFrame, 'number', null), pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) })
+ );
});
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index a020b67cd..7c1137292 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -17,8 +17,8 @@ import { SelectionManager } from '../../../util/SelectionManager';
import { Transform } from '../../../util/Transform';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
+import { OpenWhere } from '../../nodes/DocumentView';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
-import { PresBox } from '../../nodes/trails/PresBox';
import { VideoBox } from '../../nodes/VideoBox';
import { pasteImageBitmap } from '../../nodes/WebBoxRenderer';
import { PreviewCursor } from '../../PreviewCursor';
@@ -120,7 +120,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const cm = ContextMenu.Instance;
const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
if (e.key === '?') {
- cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', useCors: true }), 'add:right'));
+ cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', useCors: true }), OpenWhere.addRight));
cm.displayMenu(this._downX, this._downY, undefined, true);
e.stopPropagation();
@@ -243,7 +243,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (!(e.nativeEvent as any).marqueeHit) {
(e.nativeEvent as any).marqueeHit = true;
// allow marquee if right click OR alt+left click OR in adding presentation slide & left key drag mode
- if (e.button === 2 || (e.button === 0 && e.altKey) || (PresBox.startMarquee && e.button === 0)) {
+ if (e.button === 2 || (e.button === 0 && e.altKey)) {
// if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) {
this.setPreviewCursor(e.clientX, e.clientY, true, false);
// (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors.
@@ -272,9 +272,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.cleanupInteractions(true); // stop listening for events if another lower-level handle (e.g. another Marquee) has stopPropagated this
}
e.altKey && e.preventDefault();
- if (PresBox.startMarquee) {
- e.stopPropagation();
- }
};
@action
@@ -295,11 +292,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
document.removeEventListener('pointerdown', hideMarquee, true);
document.removeEventListener('wheel', hideMarquee, true);
};
- if (PresBox.startMarquee) {
- this.pinWithView();
- PresBox.startMarquee = false;
- }
- if (!this._commandExecuted && Math.abs(this.Bounds.height * this.Bounds.width) > 100 && !PresBox.startMarquee) {
+ if (!this._commandExecuted && Math.abs(this.Bounds.height * this.Bounds.width) > 100) {
MarqueeOptionsMenu.Instance.createCollection = this.collection;
MarqueeOptionsMenu.Instance.delete = this.delete;
MarqueeOptionsMenu.Instance.summarize = this.summary;
@@ -540,7 +533,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.y = NumCast(d.y) - this.Bounds.top;
return d;
});
- const summary = Docs.Create.TextDocument('', { backgroundColor: '#e2ad32', x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: 'overview' });
+ const summary = Docs.Create.TextDocument('', { backgroundColor: '#e2ad32', x: this.Bounds.left, y: this.Bounds.top, followLinkToggle: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: 'overview' });
const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: 'transparent' });
DocUtils.MakeLink({ doc: summary }, { doc: portal }, 'summary of:summarized by', '');
@@ -685,7 +678,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
className="marqueeView"
style={{
overflow: StrCast(this.props.Document._overflow),
- cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible || PresBox.startMarquee ? 'crosshair' : 'pointer',
+ cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible ? 'crosshair' : 'pointer',
}}
onDragOver={e => e.preventDefault()}
onScroll={e => (e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0)}
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 9778fc4fe..a2330c6b2 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -9,7 +9,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields
import { emptyFunction, returnEmptyDoclist, returnTrue, StopEvent, Utils } from '../../../../Utils';
import { CollectionViewType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
import { Colors, Shadows } from '../../global/globalEnums';
import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
@@ -150,7 +150,7 @@ export class CollectionLinearView extends CollectionSubView() {
<span className="bottomPopup-text">
Currently playing:
{CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => (
- <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}>
+ <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, { willPanZoom: true }, undefined, [])}>
{clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '' : ',')}
</span>
))}
@@ -190,6 +190,7 @@ export class CollectionLinearView extends CollectionSubView() {
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
pinToPres={emptyFunction}
+ dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
rootSelected={this.props.isSelected}
removeDocument={this.props.removeDocument}
ScreenToLocalTransform={docXf}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 465dbfe6d..b88da5191 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -9,7 +9,7 @@ import { DragManager, dropActionType } from '../../../util/DragManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
-import { DocumentView } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
import { CollectionSubView } from '../CollectionSubView';
import './CollectionMulticolumnView.scss';
import ResizeBar from './MulticolumnResizer';
@@ -234,16 +234,9 @@ export class CollectionMulticolumnView extends CollectionSubView() {
onChildClickHandler = () => ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
- addDocTab = (doc: Doc, where: string) => {
- if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
- return true;
- }
- return this.props.addDocTab(doc, where);
- };
- isContentActive = () => this.props.isSelected() || this.props.isContentActive();
- isChildContentActive = () =>
- ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+ focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options);
+ isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
+ isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
return (
<DocumentView
@@ -267,7 +260,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
hideResizeHandles={this.props.childHideResizeHandles?.()}
hideDecorationTitle={this.props.childHideDecorationTitle?.()}
fitContentsToBox={this.props.fitContentsToBox}
- focus={this.props.focus}
+ focus={this.focusDocument}
docFilters={this.childDocFilters}
docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
@@ -278,7 +271,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
+ addDocTab={this.props.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 f8de4e5de..407deaabd 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -9,7 +9,7 @@ import { DragManager, dropActionType } from '../../../util/DragManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
-import { DocumentView } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
import { CollectionSubView } from '../CollectionSubView';
import './CollectionMultirowView.scss';
import HeightLabel from './MultirowHeightLabel';
@@ -234,16 +234,9 @@ export class CollectionMultirowView extends CollectionSubView() {
onChildClickHandler = () => ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
- addDocTab = (doc: Doc, where: string) => {
- if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
- return true;
- }
- return this.props.addDocTab(doc, where);
- };
- isContentActive = () => this.props.isSelected() || this.props.isContentActive();
- isChildContentActive = () =>
- ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+ focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options);
+ isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
+ isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
return (
<DocumentView
@@ -277,7 +270,7 @@ export class CollectionMultirowView extends CollectionSubView() {
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
+ addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}
/>
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
index fb93d8b8e..97a6c5c18 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
@@ -30,6 +30,8 @@ import { DocumentIconContainer } from '../../nodes/DocumentIcon';
import { OverlayView } from '../../OverlayView';
import { CollectionView } from '../CollectionView';
import './CollectionSchemaView.scss';
+import { OpenWhere } from '../../nodes/DocumentView';
+import { PinProps } from '../../nodes/trails';
// intialize cell properties
export interface CellProps {
@@ -46,8 +48,8 @@ export interface CellProps {
// currently unused
renderDepth: number;
// called when a button is pressed on the node itself
- addDocTab: (document: Doc, where: string) => boolean;
- pinToPres: (document: Doc) => void;
+ addDocTab: (document: Doc, where: OpenWhere) => boolean;
+ pinToPres: (document: Doc, pinProps: PinProps) => void;
moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
isFocused: boolean;
changeFocusedCellByIndex: (row: number, col: number) => void;
@@ -212,7 +214,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
// Jump to the this document
- DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc));
+ DocumentManager.Instance.jumpToDocument(this._rowDoc, { willPan: true }, emptyFunction, targetContext ? [targetContext] : [], () => this.props.setPreviewDoc(this._rowDoc));
}
};
@@ -507,7 +509,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
})}
/>
</div>
- <div onClick={() => this._doc && this.props.addDocTab(this._doc, 'add:right')} className="collectionSchemaView-cellContents-docButton">
+ <div onClick={() => this._doc && this.props.addDocTab(this._doc, OpenWhere.addRight)} className="collectionSchemaView-cellContents-docButton">
<FontAwesomeIcon icon="external-link-alt" size="lg" />
</div>
</div>
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
index f872637e5..3cb2df7d3 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
@@ -10,6 +10,7 @@ import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
+import { OpenWhere } from '../../nodes/DocumentView';
import './CollectionSchemaView.scss';
export interface MovableRowProps {
@@ -138,7 +139,7 @@ export class MovableRow extends React.Component<React.PropsWithChildren<MovableR
<div className="row-option" style={{ cursor: 'grab' }} ref={reference} onPointerDown={onItemDown}>
<FontAwesomeIcon icon="grip-vertical" size="sm" />
</div>
- <div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, 'add:right')}>
+ <div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, OpenWhere.addRight)}>
<FontAwesomeIcon icon="external-link-alt" size="sm" />
</div>
</div>
diff --git a/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx b/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
index dfeee3173..1b4fcf0a4 100644
--- a/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
@@ -23,7 +23,8 @@ import { undoBatch } from '../../../util/UndoManager';
import '../../../views/DocumentDecorations.scss';
import { ContextMenu } from '../../ContextMenu';
import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss';
-import { DocumentView } from '../../nodes/DocumentView';
+import { DocumentView, OpenWhere } from '../../nodes/DocumentView';
+import { PinProps } from '../../nodes/trails';
import { DefaultStyleProvider } from '../../StyleProvider';
import { CollectionView } from '../CollectionView';
import {
@@ -86,8 +87,8 @@ export interface SchemaTableProps {
ScreenToLocalTransform: () => Transform;
active: (outsideReaction: boolean | undefined) => boolean | undefined;
onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
- addDocTab: (document: Doc, where: string) => boolean;
- pinToPres: (document: Doc) => void;
+ addDocTab: (document: Doc, where: OpenWhere) => boolean;
+ pinToPres: (document: Doc, pinProps: PinProps) => void;
isSelected: (outsideReaction?: boolean) => boolean;
isFocused: (document: Doc, outsideReaction: boolean) => boolean;
setFocused: (document: Doc) => void;
@@ -625,7 +626,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
};
onOpenClick = () => {
- this._showDoc && this.props.addDocTab(this._showDoc, 'add:right');
+ this._showDoc && this.props.addDocTab(this._showDoc, OpenWhere.addRight);
};
getPreviewTransform = (): Transform => {