diff options
author | bobzel <zzzman@gmail.com> | 2021-02-24 22:04:31 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2021-02-24 22:04:31 -0500 |
commit | 3410e107435410a5635a70f12ee05e2d874ff01c (patch) | |
tree | 5d9fdfbc66199665a33847f67edae8650f2aae34 /src | |
parent | 58adadeaaf97c57a15d42fea86e75180fc3b2c14 (diff) |
cleaned up DocumentView's contentView api to be more general. fixed screenToLocal for freeformView's whenb _fitToBox is set. moved webBox menu items out of CollectionMenu and into WebBox using the contentView API.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionMenu.tsx | 57 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 18 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 17 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 47 |
7 files changed, 68 insertions, 77 deletions
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 423c94005..591b4161e 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -560,7 +560,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu @computed get isText() { return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; } - @computed get webBoxUrl() { return this.selectedDocumentView?.ComponentView?.url?.(); } @undoBatch @action @@ -733,58 +732,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu </div>; } - - onWebUrlDrop = (e: React.DragEvent) => { - const { dataTransfer } = e; - const html = dataTransfer.getData("text/html"); - const uri = dataTransfer.getData("text/uri-list"); - const url = uri || html || this.webBoxUrl || ""; - const newurl = url.startsWith(window.location.origin) ? - url.replace(window.location.origin, this.webBoxUrl?.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url; - this.submitWebUrl(newurl); - e.stopPropagation(); - } - onWebUrlValueKeyDown = (e: React.KeyboardEvent) => { - e.key === "Enter" && this.submitWebUrl(this._keyInput.current!.value); - e.stopPropagation(); - } - submitWebUrl = (url: string) => this.selectedDocumentView?.ComponentView?.submitURL?.(url); - webUrlForward = () => this.selectedDocumentView?.ComponentView?.forward?.(); - webUrlBack = () => this.selectedDocumentView?.ComponentView?.back?.(); - - private _keyInput = React.createRef<HTMLInputElement>(); - - @computed get urlEditor() { - return ( - <div className="collectionMenu-webUrlButtons" onDrop={this.onWebUrlDrop} onDragOver={e => e.preventDefault()} > - <input className="collectionMenu-urlInput" key={this.webBoxUrl} - placeholder="ENTER URL" - defaultValue={this.webBoxUrl} - onDrop={this.onWebUrlDrop} - onDragOver={e => e.preventDefault()} - onKeyDown={this.onWebUrlValueKeyDown} - onClick={(e) => { - this._keyInput.current!.select(); - e.stopPropagation(); - }} - ref={this._keyInput} - /> - <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", maxWidth: "250px", }}> - <button className="submitUrl" onClick={() => this.submitWebUrl(this._keyInput.current!.value)} onDragOver={e => e.stopPropagation()} onDrop={this.onWebUrlDrop}> - GO - </button> - <button className="submitUrl" onClick={this.webUrlBack}> - <FontAwesomeIcon icon="caret-left" size="lg"></FontAwesomeIcon> - </button> - <button className="submitUrl" onClick={this.webUrlForward}> - <FontAwesomeIcon icon="caret-right" size="lg"></FontAwesomeIcon> - </button> - </div> - </div> - ); - } - - @observable viewType = this.selectedDoc?._viewType; render() { @@ -811,9 +758,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu </> : null} - {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) : - this.urlEditor - } + {!this.selectedDocumentView?.ComponentView?.menuControls ? (null) : this.selectedDocumentView?.ComponentView?.menuControls?.()} {!this.isText ? <> {this.drawButtons} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index a05c25c9b..eb0538c41 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -191,7 +191,7 @@ .collectionfreeformview-container { // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; - + transform-origin: top left; .collectionfreeformview-placeholder { background: gray; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 96ef7af01..92c09ff3f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -69,7 +69,7 @@ type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSch const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema); export type collectionFreeformViewProps = { parentActive: (outsideReaction: boolean) => boolean; - forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) + annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: boolean; scaleField?: string; @@ -157,10 +157,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined; freeformDocFilters = () => this._focusFilters || this.docFilters(); freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); + reverseNativeScaling = () => this.fitToContent ? true : false; panX = () => this.freeformData()?.panX ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); - contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)` + contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); getLocalTransform = () => this.cachedGetLocalTransform.copy(); getContainerTransform = () => this.cachedGetContainerTransform.copy(); @@ -1274,11 +1275,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } @undoBatch - toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); + toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight) @undoBatch @action - toggleLockTransform = () => this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true; + toggleLockTransform = () => this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true onContextMenu = (e: React.MouseEvent) => { if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; @@ -1462,7 +1463,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } @computed get contentScaling() { - if (this.props.isAnnotationOverlay && !this.props.forceScaling) return 0; + if (this.props.isAnnotationOverlay && !this.props.annotationLayerHostsContent) return 0; const nw = this.nativeWidth; const nh = this.nativeHeight; const hscale = nh ? this.props.PanelHeight() / nh : 1; @@ -1484,10 +1485,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P onContextMenu={this.onContextMenu} style={{ pointerEvents: this.backgroundEvents ? "all" : undefined, - transform: this.contentScaling ? `scale(${this.contentScaling})` : "", - transformOrigin: this.contentScaling ? "left top" : "", - width: this.contentScaling ? `${100 / this.contentScaling}%` : "", - height: this.contentScaling ? `${100 / this.contentScaling}%` : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight() + transform: `scale(${this.contentScaling || 1})`, + width: `${100 / (this.contentScaling || 1)}%`, + height: this.isAnnotationOverlay && this.Document.scrollHeight ? this.Document.scrollHeight : `${100 / (this.contentScaling || 1)}%`// : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight() }}> {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5dfb3e99b..ec2c77a82 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -76,14 +76,13 @@ export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment> export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => any; export interface DocComponentView { - getAnchor?: () => Doc; + getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus - setViewSpec?: (anchor: Doc, preview: boolean) => void; - back?: () => boolean; - forward?: () => boolean; - url?: () => string; - submitURL?: (url: string) => boolean; - freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; + setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document + reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. + menuControls?: any; // controls to display in the top menu bar when the document is selected. + // this is kind of hacky since it's not really a generic interface. need to think about how to do this better (it's used to fit a tab's contents to view when shown in a lightbox and to setup the minimap) + freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; // the content bounds, pan position and zoom scale of a content view (typically for FreeformViews) } export interface DocumentViewSharedProps { renderDepth: number; @@ -990,8 +989,8 @@ export class DocumentView extends React.Component<DocumentViewProps> { @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } - @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } - @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); } + @computed get nativeWidth() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } + @computed get nativeHeight() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); } @computed get nativeScaling() { if (this.nativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.nativeHeight > this.props.PanelWidth() / this.nativeWidth)) { return this.props.PanelWidth() / this.nativeWidth; // width-limited or fitWidth diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 728e5e02f..4c3031ae2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -381,7 +381,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD removeDocument={this.removeDocument} moveDocument={this.moveDocument} addDocument={this.addDocument} - forceScaling={true} + annotationLayerHostsContent={true} focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 435563255..ac67949f9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -552,7 +552,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} fieldKey={this.annotationKey} isAnnotationOverlay={true} - forceScaling={true} + annotationLayerHostsContent={true} select={emptyFunction} active={this.annotationsActive} scaling={returnOne} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 663a8b8e4..2cd6f5f33 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -46,6 +46,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _iframeIndicatorRef = React.createRef<HTMLDivElement>(); private _iframeDragRef = React.createRef<HTMLDivElement>(); + private _keyInput = React.createRef<HTMLInputElement>(); private _ignoreScroll = false; private _initialScroll: Opt<number>; @observable private _marqueeing: number[] | undefined; @@ -262,6 +263,52 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum return true; } + menuControls = () => this.urlEditor; + onWebUrlDrop = (e: React.DragEvent) => { + const { dataTransfer } = e; + const html = dataTransfer.getData("text/html"); + const uri = dataTransfer.getData("text/uri-list"); + const url = uri || html || this._url || ""; + const newurl = url.startsWith(window.location.origin) ? + url.replace(window.location.origin, this._url?.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url; + this.submitURL(newurl); + e.stopPropagation(); + } + onWebUrlValueKeyDown = (e: React.KeyboardEvent) => { + e.key === "Enter" && this.submitURL(this._keyInput.current!.value); + e.stopPropagation(); + } + + @computed get urlEditor() { + return ( + <div className="collectionMenu-webUrlButtons" onDrop={this.onWebUrlDrop} onDragOver={e => e.preventDefault()} > + <input className="collectionMenu-urlInput" key={this._url} + placeholder="ENTER URL" + defaultValue={this._url} + onDrop={this.onWebUrlDrop} + onDragOver={e => e.preventDefault()} + onKeyDown={this.onWebUrlValueKeyDown} + onClick={(e) => { + this._keyInput.current!.select(); + e.stopPropagation(); + }} + ref={this._keyInput} + /> + <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", maxWidth: "250px", }}> + <button className="submitUrl" onClick={() => this.submitURL(this._keyInput.current!.value)} onDragOver={e => e.stopPropagation()} onDrop={this.onWebUrlDrop}> + GO + </button> + <button className="submitUrl" onClick={this.back}> + <FontAwesomeIcon icon="caret-left" size="lg"></FontAwesomeIcon> + </button> + <button className="submitUrl" onClick={this.forward}> + <FontAwesomeIcon icon="caret-right" size="lg"></FontAwesomeIcon> + </button> + </div> + </div> + ); + } + editToggleBtn() { return <Tooltip title={<div className="dash-tooltip" >{`${this.props.Document.isAnnotating ? "Exit" : "Enter"} annotation mode`}</div>}> <div className="webBox-annotationToggle" |