diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/apis/youtube/YoutubeBox.tsx | 5 | ||||
| -rw-r--r-- | src/client/documents/Documents.ts | 1 | ||||
| -rw-r--r-- | src/client/util/Import & Export/ImageUtils.ts | 41 | ||||
| -rw-r--r-- | src/client/views/DocumentDecorations.tsx | 12 | ||||
| -rw-r--r-- | src/client/views/PreviewCursor.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 31 | ||||
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 12 | ||||
| -rw-r--r-- | src/client/views/webcam/DashWebRTCVideo.tsx | 5 |
11 files changed, 61 insertions, 55 deletions
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index ceb80acbc..d3a15cd84 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -11,6 +11,7 @@ import { FieldView, FieldViewProps } from '../../views/nodes/FieldView'; import '../../views/nodes/WebBox.scss'; import './YoutubeBox.scss'; import * as React from 'react'; +import { SnappingManager } from '../../util/SnappingManager'; interface VideoTemplate { thumbnailUrl: string; @@ -355,9 +356,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> { </div> ); - const frozen = !this.props.isSelected() || DocumentView.Interacting; + const frozen = !this.props.isSelected() || SnappingManager.IsResizing; - const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : ''); + const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !SnappingManager.IsResizing ? '-interactive' : ''); return ( <> <div className={classname}>{content}</div> diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0a4d3a294..79285deb5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1873,6 +1873,7 @@ export namespace DocUtils { proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); } + proto.data_exif = JSON.stringify(result.exifData?.data); proto.data_contentSize = result.contentSize; // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates const latitude = result.exifData?.data?.GPSLatitude; diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 55d37f544..d99828956 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -4,28 +4,33 @@ import { Cast, StrCast, NumCast } from '../../../fields/Types'; import { Networking } from '../../Network'; import { Id } from '../../../fields/FieldSymbols'; import { Utils } from '../../../Utils'; +import { DocData } from '../../../fields/DocSymbols'; export namespace ImageUtils { - export const ExtractExif = async (document: Doc): Promise<boolean> => { + export type imgInfo = { + contentSize: number; + nativeWidth: number; + nativeHeight: number; + source: string; + exifData: { error: string | undefined; data: string }; + }; + export const ExtractImgInfo = async (document: Doc): Promise<imgInfo | undefined> => { const field = Cast(document.data, ImageField); - if (!field) { - return false; + return field ? await Networking.PostToServer('/inspectImage', { source: field.url.href }) : undefined; + }; + + export const AssignImgInfo = (document: Doc, data?: imgInfo) => { + if (data) { + data.nativeWidth && (document._height = (NumCast(document._width) * data.nativeHeight) / data.nativeWidth); + const proto = document[DocData]; + const field = Doc.LayoutFieldKey(document); + proto[`${field}_nativeWidth`] = data.nativeWidth; + proto[`${field}_nativeHeight`] = data.nativeHeight; + proto[`${field}_path`] = data.source; + proto[`${field}_exif`] = JSON.stringify(data.exifData.data); + proto[`${field}_contentSize`] = data.contentSize ? data.contentSize : undefined; } - const source = field.url.href; - const { - contentSize, - nativeWidth, - nativeHeight, - exifData: { error, data }, - } = await Networking.PostToServer('/inspectImage', { source }); - document.exif = error || Doc.Get.FromJson({ data }); - const proto = Doc.GetProto(document); - nativeWidth && (document._height = (NumCast(document._width) * nativeHeight) / nativeWidth); - proto['data_nativeWidth'] = nativeWidth; - proto['data_nativeHeight'] = nativeHeight; - proto['data-path'] = source; - proto.data_contentSize = contentSize ? contentSize : undefined; - return data !== undefined; + return document; }; export const ExportHierarchyToFileSystem = async (collection: Doc): Promise<void> => { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7003485d2..f3da133c3 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -310,7 +310,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora */ @action onRadiusDown = (e: React.PointerEvent): void => { - this._isRounding = DocumentView.Interacting = true; + SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()); + this._isRounding = true; this._resizeUndo = UndoManager.StartBatch('DocDecs set radius'); setupMoveUpEvents( this, @@ -327,7 +328,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora return false; }, action(e => { - DocumentView.Interacting = this._isRounding = false; + SnappingManager.SetIsResizing(undefined); + this._isRounding = false; this._resizeUndo?.end(); }), // upEvent emptyFunction, @@ -439,10 +441,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @action onPointerDown = (e: React.PointerEvent): void => { - SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()); + SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); e.stopPropagation(); - DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them this._resizeHdlId = e.currentTarget.className; const bounds = e.currentTarget.getBoundingClientRect(); this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY }; @@ -595,7 +596,6 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora onPointerUp = (e: PointerEvent): void => { SnappingManager.SetIsResizing(undefined); SnappingManager.clearSnapLines(); - DocumentView.Interacting = false; this._resizeHdlId = ''; this._resizeUndo?.end(); @@ -766,7 +766,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora top: bounds.y - this._resizeBorderWidth / 2, transformOrigin, background: SnappingManager.ShiftKey ? undefined : 'yellow', - pointerEvents: SnappingManager.ShiftKey || DocumentView.Interacting ? 'none' : 'all', + pointerEvents: SnappingManager.ShiftKey || SnappingManager.IsResizing ? 'none' : 'all', display: SelectionManager.Views.length <= 1 || hideDecorations ? 'none' : undefined, transform: `rotate(${rotation}deg)`, }} diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 5ec9a7d46..166afc0c2 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -102,7 +102,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { x: newPoint[0], y: newPoint[1], }); - ImageUtils.ExtractExif(doc); + ImageUtils.ExtractImgInfo(doc); this._addDocument?.(doc); })(); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b56973dc6..2ff435ce2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -4,11 +4,11 @@ import * as rp from 'request-promise'; import { Utils, returnFalse } from '../../../Utils'; import CursorField from '../../../fields/CursorField'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate } from '../../../fields/DocSymbols'; +import { AclPrivate, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; -import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; @@ -309,20 +309,19 @@ export function CollectionSubView<X>(moreProps?: X) { const cors = img.includes('corsProxy') ? img.match(/http.*corsProxy\//)![0] : ''; img = cors ? img.replace(cors, '') : img; if (img) { - const split = img.split('src="')[1].split('"')[0]; - let source = split; - if (split.startsWith('data:image') && split.includes('base64')) { - const [{ accessPaths }] = await Networking.PostToServer('/uploadRemoteImage', { sources: [split] }); - if (accessPaths.agnostic.client.indexOf('dashblobstore') === -1) { - source = Utils.prepend(accessPaths.agnostic.client); - } else { - source = accessPaths.agnostic.client; - } - } - if (source.startsWith('http')) { - const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); - ImageUtils.ExtractExif(doc); - addDocument(doc); + const imgSrc = img.split('src="')[1].split('"')[0]; + const imgOpts = { ...options, _width: 300 }; + if (imgSrc.startsWith('data:image') && imgSrc.includes('base64')) { + const result = (await Networking.PostToServer('/uploadRemoteImage', { sources: [imgSrc] })).lastElement(); + const newImgSrc = + result.accessPaths.agnostic.client.indexOf('dashblobstore') === -1 // + ? Utils.prepend(result.accessPaths.agnostic.client) + : result.accessPaths.agnostic.client; + + addDocument(ImageUtils.AssignImgInfo(Docs.Create.ImageDocument(newImgSrc, imgOpts), result)); + } else if (imgSrc.startsWith('http')) { + const doc = Docs.Create.ImageDocument(imgSrc, imgOpts); + addDocument(ImageUtils.AssignImgInfo(doc, await ImageUtils.ExtractImgInfo(doc))); } return; } else { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1574deede..645e9cff7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1190,7 +1190,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; @computed get childPointerEvents() { const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine); - const pointerevents = DocumentView.Interacting + const pointerevents = SnappingManager.IsResizing ? 'none' : this._props.childPointerEvents?.() ?? (this._props.viewDefDivClick || // @@ -1479,7 +1479,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._disposers.pointerevents = reaction( () => { const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine); - return DocumentView.Interacting + return SnappingManager.IsResizing ? 'none' : this._props.childPointerEvents?.() ?? (this._props.viewDefDivClick || // diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2752fa7f5..823ec885b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1336,7 +1336,6 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { public set SELECTED(val) { runInAction(() => (this._selected = val)); } - @observable public static Interacting = false; @observable public static LongPress = false; @observable public static ExploreMode = false; @observable public static LastPressedSidebarBtn: Opt<Doc>; // bcz: this is a hack to handle highlighting buttons in the leftpanel menu .. need to find a cleaner approach diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index df73dffe4..f205dbd56 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -630,7 +630,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode)) ); this._disposers.youtubeReactionDisposer = reaction( - () => Doc.ActiveTool === InkTool.None && this._props.isSelected() && !SnappingManager.IsDragging && !DocumentView.Interacting, + () => Doc.ActiveTool === InkTool.None && this._props.isSelected() && !SnappingManager.IsDragging && !SnappingManager.IsResizing, interactive => (iframe.style.pointerEvents = interactive ? 'all' : 'none'), { fireImmediately: true } ); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 2522a674d..758c919d2 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -220,7 +220,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps } // else it's an HTMLfield } else if (this.webField && !this.dataDoc.text) { WebRequest.get(Utils.CorsProxy(this.webField.href)) // - .then(result => result && (this.dataDoc.text = htmlToText.convert(result.content))); + .then(result => result && (this.dataDoc.text = htmlToText(result.content))); } this._disposers.scrollReaction = reaction( @@ -491,12 +491,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.layoutDoc.height = Math.min(NumCast(this.layoutDoc._height), (NumCast(this.layoutDoc._width) * NumCast(this.Document.nativeHeight)) / NumCast(this.Document.nativeWidth)); } }; - const swidth = Math.max(NumCast(this.layoutDoc.nativeWidth), iframeContent.body.scrollWidth || 0); + const swidth = Math.max(NumCast(this.Document.nativeWidth), iframeContent.body.scrollWidth || 0); if (swidth) { - const aspectResize = swidth / NumCast(this.Document.nativeWidth); - this.Document.nativeWidth = swidth; - this.Document.nativeHeight = NumCast(this.Document.nativeHeight) * aspectResize; + const aspectResize = swidth / NumCast(this.Document.nativeWidth, swidth); this.layoutDoc.height = NumCast(this.layoutDoc._height) * aspectResize; + this.Document.nativeWidth = swidth; + this.Document.nativeHeight = (swidth * NumCast(this.layoutDoc._height)) / NumCast(this.layoutDoc._width); } initHeights(); this._iframetimeout && clearTimeout(this._iframetimeout); @@ -813,7 +813,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps key={this._warning} className="webBox-iframe" ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))} - style={{ pointerEvents: DocumentView.Interacting ? 'none' : undefined }} + style={{ pointerEvents: SnappingManager.IsResizing ? '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. diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 093806127..f1739a41a 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -12,6 +12,7 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; import * as React from 'react'; +import { SnappingManager } from '../../util/SnappingManager'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. @@ -71,8 +72,8 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV </div> ); - const frozen = !this.props.isSelected() || DocumentView.Interacting; - const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : ''); + const frozen = !this.props.isSelected() || SnappingManager.IsResizing; + const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !SnappingManager.IsResizing ? '-interactive' : ''); return ( <> |
