From c4c3764397eb1ab12c93ea3e07483b436e87d736 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 25 Feb 2021 11:50:54 -0500 Subject: overhaul of state preservation in lightboxview when going back/forward/reopening a doc/etc --- src/client/views/LightboxView.tsx | 101 +++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +-- src/client/views/nodes/DocumentView.tsx | 3 +- 3 files changed, 71 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 1b21bd073..babc518ff 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; @@ -28,32 +28,33 @@ export class LightboxView extends React.Component { @computed public static get LightboxDoc() { return this._doc; } @observable private static _doc: Opt; @observable private static _docTarget: Opt; - @observable private static _tourMap: Opt = []; // list of all tours available from the current target @observable private static _docFilters: string[] = []; // filters - private static _savedState: Opt<{ panX: Opt, panY: Opt, scale: Opt, transition: Opt }>; + @observable private static _tourMap: Opt = []; // list of all tours available from the current target + private static _savedState: Opt<{ panX: Opt, panY: Opt, scale: Opt }>; private static _history: Opt<{ doc: Doc, target?: Doc }[]> = []; private static _future: Opt = []; private static _docView: Opt; - static path: { doc: Opt, target: Opt, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt, saved: Opt<{ panX: Opt, panY: Opt, scale: Opt, transition: Opt }> }[] = []; + static path: { doc: Opt, target: Opt, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt, saved: Opt<{ panX: Opt, panY: Opt, scale: Opt }> }[] = []; @action public static SetLightboxDoc(doc: Opt, target?: Doc, future?: Doc[]) { + if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) { + this.LightboxDoc._panX = this._savedState.panX; + this.LightboxDoc._panY = this._savedState.panY; + this.LightboxDoc._viewScale = this._savedState.scale; + this.LightboxDoc._viewTransition = undefined; + } if (!doc) { this._docFilters && (this._docFilters.length = 0); - if (this.LightboxDoc) { - this.LightboxDoc._panX = this._savedState?.panX; - this.LightboxDoc._panY = this._savedState?.panY; - this.LightboxDoc._viewScale = this._savedState?.scale; - this.LightboxDoc._viewTransition = this._savedState?.transition; - } this._future = this._history = []; } else { TabDocView.PinDoc(doc, { hidePresBox: true }); this._history ? this._history.push({ doc, target }) : this._history = [{ doc, target }]; - this._savedState = { - panX: Cast(doc._panX, "number", null), - panY: Cast(doc._panY, "number", null), - scale: Cast(doc._viewScale, "number", null), - transition: Cast(doc._viewTransition, "string", null) - }; + if (doc !== LightboxView.LightboxDoc) { + this._savedState = { + panX: Cast(doc._panX, "number", null), + panY: Cast(doc._panY, "number", null), + scale: Cast(doc._viewScale, "number", null), + }; + } } if (future) { this._future = future.slice().sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)).sort((a, b) => DocListCast(a.links).length - DocListCast(b.links).length); @@ -92,6 +93,7 @@ export class LightboxView extends React.Component { } // adds a cookie to the lightbox view - the cookie becomes part of a filter which will display any documents whose cookie metadata field matches this cookie + @action public static SetCookie(cookie: string) { if (this.LightboxDoc && cookie) { this._docFilters = (f => this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f])(`cookies:${cookie}:provide`); @@ -117,11 +119,11 @@ export class LightboxView extends React.Component { } else { if (!target && LightboxView.path.length) { const saved = LightboxView._savedState; - if (LightboxView.LightboxDoc) { - LightboxView.LightboxDoc._panX = saved?.panX; - LightboxView.LightboxDoc._panY = saved?.panY; - LightboxView.LightboxDoc._viewScale = saved?.scale; - LightboxView.LightboxDoc._viewTransition = saved?.transition; + if (LightboxView.LightboxDoc && saved) { + LightboxView.LightboxDoc._panX = saved.panX; + LightboxView.LightboxDoc._panY = saved.panY; + LightboxView.LightboxDoc._viewScale = saved.scale; + LightboxView.LightboxDoc._viewTransition = undefined; } const pop = LightboxView.path.pop(); if (pop) { @@ -149,12 +151,17 @@ export class LightboxView extends React.Component { } const { doc, target } = LightboxView._history?.lastElement(); const docView = DocumentManager.Instance.getLightboxDocumentView(target || doc); - const focusSpeed = 1000; - doc._viewTransition = `transform ${focusSpeed}ms`; - LightboxView._doc = doc; - LightboxView._docTarget = target || doc; - docView?.focus(doc, { willZoom: true, scale: 0.9 }); - setTimeout(() => doc._viewTransition = undefined, focusSpeed); + if (docView) { + LightboxView._docTarget = undefined; + const focusSpeed = 1000; + doc._viewTransition = `transform ${focusSpeed}ms`; + if (!target) docView.ComponentView?.shrinkWrap?.(); + else docView.focus(target, { willZoom: true, scale: 0.9 }); + setTimeout(() => doc._viewTransition = undefined, focusSpeed); + } + else { + LightboxView.SetLightboxDoc(doc, target); + } if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links).map(link => { const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); @@ -185,6 +192,8 @@ export class LightboxView extends React.Component { setTimeout(LightboxView.Next); } + future = () => LightboxView._future; + tourMap = () => LightboxView._tourMap; fitToBox = () => LightboxView._docTarget === LightboxView.LightboxDoc; render() { let downx = 0, downy = 0; @@ -204,11 +213,13 @@ export class LightboxView extends React.Component { }}> { LightboxView._docView = r !== null ? r : undefined; - setTimeout(action(() => { - if (r && LightboxView._docTarget === r.props.Document) { - r.ComponentView?.shrinkWrap?.(); - } - r && (LightboxView._docTarget = undefined); + r && setTimeout(action(() => { + const target = LightboxView._docTarget; + const doc = LightboxView._doc; + const targetView = target && DocumentManager.Instance.getLightboxDocumentView(target); + if (doc === r.props.Document && (!target || target === doc)) r.ComponentView?.shrinkWrap?.(); + else target && targetView?.focus(target, { willZoom: true, scale: 0.9, instant: true }); + LightboxView._docTarget = undefined; })); })} Document={LightboxView.LightboxDoc} @@ -246,13 +257,25 @@ export class LightboxView extends React.Component { e.stopPropagation(); LightboxView.Next(); })} - {this.navBtn("50%", 0, 0, "chevron-down", - () => LightboxView.LightboxDoc && LightboxView._future?.length ? "" : "none", e => { - e.stopPropagation(); - this.stepInto(); - }, - StrCast(LightboxView._tourMap?.lastElement()?.TourMap) - )} + ; } +} +interface LightboxTourBtnProps { + navBtn: (left: Opt, bottom: Opt, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element; + tourMap: () => Opt; + future: () => Opt; + stepInto: () => void; +} +@observer +export class LightboxTourBtn extends React.Component { + render() { + return this.props.navBtn("50%", 0, 0, "chevron-down", + () => LightboxView.LightboxDoc && this.props.future()?.length ? "" : "none", e => { + e.stopPropagation(); + this.props.stepInto(); + }, + StrCast(this.props.tourMap()?.lastElement()?.TourMap) + ) + } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dfca2ba07..4040362d8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -914,7 +914,6 @@ export class CollectionFreeFormView extends CollectionSubView this._viewTransition = 0); } return resetView; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01d799255..e58aaba65 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -71,6 +71,7 @@ export interface DocFocusOptions { scale?: number; // percent of containing frame to zoom into document afterFocus?: DocAfterFocusFunc; // function to call after focusing on a document docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy + instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) } export type DocAfterFocusFunc = (notFocused: boolean) => Promise; export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; @@ -80,7 +81,7 @@ export interface DocComponentView { scrollFocus?: (doc: Doc, smooth: boolean) => Opt; // returns the duration of the focus 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. - shrinkWrap?: () => boolean; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views + shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected. } export interface DocumentViewSharedProps { -- cgit v1.2.3-70-g09d2