aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-11-16 16:26:31 -0500
committerbobzel <zzzman@gmail.com>2022-11-16 16:26:31 -0500
commitae324ff50865929be836edf3bbf129207638a9c9 (patch)
tree6a337590344071657348264404a51e3650e693fb
parent2827ad04901e076ffa399f8b069eb64e8be64b6f (diff)
big changes to make link following use the same code as pinning docs for trails.
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/util/DocumentManager.ts30
-rw-r--r--src/client/util/LinkFollower.ts7
-rw-r--r--src/client/views/DocumentButtonBar.tsx6
-rw-r--r--src/client/views/GlobalKeyHandler.ts4
-rw-r--r--src/client/views/MarqueeAnnotator.tsx1
-rw-r--r--src/client/views/StyleProvider.tsx2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx18
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/client/views/nodes/ImageBox.tsx60
-rw-r--r--src/client/views/nodes/PDFBox.tsx16
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx131
-rw-r--r--src/client/views/pdf/Annotation.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx11
18 files changed, 178 insertions, 129 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8f45802fe..e68b9e27b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -237,6 +237,7 @@ export class DocumentOptions {
childContextMenuScripts?: List<ScriptField>;
childContextMenuLabels?: List<string>;
childContextMenuIcons?: List<string>;
+ followLinkZoom?: boolean; // whether to zoom to the target of a link
hideLinkButton?: boolean; // whether the blue link counter button should be hidden
hideDecorationTitle?: boolean;
hideOpenButton?: boolean;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 9336717c0..a60c1ed6b 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -151,6 +151,21 @@ export class DocumentManager {
return toReturn;
}
+ static playAudioAnno(doc: Doc) {
+ const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement();
+ if (anno) {
+ if (anno instanceof AudioField) {
+ new Howl({
+ src: [anno.url.href],
+ format: ['mp3'],
+ autoplay: true,
+ loop: false,
+ volume: 0.5,
+ });
+ }
+ }
+ }
+
static addView = (doc: Doc, finished?: () => void) => {
CollectionDockingView.AddSplit(doc, 'right');
finished?.();
@@ -189,20 +204,6 @@ export class DocumentManager {
} else {
finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined);
!noSelect && docView?.select(false);
- if (originatingDoc?.followLinkAudio) {
- const anno = Cast(finalTargetDoc[Doc.LayoutFieldKey(finalTargetDoc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement();
- if (anno) {
- if (anno instanceof AudioField) {
- new Howl({
- src: [anno.url.href],
- format: ['mp3'],
- autoplay: true,
- loop: false,
- volume: 0.5,
- });
- }
- }
- }
}
finished?.();
};
@@ -233,6 +234,7 @@ export class DocumentManager {
}
if (focusView) {
!noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox
+ if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc);
const doFocus = (forceDidFocus: boolean) =>
focusView.focus(originalTarget ?? targetDoc, {
originalTarget,
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index c6fc7b372..68716a207 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -6,6 +6,7 @@ import { DocumentDecorations } from '../views/DocumentDecorations';
import { LightboxView } from '../views/LightboxView';
import { DocumentViewSharedProps, ViewAdjustment } from '../views/nodes/DocumentView';
import { DocumentManager } from './DocumentManager';
+import { LinkManager } from './LinkManager';
import { UndoManager } from './UndoManager';
type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void;
@@ -25,7 +26,7 @@ export class LinkFollower {
// 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 the lightbox, or in place
// depending on the followLinkLocation property of the source (or the link itself as a fallback);
- public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, docViewProps: DocumentViewSharedProps, altKey: boolean, zoom: boolean = false) => {
+ public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, docViewProps: DocumentViewSharedProps, 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>) => {
@@ -63,7 +64,6 @@ export class LinkFollower {
linkDoc,
sourceDoc,
createViewFunc,
- BoolCast(sourceDoc.followLinkZoom, zoom),
docViewProps.ContainingCollectionDoc,
action(() => {
batch.end();
@@ -73,7 +73,7 @@ export class LinkFollower {
);
};
- public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) {
+ public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, createViewFunc: CreateViewFunc, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) {
const linkDocs = link ? [link] : DocListCast(sourceDoc.links);
const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1
const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2
@@ -96,6 +96,7 @@ export class LinkFollower {
: linkDoc.anchor1
) as Doc;
if (target) {
+ const zoom = BoolCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkZoom, false);
if (target.TourMap) {
const fieldKey = Doc.LayoutFieldKey(target);
const tour = DocListCast(target[fieldKey]).reverse();
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 794b51cc5..681349ccf 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -284,7 +284,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
.views()
.filter(v => v)
.map(dv => dv!.rootDoc);
- TabDocView.PinDoc(docs, { pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
+ TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
e.stopPropagation();
}}
/>
@@ -301,7 +301,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
.views()
.filter(v => v)
.map(dv => dv!.rootDoc);
- TabDocView.PinDoc(docs, { pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
+ TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
e.stopPropagation();
}}>
<div className="documentButtonBar-pinTypes">
@@ -488,7 +488,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
Doc.noviceMode ? null : <div className="documentButtonBar-button">{this.templateButton}</div>
/*<div className="documentButtonBar-button"> {this.metadataButton} </div> */
}
- {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
+ {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
<div className="documentButtonBar-button">{this.pinButton}</div>
<div className="documentButtonBar-button">{this.recordButton}</div>
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : <div className="documentButtonBar-button">{this.shareButton}</div>}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 5a6caf995..4890d9624 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -6,7 +6,7 @@ import { Id } from '../../fields/FieldSymbols';
import { InkTool } from '../../fields/InkField';
import { List } from '../../fields/List';
import { ScriptField } from '../../fields/ScriptField';
-import { Cast, PromiseValue } from '../../fields/Types';
+import { Cast, DocCast, PromiseValue } from '../../fields/Types';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { DocumentType } from '../documents/DocumentTypes';
@@ -245,7 +245,7 @@ export class KeyManager {
if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) {
SelectionManager.Views()[0].ComponentView?.search?.('', false, false);
} else {
- const searchBtn = Doc.MySearcher;
+ const searchBtn = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MySearcher);
if (searchBtn) {
MainView.Instance.selectMenu(searchBtn);
}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index c0dd62a05..1162cde50 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -93,6 +93,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
dragComplete: e => {
if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
e.annoDragData.linkSourceDoc.isPushpin = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
+ e.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
});
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index a04f4a4f4..8ee5ebdb6 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -236,7 +236,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
? Colors.DARK_GRAY
: Colors.LIGHT_GRAY // system docs (seen in treeView) get a grayish background
: doc.annotationOn
- ? '#00000015' // faint interior for collections on PDFs, images, etc
+ ? '#00000010' // faint interior for collections on PDFs, images, etc
: doc?._isGroup
? undefined
: Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : 'linear-gradient(#065fff, #85c1f9)'));
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 7bf798656..39ae470b6 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -748,7 +748,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;
}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1a9006356..e21649648 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -229,7 +229,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');
@@ -271,7 +271,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
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 932bd789d..8a97797c7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1530,11 +1530,27 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return 0;
};
+ @action
+ scrollFocus = (anchor: Doc, smooth: boolean) => {
+ let focusSpeed: Opt<number>;
+ PresBox.restoreTargetDocView(
+ this.rootDoc, //
+ { pinDocLayout: BoolCast(anchor.presPinDocLayout) },
+ anchor,
+ (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)),
+ {
+ pannable: anchor.presPinData ? true : false,
+ }
+ );
+ return focusSpeed;
+ }; // 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>([]);
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index d74da9748..dd03b9b99 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -103,7 +103,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
<>
<DocumentView
ref={r => {
- whichDoc !== targetDoc && r?.focus(whichDoc, {});
+ whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true });
}}
{...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
isContentActive={returnFalse}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 84cacd919..dc468cf89 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -51,7 +51,7 @@ import { LinkAnchorBox } from './LinkAnchorBox';
import { LinkDocPreview } from './LinkDocPreview';
import { RadialMenu } from './RadialMenu';
import { ScriptingBox } from './ScriptingBox';
-import { PresBox } from './trails/PresBox';
+import { PinProps, PresBox } from './trails/PresBox';
import React = require('react');
const { Howl } = require('howler');
@@ -144,7 +144,7 @@ export interface DocumentViewSharedProps {
addDocument?: (doc: Doc | Doc[]) => boolean;
removeDocument?: (doc: Doc | Doc[]) => boolean;
moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
- pinToPres: (document: Doc) => void;
+ pinToPres: (document: Doc, pinProps: PinProps) => void;
ScreenToLocalTransform: () => Transform;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
canEmbedOnDrag?: boolean;
@@ -486,7 +486,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
selected: -1,
});
// RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 });
- RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document), icon: 'map-pin', selected: -1 });
+ RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document, {}), icon: 'map-pin', selected: -1 });
RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 });
SelectionManager.DeselectAll();
@@ -545,7 +545,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
.forEach(spec => (this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec])));
// after a render the general viewSpec should have created the right _componentView, so after a timeout, call the componentview to update its specific view specs
setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false));
- const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant === false || !LinkDocPreview.LinkInfo);
+ const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant !== true && !LinkDocPreview.LinkInfo);
const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing;
this.props.focus(options?.docTransform ? anchor : this.rootDoc, {
...options,
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 76ba7765c..2e594d96a 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -30,6 +30,8 @@ import { FaceRectangles } from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import './ImageBox.scss';
import React = require('react');
+import { PresBox } from './trails';
+import { DocumentViewProps } from './DocumentView';
export const pageSchema = createSchema({
googlePhotosUrl: 'string',
@@ -49,23 +51,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return FieldView.LayoutString(ImageBox, fieldKey);
}
private _dropDisposer?: DragManager.DragDropDisposer;
- private _transitioning: any; // timer for setting view spec properties
private _disposers: { [name: string]: IReactionDisposer } = {};
private _getAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
@observable _curSuffix = '';
@observable _uploadIcon = uploadIcons.idle;
- @observable _focusViewScale: number | undefined = 1;
- @observable _focusPanX: number | undefined = 0;
- @observable _focusPanY: number | undefined = 0;
- get viewScale() {
- return this._focusViewScale || StrCast(this.layoutDoc._viewScale);
- }
- get panX() {
- return this._focusPanX || StrCast(this.layoutDoc._panX);
- }
- get panY() {
- return this._focusPanY || StrCast(this.layoutDoc._panY);
- }
protected createDropTarget = (ele: HTMLDivElement) => {
this._dropDisposer?.();
@@ -73,33 +62,30 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
};
@action
- setViewSpec = (anchor: Doc, preview: boolean) => {
- if (preview && anchor._viewScale !== undefined) {
- this._focusViewScale = Cast(anchor._viewScale, 'number', null);
- this._focusPanX = Cast(anchor._panX, 'number', null);
- this._focusPanY = Cast(anchor._panX, 'number', null);
- } else if (anchor._viewScale !== undefined) {
- const smoothTime = NumCast(anchor.viewTransitionTime);
- this.layoutDoc.viewTransition = `all ${smoothTime}ms`;
- this.layoutDoc._panX = NumCast(anchor._panX, NumCast(this.layoutDoc._panY));
- this.layoutDoc._panY = NumCast(anchor._panY, NumCast(this.layoutDoc._panX));
- this.layoutDoc._viewScale = NumCast(anchor._viewScale, NumCast(this.layoutDoc._viewScale));
- this.layoutDoc[this.fieldKey + '-useAlt'] = Cast(anchor._useAlt, 'boolean', null);
- if (anchor.type === DocumentType.MARKER) {
- this.dataDoc[this.annotationKey] = new List<Doc>(DocListCast(anchor._annotations));
- }
- clearTimeout(this._transitioning);
- this._transitioning = setTimeout(() => (this.layoutDoc.viewTransition = undefined), smoothTime);
- }
+ scrollFocus = (anchor: Doc, smooth: boolean) => {
+ let focusSpeed: Opt<number>;
+ PresBox.restoreTargetDocView(
+ this.rootDoc, //
+ { pinDocLayout: BoolCast(anchor.presPinDocLayout) },
+ anchor,
+ (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)),
+ !anchor.presPinData
+ ? {}
+ : {
+ pannable: true,
+ dataannos: anchor.presAnnotations !== undefined,
+ dataview: true,
+ }
+ );
+ return focusSpeed;
}; // 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 = () => {
const anchor =
this._getAnchor?.(this._savedAnnotations) ?? // use marquee anchor, otherwise, save zoom/pan as anchor
- Docs.Create.ImageanchorDocument({ viewTransitionTime: 1000, unrendered: true, annotationOn: this.rootDoc, _viewScale: NumCast(this.layoutDoc._viewScale, 1), _panX: NumCast(this.layoutDoc._panX), _panY: NumCast(this.layoutDoc._panY) });
+ Docs.Create.ImageanchorDocument({ presTransition: 1000, unrendered: true, annotationOn: this.rootDoc });
if (anchor) {
- anchor._useAlt = Cast(this.layoutDoc[this.fieldKey + '-useAlt'], 'boolean', null);
- anchor._annotations = new List<Doc>(DocListCast(this.dataDoc[this.annotationKey]));
+ PresBox.pinDocView(anchor, { pinData: { pannable: true, dataview: true, dataannos: true } }, this.rootDoc);
this.addDocument(anchor);
return anchor;
}
@@ -130,7 +116,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
componentWillUnmount() {
- clearTimeout(this._transitioning);
Object.values(this._disposers).forEach(disposer => disposer?.());
}
@@ -425,6 +410,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this.props.select(false);
};
savedAnnotations = () => this._savedAnnotations;
+ styleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
+ if (property === StyleProp.BoxShadow) return undefined;
+ return this.props.styleProvider?.(doc, props, property);
+ };
render() {
TraceMobx();
@@ -445,6 +434,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
renderDepth={this.props.renderDepth + 1}
fieldKey={this.annotationKey}
+ styleProvider={this.styleProvider}
CollectionView={undefined}
isAnnotationOverlay={true}
annotationLayerHostsContent={true}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index fcb3ccb07..39e323247 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -5,7 +5,7 @@ import * as Pdfjs from 'pdfjs-dist';
import 'pdfjs-dist/web/pdf_viewer.css';
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
-import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField, PdfField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils';
@@ -27,6 +27,7 @@ import { ImageBox } from './ImageBox';
import './PDFBox.scss';
import { VideoBox } from './VideoBox';
import React = require('react');
+import { PresBox } from './trails';
@observer
export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
@@ -207,16 +208,19 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1;
this._initialScrollTarget = doc;
- return this._pdfViewer?.scrollFocus(doc, smooth) ?? (didToggle ? 1 : undefined);
+ PresBox.restoreTargetDocView(this.rootDoc, {}, doc, NumCast(doc.presTransition, NumCast(doc.focusSpeed, 500)), { pannable: doc.presPinData ? true : false });
+ return this._pdfViewer?.scrollFocus(doc, NumCast(doc.presPinViewScroll, NumCast(doc.y)), smooth) ?? (didToggle ? 1 : undefined);
};
getAnchor = () => {
- const anchor =
- this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ??
- Docs.Create.TextanchorDocument({
+ const docAnchor = () => {
+ const anchor = Docs.Create.TextanchorDocument({
title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)),
- y: NumCast(this.layoutDoc._scrollTop),
unrendered: true,
});
+ PresBox.pinDocView(anchor, { pinData: { scrollable: true, pannable: true } }, this.rootDoc);
+ return anchor;
+ };
+ const anchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ?? docAnchor();
this.addDocument(anchor);
return anchor;
};
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2984feba5..fdd61463d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -686,7 +686,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
};
@undoBatch
- pinToPres = (anchor: Doc) => this.props.pinToPres(anchor);
+ pinToPres = (anchor: Doc) => this.props.pinToPres(anchor, {});
@undoBatch
makePushpin = (anchor: Doc) => (anchor.isPushpin = !anchor.isPushpin);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 8d805c663..10f2dc016 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -12,7 +12,8 @@ import { List } from '../../../../fields/List';
import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils';
+import { AudioField } from '../../../../fields/URLField';
+import { emptyFunction, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils';
import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -33,6 +34,7 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresMovement, PresStatus } from './PresEnums';
+const { Howl } = require('howler');
export interface PinProps {
audioRange?: boolean;
@@ -41,6 +43,17 @@ export interface PinProps {
pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected)
pinDocLayout?: boolean; // pin layout info (width/height/x/y)
pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text)
+ pinAudioPlay?: boolean; // pin audio annotation
+ pinData?: {
+ scrollable?: boolean | undefined;
+ pannable?: boolean | undefined;
+ temporal?: boolean | undefined;
+ clippable?: boolean | undefined;
+ dataview?: boolean | undefined;
+ textview?: boolean | undefined;
+ poslayoutview?: boolean | undefined;
+ dataannos?: boolean | undefined;
+ };
}
@observer
@@ -333,26 +346,37 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.onHideDocument(); //Handles hide after/before
}
});
- static pinDataTypes(target: Doc) {
+ static pinDataTypes(target: Doc): { scrollable?: boolean; pannable?: boolean; temporal?: boolean; clippable?: boolean; dataview?: boolean; textview?: boolean; poslayoutview?: boolean; dataannos?: boolean } {
const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking;
- const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
+ const pannable = [DocumentType.IMG, DocumentType.PDF].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any);
const clippable = [DocumentType.COMPARISON].includes(target.type as any);
const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG].includes(target.type as any) && target.activeFrame === undefined;
const poslayoutview = [DocumentType.COL].includes(target.type as any) && target.activeFrame === undefined;
const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined;
- return { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview };
+ const dataannos = false;
+ return { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview, dataannos };
}
@action
- static restoreTargetDocView(bestTarget: Doc, activeItem: Doc) {
- const transTime = NumCast(activeItem.presTransition, 500);
+ playAnnotation = (anno: AudioField) => {};
+ @action
+ static restoreTargetDocView(bestTarget: Doc, pinProps: PinProps | undefined, activeItem: Doc, transTime: number, pinDataTypes = this.pinDataTypes(bestTarget)) {
const presTransitionTime = `all ${transTime}ms`;
- const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(bestTarget);
bestTarget._viewTransition = presTransitionTime;
- if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
- if (temporal) bestTarget._currentTimecode = activeItem.presStartTime;
- if (scrollable) {
+ if (pinProps?.pinDocLayout) {
+ const transTime = NumCast(activeItem.presTransition, 500);
+ bestTarget._dataTransition = `all ${transTime}ms`;
+ bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x));
+ bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y));
+ bestTarget.rotation = NumCast(activeItem.presRot, NumCast(bestTarget.rotation));
+ bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width));
+ bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height));
+ setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
+ }
+ if (pinDataTypes.clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
+ if (pinDataTypes.temporal) bestTarget._currentTimecode = activeItem.presStartTime;
+ if (pinDataTypes.scrollable) {
bestTarget._scrollTop = activeItem.presPinViewScroll;
const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
if (contentBounds) {
@@ -360,13 +384,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] });
}
}
- if (dataview && activeItem.presData !== undefined) {
+ if (pinDataTypes.dataannos) {
+ const fkey = Doc.LayoutFieldKey(bestTarget);
+ Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List<Doc>(DocListCast(activeItem.presAnnotations));
+ }
+ if (pinDataTypes.dataview && activeItem.presData !== undefined) {
const fkey = Doc.LayoutFieldKey(bestTarget);
Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt;
}
- if (textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
- if (poslayoutview) {
+ if (pinDataTypes.textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ if (pinDataTypes.poslayoutview) {
StrListCast(activeItem.presPinLayoutData)
.map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number })
.forEach(data => {
@@ -385,7 +413,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
transTime + 10
);
}
- if (pannable) {
+ if (pinDataTypes.pannable) {
const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
if (contentBounds) {
const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] };
@@ -410,9 +438,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
/// reserved fields on the pinDoc so that those values can be restored to the
/// target doc when navigating to it.
@action
- static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) {
- const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(pinDoc);
- if (pinProps?.pinDocLayout) {
+ static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) {
+ if (pinProps.pinDocLayout) {
pinDoc.presPinLayout = true;
pinDoc.presX = NumCast(targetDoc.x);
pinDoc.presY = NumCast(targetDoc.y);
@@ -420,33 +447,46 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
pinDoc.presWidth = NumCast(targetDoc.width);
pinDoc.presHeight = NumCast(targetDoc.height);
}
- if (pinProps?.pinDocContent) {
- pinDoc.presPinData = scrollable || temporal || pannable || clippable || dataview || textview || poslayoutview || pinProps.activeFrame !== undefined;
- if (dataview) {
+ if (pinProps.pinAudioPlay) pinDoc.followLinkAudio = true;
+ if (pinProps.pinData) {
+ pinDoc.presPinData =
+ pinProps.pinData.scrollable ||
+ pinProps.pinData.temporal ||
+ pinProps.pinData.pannable ||
+ pinProps.pinData.clippable ||
+ pinProps.pinData.dataview ||
+ pinProps.pinData.textview ||
+ pinProps.pinData.poslayoutview ||
+ pinProps?.activeFrame !== undefined;
+ if (pinProps.pinData.dataview) {
const fkey = Doc.LayoutFieldKey(targetDoc);
pinDoc.presUseAlt = targetDoc[fkey + '-useAlt'];
pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
}
- if (textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text;
- if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop;
- if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth;
- if (poslayoutview) pinDoc.presPinLayoutData = new List<string>(DocListCast(pinDoc.presData).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) })));
- if (pannable) {
- pinDoc.presPinViewX = NumCast(pinDoc._panX);
- pinDoc.presPinViewY = NumCast(pinDoc._panY);
- pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1);
+ if (pinProps.pinData.dataannos) {
+ const fkey = Doc.LayoutFieldKey(targetDoc);
+ pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']));
+ }
+ if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text;
+ if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop;
+ if (pinProps.pinData.clippable) pinDoc.presPinClipWidth = targetDoc._clipWidth;
+ if (pinProps.pinData.poslayoutview) pinDoc.presPinLayoutData = new List<string>(DocListCast(targetDoc.presData).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) })));
+ if (pinProps.pinData.pannable) {
+ pinDoc.presPinViewX = NumCast(targetDoc._panX);
+ pinDoc.presPinViewY = NumCast(targetDoc._panY);
+ pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1);
}
- if (temporal) {
- pinDoc.presStartTime = pinDoc._currentTimecode;
- const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(pinDoc.presStartTime) + 0.1);
- pinDoc.presEndTime = NumCast(pinDoc.clipEnd, duration);
+ if (pinProps.pinData.temporal) {
+ pinDoc.presStartTime = targetDoc._currentTimecode;
+ const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(targetDoc.presStartTime) + 0.1);
+ pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration);
}
}
if (pinProps?.pinViewport) {
// If pinWithView option set then update scale and x / y props of slide
const bounds = pinProps.pinViewport;
pinDoc.presPinView = true;
- pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1);
+ pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1);
pinDoc.presPinViewX = bounds.left + bounds.width / 2;
pinDoc.presPinViewY = bounds.top + bounds.height / 2;
pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
@@ -507,35 +547,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) {
- if ((activeItem.presPinLayout || activeItem.presPinView) && DocCast(targetDoc.context)?._currentFrame === undefined) {
- const transTime = NumCast(activeItem.presTransition, 500);
- targetDoc._dataTransition = `all ${transTime}ms`;
- targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x));
- targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y));
- targetDoc.rotation = NumCast(activeItem.presRot, NumCast(targetDoc.rotation));
- targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width));
- targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height));
- setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10);
- }
// If openDocument is selected then it should open the document for the user
if (activeItem.openDocument) {
LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc);
} else if (targetDoc && activeItem.presMovement !== PresMovement.None) {
LightboxView.SetLightboxDoc(undefined);
const zooming = activeItem.presMovement !== PresMovement.Pan;
- DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom, 1));
+ DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, activeItem, finished, undefined, true, NumCast(activeItem.presZoom, 1));
} else if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) {
(DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
}
// After navigating to the document, if it is added as a presPinView then it will
// adjust the pan and scale to that of the pinView when it was added.
- if (activeItem.presPinData || activeItem.presPinView) {
+ const pinDocLayout = (BoolCast(activeItem.presPinLayout) || BoolCast(activeItem.presPinView)) && DocCast(targetDoc.context)?._currentFrame === undefined;
+ if (activeItem.presPinData || activeItem.presPinView || pinDocLayout) {
clearTimeout(PresBox._navTimer);
// targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc
const bestTargetView = DocumentManager.Instance.getFirstDocumentView(targetDoc);
- const bestTarget = bestTargetView?.props.Document;
- if (bestTarget) PresBox._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem);
- activeItem.presPinAudioPlay && bestTargetView?.docView?.playAnnotation();
+ if (bestTargetView?.props.Document) PresBox._navTimer = PresBox.restoreTargetDocView(bestTargetView?.props.Document, { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500));
}
}
@@ -747,7 +776,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
} else {
if (!doc.aliasOf) {
const original = Doc.MakeAlias(doc);
- TabDocView.PinDoc(original);
+ TabDocView.PinDoc(original, {});
setTimeout(() => this.removeDocument(doc), 0);
return false;
} else {
@@ -1316,7 +1345,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
Effects
<div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
<div className="presBox-subheading">Play Audio Annotation</div>
- <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presPinAudioPlay = !BoolCast(activeItem.presPinAudioPlay))} checked={BoolCast(activeItem.presPinAudioPlay)} />
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.followLinkAudio = !BoolCast(activeItem.followLinkAudio))} checked={BoolCast(activeItem.followLinkAudio)} />
</div>
<div
className="presBox-dropdown"
@@ -1694,7 +1723,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const presData = Cast(this.rootDoc.data, listSpec(Doc));
if (data && presData) {
data.push(doc);
- TabDocView.PinDoc(doc);
+ TabDocView.PinDoc(doc, {});
this.gotoDocument(this.childDocs.length, this.activeItem);
} else {
this.props.addDocTab(doc, 'add:right');
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 9af0949eb..133b882f6 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -52,7 +52,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
};
@undoBatch
- pinToPres = () => this.props.pinToPres(this.annoTextRegion);
+ pinToPres = () => this.props.pinToPres(this.annoTextRegion, {});
@undoBatch
makePushpin = () => (this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6ff87ef9f..5a5c63c3d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -166,12 +166,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
// scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location,
// otherwise it will scroll smoothly.
- scrollFocus = (doc: Doc, smooth: boolean) => {
+ scrollFocus = (doc: Doc, scrollTop: number, smooth: boolean) => {
const mainCont = this._mainCont.current;
let focusSpeed: Opt<number>;
if (doc !== this.props.rootDoc && mainCont) {
const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
- const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight));
+ const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight));
if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
if (!this._pdfViewer) this._initialScroll = scrollTo;
else if (smooth) smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), mainCont, scrollTo);
@@ -203,6 +203,11 @@ export class PDFViewer extends React.Component<IViewerProps> {
}
document.removeEventListener('pagesinit', this.pagesinit);
var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : '';
+ this._disposers.scale = reaction(
+ () => NumCast(this.props.layoutDoc._viewScale, 1),
+ scale => (this._pdfViewer.currentScaleValue = scale),
+ { fireImmediately: true }
+ );
this._disposers.scroll = reaction(
() => Math.abs(NumCast(this.props.Document._scrollTop)),
pos => {
@@ -290,7 +295,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
@action
scrollToAnnotation = (scrollToAnnotation: Doc) => {
if (scrollToAnnotation) {
- this.scrollFocus(scrollToAnnotation, true);
+ this.scrollFocus(scrollToAnnotation, NumCast(scrollToAnnotation.y), true);
Doc.linkFollowHighlight(scrollToAnnotation);
}
};