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/CollectionCarousel3DView.tsx2
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx7
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx9
-rw-r--r--src/client/views/collections/CollectionMenu.tsx2
-rw-r--r--src/client/views/collections/CollectionPileView.tsx10
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss8
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx247
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx33
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx12
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx4
-rw-r--r--src/client/views/collections/CollectionView.tsx1
-rw-r--r--src/client/views/collections/SchemaTable.tsx3
-rw-r--r--src/client/views/collections/TabDocView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx13
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx12
17 files changed, 235 insertions, 137 deletions
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index c5a05da00..f0b9b5240 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -172,7 +172,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
<div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}>
{this.content}
</div>
- {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)}
+ {this.props.Document._chromeHidden ? (null) : this.buttons}
<div className="dot-bar">
{this.dots}
</div>
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 512328835..f400ac5a2 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -109,7 +109,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
render() {
return <div className="collectionCarouselView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget}>
{this.content}
- {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)}
+ {!this.props.Document._chromeHidden ? (null) : this.buttons}
</div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 57f4555a1..7e89cf55d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -188,6 +188,8 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
// if not going in a row layout, must add already existing content into column
const rowlayout = instance._goldenLayout.root.contentItems[0];
const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout);
+
+ CollectionDockingView.Instance._goldenLayout.saveScrollTops(rowlayout.element);
rowlayout.parent.replaceChild(rowlayout, newColumn);
if (pullSide === "top") {
newColumn.addChild(rowlayout, undefined, true);
@@ -196,6 +198,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
newColumn.addChild(newContentItem, undefined, true);
newColumn.addChild(rowlayout, 0, true);
}
+ CollectionDockingView.Instance._goldenLayout.restoreScrollTops(rowlayout.element);
rowlayout.config.height = 50;
newContentItem.config.height = 50;
@@ -210,8 +213,9 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
// if not going in a row layout, must add already existing content into column
const collayout = instance._goldenLayout.root.contentItems[0];
const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
- collayout.parent.replaceChild(collayout, newRow);
+ CollectionDockingView.Instance._goldenLayout.saveScrollTops(collayout.element);
+ collayout.parent.replaceChild(collayout, newRow);
if (pullSide === "left") {
newRow.addChild(collayout, undefined, true);
newRow.addChild(newContentItem, 0, true);
@@ -219,6 +223,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
newRow.addChild(newContentItem, undefined, true);
newRow.addChild(collayout, 0, true);
}
+ CollectionDockingView.Instance._goldenLayout.restoreScrollTops(collayout.element);
collayout.config.width = 50;
newContentItem.config.width = 50;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 581520619..ba701b2a4 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -26,7 +26,7 @@ interface CMVFieldRowProps {
rows: () => number;
headings: () => object[];
Document: Doc;
- chromeStatus: string;
+ chromeHidden?: boolean;
heading: string;
headingObject: SchemaHeaderField | undefined;
docList: Doc[];
@@ -190,7 +190,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@action
headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
if (e.button === 0 && !e.ctrlKey) {
- setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !this.props.chromeStatus && this.collapseSection(e));
+ setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !this.props.chromeHidden && this.collapseSection(e));
this._createAliasSelected = false;
}
}
@@ -254,8 +254,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@computed get contentLayout() {
const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
- const chromeStatus = this.props.chromeStatus;
- const showChrome = (chromeStatus !== 'view-mode' && chromeStatus);
+ const showChrome = !this.props.chromeHidden;
const stackPad = showChrome ? `0px ${this.props.parent.xMargin}px` : `${this.props.parent.yMargin}px ${this.props.parent.xMargin}px 0px ${this.props.parent.xMargin}px `;
return this.collapsed ? (null) :
<div style={{ position: "relative" }}>
@@ -288,7 +287,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}
@computed get headingView() {
- const noChrome = !this.props.chromeStatus;
+ const noChrome = this.props.chromeHidden;
const key = this.props.pivotField;
const evContents = this.heading ? this.heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
const editableHeaderView = <EditableView
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 6a9ad27c0..aaf243567 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -517,7 +517,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
</button>
</Tooltip>
{this.subChrome}
- {/* {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes} */}
+ {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
{!this._buttonizableCommands ? (null) : this.templateChrome}
</div>
</div>
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 22b5c2b2a..6f6cdd5d2 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -14,17 +14,17 @@ import React = require("react");
@observer
export class CollectionPileView extends CollectionSubView(doc => doc) {
- _originalChrome: string = "";
+ _originalChrome: any = "";
componentDidMount() {
if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") {
this.Document._pileLayoutEngine = "pass";
}
- this._originalChrome = StrCast(this.layoutDoc._chromeStatus);
- this.layoutDoc._chromeStatus = undefined;
+ this._originalChrome = this.layoutDoc._chromeHidden;
+ this.layoutDoc._chromeHidden = true;
}
componentWillUnmount() {
- this.layoutDoc._chromeStatus = this._originalChrome;
+ this.layoutDoc._chromeHidden = this._originalChrome;
}
layoutEngine = () => StrCast(this.Document._pileLayoutEngine);
@@ -119,7 +119,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
render() {
return <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown}
- style={{ width: this.props.PanelWidth(), height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
+ style={{ width: this.props.PanelWidth(), height: "100%" }}>
{this.contents}
</div>;
}
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index cc56831f3..19ad5cefa 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -58,4 +58,12 @@
left: 0;
}
}
+
+ .collectionStackedTimeline-waveform {
+ position: absolute;
+ width: 100%;
+ top: 0;
+ left: 0;
+ pointer-events: none;
+ }
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 16a1c02f7..c0cebf021 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -1,23 +1,26 @@
import React = require("react");
-import { action, computed, IReactionDisposer, observable, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
-import { Doc, Opt, DocListCast } from "../../../fields/Doc";
+import { Doc, DocListCast } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
import { listSpec, makeInterface } from "../../../fields/Schema";
import { ComputedField, ScriptField } from "../../../fields/ScriptField";
import { Cast, NumCast } from "../../../fields/Types";
-import { emptyFunction, formatTime, OmitKeys, returnFalse, setupMoveUpEvents, StopEvent } from "../../../Utils";
+import { emptyFunction, formatTime, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, StopEvent, returnTrue } from "../../../Utils";
import { Docs } from "../../documents/Documents";
+import { LinkManager } from "../../util/LinkManager";
import { Scripting } from "../../util/Scripting";
import { SelectionManager } from "../../util/SelectionManager";
+import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
+import { AudioWaveform } from "../AudioWaveform";
import { CollectionSubView } from "../collections/CollectionSubView";
-import { DocumentView, DocAfterFocusFunc } from "../nodes/DocumentView";
+import { LightboxView } from "../LightboxView";
+import { DocAfterFocusFunc, DocFocusFunc, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
import { LabelBox } from "../nodes/LabelBox";
import "./CollectionStackedTimeline.scss";
-import { Transform } from "../../util/Transform";
type PanZoomDocument = makeInterface<[]>;
const PanZoomDocument = makeInterface();
@@ -32,6 +35,7 @@ export type CollectionStackedTimelineProps = {
isChildActive: () => boolean;
startTag: string;
endTag: string;
+ mediaPath: string;
};
@observer
@@ -59,9 +63,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
super(props);
// onClick play scripts
CollectionStackedTimeline.RangeScript = CollectionStackedTimeline.RangeScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!;
- CollectionStackedTimeline.LabelScript = CollectionStackedTimeline.LabelScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!;
CollectionStackedTimeline.RangePlayScript = CollectionStackedTimeline.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!;
- CollectionStackedTimeline.LabelPlayScript = CollectionStackedTimeline.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!;
}
componentDidMount() { document.addEventListener("keydown", this.keyEvents, true); }
@@ -77,9 +79,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
}
toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.duration, screen_delta / width * this.duration));
rangeClickScript = () => CollectionStackedTimeline.RangeScript;
- labelClickScript = () => CollectionStackedTimeline.LabelScript;
rangePlayScript = () => CollectionStackedTimeline.RangePlayScript;
- labelPlayScript = () => CollectionStackedTimeline.LabelPlayScript;
// for creating key anchors with key events
@action
@@ -173,14 +173,14 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
@action
playOnClick = (anchorDoc: Doc, clientX: number) => {
- const seekTimeInSeconds = this.anchorStart(anchorDoc);
+ const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
const endTime = this.anchorEnd(anchorDoc);
- if (this.layoutDoc.autoPlay) {
+ if (this.layoutDoc.autoPlayAnchors) {
if (this.props.playing()) this.props.Pause();
else this.props.playFrom(seekTimeInSeconds, endTime);
} else {
if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) {
- if (!this.layoutDoc.autoPlay && this.props.playing()) {
+ if (!this.layoutDoc.autoPlayAnchors && this.props.playing()) {
this.props.Pause();
} else {
this.props.Play();
@@ -194,45 +194,24 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
@action
clickAnchor = (anchorDoc: Doc, clientX: number) => {
- const seekTimeInSeconds = this.anchorStart(anchorDoc);
+ if (anchorDoc.isLinkButton) LinkManager.FollowLink(undefined, anchorDoc, this.props, false);
+ const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
const endTime = this.anchorEnd(anchorDoc);
if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) {
if (this.props.playing()) this.props.Pause();
- else if (this.layoutDoc.autoPlay) this.props.Play();
- else if (!this.layoutDoc.autoPlay) {
+ else if (this.layoutDoc.autoPlayAnchors) this.props.Play();
+ else if (!this.layoutDoc.autoPlayAnchors) {
const rect = this._timeline?.getBoundingClientRect();
rect && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
} else {
- if (this.layoutDoc.autoPlay) this.props.playFrom(seekTimeInSeconds, endTime);
+ if (this.layoutDoc.autoPlayAnchors) this.props.playFrom(seekTimeInSeconds, endTime);
else this.props.setTime(seekTimeInSeconds);
}
return { select: true };
}
- // starting the drag event for anchor resizing
- onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => {
- this._timeline?.setPointerCapture(e.pointerId);
- const newTime = (e: PointerEvent) => {
- const rect = (e.target as any).getBoundingClientRect();
- return this.toTimeline(e.clientX - rect.x, rect.width);
- };
- const changeAnchor = (anchor: Doc, left: boolean, time: number) => {
- const timelineOnly = Cast(anchor[this.props.startTag], "number", null) !== undefined;
- if (timelineOnly) Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
- else left ? anchor._timecodeToShow = time : anchor._timecodeToHide = time;
- return false;
- };
- setupMoveUpEvents(this, e,
- (e) => changeAnchor(anchor, left, newTime(e)),
- (e) => {
- this.props.setTime(newTime(e));
- this._timeline?.releasePointerCapture(e.pointerId);
- },
- emptyFunction);
- }
-
// makes sure no anchors overlaps each other by setting the correct position and width
getLevel = (m: Doc, placed: { anchorStartTime: number, anchorEndTime: number, level: number }[]) => {
const timelineContentWidth = this.props.PanelWidth();
@@ -255,7 +234,154 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
return level;
}
- renderInner = computedFn(function (this: CollectionStackedTimeline, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) {
+ dictationHeight = () => this.props.PanelHeight() / 3;
+ timelineContentHeight = () => this.props.PanelHeight() * 2 / 3;
+ dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight());
+ @computed get renderDictation() {
+ const dictation = Cast(this.dataDoc[this.props.fieldKey.replace("annotations", "dictation")], Doc, null);
+ return !dictation ? (null) : <div style={{ position: "absolute", height: this.dictationHeight(), top: this.timelineContentHeight(), background: "tan" }}>
+ <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+ Document={dictation}
+ PanelHeight={this.dictationHeight}
+ isAnnotationOverlay={true}
+ select={emptyFunction}
+ scaling={returnOne}
+ xMargin={25}
+ yMargin={10}
+ ScreenToLocalTransform={this.dictationScreenToLocalTransform}
+ whenActiveChanged={emptyFunction}
+ removeDocument={returnFalse}
+ moveDocument={returnFalse}
+ addDocument={returnFalse}
+ CollectionView={undefined}
+ renderDepth={this.props.renderDepth + 1}>
+ </DocumentView>
+ </div>;
+ }
+ @computed get renderAudioWaveform() {
+ return !this.props.mediaPath ? (null) :
+ <div className="collectionStackedTimeline-waveform" >
+ <AudioWaveform
+ duration={this.duration}
+ mediaPath={this.props.mediaPath}
+ dataDoc={this.dataDoc}
+ PanelHeight={this.timelineContentHeight} />
+ </div>;
+ }
+ currentTimecode = () => this.currentTime;
+ render() {
+ const timelineContentWidth = this.props.PanelWidth();
+ const overlaps: { anchorStartTime: number, anchorEndTime: number, level: number }[] = [];
+ const drawAnchors = this.childDocs.map(anchor => ({ level: this.getLevel(anchor, overlaps), anchor }));
+ const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
+ const isActive = this.props.isChildActive() || this.props.isSelected(false);
+ return <div className="collectionStackedTimeline" ref={(timeline: HTMLDivElement | null) => this._timeline = timeline}
+ onClick={e => isActive && StopEvent(e)} onPointerDown={e => isActive && this.onPointerDownTimeline(e)}>
+ {drawAnchors.map(d => {
+ const start = this.anchorStart(d.anchor);
+ const end = this.anchorEnd(d.anchor, start + 10 / timelineContentWidth * this.duration);
+ const left = start / this.duration * timelineContentWidth;
+ const top = d.level / maxLevel * this.timelineContentHeight();
+ const timespan = end - start;
+ return this.props.Document.hideAnchors ? (null) :
+ <div className={"collectionStackedTimeline-marker-timeline"} key={d.anchor[Id]}
+ style={{ left, top, width: `${timespan / this.duration * timelineContentWidth}px`, height: `${this.timelineContentHeight() / maxLevel}px` }}
+ onClick={e => { this.props.playFrom(start, this.anchorEnd(d.anchor)); e.stopPropagation(); }} >
+ <StackedTimelineAnchor {...this.props}
+ mark={d.anchor}
+ rangeClickScript={this.rangeClickScript}
+ rangePlayScript={this.rangePlayScript}
+ left={left}
+ top={top}
+ width={timelineContentWidth * timespan / this.duration}
+ height={this.timelineContentHeight() / maxLevel}
+ toTimeline={this.toTimeline}
+ layoutDoc={this.layoutDoc}
+ currentTimecode={this.currentTimecode}
+ _timeline={this._timeline}
+ stackedTimeline={this}
+ />
+ </div>;
+ })}
+ {this.selectionContainer}
+ {this.renderAudioWaveform}
+ {this.renderDictation}
+
+ <div className="collectionStackedTimeline-current" style={{ left: `${this.currentTime / this.duration * 100}%` }} />
+ </div>;
+ }
+}
+
+interface StackedTimelineAnchorProps {
+ mark: Doc;
+ rangeClickScript: () => ScriptField;
+ rangePlayScript: () => ScriptField;
+ left: number;
+ top: number;
+ width: number;
+ height: number;
+ toTimeline: (screen_delta: number, width: number) => number;
+ playLink: (linkDoc: Doc) => void;
+ setTime: (time: number) => void;
+ isChildActive: () => boolean;
+ startTag: string;
+ endTag: string;
+ renderDepth: number;
+ layoutDoc: Doc;
+ ScreenToLocalTransform: () => Transform;
+ _timeline: HTMLDivElement | null;
+ focus: DocFocusFunc;
+ currentTimecode: () => number;
+ isSelected: (outsideReaction?: boolean) => boolean;
+ stackedTimeline: CollectionStackedTimeline;
+}
+@observer
+class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> {
+ _lastTimecode: number;
+ _disposer: IReactionDisposer | undefined;
+ constructor(props: any) {
+ super(props);
+ this._lastTimecode = this.props.currentTimecode();
+ }
+ componentDidMount() {
+ this._disposer = reaction(() => this.props.currentTimecode(),
+ (time) => {
+ const dictationDoc = Cast(this.props.layoutDoc["data-dictation"], Doc, null);
+ const isDictation = dictationDoc && DocListCast(this.props.mark.links).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc);
+ if ((isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this.props.layoutDoc)) && DocListCast(this.props.mark.links).length &&
+ time > NumCast(this.props.mark[this.props.startTag]) &&
+ time < NumCast(this.props.mark[this.props.endTag]) &&
+ this._lastTimecode < NumCast(this.props.mark[this.props.startTag])) {
+ LinkManager.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false, true);
+ }
+ this._lastTimecode = time;
+ });
+ }
+ componentWillUnmount() {
+ this._disposer?.();
+ }
+ // starting the drag event for anchor resizing
+ onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => {
+ this.props._timeline?.setPointerCapture(e.pointerId);
+ const newTime = (e: PointerEvent) => {
+ const rect = (e.target as any).getBoundingClientRect();
+ return this.props.toTimeline(e.clientX - rect.x, rect.width);
+ };
+ const changeAnchor = (anchor: Doc, left: boolean, time: number) => {
+ const timelineOnly = Cast(anchor[this.props.startTag], "number", null) !== undefined;
+ if (timelineOnly) Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
+ else left ? anchor._timecodeToShow = time : anchor._timecodeToHide = time;
+ return false;
+ };
+ setupMoveUpEvents(this, e,
+ (e) => changeAnchor(anchor, left, newTime(e)),
+ (e) => {
+ this.props.setTime(newTime(e));
+ this.props._timeline?.releasePointerCapture(e.pointerId);
+ },
+ emptyFunction);
+ }
+ renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) {
const anchor = observable({ view: undefined as any });
const focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, docTransform?: Transform) => {
this.props.playLink(mark);
@@ -276,54 +402,23 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
parentActive={out => this.props.isSelected(out) || this.props.isChildActive()}
rootSelected={returnFalse}
onClick={script}
- onDoubleClick={this.props.Document.autoPlay ? undefined : doublescript}
+ onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
ignoreAutoHeight={false}
hideResizeHandles={true}
bringToFront={emptyFunction}
- scriptContext={this} />
+ scriptContext={this.props.stackedTimeline} />
};
});
- renderAnchor = computedFn(function (this: CollectionStackedTimeline, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) {
- const inner = this.renderInner(mark, script, doublescript, x, y, width, height);
+ render() {
+ const inner = this.renderInner(this.props.mark, this.props.rangeClickScript, this.props.rangePlayScript, this.props.left, this.props.top, this.props.width, this.props.height);
return <>
{inner.view}
{!inner.anchor.view || !SelectionManager.IsSelected(inner.anchor.view) ? (null) :
<>
- <div key="left" className="collectionStackedTimeline-left-resizer" onPointerDown={e => this.onAnchorDown(e, mark, true)} />
- <div key="right" className="collectionStackedTimeline-resizer" onPointerDown={e => this.onAnchorDown(e, mark, false)} />
+ <div key="left" className="collectionStackedTimeline-left-resizer" onPointerDown={e => this.onAnchorDown(e, this.props.mark, true)} />
+ <div key="right" className="collectionStackedTimeline-resizer" onPointerDown={e => this.onAnchorDown(e, this.props.mark, false)} />
</>}
</>;
- });
-
- render() {
- const timelineContentWidth = this.props.PanelWidth();
- const timelineContentHeight = this.props.PanelHeight();
- const overlaps: { anchorStartTime: number, anchorEndTime: number, level: number }[] = [];
- const drawAnchors = this.childDocs.map(anchor => ({ level: this.getLevel(anchor, overlaps), anchor }));
- const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
- const isActive = this.props.isChildActive() || this.props.isSelected(false);
- return <div className="collectionStackedTimeline" ref={(timeline: HTMLDivElement | null) => this._timeline = timeline}
- onClick={e => isActive && StopEvent(e)} onPointerDown={e => isActive && this.onPointerDownTimeline(e)}>
- {drawAnchors.map(d => {
- const start = this.anchorStart(d.anchor);
- const end = this.anchorEnd(d.anchor, start + 10 / timelineContentWidth * this.duration);
- const left = start / this.duration * timelineContentWidth;
- const top = d.level / maxLevel * timelineContentHeight;
- const timespan = end - start;
- return this.props.Document.hideAnchors ? (null) :
- <div className={"collectionStackedTimeline-marker-timeline"} key={d.anchor[Id]}
- style={{ left, top, width: `${timespan / this.duration * timelineContentWidth}px`, height: `${timelineContentHeight / maxLevel}px` }}
- onClick={e => { this.props.playFrom(start, this.anchorEnd(d.anchor)); e.stopPropagation(); }} >
- {this.renderAnchor(d.anchor, this.rangeClickScript, this.rangePlayScript,
- left,
- top,
- timelineContentWidth * timespan / this.duration,
- timelineContentHeight / maxLevel)}
- </div>;
- })}
- {this.selectionContainer}
- <div className="collectionStackedTimeline-current" style={{ left: `${this.currentTime / this.duration * 100}%` }} />
- </div>;
}
}
Scripting.addGlobal(function formatToTime(time: number): any { return formatTime(time); }); \ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3f821bbcc..23c63561c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -36,7 +36,7 @@ type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentS
const StackingDocument = makeInterface(collectionSchema, documentSchema);
export type collectionStackingViewProps = {
- chromeStatus?: string;
+ chromeHidden?: boolean;
viewType?: CollectionViewType;
NativeWidth?: () => number;
NativeHeight?: () => number;
@@ -53,7 +53,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@observable _heightMap = new Map<string, number>();
@observable _cursor: CursorProperty = "grab";
@observable _scroll = 0; // used to force the document decoration to update when scrolling
- @computed get chromeStatus() { return this.props.chromeStatus || StrCast(this.layoutDoc._chromeStatus); }
+ @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); }
@computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); }
@computed get pivotField() { return StrCast(this.layoutDoc._pivotField); }
@computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); }
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
@computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking; }
@computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
- @computed get showAddAGroup() { return (this.pivotField && (this.chromeStatus !== 'view-mode' && this.chromeStatus)); }
+ @computed get showAddAGroup() { return this.pivotField && !this.chromeHidden; }
@computed get columnWidth() {
return Math.min(this.props.PanelWidth() - 2 * this.xMargin,
this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
@@ -223,11 +223,12 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
styleProvider={this.styleProvider}
layerProvider={this.props.layerProvider}
docViewPath={this.props.docViewPath}
+ fitWidth={this.props.childFitWidth}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
freezeDimensions={this.props.childFreezeDimensions}
- NativeWidth={this.props.childIgnoreNativeSize ? returnZero : doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
- NativeHeight={this.props.childIgnoreNativeSize ? returnZero : doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
+ NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.() || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.() || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
rootSelected={this.rootSelected}
@@ -260,13 +261,13 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const y = this._scroll; // required for document decorations to update when the text box container is scrolled
const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
// the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
- return new Transform(- translateX - (dref?.centeringX || 0), - translateY - (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
+ return new Transform(- translateX + (dref?.centeringX || 0), - translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
}
getDocWidth(d?: Doc) {
if (!d) return 0;
const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
const maxWidth = this.columnWidth / this.numGroupColumns;
- if (!this.layoutDoc._columnsFill && !childLayoutDoc._fitWidth) {
+ if (!this.layoutDoc._columnsFill && !(childLayoutDoc._fitWidth || this.props.childFitWidth?.())) {
return Math.min(d[WidthSym](), maxWidth);
}
return maxWidth;
@@ -276,8 +277,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
const maxHeight = (lim => lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1));
- const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!childLayoutDoc._fitWidth ? d[WidthSym]() : 0);
- const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!childLayoutDoc._fitWidth ? d[HeightSym]() : 0);
+ const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.()) ? d[WidthSym]() : 0);
+ const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.()) ? d[HeightSym]() : 0);
if (nw && nh) {
const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
@@ -286,7 +287,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
docWid * nh / nw);
}
const childHeight = NumCast(childLayoutDoc._height);
- const panelHeight = this.props.PanelHeight() - 2 * this.yMargin;
+ const panelHeight = (childLayoutDoc._fitWidth || this.props.childFitWidth?.()) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
return Math.min(childHeight, maxHeight, panelHeight);
}
@@ -412,7 +413,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
}
}}
addDocument={this.addDocument}
- chromeStatus={this.chromeStatus}
+ chromeHidden={this.chromeHidden}
columnHeaders={this.columnHeaders}
Document={this.props.Document}
DataDoc={this.props.DataDoc}
@@ -445,7 +446,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
return <CollectionMasonryViewFieldRow
showHandle={first}
Document={this.props.Document}
- chromeStatus={this.chromeStatus}
+ chromeHidden={this.chromeHidden}
pivotField={this.pivotField}
unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)}
observeHeight={(ref) => {
@@ -534,10 +535,6 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
ref={this.createRef}
style={{
overflowY: this.props.active() ? "auto" : "hidden",
- transform: `scale(${this.scaling}`,
- height: `${1 / this.scaling * 100}%`,
- width: `${1 / this.scaling * 100}%`,
- transformOrigin: "top left",
background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
pointerEvents: this.backgroundEvents ? "all" : undefined
}}
@@ -551,11 +548,11 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
<EditableView {...editableViewProps} />
</div>}
- {/* {!this.chromeStatus || !this.props.isSelected() ? (null) :
+ {/* {this.chromeHidden || !this.props.isSelected() ? (null) :
<Switch
onChange={this.onToggle}
onClick={this.onToggle}
- defaultChecked={this.chromeStatus !== 'view-mode'}
+ defaultChecked={true}
checkedChildren="edit"
unCheckedChildren="view"
/>} */}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 70ec1f925..bee7aeb87 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -32,7 +32,7 @@ interface CSVFieldColumnProps {
docList: Doc[];
heading: string;
pivotField: string;
- chromeStatus: string;
+ chromeHidden?: boolean;
columnHeaders: SchemaHeaderField[] | undefined;
headingObject: SchemaHeaderField | undefined;
yMargin: number;
@@ -166,7 +166,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
<div className="colorOptions">
{colors.map(col => {
const palette = PastelSchemaPalette.get(col);
- return <div className={"colorPicker" + (selected === palette ? " active" : "")} style={{ backgroundColor: palette }} onClick={() => this.changeColumnColor(palette!)} />
+ return <div className={"colorPicker" + (selected === palette ? " active" : "")}
+ style={{ backgroundColor: palette }} onClick={() => this.changeColumnColor(palette!)} />;
})}
</div>
</div>;
@@ -249,8 +250,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
style={{
marginTop: this.props.yMargin,
width: (this.props.columnWidth) /
- ((uniqueHeadings.length +
- ((this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus) ? 1 : 0)) || 1)
+ ((uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1)) || 1)
}}>
<div className={"collectionStackingView-collapseBar" + (this.props.headingObject.collapsed === true ? " active" : "")} onClick={this.collapseSection}></div>
{/* the default bucket (no key value) has a tooltip that describes what it is.
@@ -307,7 +307,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
}}>
{this.props.renderChildren(this.props.docList)}
</div>
- {(this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus && type !== DocumentType.PRES) ?
+ {!this.props.chromeHidden && type !== DocumentType.PRES ?
<div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10 }}>
<EditableView
@@ -332,7 +332,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
return (
<div className={"collectionStackingViewFieldColumn" + (SnappingManager.GetIsDragging() ? "Dragging" : "")} key={heading}
style={{
- width: `${100 / ((uniqueHeadings.length + ((this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus) ? 1 : 0)) || 1)}%`,
+ width: `${100 / (uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1) || 1)}%`,
height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined,
background: this._background
}}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 3e6deaf3a..28f4f76be 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -74,7 +74,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const { Document, DataDoc } = this.props;
const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys
- return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
+ return pair.layout && !pair.layout.hidden && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
});
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 1f6322997..0702febae 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -39,8 +39,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
getAnchor = () => {
const anchor = Docs.Create.TextanchorDocument({
title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any,
- useLinkSmallAnchor: true,
- hideLinkButton: true,
annotationOn: this.rootDoc
});
@@ -232,7 +230,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
}
return <div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} onContextMenu={this.specificMenu}
- style={{ width: this.props.PanelWidth(), height: `calc(100% - ${this.layoutDoc._chromeStatus === "enabled" ? 51 : 0}px)` }}>
+ style={{ width: this.props.PanelWidth(), height: "100%" }}>
{this.pivotKeyUI}
{this.contents}
{!this.props.isSelected() || !doTimeline ? (null) : <>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 020bb374a..1e693f594 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -73,6 +73,7 @@ export interface CollectionViewProps extends FieldViewProps {
// property overrides for child documents
children?: never | (() => JSX.Element[]) | React.ReactNode;
childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
+ childFitWidth?: () => boolean;
childOpacity?: () => number;
childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children
childHideDecorationTitle?: () => boolean;
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index d26f53e28..4005c751e 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -559,8 +559,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
{this.reactTable}
- {this.props.Document._chromeStatus ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
- : undefined}
+ {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>}
{!this._showDoc ? (null) :
<div className="collectionSchemaView-documentPreview"
style={{
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2ead98aa4..f333c4077 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -30,10 +30,9 @@ import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } fr
import { CollectionDockingView } from './CollectionDockingView';
import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { CollectionViewType } from './CollectionView';
+import { CollectionViewType, CollectionView } from './CollectionView';
import "./TabDocView.scss";
import React = require("react");
-import Color = require('color');
const _global = (window /* browser */ || global /* node */) as any;
interface TabDocViewProps {
@@ -336,7 +335,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
background={this.miniMapColor}
document={this._document}
tabView={this.tabView} />
- <Tooltip style={{ display: this._document?._viewType !== CollectionViewType.Freeform ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+ <Tooltip style={{ display: this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
<div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
<FontAwesomeIcon icon={"globe-asia"} size="lg" />
</div>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 51cb9387a..a8f5e6dd2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -40,7 +40,6 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if (SnappingManager.GetIsDragging() || !A.ContentDiv || !B.ContentDiv) return;
setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
setTimeout(action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
- if (!linkDoc.linkAutoMove) return;
const acont = A.rootDoc.type === DocumentType.LINK ? A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : [];
const bcont = B.rootDoc.type === DocumentType.LINK ? B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : [];
const adiv = acont.length ? acont[0] : A.ContentDiv;
@@ -60,8 +59,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.anchor2 as Doc)[Id])).lastElement();
if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
if (!targetAhyperlink) {
- linkDoc.anchor1_x = (apt.point.x - aleft) / awidth * 100;
- linkDoc.anchor1_y = (apt.point.y - atop) / aheight * 100;
+ if (linkDoc.linkAutoMove) {
+ linkDoc.anchor1_x = (apt.point.x - aleft) / awidth * 100;
+ linkDoc.anchor1_y = (apt.point.y - atop) / aheight * 100;
+ }
} else {
const m = targetAhyperlink.getBoundingClientRect();
const mp = A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
@@ -69,8 +70,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
linkDoc.anchor1_y = Math.min(1, mp[1] / A.props.PanelHeight()) * 100;
}
if (!targetBhyperlink) {
- linkDoc.anchor2_x = (bpt.point.x - bleft) / bwidth * 100;
- linkDoc.anchor2_y = (bpt.point.y - btop) / bheight * 100;
+ if (linkDoc.linkAutoMove) {
+ linkDoc.anchor2_x = (bpt.point.x - bleft) / bwidth * 100;
+ linkDoc.anchor2_y = (bpt.point.y - btop) / bheight * 100;
+ }
} else {
const m = targetBhyperlink.getBoundingClientRect();
const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 57dba0f75..f0d99611a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -921,7 +921,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
}
SelectionManager.DeselectAll();
- if (this.props.Document.scrollHeight) {
+ if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) {
this.props.focus(doc, options);
} else {
const xfToCollection = options?.docTransform ?? Transform.Identity();
@@ -942,7 +942,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
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
scale && (this.Document[this.scaleFieldKey] = scale);
}
- Doc.BrushDoc(doc);
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
@@ -1202,12 +1201,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
getAnchor = () => {
- const anchor = Docs.Create.TextanchorDocument({
- title: StrCast(this.layoutDoc._viewType),
- useLinkSmallAnchor: true,
- hideLinkButton: true,
- annotationOn: this.rootDoc
- });
+ const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.layoutDoc._viewType), annotationOn: 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>([]);
@@ -1245,7 +1239,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
(e as any).handlePan = true;
- if (!this.props.Document._noAutoscroll && !this.props.renderDepth && this._marqueeRef?.current) {
+ if (!this.layoutDoc._noAutoscroll && !this.props.renderDepth && this._marqueeRef?.current) {
const dragX = e.detail.clientX;
const dragY = e.detail.clientY;
const bounds = this._marqueeRef.current?.getBoundingClientRect();