diff options
author | bobzel <zzzman@gmail.com> | 2021-08-24 02:30:06 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2021-08-24 02:30:06 -0400 |
commit | 707038795f7129d30a1d4ed5f2311f18a282fecb (patch) | |
tree | 04eb6bb00883f8c3c88a9c1c771c5899f0355f07 /src | |
parent | e81bb4e087d7bdb9521bfed1c84ba4d4dac8aa75 (diff) |
fixed following link from ink stroke. made interacting with annotatable documents consistent when selections are cleared by clicking. fixed undo for webboxes. fixed limiting size of links button.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 1 | ||||
-rw-r--r-- | src/client/views/DocComponent.tsx | 10 | ||||
-rw-r--r-- | src/client/views/MarqueeAnnotator.tsx | 16 | ||||
-rw-r--r-- | src/client/views/PreviewCursor.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 10 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 15 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 25 | ||||
-rw-r--r-- | src/client/views/nodes/ScreenshotBox.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 19 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 40 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 14 |
12 files changed, 82 insertions, 79 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 48886aa3b..f8e9e8702 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -703,6 +703,7 @@ export namespace Docs { I.data = new InkField(points); I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; I["acl-Override"] = "None"; + I.links = ComputedField.MakeFunction("links(self)") as any; I[Initializing] = false; return I; } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 14d32ef12..d9cc29bed 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -90,9 +90,9 @@ export interface ViewBoxAnnotatableProps { renderDepth: number; isAnnotationOverlay?: boolean; } -export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T>(schemaCtor: (doc: Doc) => T, _annotationKey: string = "annotations") { +export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) { class Component extends Touchable<P> { - @observable _annotationKey: string = _annotationKey; + @observable _annotationKeySuffix = () => "annotations"; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @@ -125,7 +125,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; - @computed public get annotationKey() { return this.fieldKey + (this._annotationKey ? "-" + this._annotationKey : ""); } + @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? "-" + this._annotationKeySuffix() : ""); } @action.bound removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean { @@ -203,7 +203,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T added.map(doc => { if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); doc.context = this.props.Document; - if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document; + if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; this.props.layerProvider?.(doc, true); Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); }); @@ -214,7 +214,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T //DocUtils.LeavePushpin(doc); doc._stayInCollection = undefined; doc.context = this.props.Document; - if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document; + if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); }); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index a3a3bce56..c08734c3e 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -43,15 +43,13 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> { @observable private _width: number = 0; @observable private _height: number = 0; - constructor(props: any) { - super(props); - runInAction(() => { - AnchorMenu.Instance.Status = "marquee"; - AnchorMenu.Instance.fadeOut(true); - // clear out old marquees and initialize menu for new selection - Array.from(this.props.savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); - this.props.savedAnnotations.clear(); - }); + @action + static clearAnnotations(savedAnnotations: ObservableMap<number, HTMLDivElement[]>) { + AnchorMenu.Instance.Status = "marquee"; + AnchorMenu.Instance.fadeOut(true); + // clear out old marquees and initialize menu for new selection + Array.from(savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); + savedAnnotations.clear(); } @action componentDidMount() { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 679a4b81e..2b82ef475 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -158,7 +158,7 @@ export class PreviewCursor extends React.Component<{}> { } render() { return (!PreviewCursor._clickPoint || !PreviewCursor.Visible) ? (null) : - <div className="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={e => e && e.focus()} + <div className="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={e => e?.focus()} style={{ transform: `translate(${PreviewCursor._clickPoint[0]}px, ${PreviewCursor._clickPoint[1]}px)` }}> I </div >; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index a82128e47..a821aeeea 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -36,6 +36,7 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import './CollectionView.scss'; +import { returnEmptyString } from '../../../Utils'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); @@ -62,7 +63,7 @@ export enum CollectionViewType { export interface CollectionViewProps extends FieldViewProps { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) layoutEngine?: () => string; - setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; + setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; // property overrides for child documents children?: never | (() => JSX.Element[]) | React.ReactNode; @@ -84,7 +85,7 @@ export interface CollectionViewProps extends FieldViewProps { type CollectionDocument = makeInterface<[typeof documentSchema]>; const CollectionDocument = makeInterface(documentSchema); @observer -export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument, "") { +export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } @observable private static _safeMode = false; @@ -92,6 +93,11 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; + constructor(props: any) { + super(props); + runInAction(() => this._annotationKeySuffix = returnEmptyString); + } + get collectionViewType(): CollectionViewType | undefined { const viewField = StrCast(this.layoutDoc._viewType); if (CollectionView._safeMode) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 437a3cba8..81f6307d1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -41,7 +41,7 @@ interface MarqueeViewProps { trySelectCluster: (addToSel: boolean) => boolean; nudge?: (x: number, y: number, nudgeTime?: number) => boolean; ungroup?: () => void; - setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; + setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; } @observer export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps> @@ -211,7 +211,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque // allow marquee if right click OR alt+left click if (e.button === 2 || (e.button === 0 && e.altKey)) { // if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) { - this.setPreviewCursor(e.clientX, e.clientY, true); + this.setPreviewCursor(e.clientX, e.clientY, true, false); // (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors. e.preventDefault(); // } @@ -284,8 +284,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque else if (document.getSelection()) { document.getSelection()?.empty(); } } - setPreviewCursor = action((x: number, y: number, drag: boolean) => { - if (drag) { + setPreviewCursor = action((x: number, y: number, drag: boolean, hide: boolean) => { + if (hide) { + this._downX = this._lastX = x; + this._downY = this._lastY = y; + this._commandExecuted = false; + PreviewCursor.Visible = false; + } else if (drag) { this._downX = this._lastX = x; this._downY = this._lastY = y; this._commandExecuted = false; @@ -313,7 +318,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque if (!(e.nativeEvent as any).marqueeHit) { (e.nativeEvent as any).marqueeHit = true; if (!this.props.trySelectCluster(e.shiftKey)) { - this.setPreviewCursor(e.clientX, e.clientY, false); + this.setPreviewCursor(e.clientX, e.clientY, false, false); } else e.stopPropagation(); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 678be0500..121d2d556 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -777,7 +777,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps onClickFunc = () => this.onClickHandler; setHeight = (height: number) => this.layoutDoc._height = height; setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view; - isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() ? true : false; + isContentActive = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.isContentActive() ? true : false; @computed get contents() { TraceMobx(); const audioView = !this.layoutDoc._showAudio ? (null) : @@ -792,7 +792,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps </div>; return <div className="documentView-contentsView" style={{ - pointerEvents: this.props.contentPointerEvents as any, + pointerEvents: (this.props.contentPointerEvents as any) || (CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() || this.isContentActive() ? "all" : "none"), height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined, }}> <DocumentContentsView key={1} {...this.props} @@ -809,7 +809,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allLinkEndpoints} {this.hideLinkButton ? (null) : - <div style={{ transformOrigin: "top left", transform: `scale(${Math.min(1, this.props.ScreenToLocalTransform().Scale)})` }}> + <div style={{ transformOrigin: "top left", transform: `scale(${Math.min(1, this.props.ScreenToLocalTransform().scale(this.props.ContentScaling?.() || 1).Scale)})` }}> <DocumentLinksButton View={this.props.DocumentView()} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} /> </div>} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 2c0106960..c4e74ebd2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,19 +1,21 @@ -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from 'mobx'; import { observer } from "mobx-react"; import { DataSym, Doc, DocListCast, WidthSym } from '../../../fields/Doc'; import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; +import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { createSchema, makeInterface } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { Cast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnOne, Utils, returnFalse } from '../../../Utils'; +import { emptyFunction, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Networking } from '../../Network'; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; @@ -21,15 +23,13 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; +import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); -import { InkTool } from '../../../fields/InkField'; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; -import { AnchorMenu } from '../pdf/AnchorMenu'; -import { Docs } from '../../documents/Documents'; +import { SnappingManager } from '../../util/SnappingManager'; const path = require('path'); export const pageSchema = createSchema({ @@ -294,7 +294,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp <div className="imageBox-fader" > <img key="paths" ref={this._imgRef} src={srcpath} - style={{ transform, transformOrigin }} draggable={false} + style={{ transform, transformOrigin }} + draggable={false} width={nativeWidth} /> {fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker"> <img className="imageBox-fadeaway" key={"fadeaway"} ref={this._imgRef} @@ -330,11 +331,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp TraceMobx(); return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />; } - @action marqueeDown = (e: React.PointerEvent) => { if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { - this._marqueeing = [e.clientX, e.clientY]; - e.stopPropagation(); + setupMoveUpEvents(this, e, action(e => { + MarqueeAnnotator.clearAnnotations(this._savedAnnotations) + this._marqueeing = [e.clientX, e.clientY]; + return true; + }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); } } @action diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index f0db0b594..7ad96bf05 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -175,8 +175,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl @computed get content() { if (this.rootDoc.videoWall) return (null); - const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive"; - return <video className={"videoBox-content" + interactive} key="video" + return <video className={"videoBox-content"} key="video" ref={r => { this._videoRef = r; setTimeout(() => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index fc97a6f4d..d4df30b48 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -9,7 +9,7 @@ import { InkTool } from "../../../fields/InkField"; import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { AudioField, nullAudio, VideoField } from "../../../fields/URLField"; -import { emptyFunction, formatTime, OmitKeys, returnOne, setupMoveUpEvents, Utils } from "../../../Utils"; +import { emptyFunction, formatTime, OmitKeys, returnOne, setupMoveUpEvents, Utils, returnFalse } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { Networking } from "../../Network"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @@ -209,11 +209,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp componentDidMount() { this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. - this._disposers.selection = reaction(() => this.props.isSelected(), - selected => !selected && setTimeout(() => { - Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); - this._savedAnnotations.clear(); - })); this._disposers.triggerVideo = reaction( () => !LinkDocPreview.LinkInfo && this.props.renderDepth !== -1 ? NumCast(this.Document._triggerVideo, null) : undefined, time => time !== undefined && setTimeout(() => { @@ -550,9 +545,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp return <div className="imageBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />; } - marqueeDown = action((e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) this._marqueeing = [e.clientX, e.clientY]; - }); + marqueeDown = (e: React.PointerEvent) => { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + setupMoveUpEvents(this, e, action(e => { + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); + this._marqueeing = [e.clientX, e.clientY]; + return true; + }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); + } + } finishMarquee = action(() => { this._marqueeing = undefined; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 2ff41c73a..0c32a30db 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -44,7 +44,7 @@ const WebDocument = makeInterface(documentSchema); export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, WebDocument>(WebDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } public static openSidebarWidth = 250; - private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _outerRef: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; @@ -52,16 +52,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps private _keyInput = React.createRef<HTMLInputElement>(); private _initialScroll: Opt<number>; private _sidebarRef = React.createRef<SidebarAnnos>(); - @observable private _urlHash: string = ""; @observable private _scrollTimer: any; @observable private _overlayAnnoInfo: Opt<Doc>; @observable private _marqueeing: number[] | undefined; - @observable private _url: string = "hello"; @observable private _isAnnotating = false; @observable private _iframeClick: HTMLIFrameElement | undefined = undefined; @observable private _iframe: HTMLIFrameElement | null = null; @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable private _scrollHeight = 1500; + @computed get _url() { return this.webField?.toString() || ""; } + @computed get _urlHash() { return this._url ? WebBox.urlHash(this._url) + "" : ""; } @computed get scrollHeight() { return this._scrollHeight; } @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); } @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); } @@ -82,9 +82,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. runInAction(() => { - this._url = this.webField?.toString() || ""; - this._urlHash = WebBox.urlHash(this._url) + ""; - this._annotationKey = this._urlHash + "-annotations"; + this._annotationKeySuffix = () => this._urlHash + "-annotations"; // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created) this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`); this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`); @@ -214,6 +212,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this.props.scaling?.() || 1) * mainContBounds.scale; const word = getWordAtPoint(e.target, e.clientX, e.clientY); + this._setPreviewCursor?.(e.clientX, e.clientY, false, true); + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale]; if (word) { @@ -306,9 +306,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), []); if (future.length) { this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, this._url]); - this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = future.pop()!)); - this._urlHash = WebBox.urlHash(this._url) + ""; - this._annotationKey = this._urlHash + "-annotations"; + this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!)); return true; } return false; @@ -321,9 +319,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps if (history.length) { if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]); else this.dataDoc[this.fieldKey + "-future"] = new List<string>([...future, this._url]); - this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!)); - this._urlHash = WebBox.urlHash(this._url) + ""; - this._annotationKey = this._urlHash + "-annotations"; + this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!)); return true; } return false; @@ -342,17 +338,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string")); const url = this.webField?.toString(); if (url && !preview) { - if (history === undefined) { - this.dataDoc[this.fieldKey + "-history"] = new List<string>([url]); - } else { - this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, url]); - } + this.dataDoc[this.fieldKey + "-history"] = new List<string>([...(history || []), url]); this.layoutDoc._scrollTop = 0; future && (future.length = 0); } - this._url = newUrl; - this._urlHash = WebBox.urlHash(this._url) + ""; - this._annotationKey = this._urlHash + "-annotations"; if (!preview) this.dataDoc[this.fieldKey] = new WebField(new URL(newUrl)); } catch (e) { console.log("WebBox URL error:" + this._url); @@ -413,15 +402,18 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action onMarqueeDown = (e: React.PointerEvent) => { if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { - this._marqueeing = [e.clientX, e.clientY]; - this.props.select(false); + setupMoveUpEvents(this, e, action(e => { + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); + this._marqueeing = [e.clientX, e.clientY]; + return true; + }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); } } @action finishMarquee = (x?: number, y?: number) => { this._marqueeing = undefined; this._isAnnotating = false; this._iframeClick = undefined; - x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false); + x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false); } @computed @@ -511,7 +503,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno); - setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func; panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index ee553fd43..41a60bedf 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -69,7 +69,7 @@ export class PDFViewer extends React.Component<IViewerProps> { private _pdfViewer: any; private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer - private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject<HTMLDivElement> = React.createRef(); @@ -371,10 +371,11 @@ export class PDFViewer extends React.Component<IViewerProps> { this._downY = e.clientY; if ((this.props.Document._viewScale || 1) !== 1) return; if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { - this._setPreviewCursor?.(e.clientX, e.clientY, true); + this._setPreviewCursor?.(e.clientX, e.clientY, true, false); } if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { this.props.select(false); + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; if (e.target && ((e.target as any).className.includes("endOfContent") || ((e.target as any).parentElement.className !== "textLayer"))) { this._textSelecting = false; @@ -382,10 +383,7 @@ export class PDFViewer extends React.Component<IViewerProps> { } else { // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. setTimeout(action(() => this._marqueeing = undefined), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. - // clear out old marquees and initialize menu for new selection - AnchorMenu.Instance.Status = "marquee"; - Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); - this._savedAnnotations.clear(); + this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "htmlAnnotation", { "pointer-events": "none" }); document.addEventListener("pointerup", this.onSelectEnd); document.addEventListener("pointermove", this.onSelectMove); @@ -454,12 +452,12 @@ export class PDFViewer extends React.Component<IViewerProps> { if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - this._setPreviewCursor(e.clientX, e.clientY, false); + this._setPreviewCursor(e.clientX, e.clientY, false, false); } // e.stopPropagation(); // bcz: not sure why this was here. We need to allow the DocumentView to get clicks to process doubleClicks } - setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func; getCoverImage = () => { if (!this.props.Document[HeightSym]() || !Doc.NativeHeight(this.props.Document)) { |