aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2020-10-01 01:47:45 +0530
committerusodhi <61431818+usodhi@users.noreply.github.com>2020-10-01 01:47:45 +0530
commit66fa81ccc29b032ce1271cc4cba210d99e0a740d (patch)
tree29aecff86bf2dc25a2dbe9e6b08b8f24ab3b2f15 /src
parent23c4f10e0bc3d7ec94a5c74df597cdddb23d1413 (diff)
parentf24477e19320ce5055fa5c5e3dd5007d590397a9 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into acls_uv
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DocumentManager.ts12
-rw-r--r--src/client/util/DragManager.ts3
-rw-r--r--src/client/views/DocumentButtonBar.tsx11
-rw-r--r--src/client/views/DocumentDecorations.tsx12
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx23
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx21
-rw-r--r--src/client/views/collections/TabDocView.tsx14
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx4
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx35
-rw-r--r--src/client/views/nodes/DocumentView.tsx24
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx2
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx4
14 files changed, 76 insertions, 93 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index d7ff03344..2ca29cb7e 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -204,15 +204,9 @@ export class DocumentManager {
};
findView(0);
}
- } else { // there's no context view so we need to create one first and try again
- createViewFunc(targetDocContext); // so first we create the target, but don't pass finished because we still need to create the target
- setTimeout(() => {
- const finalDocView = getFirstDocView(targetDoc);
- const finalDocContextView = getFirstDocView(targetDocContext);
- setTimeout(() => // if not, wait a bit to see if the context can be loaded (e.g., a PDF). wait interval heurisitic tries to guess how we're animating based on what's just become visible
- this.jumpToDocument(targetDoc, willZoom, createViewFunc, undefined, linkDoc, true, undefined, finished), // pass true this time for closeContextIfNotFound
- finalDocView ? 0 : finalDocContextView ? 250 : 2000); // so call jump to doc again and if the doc isn't found, it will be created.
- }, 0);
+ } else { // there's no context view so we need to create one first and try again when that finishes
+ createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
+ () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, undefined, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished));
}
}
}
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 0169b07fc..3a0f306f3 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -129,6 +129,7 @@ export namespace DragManager {
treeViewDoc?: Doc;
dontHideOnDrop?: boolean;
offset: number[];
+ canEmbed?: boolean;
userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys
defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action
dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move'
@@ -324,7 +325,7 @@ export namespace DragManager {
if (dragData.dropAction === "none") return;
const batch = UndoManager.StartBatch("dragging");
eles = eles.filter(e => e);
- CanEmbed = false;
+ CanEmbed = dragData.canEmbed || false;
if (!dragDiv) {
dragDiv = document.createElement("div");
dragDiv.className = "dragManager-dragDiv";
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 1c588c9b0..d8c32a919 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -282,12 +282,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const dragDocView = this.view0!;
const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- dragData.dropAction = "alias";
- DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, {
- offsetX: dragData.offset[0],
- offsetY: dragData.offset[1],
- hideSource: false
- });
+ dragData.defaultDropAction = "alias";
+ dragData.canEmbed = true;
+ DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false });
return true;
}
return false;
@@ -303,7 +300,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
Array.from(["Caption", "Title", "TitleHover"]).map(template =>
templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template] ? true : false, false as boolean)));
return !view0 ? (null) :
- <Tooltip title={<div className="dash-tooltip">CustomizeLayout</div>} open={this._tooltipOpen} onClose={action(() => this._tooltipOpen = false)} placement="bottom">
+ <Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embeddable alias</div>} open={this._tooltipOpen} onClose={action(() => this._tooltipOpen = false)} placement="bottom">
<div className="documentButtonBar-linkFlyout" ref={this._dragRef}
onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))} >
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9432d1ffb..fa7220e7d 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -119,7 +119,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
}
@action onTitleDown = (e: React.PointerEvent): void => {
- setupMoveUpEvents(this, e, this.onBackgroundMove, (e) => { }, this.onTitleClick);
+ setupMoveUpEvents(this, e, e => this.onBackgroundMove(true, e), (e) => { }, this.onTitleClick);
}
@action onTitleClick = (e: PointerEvent): void => {
!this._edtingTitle && (this._accumulatedTitle = this._titleControlString.startsWith("#") ? this.selectionTitle : this._titleControlString);
@@ -128,22 +128,26 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
onBackgroundDown = (e: React.PointerEvent): void => {
- setupMoveUpEvents(this, e, this.onBackgroundMove, (e) => { }, (e) => { });
+ setupMoveUpEvents(this, e, e => this.onBackgroundMove(false, e), (e) => { }, (e) => { });
}
@action
- onBackgroundMove = (e: PointerEvent, down: number[]): boolean => {
+ onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
const dragDocView = SelectionManager.SelectedDocuments()[0];
const dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0);
dragData.offset = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top);
dragData.moveDocument = dragDocView.props.moveDocument;
dragData.isSelectionMove = true;
+ dragData.canEmbed = dragTitle;
dragData.dropAction = dragDocView.props.dropAction;
this.Interacting = true;
this._hidden = true;
DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(dv => dv.ContentDiv!), dragData, e.x, e.y, {
- dragComplete: action(e => this._hidden = this.Interacting = false),
+ dragComplete: action(e => {
+ dragData.canEmbed && SelectionManager.DeselectAll();
+ this._hidden = this.Interacting = false;
+ }),
hideSource: true
});
return true;
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 9269e6f33..e0935285f 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -83,23 +83,22 @@ export class Timeline extends React.Component<FieldViewProps> {
}
/////////lifecycle functions////////////
+ @action
componentDidMount() {
const relativeHeight = window.innerHeight / 20; //sets height to arbitrary size, relative to innerHeight
this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //check if relHeight is less than Maxheight. Else, just set relheight to max
this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; //offset
this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; //twice the titleheight + offset
- runInAction(() => {
- if (!this.props.Document.AnimationLength) { //if animation length did not exist
- this.props.Document.AnimationLength = this._time; //set it to default time
- } else {
- this._time = NumCast(this.props.Document.AnimationLength); //else, set time to animationlength stored from before
- }
- this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); //the entire length of the timeline div (actual div part itself)
- this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; //the visible length of the timeline (the length that you current see)
- this._visibleStart = this._infoContainer.current!.scrollLeft; //where the div starts
- this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on
- this.toggleHandle();
- });
+ if (!this.props.Document.AnimationLength) { //if animation length did not exist
+ this.props.Document.AnimationLength = this._time; //set it to default time
+ } else {
+ this._time = NumCast(this.props.Document.AnimationLength); //else, set time to animationlength stored from before
+ }
+ this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); //the entire length of the timeline div (actual div part itself)
+ this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; //the visible length of the timeline (the length that you current see)
+ this._visibleStart = this._infoContainer.current!.scrollLeft; //where the div starts
+ this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on
+ this.toggleHandle();
}
componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 699a0f966..2eaa284cc 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -21,6 +21,7 @@ import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView";
import { CollectionViewType } from './CollectionView';
import { TabDocView } from './TabDocView';
import React = require("react");
+import { stat } from 'fs';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -147,6 +148,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
if (!pullSide && stack) {
stack.addChild(docContentConfig, undefined);
+ stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]);
} else {
const newItemStackConfig = { type: 'stack', content: [docContentConfig] };
const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 1ab104f6e..51d1d5559 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -431,22 +431,21 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
this.selectedDocumentView.props.addDocument?.(alias);
}
}
- private _dragRef = React.createRef<HTMLButtonElement>();
-
- @observable _aliasDown = false;
onAliasButtonDown = (e: React.PointerEvent): void => {
setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
}
@undoBatch
onAliasButtonMoved = (e: PointerEvent) => {
- if (this._dragRef.current && this.selectedDoc) {
- const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
- const [left, top] = [e.clientX, e.clientY];
+ const contentDiv = this.selectedDocumentView?.ContentDiv;
+ if (contentDiv) {
+ const dragData = new DragManager.DocumentDragData([this.selectedDocumentView!.props.Document]);
+ const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y];
dragData.defaultDropAction = "alias";
- DragManager.StartDocumentDrag([this._dragRef.current], dragData, left, top, {
- offsetX: dragData.offset[0],
- offsetY: dragData.offset[1],
+ dragData.canEmbed = true;
+ DragManager.StartDocumentDrag([contentDiv], dragData, e.clientX, e.clientY, {
+ offsetX: offset[0],
+ offsetY: offset[1],
hideSource: false
});
return true;
@@ -458,7 +457,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
get aliasButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
- <button className="antimodeMenu-button" ref={this._dragRef} onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "copy" }}>
+ <button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />
</button>
</Tooltip>;
@@ -467,7 +466,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get lightboxButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Show Lightbox of Images"}</div>} placement="top">
- <button className="antimodeMenu-button" ref={this._dragRef} onPointerDown={action(() => targetDoc._isLightboxOpen = true)} onClick={this.onAlias}>
+ <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)} onClick={this.onAlias}>
<FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
</button>
</Tooltip>;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 23e261ef6..8c1a003b9 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -355,12 +355,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
- {this._document._viewType !== CollectionViewType.Freeform || this._document.hideMinimap ? (null) : this.renderMiniMap()}
- <Tooltip 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>
- </Tooltip>
+ {this._document._viewType !== CollectionViewType.Freeform ? (null) :
+ <>{this._document.hideMinimap ? (null) : this.renderMiniMap()}
+ <Tooltip 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>
+ </Tooltip>
+ </>}
</>;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 89e0450d7..2783011cf 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -927,7 +927,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
setScaleToZoom = (doc: Doc, scale: number = 0.75) => {
- this.Document[this.scaleFieldKey] = scale * Math.min(this.props.PanelWidth() / NumCast(doc._width), this.props.PanelHeight() / NumCast(doc._height));
+ const pw = this.props.PanelWidth();
+ const ph = this.props.PanelHeight();
+ pw && ph && (this.Document[this.scaleFieldKey] = scale * Math.min(pw / NumCast(doc._width), ph / NumCast(doc._height)));
}
@computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 055cc8d26..3a8d41fef 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -2,8 +2,8 @@ import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontaw
import { Tooltip } from '@material-ui/core';
import { action, observable, runInAction } from 'mobx';
import { observer } from "mobx-react";
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { BoolCast, Cast, StrCast } from '../../../fields/Types';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { Cast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { emptyFunction, setupMoveUpEvents } from '../../../Utils';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -11,7 +11,7 @@ import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from '../../util/DragManager';
import { Hypothesis } from '../../util/HypothesisUtils';
import { LinkManager } from '../../util/LinkManager';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
import { DocumentView } from '../nodes/DocumentView';
@@ -146,31 +146,6 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
}
- public static followLinkClick = async (linkDoc: Doc, sourceDoc: Doc, destinationDoc: Doc, addDocTab: (doc: Doc, where: string) => void) => {
- const batch = UndoManager.StartBatch("follow link click");
- const dv = DocumentManager.Instance.getFirstDocumentView(destinationDoc);
- // open up target if it's not already in view ...
- const createViewFunc = (doc: Doc, followLoc: string, finished: Opt<() => void>) => {
- const targetFocusAfterDocFocus = () => {
- const where = StrCast(destinationDoc.followLinkLocation) || followLoc;
- const hackToCallFinishAfterFocus = () => {
- finished && setTimeout(finished, 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.
- return false; // we must return false here so that the zoom to the document is not reversed. If it weren't for needing to call finished(), we wouldn't need this function at all since not having it is equivalent to returning false
- };
- addDocTab(doc, where);
- dv?.props.focus(doc, BoolCast(destinationDoc.followLinkZoom, true), undefined, hackToCallFinishAfterFocus); // add the target and focus on it.
- return where !== "inPlace"; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target)
- };
- if (!destinationDoc.followLinkZoom) {
- targetFocusAfterDocFocus();
- } else {
- // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target
- dv?.props.focus(destinationDoc, BoolCast(destinationDoc.followLinkZoom, true), 1, targetFocusAfterDocFocus);
- }
- };
-
- await DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, createViewFunc, undefined, dv?.props.ContainingCollectionDoc, batch.end, undefined);
- }
@action
public static followDefault(linkDoc: Doc, sourceDoc: Doc, destinationDoc: Doc, addDocTab: (doc: Doc, where: string) => void) {
@@ -191,7 +166,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
});
}
} else {
- DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, doc => addDocTab(doc, "add:right"), false);
+ DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, addDocTab, false);
}
linkDoc.linksToAnnotation && Hypothesis.scrollToAnnotation(StrCast(linkDoc.annotationId), destinationDoc);
@@ -274,7 +249,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
<div className="destination-icon-wrapper" >
<FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" /></div>
<p className="linkMenu-destination-title"
- onPointerDown={() => LinkMenuItem.followLinkClick(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc, this.props.addDocTab)}>
+ onPointerDown={() => DocumentView.followLinkClick(this.props.linkDoc, this.props.sourceDoc, this.props.docView.props, false, false)}>
{this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? "Annotation in" : ""} {title}
</p>
</div>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d7bd75cf4..ba762d01a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -366,7 +366,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
} else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "add:right");
} else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
- this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
+ this.allLinks.length && DocumentView.followLinkClick(undefined, this.props.Document, this.props, e.shiftKey, e.altKey);
} else {
if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
@@ -384,27 +384,35 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
// follows a link - if the target is on screen, it highlights/pans to it.
// if the target isn't onscreen, then it will open up the target in a tab, on the right, or in place
// depending on the followLinkLocation property of the source (or the link itself as a fallback);
- followLinkClick = async (altKey: boolean, ctrlKey: boolean, shiftKey: boolean) => {
+ public static followLinkClick = async (linkDoc: Opt<Doc>, sourceDoc: Doc, docView: {
+ focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: DocFocusFunc) => void,
+ addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean,
+ ContainingCollectionDoc?: Doc
+ }, shiftKey: boolean, altKey: boolean) => {
const batch = UndoManager.StartBatch("follow link click");
// open up target if it's not already in view ...
const createViewFunc = (doc: Doc, followLoc: string, finished: Opt<() => void>) => {
const targetFocusAfterDocFocus = () => {
- const where = StrCast(this.Document.followLinkLocation) || followLoc;
+ const where = StrCast(sourceDoc.followLinkLocation) || followLoc;
const hackToCallFinishAfterFocus = () => {
finished && setTimeout(finished, 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.
return false; // we must return false here so that the zoom to the document is not reversed. If it weren't for needing to call finished(), we wouldn't need this function at all since not having it is equivalent to returning false
};
- this.props.addDocTab(doc, where) && this.props.focus(doc, BoolCast(this.Document.followLinkZoom, true), undefined, hackToCallFinishAfterFocus); // add the target and focus on it.
- return where !== "inPlace"; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target)
+ const addTab = docView.addDocTab(doc, where);
+ addTab && setTimeout(() => {
+ const targDocView = DocumentManager.Instance.getFirstDocumentView(doc);
+ targDocView?.props.focus(doc, BoolCast(sourceDoc.followLinkZoom, true), undefined, hackToCallFinishAfterFocus);
+ }); // add the target and focus on it.
+ return where !== "inPlace" || addTab; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target)
};
- if (!this.Document.followLinkZoom) {
+ if (!sourceDoc.followLinkZoom) {
targetFocusAfterDocFocus();
} else {
// first focus & zoom onto this (the clicked document). Then execute the function to focus on the target
- this.props.focus(this.props.Document, BoolCast(this.Document.followLinkZoom, true), 1, targetFocusAfterDocFocus);
+ docView.focus(sourceDoc, BoolCast(sourceDoc.followLinkZoom, true), 1, targetFocusAfterDocFocus);
}
};
- await DocumentManager.Instance.FollowLink(undefined, this.props.Document, createViewFunc, shiftKey, this.props.ContainingCollectionDoc, batch.end, altKey ? true : undefined);
+ await DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, createViewFunc, BoolCast(sourceDoc.followLinkZoom, true), docView.ContainingCollectionDoc, batch.end, altKey ? true : undefined);
}
handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 10b6aa02e..ec8c43ab4 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -73,7 +73,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false);
if (anchorContainerDoc && !this.layoutDoc.onClick && !this._isOpen) {
this._timeout = setTimeout(action(() => {
- DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "add:right")), false);
+ DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, (doc, where) => this.props.addDocTab(doc, where), false);
this._editing = false;
}), 300 - (Date.now() - this._lastTap));
}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 234dce374..d14157c09 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -41,7 +41,7 @@ export class LinkDocPreview extends React.Component<Props> {
async followDefault() {
DocumentLinksButton.EditLink = undefined;
LinkDocPreview.LinkInfo = undefined;
- this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "add:right"), false) : null;
+ this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, (doc, where) => this.props.addDocTab(doc, where), false) : null;
}
componentWillUnmount() { LinkDocPreview.TargetDoc = undefined; }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index e482992d6..21b5190f9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -15,9 +15,9 @@ import { DocumentType } from "../../../documents/DocumentTypes";
import { LinkManager } from "../../../util/LinkManager";
import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
-import { LinkMenuItem } from "../../linking/LinkMenuItem";
import { ContentFittingDocumentView } from "../ContentFittingDocumentView";
import { DocumentLinksButton } from "../DocumentLinksButton";
+import { DocumentView } from "../DocumentView";
import { LinkDocPreview } from "../LinkDocPreview";
import { FormattedTextBox } from "./FormattedTextBox";
import './FormattedTextBoxComment.scss';
@@ -117,7 +117,7 @@ export class FormattedTextBoxComment {
textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right");
} else {
const target = LinkManager.getOppositeAnchor(linkDoc, textBox.dataDoc);
- target && LinkMenuItem.followLinkClick(linkDoc, textBox.dataDoc, target, textBox.props.addDocTab);
+ target && DocumentView.followLinkClick(linkDoc, textBox.dataDoc, textBox.props, e.shiftKey, e.altKey);
}
}
}