diff options
author | bobzel <zzzman@gmail.com> | 2024-05-14 23:15:24 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-05-14 23:15:24 -0400 |
commit | 3534aaf88a3c30a474b3b5a5b7f04adfe6f15fac (patch) | |
tree | 47fb7a8671b209bd4d76e0f755a5b035c6936607 /src/client/views/nodes/ImageBox.tsx | |
parent | 87bca251d87b5a95da06b2212400ce9427152193 (diff) | |
parent | 5cb7ad90e120123ca572e8ef5b1aa6ca41581134 (diff) |
Merge branch 'restoringEslint' into sarah-ai-visualization
Diffstat (limited to 'src/client/views/nodes/ImageBox.tsx')
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 185 |
1 files changed, 115 insertions, 70 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index bb1f70f97..e4b3a1b9b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,61 +1,66 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { extname } from 'path'; import * as React from 'react'; -import { Doc, Opt } from '../../../fields/Doc'; +import { ClientUtils, DashColor, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents } from '../../../ClientUtils'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; -import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; +import { emptyFunction } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils } from '../../documents/DocUtils'; import { Networking } from '../../Network'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; -import { ContextMenu } from '../../views/ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { OverlayView } from '../OverlayView'; import { AnchorMenu } from '../pdf/AnchorMenu'; -import { StyleProp } from '../StyleProvider'; -import { OpenWhere } from './DocumentView'; -import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView'; +import { PinDocView, PinProps } from '../PinFuncs'; +import { StyleProp } from '../StyleProp'; +import { DocumentView } from './DocumentView'; +import { FieldView, FieldViewProps } from './FieldView'; +import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; -import { PinProps, PresBox } from './trails'; +import { OpenWhere } from './OpenWhere'; export class ImageEditorData { + // eslint-disable-next-line no-use-before-define private static _instance: ImageEditorData; private static get imageData() { return (ImageEditorData._instance ?? new ImageEditorData()).imageData; } // prettier-ignore @observable imageData: { rootDoc: Doc | undefined; open: boolean; source: string; addDoc: Opt<(doc: Doc | Doc[], annotationKey?: string) => boolean> } = observable({ rootDoc: undefined, open: false, source: '', addDoc: undefined }); - @action private static set = (open: boolean, rootDoc: Doc | undefined, source: string, addDoc: Opt<(doc: Doc | Doc[], annotationKey?: string) => boolean>) => (this._instance.imageData = { open, rootDoc, source, addDoc }); + @action private static set = (open: boolean, rootDoc: Doc | undefined, source: string, addDoc: Opt<(doc: Doc | Doc[], annotationKey?: string) => boolean>) => { + this._instance.imageData = { open, rootDoc, source, addDoc }; + }; constructor() { makeObservable(this); ImageEditorData._instance = this; } - public static get Open() { return ImageEditorData.imageData.open; } // prettier-ignore - public static get Source() { return ImageEditorData.imageData.source; } // prettier-ignore - public static get RootDoc() { return ImageEditorData.imageData.rootDoc; } // prettier-ignore - public static get AddDoc() { return ImageEditorData.imageData.addDoc; } // prettier-ignore + public static get Open() { return ImageEditorData.imageData.open; } // prettier-ignore public static set Open(open: boolean) { ImageEditorData.set(open, this.imageData.rootDoc, this.imageData.source, this.imageData.addDoc); } // prettier-ignore + public static get Source() { return ImageEditorData.imageData.source; } // prettier-ignore public static set Source(source: string) { ImageEditorData.set(this.imageData.open, this.imageData.rootDoc, source, this.imageData.addDoc); } // prettier-ignore + public static get RootDoc() { return ImageEditorData.imageData.rootDoc; } // prettier-ignore public static set RootDoc(rootDoc: Opt<Doc>) { ImageEditorData.set(this.imageData.open, rootDoc, this.imageData.source, this.imageData.addDoc); } // prettier-ignore + public static get AddDoc() { return ImageEditorData.imageData.addDoc; } // prettier-ignore public static set AddDoc(addDoc: Opt<(doc: Doc | Doc[], annotationKey?: string) => boolean>) { ImageEditorData.set(this.imageData.open, this.imageData.rootDoc, this.imageData.source, addDoc); } // prettier-ignore } @observer -export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface { +export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } @@ -66,7 +71,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined; private _overlayIconRef = React.createRef<HTMLDivElement>(); private _marqueeref = React.createRef<MarqueeAnnotator>(); + private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); + private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); + @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable _curSuffix = ''; + @observable _error = ''; + @observable _isHovering = false; // flag to switch between primary and alternate images on hover + _ffref = React.createRef<CollectionFreeFormView>(); constructor(props: FieldViewProps) { super(props); @@ -93,7 +104,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: visibleAnchor ? false : true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !visibleAnchor } }, this.Document); return anchor; } return this.Document; @@ -106,10 +117,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl scrSize: (this.ScreenToLocalBoxXf().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), selected: this._props.isSelected(), }), - ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'), + ({ forceFull, scrSize, selected }) => { + this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'; + }, { fireImmediately: true, delay: 1000 } ); - const layoutDoc = this.layoutDoc; + const { layoutDoc } = this; this._disposers.path = reaction( () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }), ({ nativeSize, width }) => { @@ -121,10 +134,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl ); this._disposers.scroll = reaction( () => this.layoutDoc.layout_scrollTop, - s_top => { + sTop => { this._forcedScroll = true; - !this._ignoreScroll && this._mainCont.current && (this._mainCont.current.scrollTop = NumCast(s_top)); - this._mainCont.current?.scrollTo({ top: NumCast(s_top) }); + !this._ignoreScroll && this._mainCont.current && (this._mainCont.current.scrollTop = NumCast(sTop)); + this._mainCont.current?.scrollTo({ top: NumCast(sTop) }); this._forcedScroll = false; }, { fireImmediately: true } @@ -138,7 +151,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData) { - let added: boolean | undefined = undefined; + let added: boolean | undefined; const targetIsBullseye = (ele: HTMLElement): boolean => { if (!ele) return false; if (ele === this._overlayIconRef.current) return true; @@ -168,7 +181,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl }; @undoBatch - resolution = () => (this.layoutDoc._showFullRes = !this.layoutDoc._showFullRes); + resolution = () => { + this.layoutDoc._showFullRes = !this.layoutDoc._showFullRes; + }; @undoBatch setNativeSize = action(() => { @@ -176,12 +191,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw; - this.layoutDoc._freeform_panX = nw * NumCast(this.layoutDoc._freeform_panX); - this.layoutDoc._freeform_panY = nw * NumCast(this.layoutDoc._freeform_panY); - this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined; - this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined; - this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined; - this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined; + this.dataDoc._freeform_panX = nw * NumCast(this.dataDoc._freeform_panX); + this.dataDoc._freeform_panY = nw * NumCast(this.dataDoc._freeform_panY); + this.dataDoc._freeform_panX_max = this.dataDoc._freeform_panX_max ? nw * NumCast(this.dataDoc._freeform_panX_max) : undefined; + this.dataDoc._freeform_panX_min = this.dataDoc._freeform_panX_min ? nw * NumCast(this.dataDoc._freeform_panX_min) : undefined; + this.dataDoc._freeform_panY_max = this.dataDoc._freeform_panY_max ? nw * NumCast(this.dataDoc._freeform_panY_max) : undefined; + this.dataDoc._freeform_panY_min = this.dataDoc._freeform_panY_min ? nw * NumCast(this.dataDoc._freeform_panY_min) : undefined; }); @undoBatch rotate = action(() => { @@ -189,7 +204,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl const nh = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']); const w = this.layoutDoc._width; const h = this.layoutDoc._height; - this.dataDoc[this.fieldKey + '-rotation'] = (NumCast(this.dataDoc[this.fieldKey + '-rotation']) + 90) % 360; + this.dataDoc[this.fieldKey + '_rotation'] = (NumCast(this.dataDoc[this.fieldKey + '_rotation']) + 90) % 360; this.dataDoc[this.fieldKey + '_nativeWidth'] = nh; this.dataDoc[this.fieldKey + '_nativeHeight'] = nw; this.layoutDoc._width = h; @@ -197,7 +212,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl }); crop = (region: Doc | undefined, addCrop?: boolean) => { - if (!region) return; + if (!region) return undefined; const cropping = Doc.MakeCopy(region, true); const regionData = region[DocData]; regionData.lockedPosition = true; @@ -223,8 +238,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl croppingProto.type = DocumentType.IMG; croppingProto.layout = ImageBox.LayoutString('data'); croppingProto.data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField); - croppingProto['data_nativeWidth'] = anchw; - croppingProto['data_nativeHeight'] = anchh; + croppingProto.data_nativeWidth = anchw; + croppingProto.data_nativeHeight = anchh; croppingProto.freeform_scale = viewScale; croppingProto.freeform_scale_min = viewScale; croppingProto.freeform_panX = anchx / viewScale; @@ -239,19 +254,19 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl cropping.y = NumCast(this.Document.y); this._props.addDocTab(cropping, OpenWhere.inParent); } - DocumentManager.Instance.AddViewRenderedCb(cropping, dv => setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200)); + DocumentView.addViewRenderedCb(cropping, dv => setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200)); this._props.bringToFront?.(cropping); return cropping; }; - specificContextMenu = (e: React.MouseEvent): void => { + specificContextMenu = (): void => { const field = Cast(this.dataDoc[this.fieldKey], ImageField); if (field) { const funcs: ContextMenuProps[] = []; funcs.push({ description: 'Rotate Clockwise 90', event: this.rotate, icon: 'redo-alt' }); funcs.push({ description: `Show ${this.layoutDoc._showFullRes ? 'Dynamic Res' : 'Full Res'}`, event: this.resolution, icon: 'expand' }); funcs.push({ description: 'Set Native Pixel Size', event: this.setNativeSize, icon: 'expand-arrows-alt' }); - funcs.push({ description: 'Copy path', event: () => Utils.CopyText(this.choosePath(field.url)), icon: 'copy' }); + funcs.push({ description: 'Copy path', event: () => ClientUtils.CopyText(this.choosePath(field.url)), icon: 'copy' }); funcs.push({ description: 'Open Image Editor', event: action(() => { @@ -266,23 +281,23 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl } }; - choosePath(url: URL) { + choosePath = (url: URL) => { if (!url?.href) return ''; const lower = url.href.toLowerCase(); if (url.protocol === 'data') return url.href; - if (url.href.indexOf(window.location.origin) === -1 && url.href.indexOf('dashblobstore') === -1) return Utils.CorsProxy(url.href); + if (url.href.indexOf(window.location.origin) === -1 && url.href.indexOf('dashblobstore') === -1) return ClientUtils.CorsProxy(url.href); if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower) || lower.endsWith('/assets/unknown-file-icon-hi.png')) return `/assets/unknown-file-icon-hi.png`; const ext = extname(url.href); return url.href.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); - } - getScrollHeight = () => (this._props.layout_fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); + }; + getScrollHeight = () => (this._props.fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); @computed get nativeSize() { TraceMobx(); const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500)); const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500)); - const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '-nativeOrientation'], 1); + const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1); return { nativeWidth, nativeHeight, nativeOrientation }; } @computed get overlayImageIcon() { @@ -307,7 +322,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl <div className="imageBox-alternateDropTarget" ref={this._overlayIconRef} - onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))} + onPointerDown={e => + setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => { + this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined; + }) + } style={{ display: (this._props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || this.dataDoc[this.fieldKey + '_alternates'] ? 'block' : 'none', width: 'min(10%, 25px)', @@ -315,7 +334,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray', color: usePath === undefined ? 'black' : 'white', }}> - <FontAwesomeIcon icon="turn-up" size="lg" /> + <FontAwesomeIcon icon="circle-half-stroke" size="lg" /> </div> </Tooltip> ); @@ -323,8 +342,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl @computed get paths() { const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = this.dataDoc[this.fieldKey + '_alternates'] as any as List<Doc>; // retrieve alternate documents that may be rendered as alternate images - const defaultUrl = new URL(Utils.prepend('/assets/unknown-file-icon-hi.png')); + const alts = DocListCast(this.dataDoc[this.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images + const defaultUrl = new URL(ClientUtils.prepend('/assets/unknown-file-icon-hi.png')); const altpaths = alts ?.map(doc => (doc instanceof Doc ? ImageCast(doc[Doc.LayoutFieldKey(doc)])?.url ?? defaultUrl : defaultUrl)) @@ -334,9 +353,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl return paths.length ? paths : [defaultUrl.href]; } - @observable _error = ''; - - @observable _isHovering = false; // flag to switch between primary and alternate images on hover @computed get content() { TraceMobx(); @@ -344,8 +360,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1; const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0]; const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement(); - const { nativeWidth, nativeHeight, nativeOrientation } = this.nativeSize; - const rotation = NumCast(this.dataDoc[this.fieldKey + '-rotation']); + const { nativeWidth, nativeHeight /* , nativeOrientation */ } = this.nativeSize; + const rotation = NumCast(this.dataDoc[this.fieldKey + '_rotation']); const aspect = rotation % 180 ? nativeHeight / nativeWidth : 1; let transformOrigin = 'center center'; let transform = `translate(0%, 0%) rotate(${rotation}deg) scale(${aspect})`; @@ -361,12 +377,32 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`]; return ( - <div className="imageBox-cont" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}> + <div + className="imageBox-cont" + onPointerEnter={action(() => { + this._isHovering = true; + })} + onPointerLeave={action(() => { + this._isHovering = false; + })} + key={this.layoutDoc[Id]} + ref={this.createDropTarget} + onPointerDown={this.marqueeDown}> <div className="imageBox-fader" style={{ opacity: backAlpha }}> - <img key="paths" src={srcpath} style={{ transform, transformOrigin }} onError={action(e => (this._error = e.toString()))} draggable={false} width={nativeWidth} /> + <img + alt="" + key="paths" + src={srcpath} + style={{ transform, transformOrigin }} + onError={action(e => { + this._error = e.toString(); + })} + draggable={false} + width={nativeWidth} + /> {fadepath === srcpath ? null : ( <div className={`imageBox-fadeBlocker${(this._isHovering && usePath === 'alternate:hover') || usePath === 'alternate' ? '-hover' : ''}`} style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000ms') }}> - <img className="imageBox-fadeaway" key="fadeaway" src={fadepath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} /> + <img alt="" className="imageBox-fadeaway" key="fadeaway" src={fadepath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} /> </div> )} </div> @@ -375,23 +411,27 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl ); } - private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); - private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); - @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @computed get annotationLayer() { TraceMobx(); return <div className="imageBox-annotationLayer" style={{ height: this._props.PanelHeight() }} ref={this._annotationLayer} />; } screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { - if (!this.dataDoc[this.fieldKey]) return this.chooseImage(); - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!this.dataDoc[this.fieldKey]) { + this.chooseImage(); + } else if ( + !e.altKey && + e.button === 0 && + NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && + this._props.isContentActive() && + ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) + ) { setupMoveUpEvents( this, e, - action(e => { + action(moveEv => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); + this._marqueeref.current?.onInitiateSelection([moveEv.clientX, moveEv.clientY]); return true; }), returnFalse, @@ -408,7 +448,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl }; focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); - _ffref = React.createRef<CollectionFreeFormView>(); savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); @@ -419,7 +458,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl className="imageBox" onContextMenu={this.specificContextMenu} ref={this._mainCont} - onScroll={action(e => { + onScroll={action(() => { if (!this._forcedScroll) { if (this.layoutDoc._layout_scrollTop || this._mainCont.current?.scrollTop) { this._ignoreScroll = true; @@ -433,10 +472,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl height: this._props.PanelWidth() ? undefined : `100%`, pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, - overflow: this.layoutDoc.layout_fitWidth || this._props.layout_fitWidth?.(this.Document) ? 'auto' : undefined, + overflow: this.layoutDoc.layout_fitWidth || this._props.fitWidth?.(this.Document) ? 'auto' : undefined, }}> <CollectionFreeFormView ref={this._ffref} + // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} setContentViewBox={emptyFunction} NativeWidth={returnZero} @@ -444,8 +484,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl renderDepth={this._props.renderDepth + 1} fieldKey={this.annotationKey} styleProvider={this._props.styleProvider} - isAnnotationOverlay={true} - annotationLayerHostsContent={true} + isAnnotationOverlay + annotationLayerHostsContent PanelWidth={this._props.PanelWidth} PanelHeight={this._props.PanelHeight} ScreenToLocalTransform={this.screenToLocalTransform} @@ -476,7 +516,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl selectionText={returnEmptyString} annotationLayer={this._annotationLayer.current} marqueeContainer={this._mainCont.current} - highlightDragSrcColor={''} + highlightDragSrcColor="" anchorMenuCrop={this.crop} /> )} @@ -489,7 +529,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl input.type = 'file'; input.multiple = true; input.accept = 'image/*'; - input.onchange = async _e => { + input.onchange = async () => { const file = input.files?.[0]; if (file) { const disposer = OverlayView.ShowSpinner(); @@ -508,3 +548,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl input.click(); }; } + +Docs.Prototypes.TemplateMap.set(DocumentType.IMG, { + layout: { view: ImageBox, dataField: 'data' }, + options: { acl: '', freeform: '', systemIcon: 'BsFileEarmarkImageFill' }, +}); |