aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/LightboxView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/LightboxView.tsx')
-rw-r--r--src/client/views/LightboxView.tsx171
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);
+});