diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 14 | ||||
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 15 | ||||
| -rw-r--r-- | src/client/views/nodes/MapBox/MapBox.tsx | 46 | ||||
| -rw-r--r-- | src/client/views/nodes/MapBox/MapBox2.tsx | 46 | ||||
| -rw-r--r-- | src/client/views/nodes/VideoBox.scss | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 23 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 167 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 4 |
8 files changed, 118 insertions, 198 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 465bbcf2f..421d431b3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -131,9 +131,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF public static animStringFields = ['backgroundColor', 'color', 'fillColor']; // fields that are configured to be animatable using animation frames public static animDataFields = (doc: Doc) => (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames - @observable _animPos: number[] | undefined = undefined; - @observable _contentView: DocumentView | undefined | null; - get CollectionFreeFormView() { return this.props.CollectionFreeFormView; } @@ -231,7 +228,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF this.props .ScreenToLocalTransform() .translate(-this.props.w_X(), -this.props.w_Y()) - .rotateDeg(this.props.w_Rotation?.() || 0); + .rotateDeg(-(this.props.w_Rotation?.() || 0)); returnThis = () => this; /// this indicates whether the doc view is activated because of its relationshop to a group @@ -262,14 +259,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF {this.props.RenderCutoffProvider(this.props.Document) ? ( <div style={{ position: 'absolute', width: this.props.PanelWidth(), height: this.props.PanelHeight(), background: 'lightGreen' }} /> ) : ( - <DocumentView - ref={action((r: DocumentView | null) => (this._contentView = r))} - {...passOnProps} - CollectionFreeFormDocumentView={this.returnThis} - styleProvider={this.styleProvider} - ScreenToLocalTransform={this.screenToLocalTransform} - isGroupActive={this.isGroupActive} - /> + <DocumentView {...passOnProps} CollectionFreeFormDocumentView={this.returnThis} styleProvider={this.styleProvider} ScreenToLocalTransform={this.screenToLocalTransform} isGroupActive={this.isGroupActive} /> )} </div> ); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index bca062190..103843046 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -70,6 +70,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp private _disposers: { [name: string]: IReactionDisposer } = {}; private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined; private _overlayIconRef = React.createRef<HTMLDivElement>(); + private _marqueeref = React.createRef<MarqueeAnnotator>(); @observable _curSuffix = ''; @observable _uploadIcon = uploadIcons.idle; @@ -473,7 +474,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); - @observable _marqueeing: number[] | undefined; @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @computed get annotationLayer() { TraceMobx(); @@ -487,7 +487,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; + this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); return true; }), returnFalse, @@ -499,7 +499,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @action finishMarquee = () => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; - this._marqueeing = undefined; + this._marqueeref.current?.onTerminateSelection(); this.props.select(false); }; focus = (anchor: Doc, options: DocFocusOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); @@ -557,13 +557,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp {this.content} </CollectionFreeFormView> {this.annotationLayer} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current ? null : ( <MarqueeAnnotator rootDoc={this.rootDoc} scrollTop={0} - down={this._marqueeing} - scaling={this.props.NativeDimScaling} - docView={this.props.docViewPath().slice(-1)[0]} + annotationLayerScrollTop={0} + scaling={returnOne} + annotationLayerScaling={this.props.NativeDimScaling} + docView={this.props.DocumentView!} addDocument={this.addDocument} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 37935c513..9b75ca7e3 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -7,9 +7,8 @@ import * as React from 'react'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; -import { InkTool } from '../../../../fields/InkField'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; @@ -21,7 +20,6 @@ import { undoable, UndoManager } from '../../../util/UndoManager'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; -import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { SidebarAnnos } from '../../SidebarAnnos'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; @@ -67,14 +65,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps return FieldView.LayoutString(MapBox, fieldKey); } private _dragRef = React.createRef<HTMLDivElement>(); - private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); - private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _sidebarRef = React.createRef<SidebarAnnos>(); private _ref: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [key: string]: IReactionDisposer } = {}; private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); - @observable private _marqueeing: number[] | undefined; @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); @@ -278,28 +273,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => (this._setPreviewCursor = func); - @action - onMarqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { - 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; - x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false, this.rootDoc); - }; - addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => this.addDocument(doc, annotationKey); pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); @@ -832,23 +805,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps isAnyChildContentActive={this.isAnyChildContentActive} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} /> */} - - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( - <MarqueeAnnotator - rootDoc={this.rootDoc} - anchorMenuClick={this.anchorMenuClick} - scrollTop={0} - down={this._marqueeing} - scaling={returnOne} - addDocument={this.addDocumentWrapper} - docView={this.props.docViewPath().lastElement()} - finishMarquee={this.finishMarquee} - savedAnnotations={this.savedAnnotations} - annotationLayer={this._annotationLayer.current} - selectionText={returnEmptyString} - mainCont={this._mainCont.current} - /> - )} </div> {/* </LoadScript > */} <div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index c42664abe..6bad7d724 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -5,9 +5,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; -import { InkTool } from '../../../../fields/InkField'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -15,7 +14,6 @@ import { UndoManager } from '../../../util/UndoManager'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; -import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { Annotation } from '../../pdf/Annotation'; import { SidebarAnnos } from '../../SidebarAnnos'; @@ -106,8 +104,6 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @observable private selectedPlace: Doc | undefined; @observable private markerMap: { [id: string]: google.maps.Marker } = {}; @observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter; - @observable private _marqueeing: number[] | undefined; - @observable private _isAnnotating = false; @observable private inputRef = React.createRef<HTMLInputElement>(); @observable private searchMarkers: google.maps.Marker[] = []; @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options); @@ -119,7 +115,6 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps return DocListCast(this.dataDoc[this.annotationKey]); } @observable private toggleAddMarker = false; - private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); @observable _showSidebar = false; @computed get SidebarShown() { @@ -481,29 +476,6 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); - @action - onMarqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { - 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; - x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false, this.props.Document); - }; - addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => { return this.addDocument(doc, annotationKey); }; @@ -598,22 +570,6 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps {/* {this.handleMapCenter(this._map)} */} </GoogleMap> </div> - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( - <MarqueeAnnotator - rootDoc={this.rootDoc} - anchorMenuClick={this.anchorMenuClick} - scrollTop={0} - down={this._marqueeing} - scaling={returnOne} - addDocument={this.addDocumentWrapper} - docView={this.props.docViewPath().lastElement()} - finishMarquee={this.finishMarquee} - savedAnnotations={this.savedAnnotations} - annotationLayer={this._annotationLayer.current} - selectionText={returnEmptyString} - mainCont={this._mainCont.current} - /> - )} </div> {/* </LoadScript > */} <div className="MapBox2-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index f803715ad..f90c19050 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -100,6 +100,7 @@ padding: 0 10px 0 7px; transition: opacity 0.3s; z-index: 10001; + transform-origin: top left; .timecode-controls { display: flex; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6ebf84738..8bf2f4ce5 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -64,6 +64,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp private _youtubeIframeId: number = -1; private _youtubeContentCreated = false; private _audioPlayer: HTMLAudioElement | null = null; + private _marqueeref = React.createRef<MarqueeAnnotator>(); private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); // outermost div private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _playRegionTimer: any = null; // timeout for playback @@ -71,7 +72,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @observable _stackedTimeline: any; // CollectionStackedTimeline ref @observable static _nativeControls: boolean; // default html controls - @observable _marqueeing: number[] | undefined; // coords for marquee selection @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable _screenCapture = false; @observable _clicking = false; // used for transition between showing/hiding timeline @@ -867,7 +867,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; + this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); return true; }), returnFalse, @@ -881,7 +881,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp // ends marquee selection @action finishMarquee = () => { - this._marqueeing = undefined; + this._marqueeref.current?.onTerminateSelection(); this.props.select(true); }; @@ -912,7 +912,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp .scale(100 / this.heightPercent); }; - marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100; marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0]; timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`]; @@ -937,8 +936,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp <div className="videoBox-ui" style={{ - transformOrigin: 'top left', - transform: `rotate(${this.props.ScreenToLocalTransform().RotateDeg}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`, + transform: `rotate(${this.props.ScreenToLocalTransform().inverse().RotateDeg}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`, left: xPos, top: yMid, height: uiHeight, @@ -952,6 +950,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ); }; + thumbnails = () => StrListCast(this.dataDoc[this.fieldKey + '_thumbnails']); // renders CollectionStackedTimeline @computed get renderTimeline() { return ( @@ -963,7 +962,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp fieldKey={this.annotationKey} dictationKey={this.fieldKey + '_dictation'} mediaPath={this.audiopath} - thumbnails={() => StrListCast(this.dataDoc[this.fieldKey + '_thumbnails'])} + thumbnails={this.thumbnails} renderDepth={this.props.renderDepth + 1} startTag={'_timecodeToShow' /* videoStart */} endTag={'_timecodeToHide' /* videoEnd */} @@ -1095,13 +1094,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp </CollectionFreeFormView> </div> {this.annotationLayer} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current ? null : ( <MarqueeAnnotator + ref={this._marqueeref} rootDoc={this.rootDoc} scrollTop={0} - down={this._marqueeing} - scaling={this.marqueeFitScaling} - docView={this.props.docViewPath().slice(-1)[0]} + annotationLayerScrollTop={0} + scaling={returnOne} + annotationLayerScaling={this.props.NativeDimScaling} + docView={this.props.DocumentView!} containerOffset={this.marqueeOffset} addDocument={this.addDocWithTimecode} finishMarquee={this.finishMarquee} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 524a3cc4a..e42fb4a03 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -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 * as WebRequest from 'web-request'; import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; @@ -51,6 +51,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _outerRef: React.RefObject<HTMLDivElement> = React.createRef(); + private _marqueeref = React.createRef<MarqueeAnnotator>(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _keyInput = React.createRef<HTMLInputElement>(); @@ -66,10 +67,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @observable private _searching: boolean = false; @observable private _showSidebar = false; @observable private _webPageHasBeenRendered = false; - @observable private _overlayAnnoInfo: Opt<Doc>; @observable private _marqueeing: number[] | undefined; - @observable private _isAnnotating = false; - @observable private _iframeClick: HTMLIFrameElement | undefined = undefined; + get marqueeing() { + return this._marqueeing; + } + set marqueeing(val) { + val && this._marqueeref.current?.onInitiateSelection(val); + !val && this._marqueeref.current?.onTerminateSelection(); + this._marqueeing = val; + } @observable private _iframe: HTMLIFrameElement | null = null; @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight); @@ -245,6 +251,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action createTextAnnotation = (sel: Selection, selRange: Range | undefined) => { if (this._mainCont.current && selRange) { + if (this.rootDoc[this.props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.props.DocumentView!().screenToLocalTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -261,12 +268,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, 1); } } + this._mainCont.current.style.transform = ''; } - //this._selectionText = selRange.cloneContents().textContent || ""; this._selectionContent = selRange?.cloneContents(); this._selectionText = this._selectionContent?.textContent || ''; // clear selection + this._textAnnotationCreator = undefined; if (sel.empty) sel.empty(); // Chrome else if (sel.removeAllRanges) sel.removeAllRanges(); // Firefox return this._savedAnnotations; @@ -354,26 +362,27 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }; @action webClipDown = (e: React.PointerEvent) => { - const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); + e.stopPropagation(); + const sel = window.getSelection(); + this._textAnnotationCreator = undefined; + if (sel?.empty) sel.empty(); // Chrome + else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox + // bcz: NEED TO unrotate e.clientX and e.clientY const word = getWordAtPoint(e.target, e.clientX, e.clientY); this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - e.button !== 2 && (this._marqueeing = [e.clientX, e.clientY]); - if (word || (e.target as any)?.className?.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) { - e.stopPropagation(); - 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. - } else { - this._isAnnotating = true; - this.props.select(false); - e.stopPropagation(); + + if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + if (e.button !== 2) this.marqueeing = [e.clientX, e.clientY]; e.preventDefault(); } document.addEventListener('pointerup', this.webClipUp); }; + @action webClipUp = (e: PointerEvent) => { + if (window.getSelection()?.isCollapsed && this._marqueeref.current?.isEmpty) { + this.marqueeing = undefined; + } document.removeEventListener('pointerup', this.webClipUp); this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value const sel = window.getSelection(); @@ -382,7 +391,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this._selectionText = sel.toString(); AnchorMenu.Instance.setSelectedText(sel.toString()); this._textAnnotationCreator = () => this.createTextAnnotation(sel, selRange); - AnchorMenu.Instance.jumpTo(e.clientX, e.clientY); + (!sel.isCollapsed || this.marqueeing) && AnchorMenu.Instance.jumpTo(e.clientX, e.clientY); // Changing which document to add the annotation to (the currently selected WebBox) GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`); GPTPopup.Instance.addDoc = this.sidebarAddDocument; @@ -390,36 +399,26 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }; @action iframeDown = (e: PointerEvent) => { - const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); - const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale; - const word = getWordAtPoint(e.target, e.clientX, e.clientY); - this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc); + this.props.select(false); + const locpt = { + x: (e.clientX / NumCast(this.rootDoc.nativeWidth)) * this.props.PanelWidth(), + y: ((e.clientY - NumCast(this.rootDoc.layout_scrollTop))/ NumCast(this.rootDoc.nativeHeight)) * this.props.PanelHeight() }; // prettier-ignore + const scrclick = this.props.DocumentView?.().props.ScreenToLocalTransform().inverse().transformPoint(locpt.x, locpt.y)!; + const scrcent = this.props + .DocumentView?.() + .props.ScreenToLocalTransform() + .inverse() + .transformPoint(NumCast(this.rootDoc.width) / 2, NumCast(this.rootDoc.height) / 2)!; + const theclickoff = Utils.rotPt(scrclick[0] - scrcent[0], scrclick[1] - scrcent[1], -this.props.ScreenToLocalTransform().Rotate); + const theclick = [theclickoff.x + scrcent[0], theclickoff.y + scrcent[1]]; MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - e.button !== 2 && (this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale]); - if (word || (e.target as any)?.className?.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) { - 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. - } else { - this._iframeClick = this._iframe ?? undefined; - this._isAnnotating = true; - this.props.select(false); - e.stopPropagation(); - e.preventDefault(); - } - - // bcz: hack - iframe grabs all events which messes up how we handle contextMenus. So this super naively simulates the event stack to get the specific menu items and the doc view menu items. - if (e.button === 2 || (e.button === 0 && e.altKey)) { + const word = getWordAtPoint(e.target, e.clientX, e.clientY); + if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + this.marqueeing = theclick; e.preventDefault(); - //e.stopPropagation(); - ContextMenu.Instance.closeMenu(); - ContextMenu.Instance.setIgnoreEvents(true); } }; isFirefox = () => 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1; - iframeClick = () => this._iframeClick; - iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale; addWebStyleSheet(document: any, styleType: string = 'text/css') { if (document) { @@ -723,38 +722,56 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps } }; + /** + * This gets called when some other child of the webbox is selected and a pointer down occurs on the webbox. + * it's also called for html clippings when you click outside the bounds of the clipping + * @param e + */ @action onMarqueeDown = (e: React.PointerEvent) => { + const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); + this._textAnnotationCreator = undefined; + if (sel?.empty) sel.empty(); // Chrome + else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox + this.marqueeing = [e.clientX, e.clientY]; if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; return true; }), returnFalse, - () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), + action(() => { + this.marqueeing = undefined; + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); + }), false ); + } else { + this.marqueeing = undefined; } }; @action finishMarquee = (x?: number, y?: number, e?: PointerEvent) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; - this._marqueeing = undefined; - this._isAnnotating = false; - this._iframeClick = undefined; + this.marqueeing = undefined; + this._textAnnotationCreator = undefined; const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); if (sel?.empty) sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox + this._setPreviewCursor?.(x ?? 0, y ?? 0, false, !this._marqueeref.current?.isEmpty, this.rootDoc); if (x !== undefined && y !== undefined) { - this._setPreviewCursor?.(x, y, false, false, this.rootDoc); ContextMenu.Instance.closeMenu(); ContextMenu.Instance.setIgnoreEvents(false); if (e?.button === 2 || e?.altKey) { - this.specificContextMenu(undefined as any); - this.props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + e?.preventDefault(); + e?.stopPropagation(); + setTimeout(() => { + // if menu comes up right away, the down event can still be active causing a menu item to be selected + this.specificContextMenu(undefined as any); + this.props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + }); } } }; @@ -797,7 +814,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps key={this._warning} className="webBox-iframe" ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))} - style={{ pointerEvents: this._isAnyChildContentActive || DocumentView.Interacting ? 'none' : undefined }} + style={{ pointerEvents: DocumentView.Interacting ? 'none' : undefined }} src={url} onLoad={this.iframeLoaded} scrolling="no" // ugh.. on windows, I get an inner scroll bar for the iframe's body even though the scrollHeight should be set to the full height of the document. @@ -942,7 +959,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps {this.inlineTextAnnotations .sort((a, b) => NumCast(a.y) - NumCast(b.y)) .map(anno => ( - <Annotation {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} /> + <Annotation {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} /> ))} </div> ); @@ -1004,7 +1021,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps onWheel={this.onZoomWheel} onScroll={e => this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)} onPointerDown={this.onMarqueeDown}> - <div className="webBox-innerContent" style={{ height: (this._webPageHasBeenRendered && this._scrollHeight) || '100%', pointerEvents }}> + <div className="webBox-innerContent" style={{ height: (this._webPageHasBeenRendered && this._scrollHeight > this.props.PanelHeight() && this._scrollHeight) || '100%', pointerEvents }}> {this.content} <div style={{ display: SnappingManager.GetCanEmbed() ? 'none' : undefined, mixBlendMode: 'multiply' }}>{this.renderTransparentAnnotations}</div> {this.renderOpaqueAnnotations} @@ -1049,7 +1066,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps ); } searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => (this._searchString = e.currentTarget.value); - showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno)); setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => (this._setPreviewCursor = func); panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); @@ -1067,7 +1083,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps !this._draggingSidebar && this.props.isContentActive() && !MarqueeOptionsMenu.Instance?.isShown() ? 'all' // : 'none'; - annotationPointerEvents = () => (this.props.isContentActive() && (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none'); + annotationPointerEvents = () => (this.props.isContentActive() && (SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none'); render() { const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any); @@ -1090,27 +1106,26 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }} onContextMenu={this.specificContextMenu}> {this.webpage} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( - <div style={{ transformOrigin: 'top left', transform: `scale(${1 / scale})` }}> - <MarqueeAnnotator - rootDoc={this.rootDoc} - iframe={this.isFirefox() ? this.iframeClick : undefined} - iframeScaling={this.isFirefox() ? this.iframeScaling : undefined} - anchorMenuClick={this.anchorMenuClick} - scrollTop={0} - down={this._marqueeing} - scaling={returnOne} - addDocument={this.addDocumentWrapper} - docView={this.props.docViewPath().lastElement()} - finishMarquee={this.finishMarquee} - savedAnnotations={this.savedAnnotationsCreator} - selectionText={this.selectionText} - annotationLayer={this._annotationLayer.current} - mainCont={this._mainCont.current} - /> - </div> - )} </div> + {!this._mainCont.current || !this._annotationLayer.current ? null : ( + <div style={{ position: 'absolute', height: '100%', width: '100%', pointerEvents: this.marqueeing ? 'all' : 'none' }}> + <MarqueeAnnotator + ref={this._marqueeref} + rootDoc={this.rootDoc} + anchorMenuClick={this.anchorMenuClick} + scrollTop={NumCast(this.layoutDoc.layout_scrollTop)} + annotationLayerScrollTop={0} + scaling={this.props.NativeDimScaling} + addDocument={this.addDocumentWrapper} + docView={this.props.DocumentView!} + finishMarquee={this.finishMarquee} + savedAnnotations={this.savedAnnotationsCreator} + selectionText={this.selectionText} + annotationLayer={this._annotationLayer.current} + mainCont={this._mainCont.current} + /> + </div> + )} <div className="webBox-sideResizer" style={{ diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index f3f07cc21..789509784 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1640,8 +1640,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { let dataField = Doc.LayoutFieldKey(tagDoc); if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations'; - if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn["${dataField}"]`); - else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc["${dataField}"]`); + if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn?.["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc?.["${dataField}"]`); }} checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false} /> |
