diff options
Diffstat (limited to 'src/client/views/LightboxView.tsx')
-rw-r--r-- | src/client/views/LightboxView.tsx | 171 |
1 files changed, 102 insertions, 69 deletions
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index ef4b5b4ca..7198c7f05 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -1,34 +1,34 @@ +/* eslint-disable no-use-before-define */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../Utils'; -import { Doc, DocListCast, FieldResult, Opt } from '../../fields/Doc'; +import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../ClientUtils'; +import { emptyFunction } from '../../Utils'; +import { CreateLinkToActiveAudio, Doc, DocListCast, FieldResult, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkTool } from '../../fields/InkField'; -import { Cast, NumCast } from '../../fields/Types'; -import { DocUtils } from '../documents/Documents'; -import { DocumentManager } from '../util/DocumentManager'; -import { LinkManager } from '../util/LinkManager'; -import { SelectionManager } from '../util/SelectionManager'; -import { SettingsManager } from '../util/SettingsManager'; +import { Cast, NumCast, toList } from '../../fields/Types'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { GestureOverlay } from './GestureOverlay'; import './LightboxView.scss'; import { ObservableReactComponent } from './ObservableReactComponent'; import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline'; -import { TabDocView } from './collections/TabDocView'; -import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView } from './nodes/DocumentView'; +import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere'; +import { ScriptingGlobals } from '../util/ScriptingGlobals'; +import { OverlayView } from './OverlayView'; interface LightboxViewProps { PanelWidth: number; PanelHeight: number; maxBorder: number[]; + addSplit: (document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string | undefined, keyValue?: boolean | undefined) => boolean; } const savedKeys = ['freeform_panX', 'freeform_panY', 'freeform_scale', 'layout_scrollTop', 'layout_fieldKey']; @@ -41,7 +41,8 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { * @returns true if a DocumentView is descendant of the lightbox view */ public static Contains(view?:DocumentView) { return view && LightboxView.Instance?._docView && (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView); } // prettier-ignore - public static get LightboxDoc() { return LightboxView.Instance?._doc; } // prettier-ignore + public static LightboxDoc = () => LightboxView.Instance?._doc; + // eslint-disable-next-line no-use-before-define static Instance: LightboxView; private _path: { doc: Opt<Doc>; // @@ -66,19 +67,36 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { super(props); makeObservable(this); LightboxView.Instance = this; + DocumentView._setLightboxDoc = this.SetLightboxDoc; + DocumentView._lightboxContains = LightboxView.Contains; + DocumentView._lightboxDoc = LightboxView.LightboxDoc; } - + /** + * Sets the root Doc to render in the lightbox view. + * @param doc + * @param target a Doc within 'doc' to focus on (useful for freeform collections) + * @param future a list of Docs to step through with the arrow buttons of the lightbox + * @param layoutTemplate a template to apply to 'doc' to render it. + * @returns success flag which is currently always true + */ @action - public SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) { + public SetLightboxDoc = (doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) => { const lightDoc = this._doc; - lightDoc && lightDoc !== doc && savedKeys.forEach(key => (lightDoc[key] = this._savedState[key])); + lightDoc && + lightDoc !== doc && + savedKeys.forEach(key => { + lightDoc[key] = this._savedState[key]; + }); this._savedState = {}; if (doc) { - lightDoc !== doc && savedKeys.map(key => (this._savedState[key] = Doc.Get(doc, key, true))); - const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement(); + lightDoc !== doc && + savedKeys.forEach(key => { + this._savedState[key] = Doc.Get(doc, key, true); + }); + const l = CreateLinkToActiveAudio(() => doc).lastElement(); l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); - CollectionStackedTimeline.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.()); + DocumentView.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.()); this._history.push({ doc, target }); } else { this._future = []; @@ -86,14 +104,14 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { Doc.ActiveTool = InkTool.None; SnappingManager.SetExploreMode(false); } - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); if (future) { this._future.push( ...(this._doc ? [this._doc] : []), ...future .slice() .sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)) - .sort((a, b) => LinkManager.Links(a).length - LinkManager.Links(b).length) + .sort((a, b) => Doc.Links(a).length - Doc.Links(b).length) ); } this._doc = doc; @@ -104,10 +122,11 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { this._docTarget = target ?? doc; return true; - } + }; - public AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => - this.SetLightboxDoc( + public AddDocTab = (docs: Doc | Doc[], location: OpenWhere, layoutTemplate?: Doc | string) => { + const doc = toList(docs).lastElement(); + return this.SetLightboxDoc( doc, undefined, [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...this._future].sort( @@ -115,19 +134,22 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { ), layoutTemplate ); + }; @action next = () => { const lightDoc = this._doc; if (!lightDoc) return; const target = (this._docTarget = this._future.pop()); - const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target); + const targetDocView = target && DocumentView.getLightboxDocumentView(target); if (targetDocView && target) { - const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); + const l = CreateLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); - DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); + DocumentView.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); if (this._history.lastElement().target !== target) this._history.push({ doc: lightDoc, target }); } else if (!target && this._path.length) { - savedKeys.forEach(key => (lightDoc[key] = this._savedState[key])); + savedKeys.forEach(key => { + lightDoc[key] = this._savedState[key]; + }); this._path.pop(); } else { this.SetLightboxDoc(target); @@ -141,10 +163,10 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { return; } const { doc, target } = this._history.lastElement(); - const docView = DocumentManager.Instance.getLightboxDocumentView(target || doc); + const docView = DocumentView.getLightboxDocumentView(target || doc); if (docView) { this._docTarget = target; - target && DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); + target && DocumentView.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); } else { this.SetLightboxDoc(doc, target); } @@ -162,8 +184,8 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { if (this._docTarget) { const fieldKey = Doc.LayoutFieldKey(this._docTarget); const contents = [...DocListCast(this._docTarget[fieldKey]), ...DocListCast(this._docTarget[fieldKey + '_annotations'])]; - const links = LinkManager.Links(this._docTarget) - .map(link => LinkManager.getOppositeAnchor(link, this._docTarget!)!) + const links = Doc.Links(this._docTarget) + .map(link => Doc.getOppositeAnchor(link, this._docTarget!)!) .filter(doc => doc); this.SetLightboxDoc(this._docTarget, undefined, contents.length ? contents : links); } @@ -173,12 +195,16 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { const lightDoc = this._docTarget ?? this._doc; if (lightDoc) { Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightDoc); - CollectionDockingView.AddSplit(lightDoc, OpenWhereMod.none); + this._props.addSplit(lightDoc, OpenWhereMod.none); this.SetLightboxDoc(undefined); } }; - toggleFitWidth = () => this._doc && (this._doc._layout_fitWidth = !this._doc._layout_fitWidth); - togglePen = () => (Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen); + toggleFitWidth = () => { + this._doc && (this._doc._layout_fitWidth = !this._doc._layout_fitWidth); + }; + togglePen = () => { + Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen; + }; toggleExplore = () => SnappingManager.SetExploreMode(!SnappingManager.ExploreMode); lightboxDoc = () => this._doc; @@ -188,39 +214,37 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { lightboxDocTemplate = () => this._layoutTemplate; future = () => this._future; - renderNavBtn = (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: IconProp, display: any, click: () => void, color?: string) => { - return ( + renderNavBtn = (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: IconProp, display: any, click: () => void, color?: string) => ( + <div + className="lightboxView-navBtn-frame" + style={{ + display: display ? '' : 'none', + left, + width: bottom !== undefined ? undefined : Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]), + bottom, + }}> <div - className="lightboxView-navBtn-frame" - style={{ - display: display ? '' : 'none', - left, - width: bottom !== undefined ? undefined : Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]), - bottom, + className="lightboxView-navBtn" + title={color} + style={{ top, color: SnappingManager.userColor, background: undefined }} + onClick={e => { + e.stopPropagation(); + click(); }}> - <div - className="lightboxView-navBtn" - title={color} - style={{ top, color: SettingsManager.userColor, background: undefined }} - onClick={e => { - e.stopPropagation(); - click(); - }}> - <div style={{ height: 10 }}>{color}</div> - <FontAwesomeIcon icon={icon} size="3x" /> - </div> + <div style={{ height: 10 }}>{color}</div> + <FontAwesomeIcon icon={icon} size="3x" /> </div> - ); - }; + </div> + ); render() { - let downx = 0, - downy = 0; + let downx = 0; + let downy = 0; const toggleBtn = (classname: string, tooltip: string, toggleBackground: any, icon: IconProp, icon2: IconProp | string, onClick: () => void) => ( <div className={classname}> <Toggle tooltip={tooltip} - color={SettingsManager.userColor} - background={toggleBackground ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} + color={SnappingManager.userColor} + background={toggleBackground ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} toggleType={ToggleType.BUTTON} type={Type.TERT} icon={<FontAwesomeIcon icon={toggleBackground ? icon : (icon2 as IconProp) || icon} size="sm" />} @@ -231,15 +255,17 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { /> </div> ); - return !this._doc ? null : ( + return !this._doc ? ( + <OverlayView /> + ) : ( <div className="lightboxView-frame" - style={{ background: SettingsManager.userBackgroundColor }} + style={{ background: SnappingManager.userBackgroundColor }} onPointerDown={e => { downx = e.clientX; downy = e.clientY; }} - onClick={e => Utils.isClick(e.clientX, e.clientY, downx, downy, Date.now()) && this.SetLightboxDoc(undefined)}> + onClick={e => ClientUtils.isClick(e.clientX, e.clientY, downx, downy, Date.now()) && this.SetLightboxDoc(undefined)}> <div className="lightboxView-contents" style={{ @@ -248,12 +274,14 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { width: this.lightboxWidth(), height: this.lightboxHeight(), clipPath: `path('${Doc.UserDoc().renderStyle === 'comic' ? wavyBorderPath(this.lightboxWidth(), this.lightboxHeight()) : undefined}')`, - background: SettingsManager.userBackgroundColor, + background: SnappingManager.userBackgroundColor, }}> - <GestureOverlay isActive={true}> + <GestureOverlay isActive> <DocumentView key={this._doc.title + this._doc[Id]} // this makes a new DocumentView when the document changes which makes link following work, otherwise no DocView is registered for the new Doc - ref={action((r: DocumentView | null) => (this._docView = r !== null ? r : undefined))} + ref={action((r: DocumentView | null) => { + this._docView = r !== null ? r : undefined; + })} Document={this._doc} PanelWidth={this.lightboxWidth} PanelHeight={this.lightboxHeight} @@ -263,7 +291,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { styleProvider={DefaultStyleProvider} ScreenToLocalTransform={this.lightboxScreenToLocal} renderDepth={0} - suppressSetHeight={this._doc._layout_fitWidth ? true : false} + suppressSetHeight={!!this._doc._layout_fitWidth} containerViewPath={returnEmptyDoclist} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} @@ -272,8 +300,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { removeDocument={undefined} whenChildContentsActiveChanged={emptyFunction} addDocTab={this.AddDocTab} - pinToPres={TabDocView.PinDoc} - onBrowseClickScript={DocumentView.exploreMode} + pinToPres={DocumentView.PinDoc} focus={emptyFunction} /> </GestureOverlay> @@ -300,6 +327,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> { } interface LightboxTourBtnProps { navBtn: (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: IconProp, display: any, click: () => void, color?: string) => JSX.Element; + // eslint-disable-next-line react/no-unused-prop-types future: () => Opt<Doc[]>; stepInto: () => void; lightboxDoc: () => Opt<Doc>; @@ -310,3 +338,8 @@ export class LightboxTourBtn extends React.Component<LightboxTourBtnProps> { return this.props.navBtn('50%', 0, 0, 'chevron-down', this.props.lightboxDoc(), this.props.stepInto, ''); } } + +// eslint-disable-next-line prefer-arrow-callback +ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView) { + LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightboxAlways, 'layout'); // , 0); +}); |