From 57c1b8235b26a1b6a315922b4dc2926e1e597674 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 13 May 2022 18:17:10 -0400 Subject: removed layerProvider functionality. --- src/mobile/AudioUpload.tsx | 1 - src/mobile/MobileInterface.tsx | 1 - 2 files changed, 2 deletions(-) (limited to 'src/mobile') diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx index 88221732e..418464f0e 100644 --- a/src/mobile/AudioUpload.tsx +++ b/src/mobile/AudioUpload.tsx @@ -96,7 +96,6 @@ export class AudioUpload extends React.Component { isDocumentActive={returnTrue} isContentActive={emptyFunction} focus={emptyFunction} - layerProvider={undefined} styleProvider={() => "rgba(0,0,0,0)"} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index cfcc48608..78ec706d7 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -214,7 +214,6 @@ export class MobileInterface extends React.Component { isContentActive={emptyFunction} focus={DocUtils.DefaultFocus} styleProvider={this.whitebackground} - layerProvider={undefined} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} -- cgit v1.2.3-70-g09d2 From 3213c24210d67af0a4b027863773ad383404a59c Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 9 Jun 2022 11:07:34 -0400 Subject: renamed fitToBox to fitContentsToBox. fixed pinning multiple documents at same time to not bring up presBox multiple times. --- src/client/documents/Documents.ts | 3 +- src/client/views/DocumentButtonBar.tsx | 21 ++---------- src/client/views/LightboxView.tsx | 2 -- src/client/views/MainView.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 2 +- src/client/views/PropertiesView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 4 +-- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 25 +++++++-------- src/client/views/collections/TreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 37 +++++++--------------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +-- src/client/views/nodes/MapBox/MapBox.tsx | 6 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 ++-- src/client/views/nodes/trails/PresBox.tsx | 14 ++++---- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/fields/documentSchemas.ts | 6 ++-- src/mobile/AudioUpload.tsx | 4 +-- 22 files changed, 60 insertions(+), 92 deletions(-) (limited to 'src/mobile') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index acc1e341a..144a3d9cf 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -113,7 +113,8 @@ export class DocumentOptions { _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", true); _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units", true); _fitWidth?: BOOLt = new BoolInfo("whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)", true); - _fitToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents + _fitContentsToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents + _contentBounds?: List; // the (forced) bounds of the document to display. format is: [left, top, right, bottom] _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed _isPushpin?: boolean; // whether document, when clicked, toggles display of its link target diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 41224b1c5..0bbe473d7 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -204,27 +204,13 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{SelectionManager.Views().length > 1 ? "Pin multiple documents to presentation" : "Pin to presentation"}
}>
this.props.views().map(view => view && this.pinWithView(view.props.Document)))}> + onClick={(e => TabDocView.PinDoc(this.props.views().filter(v => v).map(dv => dv!.rootDoc), {pinDocView: true}))} + >
; } - @undoBatch - @action - pinWithView = (targetDoc: Doc) => targetDoc && TabDocView.PinDoc(targetDoc, {pinDocView: true}); - - @computed - get pinWithViewButton() { - const presPinWithViewIcon = ; - const targetDoc = this.view0?.props.Document; - return !targetDoc ? (null) :
{"Pin with current view"}
}> -
this.pinWithView(targetDoc)}> - {presPinWithViewIcon} -
-
; - } - @computed get shareButton() { const targetDoc = this.view0?.props.Document; @@ -349,9 +335,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{this.pinButton}
- {/*
- {this.pinWithViewButton} -
*/} {!Doc.UserDoc()["documentLinksButton-fullMenu"] ? (null) :
{this.shareButton}
} diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index f67f37bfb..fcc4aea13 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -207,7 +207,6 @@ export class LightboxView extends React.Component { future = () => LightboxView._future; tourMap = () => LightboxView._tourMap; - fitToBox = () => LightboxView._docTarget === LightboxView.LightboxDoc; render() { let downx = 0, downy = 0; return !LightboxView.LightboxDoc ? (null) : @@ -241,7 +240,6 @@ export class LightboxView extends React.Component { DataDoc={undefined} LayoutTemplate={LightboxView.LightboxDocTemplate} addDocument={undefined} - // fitContentsToDoc={this.fitToBox} // bcz: why do we want this? when we initially open a colletion, we shrinkwrap it which allows for user navigation. if we later encounter a collection, it's not clear to me that we want to make it either shrinkwrap or fitContents... isDocumentActive={returnFalse} isContentActive={returnTrue} addDocTab={this.addDocTab} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 641178cd9..84a131a57 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -287,7 +287,7 @@ export class MainView extends React.Component { styleProvider={DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} - fitContentsToDoc={returnTrue} + fitContentsToBox={returnTrue} isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events) isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive ScreenToLocalTransform={this.headerBarScreenXf} diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index f24ff09db..74055f057 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -71,7 +71,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { return this.propertyToggleBtn("Lock\xA0View", "_lockedTransform", on => `${on ? "Unlock" : "Lock"} panning of view`, on => "lock"); } @computed get fitContentButton() { - return this.propertyToggleBtn("View All", "_fitToBox", on => `${on ? "Don't" : "Do"} fit content to container visible area`, on => "eye"); + return this.propertyToggleBtn("View All", "_fitContentsToBox", on => `${on ? "Don't" : "Do"} fit content to container visible area`, on => "eye"); } @computed get fitWidthButton() { return this.propertyToggleBtn("Fit\xA0Width", "_fitWidth", on => `${on ? "Don't" : "Do"} fit content to width of container`, on => "arrows-alt-h"); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index bcfd2dd56..16eb95cf4 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -300,7 +300,7 @@ export class PropertiesView extends React.Component { Document={layoutDoc} DataDoc={this.dataDoc} renderDepth={1} - fitContentsToDoc={returnTrue} + fitContentsToBox={returnTrue} rootSelected={returnFalse} styleProvider={DefaultStyleProvider} docViewPath={returnEmptyDoclist} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 01e77f342..39f6466d6 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -252,8 +252,8 @@ export class CollectionViewBaseChrome extends React.Component this.target._fitToBox = !this.target._fitToBox), + script: "self.target._fitContentsToBox = !self.target._fitContentsToBox;", + immediate: undoBatch((source: Doc[]) => this.target._fitContentsToBox = !this.target._fitContentsToBox), initialize: emptyFunction }; _fitContentCommand = { diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 4f6f45d2f..7573b938a 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -135,7 +135,7 @@ export class CollectionTimeView extends CollectionSubView() { onClick={this.contentsDown}> { * Adds a document to the presentation view **/ @action - public static PinDoc(doc: Doc, pinProps?: PinProps) { - //add this new doc to props.Document + public static PinDoc(docs: Doc|Doc[], pinProps?: PinProps) { + const docList = ((docs instanceof Doc) ? [docs]: docs); + const batch = UndoManager.StartBatch("pinning doc"); // all docs will be added to the ActivePresentation as stored on CurrentUserUtils const curPres = CurrentUserUtils.ActivePresentation; - if (curPres) { + curPres && docList.forEach(doc => { // Edge Case 1: Cannot pin document to itself if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; } - const batch = UndoManager.StartBatch("pinning doc"); const pinDoc = Doc.MakeAlias(doc); pinDoc.presentationTargetDoc = doc; pinDoc.title = doc.title + " - Slide"; @@ -279,17 +279,16 @@ export class TabDocView extends React.Component { pinDoc.presMovement = PresMovement.None; } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; - if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { - const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); - if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); - CollectionDockingView.AddSplit(curPres, "right"); - setTimeout(() => DocumentManager.Instance.jumpToDocument(doc, false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things - } PresBox.Instance?._selectedArray.clear(); pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array - setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs - return pinDoc; + }); + if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { + const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); + if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); + CollectionDockingView.AddSplit(curPres, "right"); + setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things } + setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs } componentDidMount() { @@ -572,7 +571,7 @@ export class TabMinimapView extends React.Component { docFilters={CollectionDockingView.Instance.childDocFilters} docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters} searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} - fitContentsToDoc={returnTrue} + fitContentsToBox={returnTrue} />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 09f05f69a..8824750a3 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -796,7 +796,7 @@ export class TreeView extends React.Component { isDocumentActive={isActive} styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} hideTitle={asText} - fitContentsToDoc={returnTrue} + fitContentsToBox={returnTrue} hideDecorationTitle={this.props.treeView.outlineMode} hideResizeHandles={this.props.treeView.outlineMode} onClick={this.onChildClick} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b70e6ff98..ec3cf1fe8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -9,7 +9,7 @@ import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fiel import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; -import { createSchema, listSpec } from "../../../../fields/Schema"; +import { listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { ImageField } from "../../../../fields/URLField"; @@ -41,6 +41,7 @@ import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveIn import { LightboxView } from "../../LightboxView"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView"; +import { FieldViewProps } from "../../nodes/FieldView"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { PresBox } from "../../nodes/trails/PresBox"; import { VideoBox } from "../../nodes/VideoBox"; @@ -50,27 +51,13 @@ import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; import { TreeViewType } from "../CollectionTreeView"; import { CollectionViewType } from "../CollectionView"; +import { TabDocView } from "../TabDocView"; import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { FieldView, FieldViewProps } from "../../nodes/FieldView"; -import { TabDocView } from "../TabDocView"; -export const panZoomSchema = createSchema({ - _panX: "number", - _panY: "number", - _currentTimecode: "number", - _timecodeToShow: "number", - _currentFrame: "number", - _useClusters: "boolean", - _viewTransition: "string", - _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - _yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - _fitToBox: "boolean", - scrollHeight: "number" // this will be set when the collection is an annotation overlay for a PDF/Webpage -}); export type collectionFreeformViewProps = { annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) @@ -138,20 +125,20 @@ export class CollectionFreeFormView extends CollectionSubView e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); } - @computed get nativeWidth() { return this.fitToContent ? 0 : Doc.NativeWidth(this.Document); } - @computed get nativeHeight() { return this.fitToContent ? 0 : Doc.NativeHeight(this.Document); } + @computed get nativeWidth() { return this.fitContentsToBox ? 0 : Doc.NativeWidth(this.Document); } + @computed get nativeHeight() { return this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document); } @computed get cachedCenteringShiftX(): number { - const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; + const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling; return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections } @computed get cachedCenteringShiftY(): number { - const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; + const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling; return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / scaling;// shift so pan position is at center of window for non-overlay collections } @computed get cachedGetLocalTransform(): Transform { @@ -176,8 +163,8 @@ export class CollectionFreeFormView extends CollectionSubView !this._firstRender && (this.fitToContent || force) ? this.fitToContentVals : undefined; - reverseNativeScaling = () => this.fitToContent ? true : false; + freeformData = (force?: boolean) => !this._firstRender && (this.fitContentsToBox || force) ? this.fitToContentVals : undefined; + reverseNativeScaling = () => this.fitContentsToBox ? true : false; panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY); zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); @@ -1272,7 +1259,7 @@ export class CollectionFreeFormView extends CollectionSubView; } addDocTab = action((doc: Doc, where: string) => { @@ -1616,7 +1603,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); !Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); - appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + appearanceItems.push({ description: `${this.fitContentsToBox ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitContentsToBox = !this.fitContentsToBox, icon: !this.fitContentsToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, {pinDocView:true, panelWidth: this.props.PanelWidth(), panelHeight:this.props.PanelHeight()}), icon: "map-pin" }); //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); this.props.ContainingCollectionView && diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 3fac3350a..6df2bb102 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -516,7 +516,7 @@ export class MarqueeView extends React.Component 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; // 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. + reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. 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. isAnyChildContentActive?: () => boolean; // is any child content of the document active @@ -113,7 +113,7 @@ export interface DocumentViewSharedProps { Document: Doc; DataDoc?: Doc; contentBounds?: () => (undefined|{x:number, y:number, r:number, b:number}); - fitContentsToDoc?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document + fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; suppressSetHeight?: boolean; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 9f1c019fe..5f4c17ee6 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -259,7 +259,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitToBox && this.fitBounds(this._map); + this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapLat = this._map.getCenter()?.lat(); this.dataDoc.mapLng = this._map.getCenter()?.lng(); @@ -284,7 +284,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitToBox && this.fitBounds(this._map); + this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapZoom = this._map.getZoom(); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 7d0302b26..4e431e7bd 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -495,7 +495,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp // embed document when dragg marked as embed } else if (de.embedKey) { const target = dragData.droppedDocuments[0]; - target._fitToBox = true; + target._fitContentsToBox = true; const node = schema.nodes.dashDoc.create({ width: target[WidthSym](), height: target[HeightSym](), @@ -1557,7 +1557,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } } - fitToBox = () => this.props.Document._fitToBox; + fitContentsToBox = () => this.props.Document._fitContentsToBox; sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); @@ -1632,7 +1632,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp ScreenToLocalTransform={this.sidebarScreenToLocal} renderDepth={this.props.renderDepth + 1} setHeight={this.setSidebarHeight} - fitContentsToDoc={this.fitToBox} + fitContentsToBox={this.fitContentsToBox} noSidebar={true} fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : `${this.fieldKey}-annotations`} />; }; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 6de04bd31..cebf9487a 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -35,8 +35,8 @@ export interface PinProps { setPosition?: boolean; hidePresBox?: boolean; pinWithView?: PinViewProps; - pinDocView?: boolean; - panelWidth?: number; + pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document + panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area) panelHeight?: number } @@ -997,7 +997,7 @@ export class PresBox extends ViewBoxBaseComponent() { /** * Method called for viewing paths which adds a single line with * points at the center of each document added. - * Design choice: When this is called it sets _fitToBox as true so the + * Design choice: When this is called it sets _fitContentsToBox as true so the * user can have an overview of all of the documents in the collection. * (Design needed for when documents in presentation trail are in another * collection) @@ -1800,16 +1800,16 @@ export class PresBox extends ViewBoxBaseComponent() { doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y }); break; case 'title': - doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'header': - doc = Docs.Create.FreeformDocument([header], { title: input ? input : "Section header", _width: 400, _height: 225, _fitToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([header], { title: input ? input : "Section header", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'content': - doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : "Title and content", _width: 400, _height: 225, _fitToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : "Title and content", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'twoColumns': - doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : "Title and two columns", _width: 400, _height: 225, _fitToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : "Title and two columns", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; default: break; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 5eff47a86..ba0193e4b 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -85,7 +85,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { isContentActive={this.props.isContentActive} addDocTab={returnFalse} pinToPres={returnFalse} - fitContentsToDoc={returnTrue} + fitContentsToBox={returnTrue} PanelWidth={this.embedWidth} PanelHeight={this.embedHeight} ScreenToLocalTransform={Transform.Identity} diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index e532becb5..be39e0709 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -36,8 +36,8 @@ export const documentSchema = createSchema({ _nativeHeight: "number", // " _width: "number", // width of document in its container's coordinate system _height: "number", // " - _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitContentsToBox is set + _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitContentsToBox is set _xMargin: "number", // margin added on left/right of most documents to add separation from their container _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container _overflow: "string", // sets overflow behvavior for CollectionFreeForm views @@ -59,7 +59,7 @@ export const documentSchema = createSchema({ borderRounding: "string", // border radius rounding of document boxShadow: "string", // the amount of shadow around the perimeter of a document color: "string", // foreground color of document - fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view + fitContentsToBox: "boolean",// whether freeform view contents should be zoomed/panned to fill the area of the document view box fontSize: "string", hidden: "boolean", // whether a document should not be displayed isInkMask: "boolean", // is the document a mask (ie, sits on top of other documents, has an unbounded width/height that is dark, and content uses 'hard-light' mix-blend-mode to let other documents pop through) diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx index 418464f0e..64baa351c 100644 --- a/src/mobile/AudioUpload.tsx +++ b/src/mobile/AudioUpload.tsx @@ -19,7 +19,7 @@ import React = require('react'); @observer export class AudioUpload extends React.Component { - @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitToBox: true, boxShadow: "0 0" }), Doc)) as Doc; + @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc; /** * Handles the onclick functionality for the 'Restart' button @@ -36,7 +36,7 @@ export class AudioUpload extends React.Component { title: "mobile audio", _width: 500, _height: 100 - }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitToBox: true, boxShadow: "0 0" }), Doc)) as Doc; + }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc; } /** -- cgit v1.2.3-70-g09d2 From c0826fb904f5d2448635b5dae1fc4337fead939e Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 05:31:25 -0400 Subject: lots of changes to try to cleanup CurrentUserUtils so changes can be made without rebuilding the DB. --- src/client/documents/Documents.ts | 10 +- src/client/util/CurrentUserUtils.ts | 1216 +++++++++----------- src/client/util/DocumentManager.ts | 3 +- src/client/util/Scripting.ts | 2 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/MainView.tsx | 36 +- src/client/views/OverlayView.tsx | 2 +- src/client/views/PropertiesView.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collectionLinear/CollectionLinearView.tsx | 4 +- src/client/views/linking/LinkPopup.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 8 +- src/client/views/nodes/FilterBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 12 +- src/client/views/nodes/button/FontIconBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 8 +- src/fields/Doc.ts | 5 +- src/fields/util.ts | 3 + src/mobile/MobileInterface.tsx | 2 +- 22 files changed, 629 insertions(+), 711 deletions(-) (limited to 'src/mobile') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5f009573e..927996af2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -178,10 +178,15 @@ export class DocumentOptions { hidden?: boolean; _hidden?: boolean; pointerEvents?: string; // pointer events that the documentview should have - mediaState?: string; // status of media document: "pendingRecording", "recording", "paused", "playing" + mediaState?: string; // status of audio/video media document: "pendingRecording", "recording", "paused", "playing" + recording?: boolean; // whether WebCam is recording or not autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline. dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it. toolTip?: string; // tooltip to display on hover + contextMenuFilters?: List; + contextMenuScripts?: List; + contextMenuLabels?: List; + contextMenuIcons?: List; dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel) description?: string; // added for links layout?: string | Doc; // default layout string for a document @@ -238,7 +243,7 @@ export class DocumentOptions { isPushpin?: boolean; isGroup?: boolean; // whether a collection should use a grouping UI behavior _removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document - + noteType?: string; // BACKGROUND GRID _backgroundGridShow?: boolean; @@ -286,6 +291,7 @@ export class DocumentOptions { clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop cloneFieldFilter?: List; // fields not to copy when the document is clonedclipboard?: Doc; + filterBoolean ?: string; useCors?: boolean; icon?: string; target?: Doc; // available for use in scripts as the primary target document diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b4e18a8bb..afb1442bf 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,16 +1,17 @@ import { computed, observable, reaction } from "mobx"; import * as rp from 'request-promise'; -import { DataSym, Doc, DocListCast, DocListCastAsync } from "../../fields/Doc"; +import { DataSym, Doc, DocListCast, DocListCastAsync, StrListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; import { PrefetchProxy } from "../../fields/Proxy"; import { RichTextField } from "../../fields/RichTextField"; +import { listSpec } from "../../fields/Schema"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, DocCast, NumCast, PromiseValue, StrCast } from "../../fields/Types"; +import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, PromiseValue, ScriptCast, StrCast } from "../../fields/Types"; import { ImageField, nullAudio } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; -import { Utils } from "../../Utils"; +import { OmitKeys, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { Docs, DocumentOptions, DocUtils } from "../documents/Documents"; import { DocumentType } from "../documents/DocumentTypes"; @@ -42,17 +43,17 @@ interface Button { toolTip?: string; icon?: string; btnType?: ButtonType; - click?: string; numBtnType?: NumButtonType; numBtnMin?: number; numBtnMax?: number; switchToggle?: boolean; - script?: string; width?: number; - list?: string[]; + btnList?: List; ignoreClick?: boolean; buttonText?: string; - hidden?: string; + scripts?: { script?: string; onClick?: string; } + funcs?: { [key:string]: string }; + subMenu?: Button[]; } export let resolvedPorts: { server: number, socket: number }; @@ -73,101 +74,134 @@ export class CurrentUserUtils { @observable public static headerBarHeight: number = 0; @observable public static searchPanelWidth: number = 0; - // sets up the default User Templates - slideView, headerView - static setupExperimentalTemplateButtons(doc: Doc) { - if (doc["template-experimental-buttons"] === undefined) { - const requiredTypeNameFields = [ - { - type: "slide", icon: "address-card", template: Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) - ], - { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } - ) - }, - { - type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, - [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), - this.mobileTextContainer({}, - [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) - ] - ) - }, - ]; - const requiredTypes = requiredTypeNameFields.map(({ type, icon, template }) => { - if (doc[`template-button-${type}`] === undefined) { - template.isTemplateDoc = makeTemplate(template); - doc[`template-button-${type}`] = CurrentUserUtils.createToolButton({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(template) as any as Doc, - title: type, - icon, - }); + static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, functions?:{[key:string]: string}) { + scripts && Object.keys(scripts).map(key => { + if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && scripts[key]) { + doc[key] = ScriptField.MakeScript(scripts[key], { dragData: DragManager.DocumentDragData.name, value:"any", scriptContext: "any" }, {"_readOnly_": true}); + } + }); + functions && Object.keys(functions).map(key => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + if (ScriptCast(cfield)?.script.originalScript !== functions[key] && functions[key]) { + doc[key] = ComputedField.MakeFunction(functions[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); + } + }); + return doc; + } + static AssignOpts(doc:Doc|undefined, reqdOpts:DocumentOptions, items?:Doc[]) { + if (doc) { + const compareValues = (val1:any, val2:any) => { + if (val1 instanceof List && val2 instanceof List && val1.length === val2.length) { + return !val1.some(v => !val2.includes(v)) || !val2.some(v => val1.includes(v)); + } + return val1 === val2; + } + Object.entries(reqdOpts).forEach(pair => { + const targetDoc = pair[0].startsWith("_") ? doc : Doc.GetProto(doc as Doc); + if (!Object.getOwnPropertyNames(targetDoc).includes(pair[0].replace(/^_/,"")) || + !compareValues(pair[1], targetDoc[pair[0]])) { + targetDoc[pair[0]] = pair[1]; } - return doc[`template-button-${type}`] as Doc; }); - - doc["template-experimental-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { - title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, - hidden: ComputedField.MakeFunction("IsNoviceMode()") as any, - _stayInCollection: true, _hideContextMenu: true, _forceActive: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true - })); + items?.forEach(item => !DocListCast(doc.data).includes(item) && Doc.AddDocToList(Doc.GetProto(doc), "data", item)); } - return doc["template-experimental-buttons"] as Doc; + return doc; } - // setup the different note type skins - static setupNoteTemplates(doc: Doc) { - if (doc["template-notes"] === undefined) { - const requiredTypeNameFields = [ - { type: "Note", backgroundColor: "yellow", icon: "sticky-note" }, - { type: "Idea", backgroundColor: "pink", icon: "lightbulb" }, - { type: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; - const requiredTypes = requiredTypeNameFields.map(({ type, backgroundColor, icon }) => - doc[`template-note-${type}`] as Doc ?? - (() => { - const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor, system: true, icon }); - noteView.isTemplateDoc = makeTemplate(noteView, true, type); - return doc[`template-note-${type}`] = new PrefetchProxy(noteView); - })()); - - doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument(requiredTypes, { title: "Note Layouts", _height: 75, system: true })); - } + // initializes experimental advanced template views - slideView, headerView + static setupExperimentalTemplateButtons(doc: Doc, field="template-experimental-buttons") { + const tempDocs = DocCast(doc[field]); + const requiredTypeNameFields:{opts:DocumentOptions, template:() => Doc}[] = [ + { + opts:{type: "slide", icon: "address-card"}, template: () => Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), + Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) + ], + { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } + ) + }, + { + opts:{type: "mobile", icon: "mobile"}, template: () => this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, + [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), + this.mobileTextContainer({}, + [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) + ] + ) + }, + ]; + const requiredTypes = requiredTypeNameFields.map(({ opts, template }) => { + const docType = DocListCast(tempDocs?.data)?.find(doc => doc.title === opts.type); + const reqdOpts = { + dragFactory: template(), + title: opts.type, + icon: opts.icon + }; + const reqdScripts = {onDragStart: 'copyDragFactory(this.dragFactory)'}; + const makeTemp = (doc:Doc) => { + doc.isTemplateDoc = makeTemplate(doc); + return doc; + } + return this.AssignScripts(!docType ? makeTemp(CurrentUserUtils.createToolButton(reqdOpts)) : this.AssignOpts(docType, reqdOpts)!, reqdScripts)!; + }); + + const reqdOpts = { + title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, + _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, + _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, + }; + const reqdScripts = {dropConverter : "convertToButtons(dragData)"}; + const reqdFuncs = {hidden: "IsNoviceMode()"} + return this.AssignScripts(!tempDocs ? + (doc[field] = Docs.Create.MasonryDocument(requiredTypes, reqdOpts)) : + this.AssignOpts(tempDocs, reqdOpts, requiredTypes)!, + reqdScripts, reqdFuncs); + } + + /// Initializes templates that can be applied to notes + static setupNoteTemplates(doc: Doc, field="template-notes") { + const tempNotes = DocCast(doc[field]); + const reqdTempOpts:DocumentOptions[] = [ + { noteType: "Note", backgroundColor: "yellow", icon: "sticky-note"}, + { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" }, + { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; + const reqdNoteList = reqdTempOpts.map(opts => { + const reqdOpts = {...opts, title: "text", system: true}; + const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined; + const makeTemp = (doc:Doc, noteType?:string) => { + doc.isTemplateDoc = makeTemplate(doc, true, noteType??"Note"); + return doc; + } + return this.AssignOpts(noteType, reqdOpts) ?? makeTemp(Docs.Create.TextDocument("",reqdOpts), opts.noteType); + }); - return doc["template-notes"] as Doc; + const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, system: true }; + return this.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); } - // creates Note templates, and initial "user" templates + /// Initializes collection of templates for notes and click functions static setupDocTemplates(doc: Doc) { - if (doc.templateDocs === undefined) { - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([ - CurrentUserUtils.setupNoteTemplates(doc), - CurrentUserUtils.setupExperimentalTemplateButtons(doc), - CurrentUserUtils.setupClickEditorTemplates(doc) - ], { - title: "template layouts", _xMargin: 0, system: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) - })); - } + const templates = [ + CurrentUserUtils.setupNoteTemplates(doc), + CurrentUserUtils.setupClickEditorTemplates(doc) + ]; + const reqdOpts = { title: "template layouts", _xMargin: 0, system: true, }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; + return this.AssignScripts(this.AssignOpts(DocCast(doc.templateDocs), reqdOpts, templates) ?? (doc.templateDocs = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); } // setup templates for different document types when they are iconified from Document Decorations - static setupDefaultIconTemplates(doc: Doc) { - const templateIconsDoc = Cast(doc["template-icons"], Doc, null); + static setupDefaultIconTemplates(doc: Doc, field="template-icons") { + const templateIconsDoc = DocCast(doc[field]); const makeIconTemplate = (type: DocumentType | undefined, templateField: string, iconTemplate: () => Doc) => { const iconFieldName = "icon" + (type ? "_" + type : ""); if (!templateIconsDoc?.[iconFieldName]) { const template = MakeTemplate(iconTemplate(), true, iconFieldName, templateField); if (templateIconsDoc) { - templateIconsDoc[iconFieldName] = new PrefetchProxy(template); - Doc.AddDocToList(templateIconsDoc, "data", template); - } else { - return template; + templateIconsDoc[iconFieldName] = template; } + return template; } }; const deiconifyScript = () => ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }); @@ -182,46 +216,57 @@ export class CurrentUserUtils { const fontBox = () => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() }); - if (!templateIconsDoc) { - const newIconsList = [ - makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })), - makeIconTemplate(DocumentType.AUDIO, "title", () => labelBox({ _backgroundColor: "lightgreen" })), - makeIconTemplate(DocumentType.PDF, "title", () => labelBox({ _backgroundColor: "pink" })), - makeIconTemplate(DocumentType.WEB, "title", () => labelBox({ _backgroundColor: "brown" })), - makeIconTemplate(DocumentType.RTF, "text", () => labelBox({ _showTitle: "creationDate" })), - makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })), - makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), - makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), - makeIconTemplate(DocumentType.BUTTON, "data", fontBox), - //nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now - makeIconTemplate("transcription" as any, "transcription", () => labelBox({ _backgroundColor: "orange" })), - // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})) - ].filter(d => d).map(d => d!); - - doc["template-icons"] = Docs.Create.TreeDocument(newIconsList, { title: "icon templates", _height: 75, system: true }); - } + const iconTemplates = [ + makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })), + makeIconTemplate(DocumentType.AUDIO, "title", () => labelBox({ _backgroundColor: "lightgreen" })), + makeIconTemplate(DocumentType.PDF, "title", () => labelBox({ _backgroundColor: "pink" })), + makeIconTemplate(DocumentType.WEB, "title", () => labelBox({ _backgroundColor: "brown" })), + makeIconTemplate(DocumentType.RTF, "text", () => labelBox({ _showTitle: "creationDate" })), + makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })), + makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), + makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), + makeIconTemplate(DocumentType.BUTTON, "data", fontBox), + //nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now + makeIconTemplate("transcription" as any, "transcription", () => labelBox({ _backgroundColor: "orange" })), + // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})) + ].filter(d => d).map(d => d!); + + const reqdOpts = { title: "icon templates", _height: 75, system: true }; + this.AssignOpts(templateIconsDoc, reqdOpts, iconTemplates) ?? (doc[field] = Docs.Create.TreeDocument(iconTemplates, reqdOpts)); } + /// initalizes the set of default versions of most document types static creatorBtnDescriptors(doc: Doc): { - title: string, toolTip: string, icon: string, drag?: string, ignoreClick?: boolean, - click?: string, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean, clickFactory?: Doc + title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, + backgroundColor?: string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { const standardOps = () => ({ _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); - if (doc.emptyPresentation === undefined) { - doc.emptyPresentation = Docs.Create.PresDocument({ ...standardOps(), title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); - } - if (doc.emptyCollection === undefined) { - doc.emptyCollection = Docs.Create.FreeformDocument([], { ...standardOps(), title: "freeform", _width: 150, _height: 100 }); - } - if (doc.emptyPane === undefined) { - doc.emptyPane = Docs.Create.FreeformDocument([], { ...standardOps(), title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }); - } - if (doc.emptySlide === undefined) { - doc.emptySlide = Docs.Create.TreeDocument([], { - ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined, - allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" - }); - } + const emptyThings:{key:string, // the field name where the empty thing will be stored + opts:DocumentOptions, // the document options that are required for the empty thing + funcs?:{[key:string]: any}, // computed fields that are rquired for the empth thing + creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist + }[] = [ + {key: "emptyPresentation", creator: Docs.Create.PresDocument, opts: { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias" as any, _chromeHidden: true, boxShadow: "0 0" }}, + {key: "emptyCollection", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts: { title: "freeform", _width: 150, _height: 100 }}, + {key: "emptyPane", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts : { title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }}, + {key: "emptySlide", creator: (opts) => Docs.Create.TreeDocument([], opts), funcs: {title: 'self.text?.Text'}, opts: { + _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, + "dragFactory-count": undefined, allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" + }}, + {key: "emptyComparison", creator: Docs.Create.ComparisonDocument, opts: { title: "Comparer", _width: 300, _height: 300 }}, + {key: "emptyScript", creator: (opts) => Docs.Create.ScriptingDocument(undefined, opts), opts: { title: "script", _width: 200, _height: 250, }}, + {key: "emptyScreenshot", creator: Docs.Create.ScreenshotDocument, opts: { title: "empty screenshot", _width: 400, _height: 200 }}, + {key: "emptyWebCam", creator: (opts) => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, title: "recording", recording:true, system: true, cloneFieldFilter: new List(["system"]) }}, + {key: "emptyAudio", creator: (opts) => Docs.Create.AudioDocument(nullAudio, opts), opts: { title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }}, + {key: "emptyNote", creator: (opts) => Docs.Create.TextDocument("", opts), opts: { title: "text note", _width: 200, _autoHeight: true }}, + {key: "emptyButton", creator: Docs.Create.ButtonDocument, opts: { title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }}, + {key: "emptyWebpage", creator: (opts) => Docs.Create.WebDocument("http://www.bing.com/", opts), opts: { title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }}, + {key: "emptyMap", creator: (opts) => Docs.Create.MapDocument([], opts), opts: { title: "map", _showSidebar: true, _width: 800, _height: 600, }} + ]; + + emptyThings.forEach(thing => + this.AssignScripts(this.AssignOpts(DocCast(doc[thing.key]), {...standardOps(), ...thing.opts}) ?? (doc[thing.key] = thing.creator({...standardOps(), ...thing.opts})), thing.funcs)) + if (doc.emptyHeader === undefined) { const json = { doc: { @@ -242,196 +287,124 @@ export class CurrentUserUtils { selection: { type: "text", anchor: 1, head: 1 }, storedMarks: [] }; - const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { - ...standardOps(), title: "text", _height: 70, - _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, - }, "header"); const headerBtnHgt = 10; - headerTemplate[DataSym].layout = + const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { + ...standardOps(), title: "text", _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, + layout: "" + ` ` + " " + ` Metadata` + - ""; + "" + }, "header"); // "
" + // " " + // " " + // "
"; - (headerTemplate.proto as Doc).isTemplateDoc = makeTemplate(headerTemplate.proto as Doc, true, "headerView"); + Doc.GetProto(headerTemplate).isTemplateDoc = makeTemplate(Doc.GetProto(headerTemplate), true, "headerView"); doc.emptyHeader = headerTemplate; } - if (doc.emptyComparison === undefined) { - doc.emptyComparison = Docs.Create.ComparisonDocument({ ...standardOps(), title: "Comparer", _width: 300, _height: 300 }); - } - if (doc.emptyScript === undefined) { - doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { ...standardOps(), title: "script", _width: 200, _height: 250, }); - } - if (doc.emptyScreenshot === undefined) { - doc.emptyScreenshot = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "empty screenshot", _width: 400, _height: 200 }); - } - if (doc.emptyWall === undefined) { - doc.emptyWall = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List(["system"]) }); - (doc.emptyWall as Doc).recording = true; - } - if (doc.emptyAudio === undefined) { - doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }); - } - if (doc.emptyNote === undefined) { - doc.emptyNote = Docs.Create.TextDocument("", { ...standardOps(), title: "text note", _width: 200, _autoHeight: true }); - } - if (doc.emptyButton === undefined) { - doc.emptyButton = Docs.Create.ButtonDocument({ ...standardOps(), title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }); - } - if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("http://www.bing.com/", { ...standardOps(), title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }); - } - if (doc.emptyMap === undefined) { - doc.emptyMap = Docs.Create.MapDocument([], { ...standardOps(), title: "map", _showSidebar: true, _width: 800, _height: 600, }); - } - if (doc.activeMobileMenu === undefined) { - this.setupActiveMobileMenu(doc); - } + return [ - { toolTip: "Tap to create a note in a new pane, drag for a note", title: "Note", icon: "sticky-note", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyNote as Doc, noviceMode: true, clickFactory: doc.emptyNote as Doc, }, - { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, }, - { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true }, - { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc }, - { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, - { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc }, - { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc }, - { toolTip: "Tap to create an audio recorder in a overlay pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openInOverlay(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true }, - { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc }, - // { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true }, - { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc }, - { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, - { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc }, - { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, - { toolTip: "Tap to create a map in the new pane, drag for a map", title: "Map", icon: "map-marker-alt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyMap as Doc, noviceMode: true } - ]; - + { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, clickFactory: doc.emptyPane as Doc, }, + { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, scripts: {onClick: 'openInOverlay(copyDragFactory(this.dragFactory))',onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a custom note", title: "Custom", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, scripts: {onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a progressive slide",title: "Slide", icon: "file", dragFactory: doc.emptySlide as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreenshot as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs:{ hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a mobile view", title: "Phone", icon: "mobile", dragFactory: doc.activeMobileMenu as Doc, scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)', onDragStart: 'this.dragFactory'}, funcs: {hidden: 'IsNoviceMode()'} }, + { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, + // { toolTip: "Tap or drag to create a presentation", title: "Trails", icon: "pres-trail", dragFactory: doc.emptyPresentation as Doc,scripts: {onClick: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', onDragStart: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`}, funcs: {hidden: 'IsNoviceMode()'} }, + ]; } - // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools - static setupCreatorButtons(doc: Doc) { - let alreadyCreatedButtons: string[] = []; - const dragCreatorSet = Cast(doc.myItemCreators, Doc, null); - if (dragCreatorSet) { - alreadyCreatedButtons = DocListCast(dragCreatorSet.data).map(d => StrCast(d.title)); - } - const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); - const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({ - _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, - icon, - title, - toolTip, - btnType: ButtonType.ToolButton, - ignoreClick, - _dropAction: "alias", - onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined, - onClick: click ? ScriptField.MakeScript(click) : undefined, - backgroundColor: backgroundColor ? backgroundColor : Colors.DARK_GRAY, - color: Colors.WHITE, - _hideContextMenu: true, - _removeDropProperties: new List(["_stayInCollection"]), - _stayInCollection: true, - dragFactory, - clickFactory, - hidden: !noviceMode ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined, - system: true, - })); + /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools + static setupCreatorButtons(doc: Doc, dragCreatorDoc?:Doc):Doc { + const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => { + const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; + const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["backgroundColor"]).omit, + _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, _dropAction: "alias", + btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, + _removeDropProperties: new List(["_stayInCollection"]), + }; + return this.AssignScripts(this.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs); + }); - if (dragCreatorSet === undefined) { - doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true - })); - } else { - creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb)); - } - return doc.myItemCreators as Doc; + const reqdOpts = { + title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true, + _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, + }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; + return this.AssignScripts(this.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts); } - static menuBtnDescriptions(doc: Doc) { - const badgeValue = ScriptField.MakeFunction("((len) => len ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length)") + /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents + static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] { + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; return [ - { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' }, - { title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' }, - { title: "Files", target: Cast(doc.myFilesystem, Doc, null), icon: "folder-open", click: 'selectMainMenu(self)' }, - { title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" }, - { title: "Imports", target: Cast(doc.myImportDocs, Doc, null), icon: "upload", click: 'selectMainMenu(self)' }, - { title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' }, - { title: "Shared with me", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', badgeValue}, - { title: "Trails", target: Cast(doc.myTrails, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' }, - { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" }, + { title: "Dashboards", target: CurrentUserUtils.MyDashboards, icon: "desktop", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Search", target: CurrentUserUtils.MySearcher, icon: "search", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Files", target: CurrentUserUtils.MyFilesystem, icon: "folder-open", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Tools", target: CurrentUserUtils.MyTools, icon: "wrench", scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} }, + { title: "Imports", target: CurrentUserUtils.MyImports, icon: "upload", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Recently Closed", target: CurrentUserUtils.MyRecentlyClosed, icon: "archive", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Shared with me", target: CurrentUserUtils.MySharedDocs, icon: "users", scripts:{onClick: 'selectMainMenu(self)'}, funcs:{badgeValue:badgeValue}}, + { title: "Trails", target: CurrentUserUtils.MyTrails, icon: "pres-trail", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "User Doc", target: CurrentUserUtils.MyUserDocView, icon: "address-card",scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} }, ]; } - static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { - if (doc.menuStack === undefined) { - await this.setupLinkDocs(doc, linkDatabaseId); - await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing - const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, badgeValue, hidden }) => - Docs.Create.FontIconDocument({ - icon, - btnType: ButtonType.MenuButton, - _stayInCollection: true, - _hideContextMenu: true, - _chromeHidden: true, - system: true, - dontUndo: true, - title, - target, - dontRegisterView: true, - hidden: hidden ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined, - _dropAction: "alias", - _removeDropProperties: new List(["dropAction", "_stayInCollection"]), - _width: 60, - _height: 60, - badgeValue, - onClick: ScriptField.MakeScript(click, { scriptContext: "any" }) - }) - ); - - doc.searchBtn = menuBtns.find(btn => btn.title === "Search"); - - doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { - title: "menuItemPanel", - childDropAction: "alias", - _chromeHidden: true, - backgroundColor: Colors.DARK_GRAY, - boxShadow: "rgba(0,0,0,0)", - dontRegisterView: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - ignoreClick: true, - _gridGap: 0, - _yMargin: 0, - _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true - })); - } - return doc.menuStack as Doc; + /// setup the left sidebar container and panels that can be displayed within it + static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") { + this.AssignOpts(DocCast(doc[field]), {}) ?? (doc[field] = ((doc:Doc) => {doc.system = true; return doc;})(new Doc())); + CurrentUserUtils.setupSearcher(doc, "mySearcher"); + CurrentUserUtils.setupToolsBtnPanel(doc, "myTools"); + CurrentUserUtils.setupImportSidebar(doc, "myImports"); + CurrentUserUtils.setupDashboards(doc, "myDashboards"); + CurrentUserUtils.setupTrails(doc, "myTrails"); + CurrentUserUtils.setupFilesystem(doc, "myFilesystem"); + CurrentUserUtils.setupRecentlyClosedDocs(doc, "myRecentlyClosed"); + CurrentUserUtils.setupUserDocView(doc, "myUserDocView"); } + /// Initializes the left sidebar menu buttons and the panels they open up + static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") { + this.setupLeftSidebarPanel(doc); // the tools/panels opened up by the menu buttons + const myLeftSidebarMenu = DocCast(doc[field]); + const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => { + const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined; + const reqdBtnOpts:DocumentOptions = { + title, icon, target, btnType: ButtonType.MenuButton, system: true, dontUndo: true, dontRegisterView: true, + _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, _dropAction: "alias", + _removeDropProperties: new List(["dropAction", "_stayInCollection"]), + }; + return this.AssignScripts(this.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs); + }); - // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu - static setupActiveMobileMenu(doc: Doc) { - if (doc.activeMobileMenu === undefined) { - doc.activeMobileMenu = this.setupMobileMenu(); - } - return doc.activeMobileMenu as Doc; + const reqdStackOpts:DocumentOptions ={ + title: "menuItemPanel", childDropAction: "alias", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, + _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true + }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" } + return this.AssignScripts(this.AssignOpts(myLeftSidebarMenu, reqdStackOpts, menuBtns) ?? (doc[field] = Docs.Create.StackingDocument(menuBtns, reqdStackOpts)), reqdScripts); } - // Sets up mobileMenu stacking document - static setupMobileMenu() { - const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), { - _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true, - })); - return menu; + // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu + static setupActiveMobileMenu(doc: Doc, field="activeMobileMenu") { + const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true,}; + this.AssignOpts(DocCast(doc[field]), reqdOpts, this.setupMobileButtons()) ?? (doc[field] = Docs.Create.StackingDocument(this.setupMobileButtons(), reqdOpts)); } - // SEts up mobile buttons for inside mobile menu + // Sets up mobile buttons for inside mobile menu static setupMobileButtons(doc?: Doc, buttons?: string[]) { + return []; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, backgroundColor?: string, info: string, dragFactory?: Doc }[] = [ { title: "DASHBOARDS", icon: "bars", click: 'switchToMobileLibrary()', backgroundColor: "lightgrey", info: "Access your Dashboards from your mobile, and navigate through all of your documents. " }, { title: "UPLOAD", icon: "upload", click: 'openMobileUploads()', backgroundColor: "lightgrey", info: "Upload files from your mobile device so they can be accessed on Dash Web." }, @@ -533,375 +506,329 @@ export class CurrentUserUtils { }); } - static setupLibrary(userDoc: Doc) { - return CurrentUserUtils.setupDashboards(userDoc); - } - - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. - // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) - static setupToolsBtnPanel(doc: Doc) { - // setup a masonry view of all he creators - const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc); - const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); - - doc.myCreators = doc.myCreators ?? new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { - title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, _fitWidth: true, - _width: 500, _height: 300, ignoreClick: true, _lockedPosition: true, system: true, _chromeHidden: true, - })); - if (!DocListCast(doc.myCreators).includes(creatorBtns) || !DocListCast(doc.myCreators).includes(templateBtns)) Doc.GetProto(doc.myCreators as Doc).data = new List([creatorBtns, templateBtns]); - - doc.myColorPicker = doc.myColorPicker ?? new PrefetchProxy(Docs.Create.ColorDocument({ - title: "color picker", _width: 220, _dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, _forceActive: true, _removeDropProperties: new List(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true - })); - - doc.myTools = doc.myTools ?? new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc], { - title: "My Tools", _showTitle: "title", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true, - system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0", - })) as any as Doc; - if (!DocListCast(doc.myTools).includes(doc.myCreators as Doc)) Doc.GetProto(doc.myTools as Doc).data = new List([doc.myCreators as Doc]); - } - - static async setupDashboards(doc: Doc) { - // setup dashboards library item - await doc.myDashboards; - if (doc.myDashboards === undefined) { - const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); - const newDashboardButton: Doc = Docs.Create.FontIconDocument({ onClick: newDashboard, _forceActive: true, toolTip: "Create new dashboard", _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); - doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, - explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." - })); - const toggleDarkTheme = ScriptField.MakeScript(`this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`); - const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); - const snapshotDashboard = ScriptField.MakeScript(`snapshotDashboard()`); - const shareDashboard = ScriptField.MakeScript(`shareDashboard(self)`); - const removeDashboard = ScriptField.MakeScript('removeDashboard(self)'); - const developerFilter = ScriptField.MakeFunction('!IsNoviceMode()'); - // (doc.myDashboards as any as Doc).childContextMenuScripts = new List([newDashboard!, shareDashboard!, removeDashboard!]); - // (doc.myDashboards as any as Doc).childContextMenuLabels = new List(["Create New Dashboard", "Share Dashboard", "Remove Dashboard"]); - // (doc.myDashboards as any as Doc).childContextMenuIcons = new List(["plus", "user-friends", "times"]); - (doc.myDashboards as any as Doc).childContextMenuScripts = new List([newDashboard!, toggleDarkTheme!, toggleComic!, snapshotDashboard!, shareDashboard!, removeDashboard!]); - (doc.myDashboards as any as Doc).childContextMenuLabels = new List(["Create New Dashboard", "Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]); - (doc.myDashboards as any as Doc).childContextMenuIcons = new List(["plus", "chalkboard", "tv", "camera", "users", "times"]); - (doc.myDashboards as any as Doc).childContextMenuFilters = new List([undefined as any, developerFilter, developerFilter, developerFilter, undefined as any, undefined as any]); - } - return doc.myDashboards as any as Doc; + /// Search option on the left side button panel + static setupSearcher(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", system: true, childDropAction: "alias", + _lockedPosition: true, _viewType: CollectionViewType.Schema, _searchDoc: true, + }; + this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.SearchDocument(reqdOpts)); } - static setupPresentations(doc: Doc) { - if (doc.myTrails === undefined) { - const newTrail = ScriptField.MakeScript(`createNewPresentation()`); - const newTrailButton: Doc = Docs.Create.FontIconDocument({ onClick: newTrail, _forceActive: true, toolTip: "Create new trail", _stayInCollection: true, _hideContextMenu: true, title: "New trail", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); - doc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Trails", _showTitle: "title", _height: 100, - treeViewHideTitle: true, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, - explainer: "All of the trails that you have created will appear here." - })); - (doc.myTrails as any as Doc).contextMenuScripts = new List([newTrail!]); - (doc.myTrails as any as Doc).contextMenuLabels = new List(["Create New Trail"]); - (doc.myTrails as any as Doc).childContextMenuIcons = new List(["plus"]); - } - return doc.myTrails as any as Doc; + /// Initializes the panel of draggable tools that is opened from the left sidebar. + static setupToolsBtnPanel(doc: Doc, field:string) { + const myTools = DocCast(doc[field]); + const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined); + //const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); + const reqdToolOps:DocumentOptions = { + title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0", + _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + }; + this.AssignOpts(myTools, reqdToolOps, [creatorBtns, /*templateBtns*/]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, /*templateBtns*/], reqdToolOps)); } - static async setupFilesystem(doc: Doc) { - await doc.myFilesystem; - if (doc.myFilesystem === undefined) { - doc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); - // doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true }); - const newFolder = ScriptField.MakeFunction(`makeTopLevelFolder()`, { scriptContext: "any" })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ - onClick: newFolder, _forceActive: true, toolTip: "Create new folder", - _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, - buttonText: "New folder", icon: "folder-plus", system: true - }); - doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileOrphans as Doc], { - title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, - explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." - })); - (doc.myFilesystem as any as Doc).contextMenuScripts = new List([newFolder]); - (doc.myFilesystem as any as Doc).contextMenuLabels = new List(["Create new folder"]); - (doc.myFilesystem as any as Doc).childContextMenuIcons = new List(["plus"]); + /// initializes the left sidebar dashboard pane + static setupDashboards(doc: Doc, field:string) { + var myDashboards = DocCast(doc[field]); + + const newDashboard = `createNewDashboard(Doc.UserDoc())`; + const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, + title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true }; + const reqdBtnScript = {onClick: newDashboard,} + const newDashboardButton = this.AssignScripts(this.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); + + const reqdOpts:DocumentOptions = { + title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true, + targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 150, ignoreClick: true, + buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias", + _showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, + contextMenuLabels: new List(["Create New Dashboard"]), + contextMenuIcons: new List(["plus"]), + childContextMenuLabels: new List(["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]),// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters + childContextMenuIcons: new List(["chalkboard", "tv", "camera", "users", "times"]), // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters + explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." + }; + myDashboards = this.AssignOpts(myDashboards, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`; + const contextMenuScripts = [newDashboard]; + const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters + const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts + if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) { + myDashboards.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); + } + if (Cast(myDashboards.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) { + myDashboards.childContextMenuScripts = new List(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); + } + if (Cast(myDashboards.childContextMenuFilters, listSpec(ScriptField), null)?.length !== childContextMenuFilters.length) { + myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script: ScriptField.MakeFunction(script)!)); } - return doc.myFilesystem as any as Doc; } - static setupRecentlyClosedDocs(doc: Doc) { - if (doc.myRecentlyClosedDocs === undefined) { - const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); - const clearDocsButton: Doc = Docs.Create.FontIconDocument({ onClick: clearAll, _forceActive: true, toolTip: "Empty recently closed", _stayInCollection: true, _hideContextMenu: true, title: "Empty", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "Empty", icon: "trash", system: true }); - doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Recently Closed", _showTitle: "title", buttonMenu: true, buttonMenuDoc: clearDocsButton, childHideLinkButton: true, - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, - explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." - - })); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuScripts = new List([clearAll!]); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List(["Empty recently closed"]); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuIcons = new List(["trash"]); - + /// initializes the left sidebar Trails pane + static setupTrails(doc: Doc, field:string) { + var myTrails = DocCast(doc[field]); + const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, + title: "New trail", toolTip: "Create new trail", btnType: ButtonType.ClickButton, buttonText: "New trail", icon: "plus", system: true }; + const reqdBtnScript = {onClick: `createNewPresentation()`}; + const newTrailButton = this.AssignScripts(this.AssignOpts(DocCast(myTrails?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); + + const reqdOpts:DocumentOptions = { + title: "My Trails", _showTitle: "title", _height: 100, + treeViewHideTitle: true, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton, + contextMenuIcons: new List(["plus"]), + contextMenuLabels: new List(["Create New Trail"]), + _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, + explainer: "All of the trails that you have created will appear here." + }; + myTrails = this.AssignOpts(myTrails, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([],reqdOpts )); + const contextMenuScripts = [reqdBtnScript.onClick]; + if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) { + myTrails.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } } - static setupFilterDocs(doc: Doc) { - // setup Filter item - if (doc.currentFilter === undefined) { - doc.currentFilter = Docs.Create.FilterDocument({ - title: "Unnamed Filter", _height: 150, - treeViewHideTitle: true, _xPadding: 5, _yPadding: 5, _gridGap: 5, _forceActive: true, childDropAction: "none", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, _autoHeight: true, _fitWidth: true - }); - const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); - (doc.currentFilter as Doc).contextMenuScripts = new List([clearAll!]); - (doc.currentFilter as Doc).contextMenuLabels = new List(["Clear All"]); - (doc.currentFilter as Doc).filterBoolean = "AND"; + /// initializes the left sidebar File system pane + static setupFilesystem(doc: Doc, field:string) { + var myFilesystem = DocCast(doc[field]); + const reqdOrphansOpts:DocumentOptions = { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }; + this.AssignOpts(DocCast(doc.myFileOrphans), reqdOrphansOpts) ?? (doc.myFileOrphans = Docs.Create.TreeDocument([], reqdOrphansOpts)); + + const newFolder = `makeTopLevelFolder()`; + const newFolderOpts: DocumentOptions = { + _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30, + title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", system: true + }; + const newFolderScript = { onClick: newFolder}; + const newFolderButton = this.AssignScripts(this.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); + + const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, + title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, + treeViewTruncateTitleWidth: 150, ignoreClick: true, childDropAction: "alias", + childContextMenuLabels: new List(["Create new folder"]), + childContextMenuIcons: new List(["plus"]), + explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." + }; + myFilesystem = this.AssignOpts(myFilesystem, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([DocCast(doc.myFileOrphans)], reqdOpts)); + const childContextMenuScripts = [newFolder]; + if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) { + myFilesystem.childContextMenuScripts = new List(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } } - static setupUserDoc(doc: Doc) { - if (doc.myUserDoc === undefined) { - doc.treeViewOpen = true; - doc.treeViewExpandedView = "fields"; - doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], { - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, title: "My UserDoc", _showTitle: "title", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true - })) as any as Doc; + /// initializes the panel displaying docs that have been recently closed + static setupRecentlyClosedDocs(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, + title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true, + treeViewTruncateTitleWidth: 150, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", + contextMenuLabels: new List(["Empty recently closed"]), + contextMenuIcons:new List(["trash"]), + explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." + }; + const recentlyClosed = this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + + const clearAll = (target:string) => `getProto(${target}).data = new List([])`; + const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, + title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, buttonText: "Empty", icon: "trash", system: true, + toolTip: "Empty recently closed",}; + const clearBtnsScripts = {onClick: clearAll("self.target")} + const clearDocsButton = this.AssignScripts( + this.AssignOpts(DocCast(recentlyClosed?.clearDocsBtn), clearBtnsOpts) ?? (recentlyClosed.clearDocsBtn = Docs.Create.FontIconDocument(clearBtnsOpts)), + clearBtnsScripts); + + if (recentlyClosed.buttonMenuDoc !== clearDocsButton) Doc.GetProto(recentlyClosed).buttonMenuDoc = clearDocsButton; + + if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) { + recentlyClosed.contextMenuScripts = new List([ScriptField.MakeScript(clearAll("self"))!]) } } - static setupSidebarContainer(doc: Doc) { - if (doc.sidebar === undefined) { - const sidebarContainer = new Doc(); - sidebarContainer.system = true; - doc.sidebar = new PrefetchProxy(sidebarContainer); - } - return doc.sidebar as Doc; + /// creates a new, empty filter doc + static createFilterDoc() { + const clearAll = `getProto(self).data = new List([])`; + const reqdOpts:DocumentOptions = { + _lockedPosition: true, _autoHeight: true, _fitWidth: true, _height: 150, _xPadding: 5, _yPadding: 5, _gridGap: 5, _forceActive: true, + title: "Unnamed Filter", filterBoolean: "AND", boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, + childDropAction: "none", treeViewHideTitle: true, treeViewTruncateTitleWidth: 150, + childContextMenuLabels: new List(["Clear All"]), + childContextMenuScripts: new List([ScriptField.MakeFunction(clearAll)!]), + }; + return Docs.Create.FilterDocument(reqdOpts); } - // setup the list of sidebar mode buttons which determine what is displayed in the sidebar - static async setupSidebarButtons(doc: Doc) { - CurrentUserUtils.setupSidebarContainer(doc); - CurrentUserUtils.setupToolsBtnPanel(doc); - CurrentUserUtils.setupImportSidebar(doc); - CurrentUserUtils.setupDashboards(doc); - CurrentUserUtils.setupPresentations(doc); - CurrentUserUtils.setupFilesystem(doc); - CurrentUserUtils.setupRecentlyClosedDocs(doc); - CurrentUserUtils.setupUserDoc(doc); + /// initializes the left sidebar panel view of the UserDoc + static setupUserDocView(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", + boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, + treeViewHideTitle: true, treeViewTruncateTitleWidth: 150 + }; + if (!doc[field]) this.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }) + this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([doc], reqdOpts)); } - static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { - ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true, + static linearButtonList = (title: string, opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, { + title, ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _lockedPosition: true, system: true, flexDirection: "row" - })) as any as Doc + }) - static createToolButton = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ + static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["_dropAction", "_hideContextMenu", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts, - })) as any as Doc - - /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window - static setupDockedButtons(doc: Doc) { - if (doc.dockedBtns === undefined) { - const dockBtn = (opts: DocumentOptions) => CurrentUserUtils.createToolButton({ _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...opts }); - const btnDescs = [ - { title: "undo", opts: () => ({ icon: "undo-alt", onClick: ScriptField.MakeScript("undo()"), toolTip: "Click to undo" }) }, - { title: "redo", opts: () => ({ icon: "redo-alt", onClick: ScriptField.MakeScript("redo()"), toolTip: "Click to redo" }) } - ]; - doc.dockedBtns = CurrentUserUtils.linearButtonList({ - title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, - childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true - }, btnDescs.map(desc => doc[`dockedBtn-${desc.title}`] as Doc ?? (doc[`dockedBtn-${desc.title}`] = dockBtn({ title: desc.title, ...desc.opts() })))); + }) + + /// initializes the required buttons in the expanding button menu at the bottom of the Dash window + static setupDockedButtons(doc: Doc, field="myDockedBtns") { + const dockedBtns = DocCast(doc[field]); + const dockBtn = (title:string, onClick: string, opts: DocumentOptions) => { + const btn = this.AssignOpts(DocListCast(dockedBtns?.data)?.find(doc => doc.title === title), opts) ?? + CurrentUserUtils.createToolButton({title, ...opts}); + this.AssignScripts(btn, {onClick}) + return btn; } + const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet + { title: "undo", click: "undo()", opts: { icon: "undo-alt", toolTip: "Click to undo" }}, + { title: "redo", click:"redo()", opts: { icon: "redo-alt", toolTip: "Click to redo" }} + ]; + const btns = btnDescs.map(desc => dockBtn(desc.title, desc.click, {_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts})); + const dockBtnsReqdOpts = { + title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, + childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true + }; + reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); + reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + return this.AssignOpts(dockedBtns, dockBtnsReqdOpts, btns) ?? (doc[field] = CurrentUserUtils.linearButtonList("dockedBtns", dockBtnsReqdOpts, btns)); } - static textTools(doc: Doc) { - const tools: Button[] = - [ - { - title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, - list: ["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", - "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"], - script: 'setFont(value, _readOnly_)' - }, - { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, script: 'setFontSize(value, _readOnly_)' }, - { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, script: 'setFontColor(value, _readOnly_)' }, - { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", click: 'toggleBold(_readOnly_)' }, - { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", click: 'toggleItalic(_readOnly_)' }, - { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", click: 'toggleUnderline(_readOnly_)' }, - { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", click: 'setBulletList("bullet", _readOnly_)' }, - { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", click: 'setBulletList("decimal", _readOnly_)' }, - - // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", click: 'toggleStrikethrough()'}, - // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", click: 'toggleSuperscript()'}, - // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", click: 'toggleSubscript()'}, - { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' }, - { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' }, - { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' }, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", click: 'toggleNoAutoLinkAnchor(_readOnly_)' }, - ]; - return tools; + static textTools():Button[] { + return [ + { + title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, + btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]), + scripts :{script : 'setFont(value, _readOnly_)'} + }, + { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, scripts: {script: '{ return setFontSize(value, _readOnly_);}'} }, + { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, scripts:{script: '{ return setFontColor(value, _readOnly_); }'}}, + { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", scripts: {onClick: '{ return toggleBold(_readOnly_); }'} }, + { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", scripts: {onClick: '{ return toggleItalic(_readOnly_);}'} }, + { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline",scripts: {onClick:'{ return toggleUnderline(_readOnly_);}'} }, + { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", scripts: {onClick: '{ return setBulletList("bullet", _readOnly_);}'} }, + { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", scripts: {onClick: '{ return setBulletList("decimal", _readOnly_);}'} }, + + // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, + // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}}, + // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}}, + { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", scripts: {onClick:'{ return setAlignment("left", _readOnly_);}' }}, + { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", scripts: {onClick:'{ return setAlignment("center", _readOnly_);}'} }, + { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", scripts: {onClick:'{ return setAlignment("right", _readOnly_);}'} }, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", scripts: {onClick:'{ return toggleNoAutoLinkAnchor(_readOnly_);}'}}, + ]; } - static inkTools(doc: Doc) { - const tools: Button[] = [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", click: 'setActiveInkTool("pen", _readOnly_)' }, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", click: 'setActiveInkTool("eraser", _readOnly_)' }, - // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", click: 'setActiveInkTool("highlighter")' }, - { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' }, + static inkTools():Button[] { + return [ + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveInkTool("pen", _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveInkTool("write", _readOnly_);}'} }, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveInkTool("eraser", _readOnly_);}' }}, + // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveInkTool("highlighter")'} }, + { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveInkTool("circle", _readOnly_);}'} }, // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveInkTool("square")' }, - { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", click: 'setActiveInkTool("line", _readOnly_)' }, - { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setFillColor(value, _readOnly_)" }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, script: 'setStrokeWidth(value, _readOnly_)' }, - { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, script: 'setStrokeColor(value, _readOnly_)' }, + { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveInkTool("line", _readOnly_);}' }}, + { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: {script: "{ return setFillColor(value, _readOnly_);}"} }, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'} }, + { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, scripts: {script: '{ return setStrokeColor(value, _readOnly_);}'} }, ]; - return tools; } - static schemaTools(doc: Doc) { - const tools: Button[] = - [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", click: 'toggleSchemaPreview(_readOnly_)', }]; - return tools; + static schemaTools():Button[] { + return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{onClick:'toggleSchemaPreview(_readOnly_)'}, }]; } - static webTools(doc: Doc) { - const tools: Button[] = - [ - { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", click: 'webBack(_readOnly_)' }, - { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", click: 'webForward(_readOnly_)' }, - //{ title: "Reload", toolTip: "Reload webpage", btnType: ButtonType.ClickButton, icon: "redo-alt", click: 'webReload()' }, - { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, script: 'webSetURL(value, _readOnly_)' }, - ]; - - return tools; + static webTools() { + return [ + { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", click: 'webBack(_readOnly_)' }, + { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", click: 'webForward(_readOnly_)' }, + //{ title: "Reload", toolTip: "Reload webpage", btnType: ButtonType.ClickButton, icon: "redo-alt", click: 'webReload()' }, + { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, script: 'webSetURL(value, _readOnly_)' }, + ]; } - static contextMenuTools(doc: Doc) { + static contextMenuTools():Button[] { return [ { title: "Perspective", toolTip: "View", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, - list: [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, - CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn, - CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel, - CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, - CollectionViewType.Grid], - script: 'setView(value, _readOnly_)', + btnList: new List([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, + CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn, + CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel, + CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, + CollectionViewType.Grid]), + scripts: {script: 'setView(value, _readOnly_)'}, }, // Always show - { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame(_readOnly_)', icon: "chevron-left", hidden: 'IsNoviceMode()' }, - { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame(_readOnly_)', icon: "chevron-right", hidden: 'IsNoviceMode()' }, - { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setBackgroundColor(value, _readOnly_)", hidden: 'selectedDocumentType()' }, // Only when a document is selected - { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()', }, - { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay(_readOnly_)', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform + { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton,icon: "chevron-left", scripts:{onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'} }, + { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, icon: "chevron-right", scripts:{onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: 'selectedDocumentType()' }}, // Only when a document is selected + { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: 'selectedDocumentType()'} }, + { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: 'selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected - { title: "Text", type: "textTools", subMenu: CurrentUserUtils.textTools(doc), expanded: 'selectedDocumentType("rtf")' }, // Always available - { title: "Ink", type: "inkTools", subMenu: CurrentUserUtils.inkTools(doc), expanded: 'selectedDocumentType("ink")' }, // Always available - { title: "Web", type: "webTools", subMenu: CurrentUserUtils.webTools(doc), hidden: 'selectedDocumentType("web")' }, // Only when Web is selected - { title: "Schema", type: "schemaTools", subMenu: CurrentUserUtils.schemaTools(doc), hidden: 'selectedDocumentType(undefined, "schema")' } // Only when Schema is selected + { title: "Text", icon: "text", subMenu: CurrentUserUtils.textTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.RTF}")`} }, // Always available + { title: "Ink", icon: "ink", subMenu: CurrentUserUtils.inkTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.INK}")`} }, // Always available + { title: "Web", icon: "web", subMenu: CurrentUserUtils.webTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.WEB}")`, hidden: `!selectedDocumentType("${DocumentType.WEB}")`} }, // Only when Web is selected + { title: "Schema", icon: "schema", subMenu: CurrentUserUtils.schemaTools(), funcs: { linearViewIsExpanded: `selectedDocumentType(undefined, "${CollectionViewType.Schema}")`, hidden: `!selectedDocumentType(undefined, "${CollectionViewType.Schema}")`} } // Only when Schema is selected ]; } - // Sets up the default context menu buttons - static setupContextMenuButtons(doc: Doc) { - const btnFunc = (params: Button) => Docs.Create.FontIconDocument({ - title: params.title, icon: params.icon, toolTip: params.toolTip, color: Colors.WHITE, system: true, dontUndo: true, ignoreClick: params.ignoreClick, + /// initializes a context menu button for the top bar context menu + static setupContextMenuButton(params:Button, btnDoc?:Doc) { + const reqdOpts:DocumentOptions = { + title: params.title, btnType: params.btnType, icon: params.icon, toolTip: params.toolTip, ignoreClick: params.ignoreClick, + numBtnType: params.numBtnType, numBtnMin: params.numBtnMin, numBtnMax: params.numBtnMax,_nativeHeight: 30, btnList: params.btnList, + backgroundColor: params.scripts?.onClick ? undefined: "transparent", /// a bit hacky. if an onClick is specified, then we assume we assume a toggle use onClick to get the backgroundColor (see below). Otherwise, assume a transparent background _nativeWidth: params.width ? params.width : 30, - _nativeHeight: 30, _width: params.width ? params.width : 30, _height: 30, - btnType: params.btnType, - numBtnType: params.numBtnType, numBtnMin: params.numBtnMin, numBtnMax: params.numBtnMax, - btnList: new List(params.list), + color: Colors.WHITE, system: true, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, _dropAction: "alias", _removeDropProperties: new List(["dropAction", "_stayInCollection"]), - script: params.script ? ScriptField.MakeScript(params.script, { value: "any" }) : undefined, - backgroundColor: params.click ? ComputedField.MakeFunction(params.click) as any : "transparent", - onClick: params.click ? ScriptField.MakeScript(params.click, { scriptContext: "any" }, { _readOnly_: false }) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }); - if (doc.contextMenuBtns === undefined) { - doc.contextMenuBtns = CurrentUserUtils.linearButtonList( - { title: "menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }, - CurrentUserUtils.contextMenuTools(doc).map(params => - !params.subMenu ? - btnFunc(params) : - CurrentUserUtils.linearButtonList({ - title: params.title, - childDontRegisterViews: true, - linearViewSubMenu: true, flexGap: 0, ignoreClick: true, - linearViewExpandable: true, icon: params.title, _height: 30, - linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }, params.subMenu.map(btnFunc)))); - } else { - const menuBtnList = DocListCast((doc.contextMenuBtns as Doc).data); - let prev = ""; - CurrentUserUtils.contextMenuTools(doc).forEach(params => { - const menuBtnDoc = menuBtnList.find(doc => doc.title === params.title); - if (!menuBtnDoc) { - const newMenuBtnDoc = !params.subMenu ? - btnFunc(params) : - CurrentUserUtils.linearButtonList({ - title: params.title, - childDontRegisterViews: true, - linearViewSubMenu: true, flexGap: 0, ignoreClick: true, - linearViewExpandable: true, icon: params.title, _height: 30, - linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }, params.subMenu.map(btnFunc)); - const after = menuBtnList.find(doc => doc.title === prev); - Doc.AddDocToList(doc.contextMenuBtns as Doc, "data", newMenuBtnDoc, after, false, !after); - } - const subMenuBtnList = menuBtnDoc?.data ? DocListCast(menuBtnDoc.data) : undefined; - if (menuBtnDoc && subMenuBtnList && params.subMenu && DocListCast(doc.data).length !== subMenuBtnList.length) { - let prevSub = ""; - params.subMenu.forEach(sub => { - if (!subMenuBtnList.find(doc => doc.title === sub.title)) { - const newSubMenuBtnDoc = btnFunc(sub); - const after = subMenuBtnList.find(doc => doc.title === prevSub); - Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub); - } - prevSub = params.title; - }); - } - prev = params.title; - }); + }; + const reqdFuncs:{[key:string]:any} = { + ...params.funcs, + backgroundColor: params.scripts?.onClick /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally } + return this.AssignScripts(this.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs); } - // sets up the default set of documents to be shown in the Overlay layer - static setupOverlays(doc: Doc) { - if (doc.myOverlayDocs === undefined) { - doc.myOverlayDocs = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6", system: true })); - } + /// Initializes all the default buttons for the top bar context menu + static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") { + const ctxtMenuBtnsDoc = DocCast(doc[field]); + const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => { + const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title); + if (!params.subMenu) { + return this.setupContextMenuButton(params, menuBtnDoc); + } else { + const reqdSubMenuOpts = { title: params.title, icon: params.icon, childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: true, + linearViewSubMenu: true, linearViewExpandable: true, }; + const reqdSubMenuFuncs:{[key:string]:any} = { ...params.funcs}; + return this.AssignScripts(this.AssignOpts(menuBtnDoc, reqdSubMenuOpts) ?? + CurrentUserUtils.linearButtonList("submenu", reqdSubMenuOpts, params.subMenu.map(sub => + this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title)) + )), undefined, reqdSubMenuFuncs); + } + }); + const reqdCtxtOpts = { title: "menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; + return this.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts) ?? (doc[field] = CurrentUserUtils.linearButtonList("contextMenuButtons", reqdCtxtOpts, ctxtMenuBtns)); } - // the initial presentation Doc to use - static setupDefaultPresentation(doc: Doc) { - if (doc["template-presentation"] === undefined) { - doc["template-presentation"] = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ - title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _fitWidth: true, _height: 46, isTemplateDoc: true, isTemplateForField: "data", system: true - })); - } + /// collection of documents rendered in the overlay layer above all tabs and other UI + static setupOverlays(doc: Doc, field = "myOverlayDocs") { + const reqdOpts = { title: "overlay documents", backgroundColor: "#aca3a6", system: true }; + return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.FreeformDocument([], reqdOpts)); } - - // Sharing sidebar is where shared documents are contained + + /// The database of all links on all documents static async setupLinkDocs(doc: Doc, linkDatabaseId: string) { if (doc.myLinkDatabase === undefined) { let linkDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(linkDatabaseId); @@ -915,6 +842,8 @@ export class CurrentUserUtils { doc.myLinkDatabase = new PrefetchProxy(linkDocs); } } + + /// Shared documents option on the left side button panel // A user's sharing document is where all documents that are shared to that user are placed. // When the user views one of these documents, it will be added to the sharing documents 'viewed' list field // The sharing document also stores the user's color value which helps distinguish shared documents from personal documents @@ -941,37 +870,26 @@ export class CurrentUserUtils { }; const sharedDocs = Docs.newAccount ? undefined : DocCast(doc.mySharedDocs) ?? DocCast(await DocServer.GetRefField(sharingDocumentId + "outer")); - if (!(sharedDocs instanceof Doc)) { - doc.mySharedDocs = new PrefetchProxy( - Docs.Create.TreeDocument([], {...sharedDocOpts, ...sharedRequiredDocOpts}, sharingDocumentId + "outer", sharingDocumentId)); - } else { - Object.entries(sharedRequiredDocOpts).forEach(pair => { - const targetDoc = pair[0].startsWith("_") ? sharedDocs as Doc : Doc.GetProto(sharedDocs as Doc); - targetDoc[pair[0]] = pair[1]; - }); - } + return this.AssignOpts(DocCast(sharedDocs), sharedRequiredDocOpts) ?? + (doc.mySharedDocs = Docs.Create.TreeDocument([], {...sharedDocOpts, ...sharedRequiredDocOpts}, sharingDocumentId + "outer", sharingDocumentId)); } - // Import sidebar is where shared documents are contained - static setupImportSidebar(doc: Doc) { - if (doc.myImportDocs === undefined) { - const newImportButton: Doc = Docs.Create.FontIconDocument({ onClick: ScriptField.MakeScript("importDocument()"), _forceActive: true, toolTip: "Import from computer", _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, buttonText: "Import", icon: "upload", system: true }); - doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { - title: "My Imports", _forceActive: true, buttonMenu: true, buttonMenuDoc: newImportButton, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, - childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, - dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go." - })); - } - } - - // Search sidebar is where searches within the document are performed - static setupSearchSidebar(doc: Doc) { - if (doc.mySearchPanel === undefined) { - doc.mySearchPanel = new PrefetchProxy(Docs.Create.SearchDocument({ - dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, _searchDoc: true, - childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "Search Panel", system: true - })) as any as Doc; - } + /// Import option on the left side button panel + static setupImportSidebar(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _showTitle: "title", + _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, + childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, + dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go." + }; + const myImports = this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.StackingDocument([], reqdOpts)); + + const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer", + _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, + buttonText: "Import", icon: "upload", system: true }; + const reqdBtnScripts = { onClick: "importDocument()" }; + const newImportBtn = this.AssignOpts(DocCast(myImports.buttonMenuDoc), reqdBtnOpts) ?? (myImports.buttonMenuDoc = Docs.Create.FontIconDocument(reqdBtnOpts)); + this.AssignScripts(newImportBtn, reqdBtnScripts); } static setupClickEditorTemplates(doc: Doc) { @@ -1033,8 +951,8 @@ export class CurrentUserUtils { }, { fireImmediately: true }); // Document properties on load doc.system = true; - doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; doc.title = Doc.CurrentUserEmail; + doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; doc._raiseWhenDragged = true; doc._showLabel = true; doc._showMenuLabel = true; @@ -1053,29 +971,22 @@ export class CurrentUserUtils { doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false); doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null); doc.noviceMode = BoolCast(doc.noviceMode, true); - doc.savedFilters = new List(); + !doc.savedFilters && (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; doc.myPublishedDocs = doc.myPublishedDocs ?? new List(); - doc.myHeaderBarDoc = doc.myHeaderBarDoc ?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); + doc.myHeaderBar = doc.myHeaderBar?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents + await this.setupLinkDocs(doc, linkDatabaseId); + await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates - this.setupImportSidebar(doc); // sets up the import sidebar - this.setupSearchSidebar(doc); // sets up the search sidebar this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile - this.setupOverlays(doc); // documents in overlay layer - this.setupContextMenuButtons(doc); // set up context menu buttons + this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard + this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons - await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels - await this.setupMenuPanel(doc, sharingDocumentId, linkDatabaseId); + this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left if (!doc.globalScriptDatabase) doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); - setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered - - // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet - doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); - doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); if (doc.activeDashboard instanceof Doc) { @@ -1227,7 +1138,7 @@ export class CurrentUserUtils { public static async snapshotDashboard(userDoc: Doc) { const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(Cast(userDoc.myDashboards, Doc, null), "data", copy); + Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); CurrentUserUtils.openDashboard(userDoc, copy); } @@ -1277,15 +1188,24 @@ export class CurrentUserUtils { return tbox; } - public static get DockedBtns() { return Cast(Doc.UserDoc().dockedBtns, Doc, null); } - public static get MySearchPanelDoc() { return Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null); } - public static get ActiveDashboard() { return Cast(Doc.UserDoc().activeDashboard, Doc, null); } - public static get MyHeaderBarDoc() { return Cast(Doc.UserDoc().myHeaderBarDoc, Doc, null); } - public static get ActivePresentation() { return Cast(Doc.UserDoc().activePresentation, Doc, null); } - public static get MyRecentlyClosed() { return Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc, null); } - public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); } - public static get EmptyPane() { return Cast(Doc.UserDoc().emptyPane, Doc, null); } - public static get OverlayDocs() { return DocListCast((Doc.UserDoc().myOverlayDocs as Doc)?.data); } + public static get MyUserDocView() { return DocCast(Doc.UserDoc().myUserDocView); } + public static get MyDockedBtns() { return DocCast(Doc.UserDoc().myDockedBtns); } + public static get MySearcher() { return DocCast(Doc.UserDoc().mySearcher); } + public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } + public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } + public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } + public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } + public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } + public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } + public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } + public static get MyTrails() { return DocCast(Doc.UserDoc().myTrails); } + public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } + public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } + public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } + public static get MyOverlayDocs() { return DocListCast(DocCast(Doc.UserDoc().myOverlayDocs)?.data); } + public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } + public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } + public static get EmptyPane() { return DocCast(Doc.UserDoc().emptyPane); } public static set SelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; } @computed public static get SelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; } } @@ -1298,7 +1218,7 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { view && SelectionManager.SelectView(view, false); } }); -ScriptingGlobals.add(function MySharedDocs() { return Doc.SharingDoc(); }, "document containing all shared Docs"); +ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); @@ -1329,15 +1249,15 @@ ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colTy const parentDoc: Doc = Cast(selected.context, Doc, null); selected = parentDoc; } - if (selected && docType && selected.type === docType) return false; - else if (selected && colType && selected.viewType === colType) return false; - else if (selected && !colType && !docType) return false; - else return true; + if (selected && docType && selected.type === docType) return true; + else if (selected && colType && selected.viewType === colType) return true; + else if (selected && !colType && !docType) return true; + else return false; }); ScriptingGlobals.add(function makeTopLevelFolder() { const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); TreeView._editTitleOnLoad = { id: folder[Id], parent: undefined }; - return Doc.AddDocToList(Doc.UserDoc().myFilesystem as Doc, "data", folder); + return Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); }); ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { if (readOnly) return; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a82f99d5a..0435cd535 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -10,6 +10,7 @@ import { CollectionView } from '../views/collections/CollectionView'; import { LightboxView } from '../views/LightboxView'; import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; +import { CurrentUserUtils } from './CurrentUserUtils'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; @@ -296,7 +297,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { Doc.linkFollowHighlight(dv?.props.Document, false); } else { - const context = doc.context !== Doc.UserDoc().myFilesystem && Cast(doc.context, Doc, null); + const context = doc.context !== CurrentUserUtils.MyFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 223b0268c..3791bec73 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -223,7 +223,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp paramList.push(`${key}: ${typeof val === "object" ? Object.getPrototypeOf(val).constructor.name : typeof val}`); } const paramString = paramList.join(", "); - const body = addReturn ? `return ${script};` : script; + const body = addReturn && !script.startsWith("{ return") ? `return ${script};` : script; const reqTypes = requiredType ? `: ${requiredType}` : ''; const funcScript = `(function(${paramString})${reqTypes} { ${body} })`; host.writeFile("file.ts", funcScript); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 8486b3d62..be5927497 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -141,7 +141,7 @@ export function ViewBoxAnnotatableComponent

() const toRemove = value.filter(v => docs.includes(v)); if (toRemove.length !== 0) { - const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc; + const recent = CurrentUserUtils.MyRecentlyClosed; toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 767efdbc2..16d7c9a23 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -235,7 +235,7 @@ export class KeyManager { if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) { SelectionManager.Views()[0].ComponentView?.search?.("", false, false); } else { - const searchBtn = Doc.UserDoc().searchBtn as Doc; + const searchBtn = CurrentUserUtils.MySearcher; if (searchBtn) { MainView.Instance.selectMenu(searchBtn); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5fd76c388..7e3916b3f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -10,7 +10,7 @@ import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; -import { PromiseValue, StrCast } from '../../fields/Types'; +import { DocCast, PromiseValue, StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; @@ -79,7 +79,7 @@ export class MainView extends React.Component { @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons @observable private _panelContent: string = "none"; - @observable private _sidebarContent: any = this.userDoc?.sidebar; + @observable private _sidebarContent: any = CurrentUserUtils.MyLeftSidebarPanel; @observable private _leftMenuFlyoutWidth: number = 0; @computed private get dashboardTabHeight() { return 27; } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js @@ -92,7 +92,7 @@ export class MainView extends React.Component { @computed private get userDoc() { return Doc.UserDoc(); } @computed private get colorScheme() { return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); } @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } - @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; } + @computed private get headerBarDoc() { return CurrentUserUtils.MyHeaderBar; } @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } headerBarDocWidth = () => this.mainDocViewWidth(); @@ -249,24 +249,8 @@ export class MainView extends React.Component { @action createNewFolder = async () => { - if (!await this.userDoc.myFilesystem) { - this.userDoc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); - const newFolder = ScriptField.MakeFunction(`createNewFolder()`, { scriptContext: "any" })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ - onClick: newFolder, _forceActive: true, toolTip: "New folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", - btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true - }); - this.userDoc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([this.userDoc.myFileOrphans as Doc], { - title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, - treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, - explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." - })); - } const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); - Doc.AddDocToList(this.userDoc.myFilesystem as Doc, "data", folder); + Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); } @observable _exploreMode = false; @@ -397,7 +381,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider} + styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -423,7 +407,7 @@ export class MainView extends React.Component { @computed get leftMenuPanel() { return

(doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(CurrentUserUtils.MyDockedBtns, "data", doc), true); moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); - addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(CurrentUserUtils.MyDockedBtns, "data", doc), true); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); @@ -543,9 +527,9 @@ export class MainView extends React.Component { @computed get docButtons() { return !(this.userDoc.dockedBtns instanceof Doc) ? (null) : -
+
{ + return CurrentUserUtils.MyOverlayDocs?.map(d => { let offsetx = 0, offsety = 0; const dref = React.createRef(); const onPointerMove = action((e: PointerEvent, down: number[]) => { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 16eb95cf4..2cf334ae1 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -931,7 +931,7 @@ export class PropertiesView extends React.Component { * If it doesn't exist, it creates it. */ checkFilterDoc() { - if (!this.selectedDoc.currentFilter) CurrentUserUtils.setupFilterDocs(this.selectedDoc); + if (!this.selectedDoc.currentFilter) this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } /** @@ -944,8 +944,7 @@ export class PropertiesView extends React.Component { this.selectedDoc._docRangeFilters = new List(); (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = undefined; - CurrentUserUtils.setupFilterDocs(this.selectedDoc); + this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } /** diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d2687df17..1ebbe08ef 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -416,7 +416,7 @@ export class CollectionDockingView extends CollectionSubView() { } tabDestroyed = (tab: any) => { - Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc); + Doc.AddDocToList(CurrentUserUtils.MyHeaderBar, "data", tab.DashDoc); Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); const dview = CollectionDockingView.Instance.props.Document; const fieldKey = CollectionDockingView.Instance.props.fieldKey; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 39f6466d6..1c25421f5 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -99,7 +99,7 @@ export class CollectionMenu extends AntimodeMenu{ } @computed get contMenuButtons() { - const selDoc = Doc.UserDoc().contextMenuBtns; + const selDoc = CurrentUserUtils.MyContextMenuBtns; return !(selDoc instanceof Doc) ? (null) :
{ this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }), initialize: (button: Doc) => { - button['target-docFilters'] = (Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null)._docFilters || Cast(Doc.UserDoc().activeDashboard, Doc, null)._docFilters) instanceof ObjectField ? - ObjectField.MakeCopy((Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null)._docFilters || Cast(Doc.UserDoc().activeDashboard, Doc, null)._docFilters) as any as ObjectField) : undefined; + button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) instanceof ObjectField ? + ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) as any as ObjectField) : undefined; button['target-searchFilterDocs'] = CurrentUserUtils.ActiveDashboard._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(CurrentUserUtils.ActiveDashboard._searchFilterDocs as any as ObjectField) : undefined; }, }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 52e99f26b..c07e44fcc 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -985,7 +985,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.MyOverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1031,7 +1031,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
- {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.DockedBtns ? null : + {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : e.stopPropagation()} > @@ -226,7 +226,7 @@ export class CollectionLinearView extends CollectionSubView() { } - {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.DockedBtns ? (null) : + {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? (null) : Currently playing: diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 4b33ef8ae..a6f6bd35f 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -68,8 +68,8 @@ export class LinkPopup extends React.Component { className="linkPopup-searchBox searchBox-input" /> */} 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -563,7 +563,7 @@ export class DocumentViewInternal extends DocComponent 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index e3708d7b9..5add09653 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -35,7 +35,7 @@ export class FilterBox extends ViewBoxBaseComponent() { constructor(props: Readonly) { super(props); const targetDoc = FilterBox.targetDoc; - if (targetDoc && !targetDoc.currentFilter) CurrentUserUtils.setupFilterDocs(targetDoc); + if (targetDoc && !targetDoc.currentFilter) targetDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterBox, fieldKey); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 10974ca03..967158cbf 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -156,20 +156,22 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._annotationKeySuffix = () => this._urlHash + "-annotations"; + const reqdFuncs:{[key:string]: string} = {}; // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created) - this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`); - this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`); + reqdFuncs[this.fieldKey + "-annotations"] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`; + reqdFuncs[this.fieldKey + "-sidebar"] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`; + CurrentUserUtils.AssignScripts(this.dataDoc, {}, reqdFuncs); }); - reaction(() => this.props.isSelected() || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document), + reaction(() => this.props.isSelected(true) || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document), async (selected) => { if (selected) { this._webPageHasBeenRendered = true; - } else if ((!this.props.isContentActive() || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail) + } else if ((!this.props.isContentActive(true) || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail) !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && // don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty LightboxView.LightboxDoc !== this.rootDoc) { // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty. this.updateThumb(); } - }, { fireImmediately: this.props.isSelected() || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegree(this.props.Document) ? true : false) }); + }, { fireImmediately: this.props.isSelected(true) || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegreeUnmemoized(this.props.Document) ? true : false) }); this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight, autoHeight => { diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 97e6eddfe..f29dfe489 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -521,7 +521,7 @@ export class FontIconBox extends DocComponent() {
{this.icon === "pres-trail" ? trailsIcon : } {menuLabel} - +
); break; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 1dd6fef9b..52b03b0a5 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -623,7 +623,7 @@ export class PresBox extends ViewBoxBaseComponent() { */ @action updateMinimize = async () => { - if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); CollectionDockingView.AddSplit(this.rootDoc, "right"); @@ -868,7 +868,7 @@ export class PresBox extends ViewBoxBaseComponent() { } break; case "Escape": - if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } + if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = "edit"; if (this._presTimer) clearTimeout(this._presTimer); @@ -2511,7 +2511,7 @@ export class PresBox extends ViewBoxBaseComponent() { const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); - return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ? + return CurrentUserUtils.MyOverlayDocs.includes(this.rootDoc) ?
e.stopPropagation()}>
{"Loop"}
}>
() {
: -
+
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 7b72787d1..94be286f5 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -941,6 +941,9 @@ export namespace Doc { export function isBrushedHighlightedDegree(doc: Doc) { return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc); } + export function isBrushedHighlightedDegreeUnmemoized(doc: Doc) { + return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegreeUnmemoized(doc); + } export class DocBrush { BrushedDoc: ObservableMap = new ObservableMap(); @@ -980,7 +983,7 @@ export namespace Doc { export function SearchQuery(): string { return manager._searchQuery; } export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); } export function UserDoc(): Doc { return manager._user_doc; } - export function SharingDoc(): Doc { return Cast(Doc.UserDoc().mySharedDocs, Doc, null); } + export function SharingDoc(): Doc { return CurrentUserUtils.MySharedDocs; } export function LinkDBDoc(): Doc { return Cast(Doc.UserDoc().myLinkDatabase, Doc, null); } export function SetUserDoc(doc: Doc) { return (manager._user_doc = doc); } diff --git a/src/fields/util.ts b/src/fields/util.ts index d1e565774..37b9be31b 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -88,6 +88,9 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number delete target.__fields[prop]; } else { target.__fieldKeys && (target.__fieldKeys[prop] = true); + // if (target.__fields[prop] !== value) { + // console.log("ASSIGN " + prop + " " + value); + // } target.__fields[prop] = value; } //if (typeof value === "object" && !(value instanceof ObjectField)) debugger; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 78ec706d7..c5c6fb688 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -68,7 +68,7 @@ export class MobileInterface extends React.Component { constructor(props: Readonly<{}>) { super(props); - this._library = CurrentUserUtils.setupLibrary(Doc.UserDoc()); // to access documents in Dash Web + this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc()); // to access documents in Dash Web MobileInterface.Instance = this; } -- cgit v1.2.3-70-g09d2 From b292a055401af6236e0537cfad603016d77a535a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 13:40:07 -0400 Subject: a bunch of changes to make some userDoc() field accesses more typesafe by going through CurrentUserUtils. Some normalization of naming/functionality in CurrentUserUtils --- src/client/apis/youtube/YoutubeBox.tsx | 2 +- src/client/documents/Documents.ts | 6 +- src/client/util/CurrentUserUtils.ts | 118 +++++++++++---------- src/client/util/SettingsManager.tsx | 16 +-- src/client/util/SharingManager.tsx | 4 +- src/client/views/DashboardView.tsx | 4 +- src/client/views/DocComponent.tsx | 6 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/GestureOverlay.tsx | 12 +-- src/client/views/GlobalKeyHandler.ts | 8 +- src/client/views/InkStrokeProperties.ts | 4 +- src/client/views/InkTranscription.tsx | 2 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/MainView.tsx | 4 +- src/client/views/OverlayView.tsx | 8 +- src/client/views/PropertiesButtons.tsx | 4 +- src/client/views/PropertiesView.tsx | 86 ++++++++------- src/client/views/TemplateMenu.tsx | 11 +- .../views/collections/CollectionDockingView.tsx | 22 ++-- src/client/views/collections/CollectionMenu.tsx | 35 +++--- .../views/collections/CollectionStackingView.tsx | 2 +- .../CollectionStackingViewFieldColumn.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 8 +- src/client/views/collections/CollectionView.tsx | 14 +-- src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 30 +++--- .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- .../collectionSchema/CollectionSchemaHeaders.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 5 +- src/client/views/nodes/ColorBox.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 40 +++---- src/client/views/nodes/FilterBox.tsx | 47 ++++---- src/client/views/nodes/ImageBox.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 6 +- src/client/views/nodes/button/FontIconBox.tsx | 35 +++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +-- .../views/nodes/formattedText/RichTextMenu.tsx | 1 - src/client/views/nodes/trails/PresBox.tsx | 30 +++--- src/client/views/nodes/trails/PresElementBox.tsx | 16 +-- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/topbar/TopBar.tsx | 10 +- src/client/views/webcam/DashWebRTCVideo.tsx | 2 +- src/fields/Doc.ts | 18 ++-- src/fields/util.ts | 2 +- src/mobile/MobileInterface.tsx | 20 ++-- 49 files changed, 360 insertions(+), 335 deletions(-) (limited to 'src/mobile') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index c5ff2db68..e14dc60b4 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -351,7 +351,7 @@ export class YoutubeBox extends React.Component { const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <>
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 927996af2..f96bffb3c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -687,7 +687,7 @@ export namespace Docs { ![DocumentType.LINK, DocumentType.MARKER, DocumentType.LABEL].includes(viewDoc.type as any) && DocUtils.MakeLinkToActiveAudio(() => viewDoc); !Doc.IsSystem(dataDoc) && ![DocumentType.MARKER, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(proto.type as any) && - !dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc); + !dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, undefined, dataDoc); updateCachedAcls(dataDoc); updateCachedAcls(viewDoc); @@ -802,7 +802,7 @@ export namespace Docs { I.rotation = 0; I.data = new InkField(points); I.creationDate = new DateField; - I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + I["acl-Public"] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; I["acl-Override"] = "None"; I.links = ComputedField.MakeFunction("links(self)"); I[Initializing] = false; @@ -1204,7 +1204,7 @@ export namespace DocUtils { created = Docs.Create.RecordingDocument((field).url.href, resolved); layout = RecordingBox.LayoutString; } else if (field instanceof InkField) { - created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved); + created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved); layout = InkingStroke.LayoutString; } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index afb1442bf..7a38886fe 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -74,16 +74,16 @@ export class CurrentUserUtils { @observable public static headerBarHeight: number = 0; @observable public static searchPanelWidth: number = 0; - static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, functions?:{[key:string]: string}) { + static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, funcs?:{[key:string]: string}) { scripts && Object.keys(scripts).map(key => { if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && scripts[key]) { doc[key] = ScriptField.MakeScript(scripts[key], { dragData: DragManager.DocumentDragData.name, value:"any", scriptContext: "any" }, {"_readOnly_": true}); } }); - functions && Object.keys(functions).map(key => { + funcs && Object.keys(funcs).map(key => { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - if (ScriptCast(cfield)?.script.originalScript !== functions[key] && functions[key]) { - doc[key] = ComputedField.MakeFunction(functions[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); + if (ScriptCast(cfield)?.script.originalScript !== funcs[key] && funcs[key]) { + doc[key] = ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); } }); return doc; @@ -180,14 +180,14 @@ export class CurrentUserUtils { } /// Initializes collection of templates for notes and click functions - static setupDocTemplates(doc: Doc) { + static setupDocTemplates(doc: Doc, field="myTemplates") { const templates = [ CurrentUserUtils.setupNoteTemplates(doc), CurrentUserUtils.setupClickEditorTemplates(doc) ]; const reqdOpts = { title: "template layouts", _xMargin: 0, system: true, }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; - return this.AssignScripts(this.AssignOpts(DocCast(doc.templateDocs), reqdOpts, templates) ?? (doc.templateDocs = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); + return this.AssignScripts(this.AssignOpts(DocCast(doc[field]), reqdOpts, templates) ?? (doc[field] = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); } // setup templates for different document types when they are iconified from Document Decorations @@ -329,7 +329,7 @@ export class CurrentUserUtils { static setupCreatorButtons(doc: Doc, dragCreatorDoc?:Doc):Doc { const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => { const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; - const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["backgroundColor"]).omit, + const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, _dropAction: "alias", btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, _removeDropProperties: new List(["_stayInCollection"]), @@ -562,6 +562,7 @@ export class CurrentUserUtils { if (Cast(myDashboards.childContextMenuFilters, listSpec(ScriptField), null)?.length !== childContextMenuFilters.length) { myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script: ScriptField.MakeFunction(script)!)); } + return myDashboards; } /// initializes the left sidebar Trails pane @@ -728,13 +729,13 @@ export class CurrentUserUtils { static inkTools():Button[] { return [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveInkTool("pen", _readOnly_);}' }}, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveInkTool("write", _readOnly_);}'} }, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveInkTool("eraser", _readOnly_);}' }}, - // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveInkTool("highlighter")'} }, - { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveInkTool("circle", _readOnly_);}'} }, - // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveInkTool("square")' }, - { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveInkTool("line", _readOnly_);}' }}, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveTool("pen", _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveTool("write", _readOnly_);}'} }, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveTool("eraser", _readOnly_);}' }}, + // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveTool("highlighter")'} }, + { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveTool("circle", _readOnly_);}'} }, + // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveTool("square")' }, + { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveTool("line", _readOnly_);}' }}, { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: {script: "{ return setFillColor(value, _readOnly_);}"} }, { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'} }, { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, scripts: {script: '{ return setStrokeColor(value, _readOnly_);}'} }, @@ -941,41 +942,39 @@ export class CurrentUserUtils { } static async updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { - if (!doc.globalGroupDatabase) doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument(); - await DocListCastAsync((doc.globalGroupDatabase as Doc).data); - reaction(() => DateCast((doc.globalGroupDatabase as Doc)["data-lastModified"]), + doc.globalGroupDatabase ?? (doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument()); + await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); + reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data-lastModified"]), async () => { - const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data); + const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || []; SnappingManager.SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]); }, { fireImmediately: true }); // Document properties on load - doc.system = true; - doc.title = Doc.CurrentUserEmail; - doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; - doc._raiseWhenDragged = true; - doc._showLabel = true; - doc._showMenuLabel = true; - doc.textAlign = StrCast(doc.textAlign, "left"); - doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)"); - doc.activeInkWidth = Number(StrCast(doc.activeInkWidth, "1")); - doc.activeInkBezier = StrCast(doc.activeInkBezier, "0"); - doc.activeFillColor = StrCast(doc.activeFillColor, ""); - doc.activeArrowStart = StrCast(doc.activeArrowStart, ""); - doc.activeArrowEnd = StrCast(doc.activeArrowEnd, ""); - doc.activeDash = StrCast(doc.activeDash, "0"); - doc.fontSize = StrCast(doc.fontSize, "12px"); - doc.fontFamily = StrCast(doc.fontFamily, "Arial"); - doc.fontColor = StrCast(doc.fontColor, "black"); - doc.fontHighlight = StrCast(doc.fontHighlight, ""); - doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false); - doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null); - doc.noviceMode = BoolCast(doc.noviceMode, true); - !doc.savedFilters && (doc.savedFilters = new List()); + doc.system ?? (doc.system = true); + doc.title ?? (doc.title = Doc.CurrentUserEmail); + Doc.noviceMode ?? (Doc.noviceMode = true); + doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); + doc._showLabel ?? (doc._showLabel = true); + doc._showMenuLabel ?? (doc._showMenuLabel = true); + doc.textAlign ?? (doc.textAlign = "left"); + doc.activeInkColor ?? (doc.activeInkColor = "rgb(0, 0, 0)");; + doc.activeInkWidth ?? (doc.activeInkWidth = 1); + doc.activeInkBezier ?? (doc.activeInkBezier = "0"); + doc.activeFillColor ?? (doc.activeFillColor = ""); + doc.activeArrowStart ?? (doc.activeArrowStart = ""); + doc.activeArrowEnd ?? (doc.activeArrowEnd = ""); + doc.activeDash ?? (doc.activeDash == "0"); + doc.fontSize ?? (doc.fontSize = "12px"); + doc.fontFamily ?? (doc.fontFamily = "Arial"); + doc.fontColor ?? (doc.fontColor = "black"); + doc.fontHighlight ?? (doc.fontHighlight = ""); + doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false); + doc.savedFilters ?? (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; - doc.myPublishedDocs = doc.myPublishedDocs ?? new List(); - doc.myHeaderBar = doc.myHeaderBar?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents + doc.myPublishedDocs ?? (doc.myPublishedDocs = new List()); + doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents await this.setupLinkDocs(doc, linkDatabaseId); await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon @@ -985,7 +984,7 @@ export class CurrentUserUtils { this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left - if (!doc.globalScriptDatabase) doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); + doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument()); setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); @@ -1022,7 +1021,7 @@ export class CurrentUserUtils { const userDoc = Docs.newAccount ? new Doc(userDocumentId, true) : field as Doc; Docs.newAccount &&(userDoc.activePage = "home"); const updated = this.updateUserDocument(Doc.SetUserDoc(userDoc), sharingDocumentId, linkDatabaseId); - (await DocListCastAsync(Cast(Doc.UserDoc().myLinkDatabase, Doc, null)?.data))?.forEach(async link => { // make sure anchors are loaded to avoid incremental updates to computedFn's in LinkManager + (await DocListCastAsync(Doc.LinkDBDoc()?.data))?.forEach(async link => { // make sure anchors are loaded to avoid incremental updates to computedFn's in LinkManager const a1 = await Cast(link?.anchor1, Doc, null); const a2 = await Cast(link?.anchor2, Doc, null); }); @@ -1097,7 +1096,7 @@ export class CurrentUserUtils { } } } else if (input.files && input.files.length !== 0) { - const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null); + const importDocs = CurrentUserUtils.MyImports; const disposer = OverlayView.ShowSpinner(); DocListCastAsync(importDocs.data).then(async list => { const results = await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {}); @@ -1115,9 +1114,10 @@ export class CurrentUserUtils { } public static CaptureDashboardThumbnail() { + const activeDashboard = CurrentUserUtils.ActiveDashboard; const docView = CollectionDockingView.Instance.props.DocumentView?.(); const content = docView?.ContentDiv; - if (docView && content) { + if (docView && content && activeDashboard) { const _width = Number(getComputedStyle(content).width.replace("px","")); const _height = Number(getComputedStyle(content).height.replace("px","")); return CollectionFreeFormView.UpdateIcon( @@ -1130,20 +1130,22 @@ export class CurrentUserUtils { const proto = Cast(img.proto, Doc, null)!; proto["data-nativeWidth"] = _width; proto["data-nativeHeight"] = _height; - Doc.GetProto(CurrentUserUtils.ActiveDashboard).thumb = img; + Doc.GetProto(activeDashboard).thumb = img; }); } } public static async snapshotDashboard(userDoc: Doc) { - const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); - CurrentUserUtils.openDashboard(userDoc, copy); + if (CurrentUserUtils.ActiveDashboard) { + const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); + Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); + CurrentUserUtils.openDashboard(userDoc, copy); + } } public static closeActiveDashboard = () => { - Doc.UserDoc().activeDashboard = undefined; + CurrentUserUtils.ActiveDashboard = undefined; } public static createNewDashboard = async (userDoc: Doc, id?: string) => { @@ -1195,6 +1197,8 @@ export class CurrentUserUtils { public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } + public static get MyFileOrphans() { return DocCast(Doc.UserDoc().myFileOrphans); } + public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } @@ -1202,12 +1206,16 @@ export class CurrentUserUtils { public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } - public static get MyOverlayDocs() { return DocListCast(DocCast(Doc.UserDoc().myOverlayDocs)?.data); } + public static get MyOverlayDocs() { return DocCast(Doc.UserDoc().myOverlayDocs); } public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } + public static set ActiveDashboard(val:Doc|undefined) { Doc.UserDoc().activeDashboard = val; } public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } + public static set ActivePresentation(val) { Doc.UserDoc().activePresentation = val; } + public static get ActivePage() { return StrCast(Doc.UserDoc().activePage); } + public static set ActivePage(val) { Doc.UserDoc().activePage = val; } public static get EmptyPane() { return DocCast(Doc.UserDoc().emptyPane); } - public static set SelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; } - @computed public static get SelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; } + public static set ActiveTool(tool: InkTool) { Doc.UserDoc().activeTool = tool; } + public static get ActiveTool(): InkTool { return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; } } ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { @@ -1219,7 +1227,7 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { } }); ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); -ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); +ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, "creates a new dashboard when called"); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 6a26dfdc7..382274462 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -38,7 +38,7 @@ export class SettingsManager extends React.Component<{}> { @observable activeTab = "Accounts"; @computed get backgroundColor() { return Doc.UserDoc().activeCollectionBackground; } - @computed get colorScheme() { return CurrentUserUtils.ActiveDashboard.colorScheme; } + @computed get colorScheme() { return CurrentUserUtils.ActiveDashboard?.colorScheme; } constructor(props: {}) { super(props); @@ -59,7 +59,7 @@ export class SettingsManager extends React.Component<{}> { } } - @undoBatch selectUserMode = action((e: React.ChangeEvent) => Doc.UserDoc().noviceMode = (e.currentTarget as any)?.value === "Novice"); + @undoBatch selectUserMode = action((e: React.ChangeEvent) => Doc.noviceMode = (e.currentTarget as any)?.value === "Novice"); @undoBatch changeShowTitle = action((e: React.ChangeEvent) => Doc.UserDoc().showTitle = (e.currentTarget as any).value ? "title" : undefined); @undoBatch changeFontFamily = action((e: React.ChangeEvent) => Doc.UserDoc().fontFamily = (e.currentTarget as any).value); @undoBatch changeFontSize = action((e: React.ChangeEvent) => Doc.UserDoc().fontSize = (e.currentTarget as any).value); @@ -78,19 +78,21 @@ export class SettingsManager extends React.Component<{}> { @undoBatch @action changeColorScheme = action((e: React.ChangeEvent) => { + const activeDashboard= CurrentUserUtils.ActiveDashboard; + if (!activeDashboard) return; const scheme: ColorScheme = (e.currentTarget as any).value; switch (scheme) { case ColorScheme.Light: - CurrentUserUtils.ActiveDashboard.colorScheme = undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) + activeDashboard.colorScheme = undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) addStyleSheetRule(SettingsManager._settingsStyle, "lm_header", { background: "#d3d3d3 !important" }); break; case ColorScheme.Dark: - CurrentUserUtils.ActiveDashboard.colorScheme = ColorScheme.Dark; + activeDashboard.colorScheme = ColorScheme.Dark; addStyleSheetRule(SettingsManager._settingsStyle, "lm_header", { background: "black !important" }); break; case ColorScheme.System: default: window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { - CurrentUserUtils.ActiveDashboard.colorScheme = e.matches ? ColorScheme.Dark : undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) + activeDashboard.colorScheme = e.matches ? ColorScheme.Dark : undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) }); break; } @@ -254,7 +256,7 @@ export class SettingsManager extends React.Component<{}> {
Modes
- @@ -270,7 +272,7 @@ export class SettingsManager extends React.Component<{}> {
Doc.UserDoc().defaultAclPrivate = !Doc.UserDoc().defaultAclPrivate)} /> + onChange={action(() => Doc.defaultAclPrivate = !Doc.defaultAclPrivate)} />
Default access private
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index f439d4488..d77633b8d 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -369,7 +369,7 @@ export class SharingManager extends React.Component<{}> { const dropdownValues: string[] = Object.values(SharingPermissions); if (!uniform) dropdownValues.unshift("-multiple-"); if (override) dropdownValues.unshift("None"); - return dropdownValues.filter(permission => !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => + return dropdownValues.filter(permission => !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => (
- {Doc.UserDoc().noviceMode ? (null) : + {Doc.noviceMode ? (null) :
this.layoutDocAcls = !this.layoutDocAcls)} checked={this.layoutDocAcls} />
} diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index efc1644fe..9a0f25fe3 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -34,8 +34,8 @@ export class DashboardView extends React.Component { clickDashboard = async (e: React.MouseEvent, dashboard: Doc) => { if (e.detail === 2) { - Doc.UserDoc().activeDashboard = dashboard; - Doc.UserDoc().activePage = "dashboard"; + CurrentUserUtils.ActiveDashboard = dashboard; + CurrentUserUtils.ActivePage = "dashboard"; } } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index be5927497..169bd3873 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -65,7 +65,7 @@ export function ViewBoxBaseComponent

() { isContentActive = (outsideReaction?: boolean) => ( this.props.isContentActive?.() === false ? false : - (CurrentUserUtils.SelectedTool !== InkTool.None || + (CurrentUserUtils.ActiveTool !== InkTool.None || (this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction)) ? true : undefined)) @@ -200,7 +200,7 @@ export function ViewBoxAnnotatableComponent

() if (effectiveAcl === AclAugment) { added.map(doc => { - if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); + if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); doc.context = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); @@ -213,7 +213,7 @@ export function ViewBoxAnnotatableComponent

() doc.context = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; - inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); + CurrentUserUtils.ActiveDashboard && inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); }); const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List; if (annoDocs instanceof List) annoDocs.push(...added); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 0bbe473d7..9b8f7238d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -347,7 +347,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV

{this.menuButton}
- {/* {Doc.UserDoc().noviceMode ? (null) :
+ {/* {Doc.noviceMode ? (null) :
{this.moreButton}
} */}
; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 6afe64868..e960f5cca 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -129,7 +129,7 @@ export class GestureOverlay extends Touchable { // and this seems to be the only way of differentiating pen and touch on touch events if (pt.radiusX > 1 && pt.radiusY > 1) { InkTranscription.Instance.createInkGroup(); - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; this.prevPoints.set(pt.identifier, pt); } } @@ -498,18 +498,18 @@ export class GestureOverlay extends Touchable { setupMoveUpEvents(this, e, returnFalse, returnFalse, action((e: PointerEvent, doubleTap?: boolean) => { if (doubleTap) { InkTranscription.Instance.createInkGroup(); - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; return; } })); } - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - CurrentUserUtils.SelectedTool = InkTool.Write; + CurrentUserUtils.ActiveTool = InkTool.Write; } this._points.push({ X: e.clientX, Y: e.clientY }); setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); - // if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); + // if (CurrentUserUtils.ActiveTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); } } @@ -606,7 +606,7 @@ export class GestureOverlay extends Touchable { this._points = []; if (!CollectionFreeFormViewChrome.Instance?._keepPrimitiveMode) { this.InkShape = ""; - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; } } // if we're not drawing in a toolglass try to recognize as gesture diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 16d7c9a23..f5122df3f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -57,7 +57,7 @@ export class KeyManager { public handle = action((e: KeyboardEvent) => { if (e.key?.toLowerCase() === "shift") DocumentDecorations.Instance.AddToSelection = true; - //if (!Doc.UserDoc().noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.UPDATE_SERVER_CACHE(true); + //if (!Doc.noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.UPDATE_SERVER_CACHE(true); const keyname = e.key && e.key.toLowerCase(); this.handleGreedy(keyname); @@ -112,7 +112,7 @@ export class KeyManager { DocumentLinksButton.StartLink = undefined; DocumentLinksButton.StartLinkView = undefined; InkStrokeProperties.Instance._controlButton = false; - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; DragManager.CompleteWindowDrag?.(true); var doDeselect = true; if (SnappingManager.GetIsDragging()) { @@ -241,9 +241,9 @@ export class KeyManager { } } break; - case "e": CurrentUserUtils.SelectedTool = InkTool.Eraser; + case "e": CurrentUserUtils.ActiveTool = InkTool.Eraser; break; - case "p": CurrentUserUtils.SelectedTool = InkTool.Pen; + case "p": CurrentUserUtils.ActiveTool = InkTool.Pen; break; case "o": const target = SelectionManager.Docs().lastElement(); diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 0449da483..471ad09e9 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -25,8 +25,8 @@ export class InkStrokeProperties { constructor() { InkStrokeProperties._Instance = this; - reaction(() => this._controlButton, button => button && (CurrentUserUtils.SelectedTool = InkTool.None)); - reaction(() => CurrentUserUtils.SelectedTool, tool => (tool !== InkTool.None) && (this._controlButton = false)); + reaction(() => this._controlButton, button => button && (CurrentUserUtils.ActiveTool = InkTool.None)); + reaction(() => CurrentUserUtils.ActiveTool, tool => (tool !== InkTool.None) && (this._controlButton = false)); } /** diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 8ab54918c..487bbcd00 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -254,7 +254,7 @@ export class InkTranscription extends React.Component { */ createInkGroup() { // TODO nda - if document being added to is a inkGrouping then we can just add to that group - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those const selected = ffView.unprocessedDocs; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index aa5a815ac..35d89d2b1 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -345,7 +345,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; - !Doc.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); + !Doc.noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7e3916b3f..791c64630 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -381,7 +381,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} + styleProvider={this._sidebarContent.proto === CurrentUserUtils.MyDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -656,7 +656,7 @@ export class MainView extends React.Component { {this.mainDashboardArea} ; case "home": return ; - } })(StrCast(Doc.UserDoc().activePage)) + } })(CurrentUserUtils.ActivePage) } diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index bdb3bb857..598fff29a 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import * as React from "react"; import ReactLoading from 'react-loading'; -import { Doc, WidthSym, HeightSym } from "../../fields/Doc"; +import { Doc, WidthSym, HeightSym, DocListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { Cast, NumCast } from "../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../Utils"; @@ -149,7 +149,7 @@ export class OverlayView extends React.Component { } removeOverlayDoc = (doc: Doc | Doc[]) => { - (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc)); + (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc)); return true; } @@ -158,7 +158,7 @@ export class OverlayView extends React.Component { }.bind(this)); @computed get overlayDocs() { - return CurrentUserUtils.MyOverlayDocs?.map(d => { + return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).map(d => { let offsetx = 0, offsety = 0; const dref = React.createRef(); const onPointerMove = action((e: PointerEvent, down: number[]) => { @@ -172,7 +172,7 @@ export class OverlayView extends React.Component { dragData.dropAction = "move"; dragData.removeDocument = (doc: Doc | Doc[]) => { const docs = (doc instanceof Doc) ? [doc] : doc; - docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d)); + docs.forEach(d => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, d)); return true; }; dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 74055f057..9c6d9a108 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -200,7 +200,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { {list}
- {Doc.UserDoc().noviceMode ? (null) :
Edit onClick Script
} + {Doc.noviceMode ? (null) :
Edit onClick Script
}
; } @computed @@ -229,7 +229,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree; const isTabView = this.selectedTabView; const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) =>
{ele}
; - const isNovice = Doc.UserDoc().noviceMode; + const isNovice = Doc.noviceMode; return !this.selectedDoc ? (null) :
{toggle(this.titleButton)} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 2cf334ae1..90c86fa18 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -11,7 +11,7 @@ import { Id } from "../../fields/FieldSymbols"; import { InkField } from "../../fields/InkField"; import { List } from "../../fields/List"; import { ComputedField } from "../../fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; +import { Cast, NumCast, StrCast, DocCast } from "../../fields/Types"; import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from "../../Utils"; import { DocumentType } from "../documents/DocumentTypes"; @@ -340,7 +340,7 @@ export class PropertiesView extends React.Component { */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.props.Document); + const docs = SelectionManager.Views().length < 2 ? (this.selectedDoc ? [this.selectedDoc]:[]) : SelectionManager.Views().map(docView => docView.props.Document); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs); } @@ -355,7 +355,7 @@ export class PropertiesView extends React.Component { value={permission} onChange={e => this.changePermissions(e, user)}> {dropdownValues.filter(permission => - !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => + !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => )} ; } @@ -419,7 +419,7 @@ export class PropertiesView extends React.Component { // all selected docs const docs = SelectionManager.Views().length < 2 ? - [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc[DataSym]] + [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc?.[DataSym]] : SelectionManager.Views().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]); const target = docs[0]; @@ -907,7 +907,7 @@ export class PropertiesView extends React.Component { {!this.openSharing ? (null) :
- {!Doc.UserDoc().noviceMode ? (
+ {!Doc.noviceMode ? (
this.layoutDocAcls = !this.layoutDocAcls)} @@ -931,42 +931,46 @@ export class PropertiesView extends React.Component { * If it doesn't exist, it creates it. */ checkFilterDoc() { - if (!this.selectedDoc.currentFilter) this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + if (!this.selectedDoc?.currentFilter) this.selectedDoc!.currentFilter = CurrentUserUtils.createFilterDoc(); } /** * Creates a new currentFilter for this.filterDoc, */ createNewFilterDoc = () => { - const currentDocFilters = this.selectedDoc._docFilters; - const currentDocRangeFilters = this.selectedDoc._docRangeFilters; - this.selectedDoc._docFilters = new List(); - this.selectedDoc._docRangeFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; - (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + if (this.selectedDoc) { + const currentDocFilters = this.selectedDoc._docFilters; + const currentDocRangeFilters = this.selectedDoc._docRangeFilters; + this.selectedDoc._docFilters = new List(); + this.selectedDoc._docRangeFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; + (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; + this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + } } /** * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter */ updateFilterDoc = (doc: Doc) => { - if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc - const savedDocFilters = doc._docFiltersList; - const currentDocFilters = this.selectedDoc._docFilters; - this.selectedDoc._docFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; - this.selectedDoc.currentFilter = doc; - doc._docFiltersList = new List(); - this.selectedDoc._docFilters = savedDocFilters; - - const savedDocRangeFilters = doc._docRangeFiltersList; - const currentDocRangeFilters = this.selectedDoc._docRangeFilters; - this.selectedDoc._docRangeFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = doc; - doc._docRangeFiltersList = new List(); - this.selectedDoc._docRangeFilters = savedDocRangeFilters; + if (this.selectedDoc) { + if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc + const savedDocFilters = doc._docFiltersList; + const currentDocFilters = this.selectedDoc._docFilters; + this.selectedDoc._docFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; + this.selectedDoc.currentFilter = doc; + doc._docFiltersList = new List(); + this.selectedDoc._docFilters = savedDocFilters; + + const savedDocRangeFilters = doc._docRangeFiltersList; + const currentDocRangeFilters = this.selectedDoc._docRangeFilters; + this.selectedDoc._docRangeFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; + this.selectedDoc.currentFilter = doc; + doc._docRangeFiltersList = new List(); + this.selectedDoc._docRangeFilters = savedDocRangeFilters; + } } @computed get filtersSubMenu() { @@ -1059,13 +1063,13 @@ export class PropertiesView extends React.Component {
- {!Doc.UserDoc().noviceMode && this.openFields ?
+ {!Doc.noviceMode && this.openFields ?
{this.fieldsCheckbox}
Layout
: null} {!this.openFields ? (null) :
- {Doc.UserDoc().noviceMode ? this.noviceFields : this.expandedField} + {Doc.noviceMode ? this.noviceFields : this.expandedField}
}
; } @@ -1122,7 +1126,7 @@ export class PropertiesView extends React.Component { @undoBatch handleDescriptionChange = action((value: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.description = value; this.description = value; return true; @@ -1131,7 +1135,7 @@ export class PropertiesView extends React.Component { @undoBatch handleLinkRelationshipChange = action((value: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.linkRelationship = value; this.relationship = value; return true; @@ -1188,7 +1192,7 @@ export class PropertiesView extends React.Component { @undoBatch changeFollowBehavior = action((follow: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.followLinkLocation = follow; return true; } @@ -1219,18 +1223,18 @@ export class PropertiesView extends React.Component { } toggleAnchor = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)))); } toggleArrow = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow)))); } toggleZoomToTarget1 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => Cast(this.selectedDoc.anchor1, Doc, null).followLinkZoom = !Cast(this.selectedDoc.anchor1, Doc, null).followLinkZoom))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor1).followLinkZoom = !DocCast(this.selectedDoc.anchor1).followLinkZoom)))); } toggleZoomToTarget2 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => Cast(this.selectedDoc.anchor2, Doc, null).followLinkZoom = !Cast(this.selectedDoc.anchor2, Doc, null).followLinkZoom))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor2).followLinkZoom = !DocCast(this.selectedDoc.anchor2).followLinkZoom)))); } @computed @@ -1238,7 +1242,7 @@ export class PropertiesView extends React.Component { return this.handleLinkRelationshipChange(e.currentTarget.value)} @@ -1252,7 +1256,7 @@ export class PropertiesView extends React.Component { return this.handleDescriptionChange(e.currentTarget.value)} @@ -1273,7 +1277,7 @@ export class PropertiesView extends React.Component { // } render() { - const isNovice = BoolCast(Doc.UserDoc().noviceMode); + const isNovice = Doc.noviceMode; if (!this.selectedDoc && !this.isPres) { return
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 636f7042f..689ee4fc1 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -15,6 +15,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { DefaultStyleProvider } from "./StyleProvider"; import './TemplateMenu.scss'; import React = require("react"); +import { CurrentUserUtils } from "../util/CurrentUserUtils"; @observer class TemplateToggle extends React.Component<{ template: string, checked: boolean, toggle: (event: React.ChangeEvent, template: string) => void }> { @@ -111,22 +112,22 @@ export class TemplateMenu extends React.Component { const firstDoc = this.props.docViews[0].props.Document; const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", ""); const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data); - const addedTypes = Doc.UserDoc().noviceMode ? [] : DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); + const addedTypes = Doc.noviceMode ? [] : DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); const layout = Doc.Layout(firstDoc); const templateMenu: Array = []; this.props.templates?.forEach((checked, template) => templateMenu.push()); templateMenu.push(); templateMenu.push(); - !Doc.UserDoc().noviceMode && templateMenu.push(); + !Doc.noviceMode && templateMenu.push(); addedTypes.concat(noteTypes).map(template => template.treeViewChecked = this.templateIsUsed(firstDoc, template)); this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( this.toggleLayout(e, template)} />)); return
    - {Doc.UserDoc().noviceMode ? (null) : } + {Doc.noviceMode ? (null) : } {templateMenu} - {Doc.UserDoc().noviceMode ? (null) : { stack.header?.element.on('mousedown', (e: any) => { - if (e.target === stack.header?.element[0] && e.button === 2) { - const dashboard= CurrentUserUtils.ActiveDashboard; + const dashboard = CurrentUserUtils.ActiveDashboard; + if (dashboard && e.target === stack.header?.element[0] && e.button === 2) { dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; const docToAdd = Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _backgroundGridShow: true, _fitWidth: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}`, @@ -462,12 +462,14 @@ export class CollectionDockingView extends CollectionSubView() { .click(action(() => { // stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size const dashboard = CurrentUserUtils.ActiveDashboard; - dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; - const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}` - }); - this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, "", stack); + if (dashboard) { + dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; + const docToAdd = Docs.Create.FreeformDocument([], { + _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}` + }); + this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); + CollectionDockingView.AddSplit(docToAdd, "", stack); + } })); } @@ -480,6 +482,6 @@ ScriptingGlobals.add(function openInLightbox(doc: any) { LightboxView.AddDocTab( "opens up document in a lightbox", "(doc: any)"); ScriptingGlobals.add(function openOnRight(doc: any) { return CollectionDockingView.AddSplit(doc, "right"); }, "opens up document in tab on right side of the screen", "(doc: any)"); -ScriptingGlobals.add(function openInOverlay(doc: any) { return Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); }, +ScriptingGlobals.add(function openInOverlay(doc: any) { return Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc); }, "opens up document in screen overlay layer", "(doc: any)"); ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 1c25421f5..9b1bb5b97 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -268,17 +268,20 @@ export class CollectionViewBaseChrome extends React.Component { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }), initialize: (button: Doc) => { - button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) instanceof ObjectField ? - ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) as any as ObjectField) : undefined; - button['target-searchFilterDocs'] = CurrentUserUtils.ActiveDashboard._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(CurrentUserUtils.ActiveDashboard._searchFilterDocs as any as ObjectField) : undefined; + const activeDash = CurrentUserUtils.ActiveDashboard; + if (activeDash) { + button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? + ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined; + button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined; + } }, }; - @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } - @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } - @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } - @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } - @computed get _doc_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; } + @computed get _freeform_commands() { return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } + @computed get _stacking_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _masonry_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _schema_commands() { return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } + @computed get _doc_commands() { return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; } @computed get _tree_commands() { return undefined; } private get _buttonizableCommands() { switch (this.props.type) { @@ -467,7 +470,7 @@ export class CollectionViewBaseChrome extends React.Component { const doc = Docs.Create.ScreenshotDocument({ title: "screen recording", _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" }); - //Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + //Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc); CollectionDockingView.AddSplit(doc, "right"); } @@ -691,8 +694,8 @@ export class CollectionFreeFormViewChrome extends React.Component Back Frame
} placement="bottom">
@@ -879,7 +882,7 @@ export class CollectionStackingViewChrome extends React.Component key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index dddae4a34..277fcd59c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -598,7 +598,7 @@ export class CollectionStackingView extends CollectionSubView {buttonMenu || noviceExplainer ?
{buttonMenu ? this.buttonMenu : null} - {Doc.UserDoc().noviceMode && noviceExplainer ? + {Doc.noviceMode && noviceExplainer ?
{noviceExplainer}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 7f96217b8..f3a798143 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -224,8 +224,8 @@ export class CollectionStackingViewFieldColumn extends React.Component { Doc.GetProto(this.props.Document)[name] = ""; const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true }); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e809bfbce..ba72fb7b9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -67,7 +67,7 @@ export class CollectionTreeView extends CollectionSubView this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); - isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None || + isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.ActiveTool !== InkTool.None || (this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction)) ? true : false) @@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { const layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: "Make tree state " + (this.doc.treeViewOpenIsTransient ? "persistent" : "transient"), event: () => this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient, icon: "paint-brush" }); layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields, icon: "paint-brush" }); @@ -286,7 +286,7 @@ export class CollectionTreeView extends CollectionSubView {this.rootDoc.explainer}
; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 965f0a352..4b5c5e3fb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -160,8 +160,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent func(CollectionViewType.Masonry), icon: "columns" }); subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); subItems.push({ description: "3D Carousel", event: () => func(CollectionViewType.Carousel3D), icon: "columns" }); - !Doc.UserDoc().noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); - !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); + !Doc.noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); + !Doc.noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { @@ -184,16 +184,16 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; + !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; if (this.rootDoc.childLayout instanceof Doc) { optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" }); } if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" }); } - !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); + !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { optionItems.push({ description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram" }); @@ -210,7 +210,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 022b9fa24..70db121d1 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -277,7 +277,7 @@ export class TabDocView extends React.Component { pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array }); if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { - const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); + const docs = Cast(CurrentUserUtils.MyOverlayDocs.data, listSpec(Doc), []); if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); CollectionDockingView.AddSplit(curPres, "right"); setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 59dc5671b..704b8989a 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -114,7 +114,7 @@ export class TreeView extends React.Component { return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey : this.props.treeView.dashboardMode ? this.fieldKey : this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") : // for displaying - this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields"); + this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields"); } @computed get doc() { return this.props.document; } @@ -560,8 +560,8 @@ export class TreeView extends React.Component { const links = () => DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? "links" : ""; const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : ""; const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases"; - const fields = () => Doc.UserDoc().noviceMode ? "" : "fields"; - const layout = (Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; + const fields = () => Doc.noviceMode ? "" : "fields"; + const layout = (Doc.noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c07e44fcc..ffe146ae4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -458,7 +458,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return; if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; if (this.props.isContentActive(true)) e.stopPropagation(); } else if (!e.cancelBubble) { if (this.tryDragCluster(e, this._hitCluster)) { @@ -834,7 +834,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.MyOverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1031,7 +1031,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); - !Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); + !Doc.noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); appearanceItems.push({ description: `${this.fitContentsToBox ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitContentsToBox = !this.fitContentsToBox, icon: !this.fitContentsToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, {pinDocView:true, panelWidth: this.props.PanelWidth(), panelHeight:this.props.PanelHeight()}), icon: "map-pin" }); //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); @@ -1640,27 +1640,27 @@ export class CollectionFreeFormView extends CollectionSubView s.type === DocumentType.INK).length > 0 && appearanceItems.push({ description: "Ink to math", event: () => this.transcribeStrokes(true), icon: "square-root-alt" }); - !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; + !Doc.noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" }); const viewctrls = ContextMenu.Instance.findByDescription("UI Controls..."); const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : []; - !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; - !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); const options = ContextMenu.Instance.findByDescription("Options..."); const optionItems = options && "subitems" in options ? options.subitems : []; - !this.props.isAnnotationOverlay && !Doc.UserDoc().noviceMode && + !this.props.isAnnotationOverlay && !Doc.noviceMode && optionItems.push({ description: (this._showAnimTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this._showAnimTimeline = !this._showAnimTimeline), icon: "eye" }); this.props.renderDepth && optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); } !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); const mores = ContextMenu.Instance.findByDescription("More..."); const moreItems = mores && "subitems" in mores ? mores.subitems : []; - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { moreItems.push({ description: "Export collection", icon: "download", event: async () => Doc.Zip(this.props.Document) }); moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 051da795f..b62020a04 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -330,7 +330,7 @@ export class MarqueeView extends React.Component { if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - if (CurrentUserUtils.SelectedTool === InkTool.None) { + if (CurrentUserUtils.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { (e.nativeEvent as any).marqueeHit = true; if (!this.props.trySelectCluster(e.shiftKey)) { @@ -367,7 +367,7 @@ export class MarqueeView extends React.Component { Doc.GetProto(doc).data = new List(selected); Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform"; - !this.props.isAnnotationOverlay && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", Doc.GetProto(doc)); + !this.props.isAnnotationOverlay && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, undefined, Doc.GetProto(doc)); doc._panX = doc._panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); @@ -643,7 +643,7 @@ export class MarqueeView extends React.Component e.preventDefault()} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index 0875c80b3..9653f2808 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -321,7 +321,7 @@ export class KeysDropdown extends React.Component { const whitelistKeys = ["context", "author", "*lastModified", "text", "data", "tags", "creationDate"]; const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); const showKeys = new Set(); - [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.UserDoc().noviceMode || + [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.noviceMode || whitelistKeys.includes(key) || ((!key.startsWith("_") && key[0] === key[0].toUpperCase()) || key[0] === "#")) ? showKeys.add(key) : null); return Array.from(showKeys.keys()).filter(key => !this._searchTerm || key.includes(this._searchTerm)); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 669622455..8e24fce11 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -348,11 +348,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @undoBatch @action static switchColor(color: ColorState) { - // Doc.UserDoc().backgroundColor = Utils.colorString(color); // bcz: this can't go here ... needs a proper home in the settings panel SetActiveInkColor(color.hex); SelectionManager.Views().map(view => { @@ -49,7 +48,7 @@ export class ColorBox extends ViewBoxBaseComponent() { style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }} > CurrentUserUtils.SelectedTool === InkTool.None && ColorBox.switchColor(c)} + onChange={c => CurrentUserUtils.ActiveTool === InkTool.None && ColorBox.switchColor(c)} color={StrCast(SelectionManager.Views()?.[0]?.rootDoc?._backgroundColor, ActiveInkColor())} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e2b37d2b4..4d84a8ad2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -327,7 +327,7 @@ export class DocumentViewInternal extends DocComponent 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -543,9 +543,9 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.type === DocumentType.INK && CurrentUserUtils.SelectedTool === InkTool.Eraser) return; + if (this.rootDoc.type === DocumentType.INK && CurrentUserUtils.ActiveTool === InkTool.Eraser) return; // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document) - if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) { + if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it @@ -563,7 +563,7 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; - if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) return; + if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) return; - if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { + if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); @@ -697,7 +697,7 @@ export class DocumentViewInternal extends DocComponent { - if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) { + if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); @@ -747,8 +747,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, "add:right"), icon: "eye" }); - !Doc.UserDoc().noviceMode && appearanceItems.push({ + !Doc.noviceMode && templateDoc && appearanceItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" }); + !Doc.noviceMode && appearanceItems.push({ description: "Add a Field", event: () => { const alias = Doc.MakeAlias(this.rootDoc); alias.layout = FormattedTextBox.LayoutString("newfield"); @@ -765,7 +765,7 @@ export class DocumentViewInternal extends DocComponent this.layoutDoc._showAudio = !this.layoutDoc._showAudio), icon: "microphone" }); + !Doc.noviceMode && appearanceItems.splice(0, 0, { description: `${!this.layoutDoc._showAudio ? "Show" : "Hide"} Audio Button`, event: action(() => this.layoutDoc._showAudio = !this.layoutDoc._showAudio), icon: "microphone" }); const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; @@ -778,8 +778,8 @@ export class DocumentViewInternal extends DocComponent this.Document.followLinkZoom = !this.Document.followLinkZoom, icon: this.Document.ignoreClick ? "unlock" : "lock" }); if (!this.Document.annotationOn) { @@ -803,7 +803,7 @@ export class DocumentViewInternal extends DocComponent this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) }); funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) }); funcs.push({ description: "Drag Document", icon: "edit", event: () => this.layoutDoc.onDragStart = undefined }); @@ -813,8 +813,8 @@ export class DocumentViewInternal extends DocComponent SharingManager.Instance.open(this.props.DocumentView()), icon: "users" }); - if (!Doc.UserDoc().noviceMode) { + (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: "users" }); + if (!Doc.noviceMode) { moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeHidden ? "Show" : "Hide"} Chrome`, event: () => this.Document._chromeHidden = !this.Document._chromeHidden, icon: "project-diagram" }); @@ -835,9 +835,9 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" }); + !Doc.noviceMode && helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); + !Doc.noviceMode && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); + !Doc.noviceMode && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); } @@ -860,7 +860,7 @@ export class DocumentViewInternal extends DocComponent Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view); isContentActive = (outsideReaction?: boolean) => { return this.props.isContentActive() === false ? false : ( - CurrentUserUtils.SelectedTool !== InkTool.None || + CurrentUserUtils.ActiveTool !== InkTool.None || SnappingManager.GetIsDragging() || this.rootSelected() || this.props.Document.forceActive || diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 5add09653..17b57cb3b 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -8,7 +8,7 @@ import { List } from "../../../fields/List"; import { RichTextField } from "../../../fields/RichTextField"; import { listSpec } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { Cast, NumCast, StrCast, DocCast } from "../../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; @@ -84,7 +84,7 @@ export class FilterBox extends ViewBoxBaseComponent() { return "data"; } @computed static get targetDocChildren() { - return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard.data); + return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard?.data); } @observable _loaded = false; @@ -115,7 +115,7 @@ export class FilterBox extends ViewBoxBaseComponent() { const keys = new Set(noviceFields); this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key))); - return Array.from(keys.keys()).filter(key => key[0]).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.UserDoc().noviceMode).sort(); + return Array.from(keys.keys()).filter(key => key[0]).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.noviceMode).sort(); } @@ -167,23 +167,25 @@ export class FilterBox extends ViewBoxBaseComponent() { removeFilterDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).map(doc => this.removeFilter(StrCast(doc.title))).length ? true : false; public removeFilter = (filterName: string) => { const targetDoc = FilterBox.targetDoc; - const filterDoc = targetDoc.currentFilter as Doc; - const attributes = DocListCast(filterDoc.data); - const found = attributes.findIndex(doc => doc.title === filterName); - if (found !== -1) { - (filterDoc.data as List).splice(found, 1); - const docFilter = Cast(targetDoc._docFilters, listSpec("string")); - if (docFilter) { - let index: number; - while ((index = docFilter.findIndex(item => item.split(":")[0] === filterName)) !== -1) { - docFilter.splice(index, 1); + if (targetDoc) { + const filterDoc = targetDoc.currentFilter as Doc; + const attributes = DocListCast(filterDoc.data); + const found = attributes.findIndex(doc => doc.title === filterName); + if (found !== -1) { + (filterDoc.data as List).splice(found, 1); + const docFilter = Cast(targetDoc._docFilters, listSpec("string")); + if (docFilter) { + let index: number; + while ((index = docFilter.findIndex(item => item.split(":")[0] === filterName)) !== -1) { + docFilter.splice(index, 1); + } } - } - const docRangeFilters = Cast(targetDoc._docRangeFilters, listSpec("string")); - if (docRangeFilters) { - let index: number; - while ((index = docRangeFilters.findIndex(item => item.split(":")[0] === filterName)) !== -1) { - docRangeFilters.splice(index, 3); + const docRangeFilters = Cast(targetDoc._docRangeFilters, listSpec("string")); + if (docRangeFilters) { + let index: number; + while ((index = docRangeFilters.findIndex(item => item.split(":")[0] === filterName)) !== -1) { + docRangeFilters.splice(index, 3); + } } } } @@ -194,6 +196,7 @@ export class FilterBox extends ViewBoxBaseComponent() { */ facetClick = (facetHeader: string) => { const { targetDoc, targetDocChildren } = FilterBox; + if (!targetDoc) return; const found = this.activeAttributes.findIndex(doc => doc.title === facetHeader); if (found !== -1) { this.removeFilter(facetHeader); @@ -267,7 +270,7 @@ export class FilterBox extends ViewBoxBaseComponent() { */ @action changeBool = (e: any) => { - (FilterBox.targetDoc.currentFilter as Doc).filterBoolean = e.currentTarget.value; + FilterBox.targetDoc && (DocCast(FilterBox.targetDoc.currentFilter).filterBoolean = e.currentTarget.value); } /** @@ -322,7 +325,7 @@ export class FilterBox extends ViewBoxBaseComponent() { * Changes the title of the filterDoc */ onTitleValueChange = (val: string) => { - this.props.Document.title = val || `FilterDoc for ${FilterBox.targetDoc.title}`; + this.props.Document.title = val || `FilterDoc for ${FilterBox.targetDoc?.title}`; return true; } @@ -373,7 +376,7 @@ export class FilterBox extends ViewBoxBaseComponent() {
- diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 8c27b3508..60eb48114 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -179,7 +179,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(this.choosePath(field.url)), icon: "expand-arrows-alt" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" }); const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers..."); @@ -357,7 +357,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._viewScale,1) <= NumCast(this.rootDoc.viewScaleMin,1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._viewScale,1) <= NumCast(this.rootDoc.viewScaleMin,1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index b0b050cea..b58a9affb 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -52,7 +52,7 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro get paramsDoc() { return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; } specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - !Doc.UserDoc().noviceMode && funcs.push({ + !Doc.noviceMode && funcs.push({ description: "Clear Script Params", event: () => { const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); params?.map(p => this.paramsDoc[p] = undefined); diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 5f4c17ee6..0b7264d79 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -471,7 +471,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -570,7 +570,7 @@ export class MapBox extends ViewBoxAnnotatableComponent; + // pointerEvents={CurrentUserUtils.ActiveTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />; return
{/*console.log(apiKey)*/} {/* Loading
:
@@ -484,7 +484,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.layoutDoc._currentTimecode, () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode))); this._disposers.youtubeReactionDisposer = reaction( - () => CurrentUserUtils.SelectedTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, + () => CurrentUserUtils.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, (interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true }); }; if (typeof (YT) === undefined) setTimeout(() => this.loadYouTube(iframe), 100); @@ -707,7 +707,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 967158cbf..d14af49ea 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -536,7 +536,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); + !Doc.noviceMode && funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); funcs.push({ description: (this.layoutDoc.allowScripts ? "Prevent" : "Allow") + " Scripts", event: () => { this.layoutDoc.allowScripts = !this.layoutDoc.allowScripts; @@ -561,7 +561,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -678,7 +678,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}> diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index f29dfe489..3af6a3d51 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -1,6 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; +import { StringIterator } from 'lodash'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -70,7 +71,7 @@ export class FontIconBox extends DocComponent() { useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); }; specificContextMenu = (): void => { - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { const cm = ContextMenu.Instance; cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" }); cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" }); @@ -269,7 +270,7 @@ export class FontIconBox extends DocComponent() { // Get items to place into the list const list = this.buttonList.map((value) => { - if (Doc.UserDoc().noviceMode && !noviceList.includes(value)) { + if (Doc.noviceMode && !noviceList.includes(value)) { return; } return
= 1) return Colors.MEDIUM_BLUE; + if (checkResult) { + if (NumCast(selected?.Document.z) >= 1) return Colors.MEDIUM_BLUE; return "transparent"; } selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("[FontIconBox.tsx] toggleOverlay failed"); @@ -710,7 +711,7 @@ ScriptingGlobals.add(function toggleItalic(checkResult?: boolean) { export function checkInksToGroup() { // console.log("getting here to inks group"); - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those // find all inkDocs in ffView.unprocessedDocs that are within 200 pixels of each other @@ -723,7 +724,7 @@ export function checkInksToGroup() { export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { // TODO nda - if document being added to is a inkGrouping then we can just add to that group - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those const selected = ffView.unprocessedDocs; @@ -785,38 +786,38 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { /** INK - * setActiveInkTool + * setActiveTool * setStrokeWidth * setStrokeColor **/ -ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boolean) { +ScriptingGlobals.add(function setActiveTool(tool: string, checkResult?: boolean) { InkTranscription.Instance?.createInkGroup(); if (checkResult) { - return ((Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ? + return ((CurrentUserUtils.ActiveTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ? Colors.MEDIUM_BLUE : "transparent"; } if (["circle", "square", "line"].includes(tool)) { if (GestureOverlay.Instance.InkShape === tool) { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; GestureOverlay.Instance.InkShape = InkTool.None; } else { - Doc.UserDoc().activeInkTool = InkTool.Pen; + CurrentUserUtils.ActiveTool = InkTool.Pen; GestureOverlay.Instance.InkShape = tool; } } else if (tool) { // pen or eraser - if (Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance.InkShape) { - Doc.UserDoc().activeInkTool = InkTool.None; - } else if (tool == "write") { + if (CurrentUserUtils.ActiveTool === tool && !GestureOverlay.Instance.InkShape) { + CurrentUserUtils.ActiveTool = InkTool.None; + } else if (tool == InkTool.Write) { // console.log("write mode selected - create groupDoc here!", tool) - Doc.UserDoc().activeInkTool = tool; + CurrentUserUtils.ActiveTool = tool; GestureOverlay.Instance.InkShape = ""; } else { - Doc.UserDoc().activeInkTool = tool; + CurrentUserUtils.ActiveTool = tool as any; GestureOverlay.Instance.InkShape = ""; } } else { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; } }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 16a523b40..90199618b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -648,7 +648,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const highlighting: ContextMenuProps[] = []; const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others", "Bold Text"]; const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"]; - (Doc.UserDoc().noviceMode ? noviceHighlighting : expertHighlighting).forEach(option => + (Doc.noviceMode ? noviceHighlighting : expertHighlighting).forEach(option => highlighting.push({ description: (FormattedTextBox._globalHighlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { e.stopPropagation(); @@ -663,11 +663,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp })); const uicontrols: ContextMenuProps[] = []; - !Doc.UserDoc().noviceMode && uicontrols.push({ description: `${FormattedTextBox._canAnnotate ? "Don't" : ""} Show Menu on Selections`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" }); + !Doc.noviceMode && uicontrols.push({ description: `${FormattedTextBox._canAnnotate ? "Don't" : ""} Show Menu on Selections`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" }); uicontrols.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, icon: "expand-arrows-alt" }); uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" }); - !Doc.UserDoc().noviceMode && uicontrols.push({ + !Doc.noviceMode && uicontrols.push({ description: "Broadcast Message", event: () => DocServer.GetRefField("rtfProto").then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt" }); @@ -677,7 +677,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : []; appearanceItems.push({ description: "Change Perspective...", noexpand: true, subitems: changeItems, icon: "external-link-alt" }); // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" }); - !Doc.UserDoc().noviceMode && appearanceItems.push({ + !Doc.noviceMode && appearanceItems.push({ description: "Make Default Layout", event: () => { if (!this.layoutDoc.isTemplateDoc) { const title = StrCast(this.rootDoc.title); @@ -1636,7 +1636,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp noSidebar={true} fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : `${this.fieldKey}-annotations`} />; }; - return
{renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
; @@ -1647,7 +1647,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const active = this.props.isContentActive(); const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; - const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition); + const interactive = (CurrentUserUtils.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition); if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide); const minimal = this.props.ignoreAutoHeight; const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 9bc2e5628..98343a261 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -67,7 +67,6 @@ export class RichTextMenu extends AntimodeMenu { runInAction(() => { RichTextMenu.Instance = this; this._canFade = false; - //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]); this.Pinned = true; }); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 52b03b0a5..0d2cffc2c 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -134,7 +134,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); - if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); + if (CurrentUserUtils.ActivePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" @@ -178,16 +178,16 @@ export class PresBox extends ViewBoxBaseComponent() { this.layoutDoc._gridGap = 0; this.layoutDoc._yMargin = 0; this.turnOffEdit(true); - DocListCastAsync((Doc.UserDoc().myTrails as Doc).data).then(pres => - !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myTrails as Doc, "data", this.rootDoc)); + DocListCastAsync(CurrentUserUtils.MyTrails.data).then(pres => + !pres?.includes(this.rootDoc) && Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", this.rootDoc)); this._disposers.selection = reaction(() => SelectionManager.Views(), views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()); } @action updateCurrentPresentation = (pres?: Doc) => { - if (pres) Doc.UserDoc().activePresentation = pres; - else Doc.UserDoc().activePresentation = this.rootDoc; + if (pres) CurrentUserUtils.ActivePresentation = pres; + else CurrentUserUtils.ActivePresentation = this.rootDoc; document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); document.addEventListener("keydown", PresBox.keyEventsWrapper, true); this._presKeyEventsActive = true; @@ -623,9 +623,9 @@ export class PresBox extends ViewBoxBaseComponent() { */ @action updateMinimize = async () => { - if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { + if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); CollectionDockingView.AddSplit(this.rootDoc, "right"); } else { this.layoutDoc.presStatus = PresStatus.Edit; @@ -635,7 +635,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.rootDoc.y = pt[1] + 10; this.rootDoc._height = 30; this.rootDoc._width = 248; - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); this.props.removeDocument?.(this.layoutDoc); } } @@ -732,7 +732,7 @@ export class PresBox extends ViewBoxBaseComponent() { removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.layoutDoc._lockedPosition) && + isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) /** @@ -868,7 +868,7 @@ export class PresBox extends ViewBoxBaseComponent() { } break; case "Escape": - if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } + if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = "edit"; if (this._presTimer) clearTimeout(this._presTimer); @@ -2247,7 +2247,7 @@ export class PresBox extends ViewBoxBaseComponent() { const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel"; const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); + const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); const activeColor = Colors.LIGHT_BLUE; const inactiveColor = Colors.WHITE; return (mode === CollectionViewType.Carousel3D) ? (null) : ( @@ -2305,7 +2305,7 @@ export class PresBox extends ViewBoxBaseComponent() { value={mode}> - {Doc.UserDoc().noviceMode ? (null) : } + {Doc.noviceMode ? (null) : } }
@@ -2508,10 +2508,10 @@ export class PresBox extends ViewBoxBaseComponent() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); + const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); - return CurrentUserUtils.MyOverlayDocs.includes(this.rootDoc) ? + return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.rootDoc) ?
e.stopPropagation()}>
{"Loop"}
}>
() {
: -
+
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 50df00612..1a2f4b93f 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -309,7 +309,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get recordingIsInOverlay() { let isInOverlay = false - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides === this.rootDoc) { isInOverlay = true return @@ -319,9 +319,9 @@ export class PresElementBox extends ViewBoxBaseComponent() { } removeAllRecordingInOverlay = () => { - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides === this.rootDoc) { - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc); } }) } @@ -339,7 +339,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { this.removeAllRecordingInOverlay() if (activeItem.recording) { // if we already have an existing recording - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null)); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, Cast(activeItem.recording, Doc, null)); } } @@ -348,15 +348,15 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action startRecording = (activeItem: Doc) => { // Remove every recording that already exists in overlay view - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides !== null) { - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc); } }) if (activeItem.recording) { // if we already have an existing recording - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null)); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, Cast(activeItem.recording, Doc, null)); } else { // if we dont have any recording @@ -376,7 +376,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // make recording box appear in the bottom right corner of the screen recording.x = window.innerWidth - recording[WidthSym]() - 20; recording.y = window.innerHeight - recording[HeightSym]() - 20; - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, recording); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 0ded1bb3c..2869d4f2d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -340,7 +340,7 @@ export class PDFViewer extends React.Component { if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { this._setPreviewCursor?.(e.clientX, e.clientY, true, false); } - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0db3950a2..1de0c0b10 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -27,12 +27,12 @@ import "./TopBar.scss"; export class TopBar extends React.Component { navigateToHome = () => { CurrentUserUtils.CaptureDashboardThumbnail()?.then(() => { - Doc.UserDoc().activePage = "home"; + CurrentUserUtils.ActivePage = "home"; CurrentUserUtils.closeActiveDashboard(); // bcz: if we do this, we need some other way to keep track, for user convenience, of the last dashboard in use }); } render() { - const activeDashboard = Cast(Doc.UserDoc().activeDashboard, Doc, null) + const activeDashboard = CurrentUserUtils.ActiveDashboard; return ( //TODO:glr Add support for light / dark mode
@@ -44,11 +44,11 @@ export class TopBar extends React.Component { }}>{Doc.CurrentUserEmail}
: (null)}
-
SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(activeDashboard)!, false)}> +
activeDashboard && SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(activeDashboard)!, false)}> {activeDashboard ? StrCast(activeDashboard.title) : "Dash"}
{ - const dashView = DocumentManager.Instance.getDocumentView(activeDashboard); + const dashView = activeDashboard && DocumentManager.Instance.getDocumentView(activeDashboard); ContextMenu.Instance.addItem({ description: "Open Dashboard View", event: this.navigateToHome, icon: "edit" }); ContextMenu.Instance.addItem({ description: "Snapshot Dashboard", event: async () => { const batch = UndoManager.StartBatch("snapshot"); @@ -69,7 +69,7 @@ export class TopBar extends React.Component {
{SharingManager.Instance.open(undefined, activeDashboard)}}> {/* TODO: if this is my dashboard, display share if this is a shared dashboard, display "view original or view annotated" */} - { Doc.GetProto(CurrentUserUtils.ActiveDashboard)?.author === Doc.CurrentUserEmail ? "Share": "view original" } + { CurrentUserUtils.ActiveDashboard && (Doc.GetProto(CurrentUserUtils.ActiveDashboard)?.author === Doc.CurrentUserEmail ? "Share": "view original") }
window.open( "https://brown-dash.github.io/Dash-Documentation/", "_blank")}> diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index e0d328c89..6c0c9b301 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -71,7 +71,7 @@ export class DashWebRTCVideo extends React.Component; const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <> diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 94be286f5..74213652b 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -21,7 +21,7 @@ import { FieldId, RefField } from "./RefField"; import { RichTextField } from "./RichTextField"; import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; +import { BoolCast, Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, MapField, PdfField, VideoField, WebField } from "./URLField"; import { deleteProperty, GetEffectiveAcl, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); @@ -233,6 +233,10 @@ export class Doc extends RefField { } private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; + public static get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode); } + public static set noviceMode(val) { Doc.UserDoc().noviceMode = val; } + public static get defaultAclPrivate() { return Doc.UserDoc().defaultAclPrivate; } + public static set defaultAclPrivate(val) { Doc.UserDoc().defaultAclPrivate = val; } public static CurrentUserEmail: string = ""; public static get CurrentUserEmailNormalized() { return normalizeEmail(Doc.CurrentUserEmail); } public async [HandleUpdate](diff: any) { @@ -805,7 +809,7 @@ export namespace Doc { Doc.AddDocToList(Doc.GetProto(copy)[DataSym], "aliases", copy); } copy.context = undefined; - Doc.UserDoc().defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); + Doc.defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); if (retitle) { copy.title = incrementTitleCopy(StrCast(copy.title)); } @@ -861,7 +865,7 @@ export namespace Doc { const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); target.layoutKey = targetKey; applied && (Doc.GetProto(applied).type = templateDoc.type); - Doc.UserDoc().defaultAclPrivate && (applied["acl-Public"] = "Not Shared"); + Doc.defaultAclPrivate && (applied["acl-Public"] = "Not Shared"); return applied; } return undefined; @@ -1234,19 +1238,19 @@ export namespace Doc { export function isDocPinned(doc: Doc) { //add this new doc to props.Document - const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + const curPres = CurrentUserUtils.ActivePresentation; return !curPres ? false : DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; } export function copyDragFactory(dragFactory: Doc) { const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true); - ndoc && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", Doc.GetProto(ndoc)); + ndoc && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, "data", Doc.GetProto(ndoc)); if (ndoc && dragFactory["dragFactory-count"] !== undefined) { dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true); } - if (ndoc) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); + if (ndoc && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); return ndoc; } @@ -1448,7 +1452,7 @@ ScriptingGlobals.add(function DOC(id: string) { console.log("Can't parse a docum ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); ScriptingGlobals.add(function docCast(doc: FieldResult): any { return DocCastAsync(doc); }); ScriptingGlobals.add(function activePresentationItem() { - const curPres = Doc.UserDoc().activePresentation as Doc; + const curPres = CurrentUserUtils.ActivePresentation; return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); ScriptingGlobals.add(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 37b9be31b..8fb35981b 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -145,7 +145,7 @@ export function inheritParentAcls(parent: Doc, child: Doc) { const dataDoc = parent[DataSym]; for (const key of Object.keys(dataDoc)) { // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private. - const permission = (key === "acl-Public" && Doc.UserDoc().defaultAclPrivate) ? AclPrivate : dataDoc[key]; + const permission = (key === "acl-Public" && Doc.defaultAclPrivate) ? AclPrivate : dataDoc[key]; key.startsWith("acl") && distributeAcls(key, permission, child); } } diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index c5c6fb688..fe8100997 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -51,7 +51,7 @@ library.add(...[faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, fa @observer export class MobileInterface extends React.Component { static Instance: MobileInterface; - private _library: Promise; + private _library: Doc; private _mainDoc: any = CurrentUserUtils.setupActiveMobileMenu(Doc.UserDoc()); @observable private _sidebarActive: boolean = false; //to toggle sidebar display @observable private _imageUploadActive: boolean = false; //to toggle image upload @@ -68,7 +68,7 @@ export class MobileInterface extends React.Component { constructor(props: Readonly<{}>) { super(props); - this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc()); // to access documents in Dash Web + this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc(), "myDashboards"); // to access documents in Dash Web MobileInterface.Instance = this; } @@ -76,7 +76,7 @@ export class MobileInterface extends React.Component { componentDidMount = () => { // if the home menu is in list view -> adjust the menu toggle appropriately this._menuListView = this._homeDoc._viewType === "stacking" ? true : false; - CurrentUserUtils.SelectedTool = InkTool.None; // ink should intially be set to none + CurrentUserUtils.ActiveTool = InkTool.None; // ink should intially be set to none Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home AudioBox.Enabled = true; @@ -125,7 +125,7 @@ export class MobileInterface extends React.Component { * Method called when 'Library' button is pressed on the home screen */ switchToLibrary = async () => { - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); runInAction(() => this._homeMenu = false); this.toggleSidebar(); } @@ -140,7 +140,7 @@ export class MobileInterface extends React.Component { // Case 1: Parent document is 'dashboards' if (doc === Cast(this._library, Doc) as Doc) { this.dashboards = null; - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); // Case 2: Parent document is the 'home' menu (root node) } else if (doc === Cast(this._homeDoc, Doc) as Doc) { this._homeMenu = true; @@ -179,7 +179,7 @@ export class MobileInterface extends React.Component { @action returnMain = () => { this._parents = [this._homeDoc]; - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); this._homeMenu = false; this.dashboards = null; } @@ -419,10 +419,10 @@ export class MobileInterface extends React.Component { button.style.color = this._ink ? "black" : "white"; if (!this._ink) { - CurrentUserUtils.SelectedTool = InkTool.Pen; + CurrentUserUtils.ActiveTool = InkTool.Pen; this._ink = true; } else { - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; this._ink = false; } } @@ -514,7 +514,7 @@ export class MobileInterface extends React.Component { return
TabDocView.PinDoc(this._activeDoc, { unpin: isPinned })}> + onClick={e => TabDocView.PinDoc(this._activeDoc)}>
; } else return (null); @@ -573,7 +573,7 @@ export class MobileInterface extends React.Component { // For setting up the presentation document for the home menu @action setupDefaultPresentation = () => { - const presentation = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + const presentation = CurrentUserUtils.ActivePresentation; if (presentation) { this.switchCurrentView(presentation); -- cgit v1.2.3-70-g09d2 From 3e22a44461095d95062e3b809b525a0a87342ac3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 22:18:42 -0400 Subject: more cleanup to get rid of unecessary references to Doc.UserDoc(). --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 48 +++++++++++++--------- src/client/util/DragManager.ts | 4 +- src/client/util/History.ts | 2 +- src/client/util/SettingsManager.tsx | 19 ++++----- src/client/util/SnappingManager.ts | 4 ++ src/client/views/DashboardView.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/MainView.tsx | 21 ++++------ .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/button/FontIconBox.tsx | 30 +++++++------- .../nodes/button/colorDropdown/ColorDropdown.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 11 +---- src/client/views/topbar/TopBar.tsx | 2 +- src/mobile/MobileInterface.tsx | 2 +- 22 files changed, 93 insertions(+), 89 deletions(-) (limited to 'src/mobile') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e36103938..73b756a8d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -662,7 +662,7 @@ export namespace Docs { const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, "^_"); dataProps["acl-Override"] = "None"; - dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; dataProps.system = viewProps.system; dataProps.isPrototype = true; @@ -679,7 +679,7 @@ export namespace Docs { const dataDoc = Doc.assign(Doc.MakeDelegate(proto, protoId), dataProps, undefined, true); const viewFirstProps: { [id: string]: any } = {}; - viewFirstProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + viewFirstProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; viewFirstProps["acl-Override"] = "None"; viewFirstProps.author = Doc.CurrentUserEmail; const viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 1d5a9fa09..9b5fc5b98 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -181,7 +181,12 @@ export class CurrentUserUtils { /// Initializes collection of templates for notes and click functions static setupDocTemplates(doc: Doc, field="myTemplates") { + const preEleOpts:DocumentOptions = { + title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" + }; + this.AssignOpts(DocCast(doc.presElement), preEleOpts) ?? (doc.presElement= Docs.Create.PresElementBoxDocument(preEleOpts)); const templates = [ + DocCast(doc.presElement), CurrentUserUtils.setupNoteTemplates(doc), CurrentUserUtils.setupClickEditorTemplates(doc) ]; @@ -323,8 +328,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, { toolTip: "Tap or drag to create a mobile view", title: "Phone", icon: "mobile", dragFactory: doc.activeMobileMenu as Doc, scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)', onDragStart: 'this.dragFactory'}, funcs: {hidden: 'IsNoviceMode()'} }, { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, - // { toolTip: "Tap or drag to create a presentation", title: "Trails", icon: "pres-trail", dragFactory: doc.emptyPresentation as Doc,scripts: {onClick: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', onDragStart: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`}, funcs: {hidden: 'IsNoviceMode()'} }, - ]; + ]; } /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools @@ -533,7 +537,7 @@ export class CurrentUserUtils { static setupDashboards(doc: Doc, field:string) { var myDashboards = DocCast(doc[field]); - const newDashboard = `createNewDashboard(Doc.UserDoc())`; + const newDashboard = `createNewDashboard()`; const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true }; const reqdBtnScript = {onClick: newDashboard,} @@ -830,6 +834,11 @@ export class CurrentUserUtils { const reqdOpts = { title: "overlay documents", backgroundColor: "#aca3a6", system: true }; return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.FreeformDocument([], reqdOpts)); } + + static setupPublished(doc:Doc, field = "myPublishedDocs") { + const reqdOpts = { title: "published docs", backgroundColor: "#aca3a6", system: true }; + return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + } /// The database of all links on all documents static async setupLinkDocs(doc: Doc, linkDatabaseId: string) { @@ -958,7 +967,6 @@ export class CurrentUserUtils { Doc.noviceMode ?? (Doc.noviceMode = true); doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); doc._showLabel ?? (doc._showLabel = true); - doc._showMenuLabel ?? (doc._showMenuLabel = true); doc.textAlign ?? (doc.textAlign = "left"); doc.activeInkColor ?? (doc.activeInkColor = "rgb(0, 0, 0)");; doc.activeInkWidth ?? (doc.activeInkWidth = 1); @@ -975,17 +983,17 @@ export class CurrentUserUtils { doc.savedFilters ?? (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; - doc.myPublishedDocs ?? (doc.myPublishedDocs = new List()); doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents await this.setupLinkDocs(doc, linkDatabaseId); await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon - this.setupDocTemplates(doc); // sets up the template menu of templates this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard + this.setupPublished(doc); // sets up the list doc of all docs that have been published (meaning that they can be auto-linked by typing their title into another text box) this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left + this.setupDocTemplates(doc); // sets up the template menu of templates doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument()); setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); @@ -1037,7 +1045,8 @@ export class CurrentUserUtils { public static _urlState: HistoryUtil.DocUrl; - public static openDashboard = (userDoc: Doc, doc: Doc, fromHistory = false) => { + public static openDashboard = (doc: Doc, fromHistory = false) => { + const userDoc = Doc.UserDoc(); CurrentUserUtils.MainDocId = doc[Id]; if (!DocListCast(CurrentUserUtils.MyDashboards.data).includes(doc)) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", doc); @@ -1045,7 +1054,7 @@ export class CurrentUserUtils { if (doc) { // this has the side-effect of setting the main container since we're assigning the active/guest dashboard !("presentationView" in doc) && (doc.presentationView = new List([Docs.Create.TreeDocument([], { title: "Presentation" })])); - userDoc ? (userDoc.activeDashboard = doc) : (CurrentUserUtils.GuestDashboard = doc); + userDoc ? (CurrentUserUtils.ActiveDashboard = doc) : (CurrentUserUtils.GuestDashboard = doc); } const state = CurrentUserUtils._urlState; if (state.sharing === true && !userDoc) { @@ -1138,11 +1147,11 @@ export class CurrentUserUtils { } - public static async snapshotDashboard(userDoc: Doc) { + public static async snapshotDashboard() { if (CurrentUserUtils.ActiveDashboard) { const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); - CurrentUserUtils.openDashboard(userDoc, copy); + CurrentUserUtils.openDashboard(copy); } } @@ -1150,9 +1159,9 @@ export class CurrentUserUtils { CurrentUserUtils.ActiveDashboard = undefined; } - public static createNewDashboard = async (userDoc: Doc, id?: string) => { - const presentation = Doc.MakeCopy(userDoc.emptyPresentation as Doc, true); - const dashboards = await Cast(userDoc.myDashboards, Doc) as Doc; + public static createNewDashboard = (id?: string) => { + const presentation = Doc.MakeCopy(Doc.UserDoc().emptyPresentation as Doc, true); + const dashboards = CurrentUserUtils.MyDashboards; const dashboardCount = DocListCast(dashboards.data).length + 1; const freeformOptions: DocumentOptions = { x: 0, @@ -1172,10 +1181,10 @@ export class CurrentUserUtils { dashboardDoc.data = new List(dashboardTabs); dashboardDoc["pane-count"] = 1; - userDoc.activePresentation = presentation; + CurrentUserUtils.ActivePresentation = presentation; Doc.AddDocToList(dashboards, "data", dashboardDoc); - // CurrentUserUtils.openDashboard(userDoc, dashboardDoc); + // CurrentUserUtils.openDashboard(dashboardDoc); } public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) { @@ -1209,6 +1218,7 @@ export class CurrentUserUtils { public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } public static get MyOverlayDocs() { return DocCast(Doc.UserDoc().myOverlayDocs); } + public static get MyPublishedDocs() { return DocCast(Doc.UserDoc().myPublishedDocs); } public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } public static set ActiveDashboard(val:Doc|undefined) { Doc.UserDoc().activeDashboard = val; } public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } @@ -1230,8 +1240,8 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); -ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); -ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, "creates a new dashboard when called"); +ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(); }, "creates a snapshot copy of a dashboard"); +ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(); }, "creates a new dashboard when called"); ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called"); ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called"); ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); @@ -1240,7 +1250,7 @@ ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { SharingManager.In ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); if (dashboards && dashboards.length > 1) { - if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboards.find(doc => doc !== dashboard)!); + if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(dashboards.find(doc => doc !== dashboard)!); Doc.RemoveDocFromList(CurrentUserUtils.MyDashboards, "data", dashboard); } }, @@ -1248,7 +1258,7 @@ ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); - CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); + CurrentUserUtils.openDashboard(dashboardAlias); }, "adds Dashboard to set of Dashboards"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index dbfba8992..2b62945af 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -6,7 +6,7 @@ import { PrefetchProxy } from "../../fields/Proxy"; import { listSpec } from "../../fields/Schema"; import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { ScriptField } from "../../fields/ScriptField"; -import { Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; import { emptyFunction, Utils } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; import * as globalCssVariables from "../views/global/globalCssVariables.scss"; @@ -72,6 +72,8 @@ export namespace DragManager { export let StartWindowDrag: Opt<((e: { pageX: number, pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void)>; export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; + export function GetRaiseWhenDragged() { return BoolCast(Doc.UserDoc()._raiseWhenDragged); } + export function SetRaiseWhenDragged(val:boolean) { Doc.UserDoc()._raiseWhenDragged = val } export function Root() { const root = document.getElementById("root"); if (!root) { diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 632348306..7dcff9c56 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -197,7 +197,7 @@ export namespace HistoryUtil { await Promise.all(Object.keys(init).map(id => initDoc(id, init[id]))); } if (field instanceof Doc) { - CurrentUserUtils.openDashboard(Doc.UserDoc(), field, true); + CurrentUserUtils.openDashboard(field, true); } } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 382274462..22e33ab1e 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -10,7 +10,9 @@ import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager import { DocServer } from "../DocServer"; import { Networking } from "../Network"; import { MainViewModal } from "../views/MainViewModal"; +import { FontIconBox } from "../views/nodes/button/FontIconBox"; import { CurrentUserUtils } from "./CurrentUserUtils"; +import { DragManager } from "./DragManager"; import { GroupManager } from "./GroupManager"; import "./SettingsManager.scss"; import { undoBatch } from "./UndoManager"; @@ -155,19 +157,14 @@ export class SettingsManager extends React.Component<{}> {
Show full toolbar
- Doc.UserDoc()._raiseWhenDragged = !Doc.UserDoc()._raiseWhenDragged} - checked={BoolCast(Doc.UserDoc()._raiseWhenDragged)} /> + DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged())} + checked={DragManager.GetRaiseWhenDragged()} />
Raise on drag
- Doc.UserDoc()._showLabel = !Doc.UserDoc()._showLabel} - checked={BoolCast(Doc.UserDoc()._showLabel)} /> -
Show tool button labels
-
-
- Doc.UserDoc()._showMenuLabel = !Doc.UserDoc()._showMenuLabel} - checked={BoolCast(Doc.UserDoc()._showMenuLabel)} /> -
Show menu button labels
+ FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} + checked={FontIconBox.GetShowLabels()} /> +
Show button labels
; } @@ -271,7 +268,7 @@ export class SettingsManager extends React.Component<{}> {
- Doc.defaultAclPrivate = !Doc.defaultAclPrivate)} />
Default access private
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index 069f81d38..057843c68 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -1,5 +1,6 @@ import { observable, action, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; +import { Doc } from "../../fields/Doc"; export namespace SnappingManager { @@ -30,6 +31,9 @@ export namespace SnappingManager { export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); } export function GetIsDragging() { return manager.IsDragging; } + export function SetShowSnapLines(show: boolean) { runInAction(() => Doc.UserDoc().showSnapLines = show); } + export function GetShowSnapLines() { return Doc.UserDoc().showSnapLines; } + /// bcz; argh!! TODO; These do not belong here, but there were include order problems with leaving them in util.ts // need to investigate further what caused the mobx update problems and move to a better location. const getCachedGroupByNameCache = computedFn(function (name: string) { return manager.cachedGroups.includes(name); }, true); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 9a0f25fe3..a126218c4 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -28,7 +28,7 @@ export class DashboardView extends React.Component { newDashboard = async () => { const batch = UndoManager.StartBatch("new dash"); - await CurrentUserUtils.createNewDashboard(Doc.UserDoc()); + await CurrentUserUtils.createNewDashboard(); batch.end(); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 18cf785b9..4247501bb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -87,10 +87,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P if (titleFieldKey === "title") { d.dataDoc["title-custom"] = !this._accumulatedTitle.startsWith("-"); if (StrCast(d.rootDoc.title).startsWith("@") && !this._accumulatedTitle.startsWith("@")) { - Doc.RemoveDocFromList(Doc.UserDoc(), "myPublishedDocs", d.rootDoc); + Doc.RemoveDocFromList(CurrentUserUtils.MyPublishedDocs, undefined, d.rootDoc); } if (!StrCast(d.rootDoc.title).startsWith("@") && this._accumulatedTitle.startsWith("@")) { - Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", d.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyPublishedDocs, undefined, d.rootDoc); } } //@ts-ignore diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 61cca0421..6ee8065f5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -225,26 +225,21 @@ export class MainView extends React.Component { // Load the user's active dashboard, or create a new one if initial session after signup const received = CurrentUserUtils.MainDocId; if (received && !this.userDoc) { - reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(Doc.UserDoc()), { fireImmediately: true }); + reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(), { fireImmediately: true }); } else { PromiseValue(this.userDoc.activeDashboard).then(dash => { - if (dash instanceof Doc) CurrentUserUtils.openDashboard(this.userDoc, dash); - else CurrentUserUtils.createNewDashboard(this.userDoc); + if (dash instanceof Doc) CurrentUserUtils.openDashboard(dash); + else CurrentUserUtils.createNewDashboard(); }); } } @action createNewPresentation = async () => { - if (!await this.userDoc.myTrails) { - this.userDoc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "TRAILS", childDontRegisterViews: true, _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true - })); - } const pres = Docs.Create.PresDocument({ title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); CollectionDockingView.AddSplit(pres, "left"); - this.userDoc.activePresentation = pres; - Doc.AddDocToList(this.userDoc.myTrails as Doc, "data", pres); + CurrentUserUtils.ActivePresentation = pres; + Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", pres); } @action @@ -353,9 +348,9 @@ export class MainView extends React.Component { addDocTabFunc = (doc: Doc, location: string): boolean => { const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); const locationParams = locationFields.length > 1 ? locationFields[1] : ""; - if (doc.dockingConfig) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + if (doc.dockingConfig) return CurrentUserUtils.openDashboard(doc); switch (locationFields[0]) { - case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + case "dashboard": return CurrentUserUtils.openDashboard(doc); case "close": return CollectionDockingView.CloseSplit(doc, locationParams); case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); case "lightbox": return LightboxView.AddDocTab(doc, location); @@ -563,7 +558,7 @@ export class MainView extends React.Component {
; } @computed get snapLines() { - return !this.userDoc.showSnapLines ? (null) :
+ return !SnappingManager.GetShowSnapLines() ? (null) :
{SnappingManager.horizSnapLines().map(l => )} {SnappingManager.vertSnapLines().map(l => )} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5f36a7a51..19355b8e1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -121,7 +121,7 @@ export class CollectionDockingView extends CollectionSubView() { SelectionManager.DeselectAll(); const instance = CollectionDockingView.Instance; if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { - return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + return CurrentUserUtils.openDashboard(doc); } const newItemStackConfig = { type: 'stack', @@ -172,7 +172,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) { - if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document); + if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(document); const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document); if (tab) { diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 9b1bb5b97..668d82387 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -164,7 +164,7 @@ export class CollectionMenu extends AntimodeMenu{ // // ; - // OLD BUTTONS + // //OLD BUTTONS // return this.getElement(!this.SelectedCollection ? [/*button*/] : // [ { - const target = this.document !== Doc.UserDoc().sidebar ? this.document : this.document.proto as Doc; + const target = this.document !== CurrentUserUtils.MyLeftSidebarPanel ? this.document : this.document.proto as Doc; //@ts-ignore target._viewType = e.target.selectedOptions[0].value; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4b5c5e3fb..63616263e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -205,7 +205,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent CurrentUserUtils.createNewDashboard(Doc.UserDoc()), icon: "project-diagram" }); + optionItems.push({ description: "Create Dashboard", event: () => CurrentUserUtils.createNewDashboard(), icon: "project-diagram" }); } !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 70db121d1..62d07b0e4 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -329,7 +329,7 @@ export class TabDocView extends React.Component { const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); const locationParams = locationFields.length > 1 ? locationFields[1] : ""; switch (locationFields[0]) { - case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + case "dashboard": return CurrentUserUtils.openDashboard(doc); case "close": return CollectionDockingView.CloseSplit(doc, locationParams); case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ffe146ae4..99eec7892 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -253,7 +253,7 @@ export class CollectionFreeFormView extends CollectionSubView Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (SnappingManager.GetShowSnapLines() ? "Hide" : "Show") + " Snap Lines", event: () => SnappingManager.SetShowSnapLines(!SnappingManager.GetShowSnapLines()), icon: "compress-arrows-alt" }) : null; !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b62020a04..081a1a924 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -6,7 +6,7 @@ import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; +import { Cast, DocCast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; import { ImageField } from "../../../../fields/URLField"; import { GetEffectiveAcl } from "../../../../fields/util"; import { intersectRect, returnFalse, Utils } from "../../../../Utils"; @@ -156,7 +156,7 @@ export class MarqueeView extends React.Component StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name); - (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); + (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (this._timeout) { clearTimeout(this._timeout); diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 3af6a3d51..1b37e729b 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -79,6 +79,9 @@ export class FontIconBox extends DocComponent() { } } + static GetShowLabels() { return BoolCast(Doc.UserDoc()._showLabel); } + static SetShowLabels(show:boolean) { Doc.UserDoc()._showLabel = show; } + // Determining UI Specs @observable private label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); @observable private icon = StrCast(this.dataDoc.icon, "user") as any; @@ -111,7 +114,7 @@ export class FontIconBox extends DocComponent() { // Script for checking the outcome of the toggle const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0; - const label = !Doc.UserDoc()._showLabel ? (null) : + const label = !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -212,7 +215,7 @@ export class FontIconBox extends DocComponent() { style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }} onClick={action(() => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen)}> - {!this.label || !Doc.UserDoc()._showLabel ? (null) :
{this.label}
} + {!this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
}
@@ -283,7 +286,7 @@ export class FontIconBox extends DocComponent() {
; }); - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -337,7 +340,7 @@ export class FontIconBox extends DocComponent() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const curColor = this.colorScript?.script.run({ value: undefined, _readOnly_: true }).result ?? "transparent"; - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -349,7 +352,7 @@ export class FontIconBox extends DocComponent() {
; setTimeout(() => this.colorPicker(curColor)); // cause an update to the color picker rendered in MainView return ( -
this.colorPickerClosed = !this.colorPickerClosed)} onPointerDown={e => e.stopPropagation()}> @@ -381,7 +384,7 @@ export class FontIconBox extends DocComponent() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); // Button label - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -400,7 +403,7 @@ export class FontIconBox extends DocComponent() { ); } else { return ( -
{label} @@ -423,7 +426,7 @@ export class FontIconBox extends DocComponent() { style={{ backgroundColor: "transparent", borderBottomLeftRadius: this.dropdown ? 0 : undefined }}>
- {!this.label || !Doc.UserDoc()._showLabel ? (null) : + {!this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
}
@@ -450,12 +453,12 @@ export class FontIconBox extends DocComponent() { render() { const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; - const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) : + const menuLabel = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -497,7 +500,7 @@ export class FontIconBox extends DocComponent() { break; case ButtonType.ToolButton: button = ( -
+
{label}
@@ -509,7 +512,7 @@ export class FontIconBox extends DocComponent() { break; case ButtonType.ClickButton: button = ( -
+
{label}
@@ -675,10 +678,9 @@ ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: b ScriptingGlobals.add(function toggleNoAutoLinkAnchor(checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; if (checkResult) { - return (editorView ? RichTextMenu.Instance.noAutoLink : Doc.UserDoc().noAutoLink) ? Colors.MEDIUM_BLUE : "transparent"; + return (editorView ? RichTextMenu.Instance.noAutoLink : false) ? Colors.MEDIUM_BLUE : "transparent"; } if (editorView) RichTextMenu.Instance?.toggleNoAutoLinkAnchor(); - else Doc.UserDoc().noAutoLink = Doc.UserDoc().noAutoLink ? true : false; }); ScriptingGlobals.add(function toggleBold(checkResult?: boolean) { diff --git a/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx b/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx index 235495250..7f414ddbb 100644 --- a/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx +++ b/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx @@ -5,6 +5,7 @@ import { IButtonProps } from '../ButtonInterface'; import { ColorState, SketchPicker } from 'react-color'; import { ScriptField } from '../../../../../fields/ScriptField'; import { Doc } from '../../../../../fields/Doc'; +import { FontIconBox } from '../FontIconBox'; export class ColorDropdown extends Component { render() { @@ -31,7 +32,7 @@ export class ColorDropdown extends Component { disableAlpha={!stroke} onChange={func} color={boolResult ? boolResult : "#FFFFFF"} presetColors={colorOptions} />; - const label = !this.props.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.props.label || !FontIconBox.GetShowLabels() ? (null) :
{this.props.label}
; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 90199618b..600730d87 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -355,7 +355,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp var tr = this._editorView.state.tr as any; const autoAnch = this._editorView.state.schema.marks.autoLinkAnchor; tr = tr.removeMark(0, tr.doc.content.size, autoAnch); - DocListCast(Doc.UserDoc().myPublishedDocs).forEach(term => tr = this.hyperlinkTerm(tr, term, newAutoLinks)); + DocListCast(CurrentUserUtils.MyPublishedDocs.data).forEach(term => tr = this.hyperlinkTerm(tr, term, newAutoLinks)); tr = tr.setSelection(new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t))); this._editorView?.dispatch(tr); oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.anchor2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink); @@ -376,7 +376,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (!(cfield instanceof ComputedField)) { this.dataDoc.title = prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : ""); if (str.startsWith("@") && str.length > 1) { - Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", this.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyPublishedDocs, undefined, this.rootDoc); } } } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0d2cffc2c..9f858539f 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -10,7 +10,7 @@ import { InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { PrefetchProxy } from "../../../../fields/Proxy"; import { listSpec } from "../../../../fields/Schema"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from "../../../../fields/Types"; import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from "../../../documents/Documents"; import { DocumentType } from "../../../documents/DocumentTypes"; @@ -131,17 +131,10 @@ export class PresBox extends ViewBoxBaseComponent() { if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true; else return false; } - @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); if (CurrentUserUtils.ActivePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); - if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. - Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ - title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" - })); - } this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox - } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -728,7 +721,7 @@ export class PresBox extends ViewBoxBaseComponent() { }); return true; } - childLayoutTemplate = () => !this.isTreeOrStack ? undefined : this.presElement; + childLayoutTemplate = () => !this.isTreeOrStack ? undefined : DocCast(Doc.UserDoc().presElement); removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 1de0c0b10..6a4deca38 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -52,7 +52,7 @@ export class TopBar extends React.Component { ContextMenu.Instance.addItem({ description: "Open Dashboard View", event: this.navigateToHome, icon: "edit" }); ContextMenu.Instance.addItem({ description: "Snapshot Dashboard", event: async () => { const batch = UndoManager.StartBatch("snapshot"); - await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); + await CurrentUserUtils.snapshotDashboard(); batch.end(); }, icon: "edit" }); dashView?.showContextMenu(e.clientX+20, e.clientY+30); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index fe8100997..bf06faeb9 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -391,7 +391,7 @@ export class MobileInterface extends React.Component { * Handles the 'Create New Dashboard' button in the menu (taken from MainView.tsx) */ @action - createNewDashboard = async (id?: string) => { + createNewDashboard = (id?: string) => { const scens = CurrentUserUtils.MyDashboards; const dashboardCount = DocListCast(scens.data).length + 1; const freeformOptions: DocumentOptions = { -- cgit v1.2.3-70-g09d2 From dd16695b0c5fe8c54bc276a230381ae36e19e5ac Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 7 Jul 2022 13:02:33 -0400 Subject: trying to fix errors in compiles --- package-lock.json | 2282 +++++++++++++++++-- package.json | 40 +- src/client/util/CaptureManager.tsx | 157 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/GroupManager.tsx | 253 ++- src/client/util/ScrollBox.tsx | 23 +- src/client/util/SharingManager.tsx | 566 +++-- src/client/views/Main.tsx | 44 +- src/client/views/MainView.tsx | 1086 ++++++---- src/client/views/Touchable.tsx | 68 +- src/client/views/animationtimeline/Timeline.tsx | 286 ++- .../views/collections/CollectionStackingView.tsx | 657 +++--- .../views/collections/CollectionTreeView.tsx | 321 +-- src/client/views/collections/CollectionView.tsx | 266 ++- .../CollectionFreeFormLinksView.tsx | 34 +- .../views/collections/collectionGrid/Grid.tsx | 17 +- .../collectionLinear/CollectionLinearView.tsx | 291 +-- src/client/views/linking/LinkEditor.tsx | 346 +-- src/client/views/linking/LinkMenuItem.tsx | 226 +- src/client/views/nodes/DocumentContentsView.tsx | 259 ++- src/client/views/nodes/LinkDocPreview.tsx | 192 +- src/client/views/nodes/MapBox/MapBox.tsx | 505 ++--- src/client/views/nodes/PDFBox.tsx | 451 ++-- src/client/views/nodes/formattedText/schema_rts.ts | 13 +- src/client/views/nodes/trails/PresBox.tsx | 2285 +++++++++++++------- src/client/views/search/SearchBox.tsx | 213 +- src/mobile/MobileInterface.tsx | 602 ++++-- src/server/authentication/AuthenticationManager.ts | 306 +-- 28 files changed, 7658 insertions(+), 4133 deletions(-) (limited to 'src/mobile') diff --git a/package-lock.json b/package-lock.json index e895161b5..7e413d5c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -462,6 +462,76 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, "@ffmpeg/core": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.10.0.tgz", @@ -547,9 +617,9 @@ } }, "@fortawesome/react-fontawesome": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz", - "integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", + "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", "requires": { "prop-types": "^15.8.1" } @@ -580,6 +650,19 @@ "emotion": "^10.0.0", "prop-types": "^15.7.1", "react-transition-group": "^2.3.1" + }, + "dependencies": { + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + } } }, "@hig/theme-context": { @@ -608,6 +691,40 @@ "lodash.memoize": "^4.1.2" } }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@hypnosphi/create-react-context": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", @@ -1184,9 +1301,9 @@ } }, "@types/express-session": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.4.tgz", - "integrity": "sha512-7cNlSI8+oOBUHTfPXMwDxF/Lchx5aJ3ho7+p9jJZYVg9dVDJFh3qdMXmJtRsysnvS+C6x46k9DRYmrmCkE+MVg==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.5.tgz", + "integrity": "sha512-l0DhkvNVfyUPEEis8fcwbd46VptfA/jmMwHfob2TfDMf3HyPLiB9mKD71LXhz5TMUobODXPD27zXSwtFQLHm+w==", "dev": true, "requires": { "@types/express": "*" @@ -1332,6 +1449,12 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "@types/keygrip": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", @@ -1461,9 +1584,9 @@ "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" }, "@types/passport": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.8.tgz", - "integrity": "sha512-Gdcvis7+7G/Mobm+25AeFi+oe5teBhHzpbCOFWeN10Bj8tnoEE1L5lkraQjzmDEKkJQuM7xSJUGIFGl/giyRfQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.9.tgz", + "integrity": "sha512-9+ilzUhmZQR4JP49GdC2O4UdDE3POPLwpmaTC/iLkW7l0TZCXOo1zsTnnlXPq6rP1UsUZPfbAV4IUdiwiXyC7g==", "dev": true, "requires": { "@types/express": "*" @@ -1663,10 +1786,9 @@ } }, "@types/react": { - "version": "16.14.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.26.tgz", - "integrity": "sha512-c/5CYyciOO4XdFcNhZW1O2woVx86k4T+DO2RorHZL7EhitkNQgSD/SgpdZJAUJa/qjVgOmTM44gHkAdZSXeQuQ==", - "dev": true, + "version": "18.0.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", + "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1676,8 +1798,7 @@ "csstype": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", - "dev": true + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" } } }, @@ -1720,18 +1841,18 @@ } }, "@types/react-dom": { - "version": "16.9.16", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.16.tgz", - "integrity": "sha512-Oqc0RY4fggGA3ltEgyPLc3IV9T73IGoWjkONbsyJ3ZBn+UPPCYpU2ec0i3cEbJuEdZtkqcCF2l1zf2pBdgUGSg==", + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", + "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", "dev": true, "requires": { - "@types/react": "^16" + "@types/react": "*" } }, "@types/react-grid-layout": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-0.17.2.tgz", - "integrity": "sha512-iLKQ5rI9KyPGs/BlWmeBfoikRnoOmTuddK8V5mOCgJ46e2JaecZuPhuIX1kV0mkQSk6X3XoEZALVW0XQbz9g5Q==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz", + "integrity": "sha512-ZzpBEOC1JTQ7MGe1h1cPKSLP4jSWuxc+yvT4TsAlEW9+EFPzAf8nxQfFd7ea9gL17Em7PbwJZAsiwfQQBUklZQ==", "dev": true, "requires": { "@types/react": "*" @@ -1741,6 +1862,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/react-icons/-/react-icons-3.0.0.tgz", "integrity": "sha512-Vefs6LkLqF61vfV7AiAqls+vpR94q67gunhMueDznG+msAkrYgRxl7gYjNem/kZ+as2l2mNChmF1jRZzzQQtMg==", + "dev": true, "requires": { "react-icons": "*" } @@ -1758,6 +1880,7 @@ "version": "0.26.7", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "dev": true, "requires": { "@types/react": "*" }, @@ -1766,6 +1889,7 @@ "version": "18.0.12", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.12.tgz", "integrity": "sha512-duF1OTASSBQtcigUvhuiTB1Ya3OvSy+xORCiEf20H0P0lzx+/KeVsA99U5UjLXSbyo1DRJDlLKqTeM1ngosqtg==", + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1775,7 +1899,8 @@ "csstype": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", + "dev": true } } }, @@ -1844,28 +1969,11 @@ } }, "@types/react-transition-group": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", - "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", "requires": { "@types/react": "*" - }, - "dependencies": { - "@types/react": { - "version": "18.0.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.12.tgz", - "integrity": "sha512-duF1OTASSBQtcigUvhuiTB1Ya3OvSy+xORCiEf20H0P0lzx+/KeVsA99U5UjLXSbyo1DRJDlLKqTeM1ngosqtg==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "csstype": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" - } } }, "@types/reactcss": { @@ -2359,22 +2467,22 @@ } }, "@webpack-cli/configtest": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", - "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==" }, "@webpack-cli/info": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", - "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", - "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==" }, "@webscopeio/react-textarea-autocomplete": { "version": "4.9.1", @@ -2487,7 +2595,7 @@ "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" }, "agent-base": { "version": "6.0.2", @@ -2617,6 +2725,23 @@ } } }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, "ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -2735,6 +2860,16 @@ "sprintf-js": "~1.0.2" } }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -2852,6 +2987,19 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -2872,6 +3020,30 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, "array.prototype.reduce": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", @@ -2922,6 +3094,18 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", @@ -3006,6 +3190,12 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "axe-core": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz", + "integrity": "sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA==", + "dev": true + }, "axios": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", @@ -3014,6 +3204,12 @@ "follow-redirects": "1.5.10" } }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, "babel": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel/-/babel-6.23.0.tgz", @@ -3078,6 +3274,28 @@ } } }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, "babel-plugin-emotion": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", @@ -3169,7 +3387,7 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" }, "balanced-match": { "version": "1.0.2", @@ -3234,7 +3452,7 @@ "base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" }, "base64-js": { "version": "1.5.1", @@ -3752,9 +3970,9 @@ "integrity": "sha512-u+Ll+RDaiQEproTQjZLjZwyfNgNezA1fERMT7/54npcz+PkbVJUAHXMUz4bkXQYRPWrcFNO0Fbi1mwjfXg6N5g==" }, "canvas": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz", - "integrity": "sha512-vSQti1uG/2gjv3x6QLOZw7TctfufaerTWbVe+NSduHxxLGB+qf3kFgQ6n66DSnuoINtVUjrLLIK2R+lxrBG07A==", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.3.tgz", + "integrity": "sha512-WOUM7ghii5TV2rbhaZkh1youv/vW1/Canev6Yx6BG2W+1S07w8jKZqKkPnbiPpQEDsnJdN8ouDd7OvQEGXDcUw==", "requires": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.15.0", @@ -3822,6 +4040,12 @@ "is-regex": "^1.0.3" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -3932,6 +4156,21 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, "clipboard": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", @@ -4140,7 +4379,7 @@ "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" }, "component-emitter": { "version": "1.3.0", @@ -4150,7 +4389,7 @@ "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" }, "compress-brotli": { "version": "1.3.8", @@ -4295,6 +4534,12 @@ } } }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, "connect-flash": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz", @@ -4860,16 +5105,6 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "d3-array": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", @@ -4995,6 +5230,12 @@ "d3-transition": "2" } }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -5584,6 +5825,15 @@ "buffer-indexof": "^1.0.0" } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", @@ -5809,9 +6059,9 @@ } }, "engine.io": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", - "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.6.0.tgz", + "integrity": "sha512-Kc8fo5bbg8F4a2f3HPHTEpGyq/IRIQpyeHu3H1ThR14XDD7VrLcsGBo16HUpahgp8YkHJDaU5gNxJZbuGcuueg==", "requires": { "accepts": "~1.3.4", "base64id": "2.0.0", @@ -5865,7 +6115,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "ws": { "version": "7.4.6", @@ -5985,6 +6235,15 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -5995,28 +6254,6 @@ "is-symbol": "^1.0.2" } }, - "es5-ext": { - "version": "0.10.61", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", - "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", - "dev": true, - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, "es6-promise": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", @@ -6028,7 +6265,6 @@ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "d": "^1.0.1", "ext": "^1.1.2" } }, @@ -6069,36 +6305,1192 @@ } } }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "eslint": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", "dev": true, "requires": { - "estraverse": "^5.2.0" + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true - } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "dependencies": { + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "dependencies": { + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-config-esnext": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz", + "integrity": "sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA==", + "dev": true, + "requires": { + "babel-eslint": "^10.0.1", + "eslint": "^6.8.0", + "eslint-plugin-babel": "^5.2.1", + "eslint-plugin-import": "^2.14.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "eslint-config-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-node/-/eslint-config-node-4.1.0.tgz", + "integrity": "sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + } + } + }, + "eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz", + "integrity": "sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.18.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.1", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz", + "integrity": "sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "estraverse": { @@ -6451,6 +7843,28 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -6554,6 +7968,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -6614,6 +8034,24 @@ "when": ">= 0.0.1" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-loader": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", @@ -6818,6 +8256,22 @@ "is-buffer": "~2.0.3" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, "flexlayout-react": { "version": "0.3.11", "resolved": "https://registry.npmjs.org/flexlayout-react/-/flexlayout-react-0.3.11.tgz", @@ -7144,6 +8598,12 @@ "functions-have-names": "^1.2.2" } }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -7645,14 +9105,14 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" }, "has-flag": { "version": "3.0.0", @@ -7963,11 +9423,6 @@ } } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" - }, "hyntax": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/hyntax/-/hyntax-1.1.9.tgz", @@ -8153,7 +9608,7 @@ "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" }, "inflight": { "version": "1.0.6", @@ -8198,6 +9653,116 @@ "css-in-js-utils": "^2.0.0" } }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "inspect-function": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/inspect-function/-/inspect-function-0.2.2.tgz", @@ -9055,6 +10620,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -9195,6 +10766,30 @@ "promise": "^7.0.1" } }, + "jsx-ast-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz", + "integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" + }, + "dependencies": { + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, "jszip": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz", @@ -9292,6 +10887,21 @@ "graceful-fs": "^4.1.9" } }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, "latest-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", @@ -9460,7 +11070,7 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, "lodash.isplainobject": { "version": "4.0.6", @@ -9711,7 +11321,7 @@ "mathquill": { "version": "0.10.1-a", "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz", - "integrity": "sha1-vyylaQEAY6w0vNXVKa3Ag3zVPD8=", + "integrity": "sha512-snSAEwAtwdwBFSor+nVBnWWQtTw67kgAgKMyAIxuz4ZPboy0qkWZmd7BL3lfOXp/INihhRlU1PcfaAtDaRhmzA==", "requires": { "jquery": "^1.12.3" }, @@ -9719,7 +11329,7 @@ "jquery": { "version": "1.12.4", "resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz", - "integrity": "sha1-AeHfuikP5z3rp3zurLD5ui/sngw=" + "integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg==" } } }, @@ -9817,7 +11427,8 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "methods": { "version": "1.1.2", @@ -9871,7 +11482,8 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true }, "mimic-response": { "version": "2.1.0", @@ -10301,6 +11913,12 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "nan": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", @@ -10339,6 +11957,12 @@ "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz", "integrity": "sha1-OcR7/Xgl0fuf+tMiEK4l2q3xAck=" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -14468,6 +16092,28 @@ "object-keys": "^1.0.11" } }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, "object.getownpropertydescriptors": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", @@ -14479,6 +16125,16 @@ "es-abstract": "^1.20.1" } }, + "object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -14487,6 +16143,17 @@ "isobject": "^3.0.1" } }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -14518,6 +16185,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -14563,9 +16231,9 @@ } }, "orderedmap": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.8.tgz", - "integrity": "sha512-eWEYOAggZZpZbJ9CTsqAKOTxlbBHdHZ8pzcfEvNTxGrjQ/m+Q25nSWUiMlT9MTbgpB6FOiBDKqsgJ2FlLDVNaw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.0.0.tgz", + "integrity": "sha512-buf4PoAMlh45b8a8gsGy/X6w279TSqkyAS0C0wdTSJwFSU+ljQFJON5I8NfjLHoCXwpSROIo2wr0g33T+kQshQ==" }, "os-homedir": { "version": "1.0.2", @@ -15270,6 +16938,21 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", @@ -15402,11 +17085,11 @@ } }, "prosemirror-model": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.18.0.tgz", - "integrity": "sha512-EZLl0mvVIixEL1V538GsPP4Iw+D83gBRdLcjL7VouzoPPWlhhv/0Y0V9ttT5lUhF7jieIrNHOa3XNFs1FwgrOw==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.18.1.tgz", + "integrity": "sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==", "requires": { - "orderedmap": "^1.1.0" + "orderedmap": "^2.0.0" } }, "prosemirror-schema-list": { @@ -15420,9 +17103,9 @@ } }, "prosemirror-state": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.0.tgz", - "integrity": "sha512-mVDZdjNX/YT5FvypiwbphJe9psA5h+j9apsSszVRFc6oKFoIInvzdujh8QW9f9lwHtSYajLxNiM1hPhd0Sl1XA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.1.tgz", + "integrity": "sha512-U/LBDW2gNmVa07sz/D229XigSdDQ5CLFwVB1Vb32MJbAHHhWe/6pOc721faI17tqw4pZ49i1xfY/jEZ9tbIhPg==", "requires": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0" @@ -15437,9 +17120,9 @@ } }, "prosemirror-view": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.0.tgz", - "integrity": "sha512-tT8ICUAw6YfOTRIwVQJoCdF65BYxoWFjAqmv44Kn4phYjdLJ8Vc92dhL3LnmwAQuZ9yfPHzRR6Lfb3/5EVJHWg==", + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.5.tgz", + "integrity": "sha512-SO+AX6WwdbJZHVvuloXI0qfO+YJAnZAat8qrYwfiqTQwL/FewLUnr0m3EXZ6a60hQs8/Q/lzeJXiFR/dOPaaKQ==", "requires": { "prosemirror-model": "^1.16.0", "prosemirror-state": "^1.0.0", @@ -15981,15 +17664,26 @@ } }, "react-grid-layout": { - "version": "0.18.3", - "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-0.18.3.tgz", - "integrity": "sha512-lHkrk941Tk5nTwZPa9uj6ttHBT0VehSHwEhWbINBJKvM1GRaFNOefvjcuxSyuCI5JWjVUP+Qm3ARt2470AlxMA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.3.4.tgz", + "integrity": "sha512-sB3rNhorW77HUdOjB4JkelZTdJGQKuXLl3gNg+BI8gJkTScspL1myfZzW/EM0dLEn+1eH+xW+wNqk0oIM9o7cw==", "requires": { - "classnames": "2.x", + "clsx": "^1.1.1", "lodash.isequal": "^4.0.0", - "prop-types": "^15.0.0", + "prop-types": "^15.8.1", "react-draggable": "^4.0.0", - "react-resizable": "^1.9.0" + "react-resizable": "^3.0.4" + }, + "dependencies": { + "react-resizable": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.4.tgz", + "integrity": "sha512-StnwmiESiamNzdRHbSSvA65b0ZQJ7eVQpPusrSmcpyGKzC0gojhtO62xxH6YOBmepk9dQTBi9yxidL3W4s3EBA==", + "requires": { + "prop-types": "15.x", + "react-draggable": "^4.0.3" + } + } } }, "react-icons": { @@ -16189,9 +17883,9 @@ } }, "react-refresh-typescript": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/react-refresh-typescript/-/react-refresh-typescript-2.0.5.tgz", - "integrity": "sha512-TlcxF9VMBBS8dHvMD+3dklgArXeIhjbtT7R09ycsXvhPPYmv70J67kiGT8mxe6/tYzkql9aCHaZAY6QYdutLdw==" + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/react-refresh-typescript/-/react-refresh-typescript-2.0.7.tgz", + "integrity": "sha512-KbuW57FauO11e6a9gU836sCm3M3z0b2+J2qPhUudg0QplOfz0eAF3gMeshcUC/ChfNLJCK1SZxvYmUtRxiZE5A==" }, "react-resizable": { "version": "1.11.1", @@ -16298,14 +17992,30 @@ "integrity": "sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A==" }, "react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", "requires": { - "dom-helpers": "^3.4.0", + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" + "prop-types": "^15.6.2" + }, + "dependencies": { + "csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + } } }, "react-use-measure": { @@ -16492,6 +18202,12 @@ "functions-have-names": "^1.2.2" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "registry-auth-token": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", @@ -16811,6 +18527,16 @@ } } }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -16856,6 +18582,12 @@ "sdp": "^2.6.0" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, "run-queue": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", @@ -16873,6 +18605,23 @@ } } }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -17446,6 +19195,17 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -17567,15 +19327,15 @@ } }, "socket.io": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", - "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.5.0.tgz", + "integrity": "sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w==", "requires": { "debug": "~4.1.0", - "engine.io": "~3.5.0", + "engine.io": "~3.6.0", "has-binary2": "~1.0.2", "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.4.0", + "socket.io-client": "2.5.0", "socket.io-parser": "~3.4.0" }, "dependencies": { @@ -17595,9 +19355,9 @@ "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" }, "socket.io-client": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", - "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz", + "integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==", "requires": { "backo2": "1.0.2", "component-bind": "1.0.0", @@ -17623,12 +19383,12 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "socket.io-parser": { "version": "3.3.2", @@ -18052,6 +19812,22 @@ "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" }, + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + } + }, "string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -18128,11 +19904,6 @@ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", @@ -18240,6 +20011,46 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "table-layout": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", @@ -18373,6 +20184,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "textarea-caret": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.1.0.tgz", @@ -18451,10 +20268,19 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" }, "to-fast-properties": { "version": "2.0.0", @@ -18835,6 +20661,26 @@ } } }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", @@ -18946,12 +20792,6 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -18966,6 +20806,12 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -18986,9 +20832,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", - "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true }, "typescript-collections": { @@ -19415,6 +21261,12 @@ "resolved": "https://registry.npmjs.org/uuid-js/-/uuid-js-0.7.5.tgz", "integrity": "sha1-bIhtAqU9LUDc8l2RoXC0p7JblNA=" }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", @@ -19637,17 +21489,17 @@ } }, "webpack-cli": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", - "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.1", - "@webpack-cli/info": "^1.4.1", - "@webpack-cli/serve": "^1.6.1", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", "colorette": "^2.0.14", "commander": "^7.0.0", - "execa": "^5.0.0", + "cross-spawn": "^7.0.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", @@ -19670,40 +21522,11 @@ "which": "^2.0.1" } }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -20281,6 +22104,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", @@ -20445,7 +22277,7 @@ "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" }, "yn": { "version": "2.0.0", diff --git a/package.json b/package.json index e4ec2798d..93968dce4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@types/exif": "^0.6.3", "@types/express": "^4.17.13", "@types/express-flash": "0.0.0", - "@types/express-session": "^1.17.4", + "@types/express-session": "^1.17.5", "@types/express-validator": "^3.0.0", "@types/file-saver": "^2.0.5", "@types/google-maps-react": "^2.0.5", @@ -49,7 +49,7 @@ "@types/mongoose": "^5.11.97", "@types/node": "^10.17.60", "@types/nodemailer": "^4.6.6", - "@types/passport": "^1.0.7", + "@types/passport": "^1.0.9", "@types/passport-google-oauth20": "^2.0.11", "@types/passport-local": "^1.0.34", "@types/pdfjs-dist": "^2.10.378", @@ -65,12 +65,15 @@ "@types/prosemirror-transform": "^1.1.5", "@types/prosemirror-view": "^1.23.1", "@types/rc-switch": "^1.9.2", - "@types/react": "^16.14.23", + "@types/react": "^18.0.15", + "@types/react-icons": "^3.0.0", + "@types/react-reconciler": "^0.26.4", + "@types/react-transition-group": "^4.4.5", "@types/react-autosuggest": "^9.3.14", "@types/react-color": "^2.17.6", "@types/react-datepicker": "^3.1.8", - "@types/react-dom": "^16.9.14", - "@types/react-grid-layout": "^0.17.2", + "@types/react-dom": "^18.0.6", + "@types/react-grid-layout": "^1.3.2", "@types/react-measure": "^2.0.8", "@types/react-select": "^3.1.2", "@types/react-table": "^6.8.9", @@ -117,7 +120,7 @@ "ts-node-dev": "^1.1.8", "tslint": "^5.20.1", "tslint-loader": "^3.6.0", - "typescript": "^4.6.2", + "typescript": "^4.7.4", "webpack": "^5.69.1", "webpack-dev-server": "^3.11.3", "webpack-hot-middleware": "^2.25.1" @@ -129,7 +132,7 @@ "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4", - "@fortawesome/react-fontawesome": "^0.1.17", + "@fortawesome/react-fontawesome": "^0.1.19", "@hig/flyout": "^1.3.1", "@hig/theme-context": "^2.1.3", "@hig/theme-data": "^2.23.1", @@ -145,14 +148,13 @@ "@types/dom-speech-recognition": "0.0.1", "@types/formidable": "1.0.31", "@types/google-maps": "^3.2.3", - "@types/react-icons": "^3.0.0", - "@types/react-reconciler": "^0.26.4", "@types/reveal": "^3.3.33", "@types/supercluster": "^7.1.0", "@types/three": "^0.126.2", "@types/web": "0.0.53", "@types/webscopeio__react-textarea-autocomplete": "^4.7.2", "@webscopeio/react-textarea-autocomplete": "^4.9.1", + "D": "^1.0.0", "adm-zip": "^0.4.16", "archiver": "^3.1.1", "array-batcher": "^1.2.3", @@ -167,7 +169,7 @@ "bootstrap": "^4.6.1", "browser-assert": "^1.2.1", "bson": "^4.6.1", - "canvas": "^2.9.0", + "canvas": "^2.9.3", "child_process": "^1.0.2", "chrome": "^0.1.0", "class-transformer": "^0.2.0", @@ -178,7 +180,6 @@ "cookie-parser": "^1.4.6", "cookie-session": "^2.0.0", "cors": "^2.8.5", - "D": "^1.0.0", "depcheck": "^0.9.2", "equation-editor-react": "github:bobzel/equation-editor-react#useLocally", "exif": "^0.6.0", @@ -250,11 +251,11 @@ "prosemirror-history": "^1.2.0", "prosemirror-inputrules": "^1.1.3", "prosemirror-keymap": "^1.1.5", - "prosemirror-model": "^1.16.1", + "prosemirror-model": "^1.18.1", "prosemirror-schema-list": "^1.1.6", - "prosemirror-state": "^1.3.4", + "prosemirror-state": "^1.4.1", "prosemirror-transform": "^1.3.4", - "prosemirror-view": "^1.23.7", + "prosemirror-view": "^1.26.5", "pug": "^2.0.4", "puppeteer": "^3.3.0", "query-string": "^6.14.1", @@ -268,18 +269,19 @@ "react-compound-slider": "^2.5.0", "react-datepicker": "^3.8.0", "react-dom": "^16.14.0", - "react-grid-layout": "^0.18.3", + "react-grid-layout": "^1.3.4", "react-icons": "^4.3.1", "react-image-lightbox-with-rotate": "^5.1.1", "react-jsx-parser": "^1.29.0", "react-loading": "^2.0.3", "react-measure": "^2.5.2", - "react-refresh-typescript": "^2.0.3", + "react-refresh-typescript": "^2.0.7", "react-resizable": "^1.11.1", "react-resizable-rotatable-draggable": "^0.2.0", "react-reveal": "^1.2.2", "react-select": "^3.2.0", "react-table": "^6.11.5", + "react-transition-group": "^4.4.2", "readline": "^1.3.0", "request": "^2.88.2", "request-promise": "^4.2.6", @@ -288,8 +290,8 @@ "serializr": "^1.5.4", "sharp": "^0.23.4", "shelljs": "^0.8.5", - "socket.io": "^2.4.1", - "socket.io-client": "^2.4.0", + "socket.io": "^2.5.0", + "socket.io-client": "^2.5.0", "solr-node": "^1.2.1", "standard-http-error": "^2.0.1", "stream-browserify": "^3.0.0", @@ -306,7 +308,7 @@ "uuid": "^3.4.0", "valid-url": "^1.0.9", "web-request": "^1.0.7", - "webpack-cli": "^4.9.2", + "webpack-cli": "^4.10.0", "webpack-dev-middleware": "^5.3.1", "webrtc-adapter": "^7.7.1", "wikijs": "^6.3.3", diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index c247afa26..0b5957fac 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -1,17 +1,17 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { convertToObject } from "typescript"; -import { Doc, DocListCast } from "../../fields/Doc"; -import { BoolCast, StrCast, Cast } from "../../fields/Types"; -import { addStyleSheet, addStyleSheetRule, Utils } from "../../Utils"; -import { LightboxView } from "../views/LightboxView"; -import { MainViewModal } from "../views/MainViewModal"; -import "./CaptureManager.scss"; -import { SelectionManager } from "./SelectionManager"; -import { undoBatch } from "./UndoManager"; -const higflyout = require("@hig/flyout"); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { convertToObject } from 'typescript'; +import { Doc, DocListCast } from '../../fields/Doc'; +import { BoolCast, StrCast, Cast } from '../../fields/Types'; +import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils'; +import { LightboxView } from '../views/LightboxView'; +import { MainViewModal } from '../views/MainViewModal'; +import './CaptureManager.scss'; +import { SelectionManager } from './SelectionManager'; +import { undoBatch } from './UndoManager'; +const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -22,32 +22,31 @@ export class CaptureManager extends React.Component<{}> { @observable _document: any; @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not. - constructor(props: {}) { super(props); CaptureManager.Instance = this; } - public close = action(() => this.isOpen = false); + public close = action(() => (this.isOpen = false)); public open = action((doc: Doc) => { this.isOpen = true; this._document = doc; }); - @computed get visibilityContent() { - - return
-
Visibility
-
-
- Private -
-
- Public + return ( +
+
Visibility
+
+
+ Private +
+
+ Public +
-
; + ); } @computed get linksContent() { @@ -66,75 +65,79 @@ export class CaptureManager extends React.Component<{}> { order.push(
{i}
- {(l.anchor1 as Doc).title} + {StrCast((l.anchor1 as Doc).title)}
); } }); } - return
-
Links
-
- {order} + return ( +
+
Links
+
{order}
-
; + ); } @computed get closeButtons() { - return
-
-
{ - LightboxView.SetLightboxDoc(this._document); - this.close(); - }}> - Save -
-
{ - const selected = SelectionManager.Views().slice(); - SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); - this.close(); - }}> - Cancel + return ( +
+
+
{ + LightboxView.SetLightboxDoc(this._document); + this.close(); + }}> + Save +
+
{ + const selected = SelectionManager.Views().slice(); + SelectionManager.DeselectAll(); + selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); + this.close(); + }}> + Cancel +
-
; + ); } - - private get captureInterface() { - return
-
-
-
+ return ( +
+
+
+
+ Conversation Capture
- Conversation Capture -
-
- -
- {this.visibilityContent} - {this.linksContent} -
- +
+ {this.visibilityContent} + {this.linksContent} +
+ +
+ {this.closeButtons}
- {this.closeButtons} -
; - + ); } render() { - return ; + return ( + + ); } -} \ No newline at end of file +} diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b2a5fddcd..84efcb966 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -957,7 +957,7 @@ export class CurrentUserUtils { } new LinkManager(); - DocServer.UPDATE_SERVER_CACHE(); + setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500); return doc; } static setupFieldInfos(doc:Doc, field="fieldInfos") { diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 62d656c5d..59334f6a2 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -1,19 +1,19 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import Select from 'react-select'; -import * as RequestPromise from "request-promise"; -import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; -import { StrCast, Cast } from "../../fields/Types"; -import { Utils } from "../../Utils"; -import { MainViewModal } from "../views/MainViewModal"; -import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; -import "./GroupManager.scss"; -import { GroupMemberView } from "./GroupMemberView"; -import { SharingManager, User } from "./SharingManager"; -import { listSpec } from "../../fields/Schema"; -import { DateField } from "../../fields/DateField"; +import * as RequestPromise from 'request-promise'; +import { Doc, DocListCast, DocListCastAsync, Opt } from '../../fields/Doc'; +import { StrCast, Cast } from '../../fields/Types'; +import { Utils } from '../../Utils'; +import { MainViewModal } from '../views/MainViewModal'; +import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; +import './GroupManager.scss'; +import { GroupMemberView } from './GroupMemberView'; +import { SharingManager, User } from './SharingManager'; +import { listSpec } from '../../fields/Schema'; +import { DateField } from '../../fields/DateField'; /** * Interface for options for the react-select component @@ -25,7 +25,6 @@ export interface UserOptions { @observer export class GroupManager extends React.Component<{}> { - static Instance: GroupManager; @observable isOpen: boolean = false; // whether the GroupManager is to be displayed or not. @observable private users: string[] = []; // list of users populated from the database. @@ -34,24 +33,26 @@ export class GroupManager extends React.Component<{}> { @observable private createGroupModalOpen: boolean = false; private inputRef: React.RefObject = React.createRef(); // the ref for the input box. private createGroupButtonRef: React.RefObject = React.createRef(); // the ref for the group creation button - @observable private buttonColour: "#979797" | "black" = "#979797"; - @observable private groupSort: "ascending" | "descending" | "none" = "none"; + @observable private buttonColour: '#979797' | 'black' = '#979797'; + @observable private groupSort: 'ascending' | 'descending' | 'none' = 'none'; constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; } - componentDidMount() { this.populateUsers(); } + componentDidMount() { + this.populateUsers(); + } /** * Fetches the list of users stored on the database. */ populateUsers = async () => { - const userList = await RequestPromise.get(Utils.prepend("/getUsers")); + const userList = await RequestPromise.get(Utils.prepend('/getUsers')); const raw = JSON.parse(userList) as User[]; raw.map(action(user => !this.users.some(umail => umail === user.email) && this.users.push(user.email))); - } + }; /** * @returns the options to be rendered in the dropdown menu to add users and create a group. @@ -68,11 +69,11 @@ export class GroupManager extends React.Component<{}> { // SelectionManager.DeselectAll(); this.isOpen = true; this.populateUsers(); - } + }; /** * Hides the GroupManager. - */ + */ @action close = () => { this.isOpen = false; @@ -81,26 +82,32 @@ export class GroupManager extends React.Component<{}> { // this.users = []; this.createGroupModalOpen = false; TaskCompletionBox.taskCompleted = false; - } + }; /** * @returns the database of groups. */ - @computed get GroupManagerDoc(): Doc | undefined { return Doc.UserDoc().globalGroupDatabase as Doc; } + @computed get GroupManagerDoc(): Doc | undefined { + return Doc.UserDoc().globalGroupDatabase as Doc; + } /** * @returns a list of all group documents. */ - @computed get allGroups(): Doc[] { return DocListCast(this.GroupManagerDoc?.data); } + @computed get allGroups(): Doc[] { + return DocListCast(this.GroupManagerDoc?.data); + } /** * @returns the members of the admin group. */ - @computed get adminGroupMembers(): string[] { return this.getGroup("Admin") ? JSON.parse(StrCast(this.getGroup("Admin")!.members)) : ""; } + @computed get adminGroupMembers(): string[] { + return this.getGroup('Admin') ? JSON.parse(StrCast(this.getGroup('Admin')!.members)) : ''; + } /** * @returns a group document based on the group name. - * @param groupName + * @param groupName */ getGroup(groupName: string): Doc | undefined { return this.allGroups.find(group => group.title === groupName); @@ -114,10 +121,9 @@ export class GroupManager extends React.Component<{}> { return JSON.parse(StrCast(this.getGroup(group)!.members)) as string[]; } - /** * @returns a boolean indicating whether the current user has access to edit group documents. - * @param groupDoc + * @param groupDoc */ hasEditAccess(groupDoc: Doc): boolean { if (!groupDoc) return false; @@ -127,12 +133,12 @@ export class GroupManager extends React.Component<{}> { /** * Helper method that sets up the group document. - * @param groupName - * @param memberEmails + * @param groupName + * @param memberEmails */ createGroupDoc(groupName: string, memberEmails: string[] = []) { - const name = groupName.toLowerCase() === "admin" ? "Admin" : groupName; - const groupDoc = new Doc("GROUP:" + name, true); + const name = groupName.toLowerCase() === 'admin' ? 'Admin' : groupName; + const groupDoc = new Doc('GROUP:' + name, true); groupDoc.title = name; groupDoc.owners = JSON.stringify([Doc.CurrentUserEmail]); groupDoc.members = JSON.stringify(memberEmails); @@ -141,12 +147,12 @@ export class GroupManager extends React.Component<{}> { /** * Helper method that adds a group document to the database of group documents and @returns whether it was successfully added or not. - * @param groupDoc + * @param groupDoc */ addGroup(groupDoc: Doc): boolean { if (this.GroupManagerDoc) { - Doc.AddDocToList(this.GroupManagerDoc, "data", groupDoc); - this.GroupManagerDoc["data-lastModified"] = new DateField; + Doc.AddDocToList(this.GroupManagerDoc, 'data', groupDoc); + this.GroupManagerDoc['data-lastModified'] = new DateField(); return true; } return false; @@ -154,20 +160,20 @@ export class GroupManager extends React.Component<{}> { /** * Deletes a group from the database of group documents and @returns whether the group was deleted or not. - * @param group + * @param group */ @action deleteGroup(group: Doc): boolean { if (group) { if (this.GroupManagerDoc && this.hasEditAccess(group)) { - Doc.RemoveDocFromList(this.GroupManagerDoc, "data", group); + Doc.RemoveDocFromList(this.GroupManagerDoc, 'data', group); SharingManager.Instance.removeGroup(group); const members = JSON.parse(StrCast(group.members)); if (members.includes(Doc.CurrentUserEmail)) { const index = DocListCast(this.GroupManagerDoc.data).findIndex(grp => grp === group); index !== -1 && Cast(this.GroupManagerDoc.data, listSpec(Doc), [])?.splice(index, 1); } - this.GroupManagerDoc["data-lastModified"] = new DateField; + this.GroupManagerDoc['data-lastModified'] = new DateField(); if (group === this.currentGroup) { this.currentGroup = undefined; } @@ -179,8 +185,8 @@ export class GroupManager extends React.Component<{}> { /** * Adds a member to a group. - * @param groupDoc - * @param email + * @param groupDoc + * @param email */ addMemberToGroup(groupDoc: Doc, email: string) { if (this.hasEditAccess(groupDoc)) { @@ -188,14 +194,14 @@ export class GroupManager extends React.Component<{}> { !memberList.includes(email) && memberList.push(email); groupDoc.members = JSON.stringify(memberList); SharingManager.Instance.shareWithAddedMember(groupDoc, email); - this.GroupManagerDoc && (this.GroupManagerDoc["data-lastModified"] = new DateField); + this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField()); } } /** * Removes a member from the group. - * @param groupDoc - * @param email + * @param groupDoc + * @param email */ removeMemberFromGroup(groupDoc: Doc, email: string) { if (this.hasEditAccess(groupDoc)) { @@ -205,27 +211,27 @@ export class GroupManager extends React.Component<{}> { const user = memberList.splice(index, 1)[0]; groupDoc.members = JSON.stringify(memberList); SharingManager.Instance.removeMember(groupDoc, email); - this.GroupManagerDoc && (this.GroupManagerDoc["data-lastModified"] = new DateField); + this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField()); } } } /** * Handles changes in the users selected in the "Select users" dropdown. - * @param selectedOptions + * @param selectedOptions */ @action handleChange = (selectedOptions: any) => { this.selectedUsers = selectedOptions as UserOptions[]; - } + }; /** * Creates the group when the enter key has been pressed (when in the input). - * @param e + * @param e */ handleKeyDown = (e: React.KeyboardEvent) => { - e.key === "Enter" && this.createGroup(); - } + e.key === 'Enter' && this.createGroup(); + }; /** * Handles the input of required fields in the setup of a group and resets the relevant variables. @@ -234,32 +240,37 @@ export class GroupManager extends React.Component<{}> { createGroup = () => { const { value } = this.inputRef.current!; if (!value) { - alert("Please enter a group name"); + alert('Please enter a group name'); return; } - if (["admin", "public", "override"].includes(value.toLowerCase())) { - if (value.toLowerCase() !== "admin" || (value.toLowerCase() === "admin" && this.getGroup("Admin"))) { + if (['admin', 'public', 'override'].includes(value.toLowerCase())) { + if (value.toLowerCase() !== 'admin' || (value.toLowerCase() === 'admin' && this.getGroup('Admin'))) { alert(`You cannot override the ${value.charAt(0).toUpperCase() + value.slice(1)} group`); return; } } if (this.getGroup(value)) { - alert("Please select a unique group name"); + alert('Please select a unique group name'); return; } - this.createGroupDoc(value, this.selectedUsers?.map(user => user.value)); + this.createGroupDoc( + value, + this.selectedUsers?.map(user => user.value) + ); this.selectedUsers = null; - this.inputRef.current!.value = ""; - this.buttonColour = "#979797"; + this.inputRef.current!.value = ''; + this.buttonColour = '#979797'; const { left, width, top } = this.createGroupButtonRef.current!.getBoundingClientRect(); TaskCompletionBox.popupX = left - 2 * width; TaskCompletionBox.popupY = top; - TaskCompletionBox.textDisplayed = "Group created!"; + TaskCompletionBox.textDisplayed = 'Group created!'; TaskCompletionBox.taskCompleted = true; - setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2000); - - } + setTimeout( + action(() => (TaskCompletionBox.taskCompleted = false)), + 2000 + ); + }; /** * @returns the MainViewModal which allows the user to create groups. @@ -268,50 +279,43 @@ export class GroupManager extends React.Component<{}> { const contents = (
-

New Group

-
{ - this.createGroupModalOpen = false; TaskCompletionBox.taskCompleted = false; - })}> - +

+ New Group +

+
{ + this.createGroupModalOpen = false; + TaskCompletionBox.taskCompleted = false; + })}> +
- this.buttonColour = this.inputRef.current?.value ? "black" : "#979797")} /> + (this.buttonColour = this.inputRef.current?.value ? 'black' : '#979797'))} /> this.setInternalSharing({ user, linkDatabase, sharingDoc, userColor }, e.currentTarget.value)} - > - {this.sharingOptions(uniform)} - - ) : ( -
- {permissions} -
- )} + const userListContents: (JSX.Element | null)[] = users + .filter(({ user }) => (docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email)) + .map(({ user, linkDatabase, sharingDoc, userColor }) => { + const userKey = `acl-${normalizeEmail(user.email)}`; + const uniform = docs.every(doc => (this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey])); + const permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-'; + + return !permissions ? null : ( +
+ {user.email} +
+ {admin || this.myDocAcls ? ( + + ) : ( +
{permissions}
+ )} +
-
- ); - }); + ); + }); // checks if every doc has the same author const sameAuthor = docs.every(doc => doc?.author === docs[0]?.author); // the owner of the doc and the current user are placed at the top of the user list. userListContents.unshift( - sameAuthor ? - ( -
- {targetDoc?.author === Doc.CurrentUserEmail ? "Me" : targetDoc?.author} -
-
- Owner -
-
+ sameAuthor ? ( +
+ {targetDoc?.author === Doc.CurrentUserEmail ? 'Me' : targetDoc?.author} +
+
Owner
- ) : null, - sameAuthor && targetDoc?.author !== Doc.CurrentUserEmail ? - ( -
- Me -
-
- {effectiveAcls.every(acl => acl === effectiveAcls[0]) ? this.AclMap.get(effectiveAcls[0])! : "-multiple-"} -
-
+
+ ) : null, + sameAuthor && targetDoc?.author !== Doc.CurrentUserEmail ? ( +
+ Me +
+
{effectiveAcls.every(acl => acl === effectiveAcls[0]) ? this.AclMap.get(effectiveAcls[0])! : '-multiple-'}
- ) : null +
+ ) : null ); - // the list of groups shared with - const groupListMap: (Doc | { title: string })[] = groups.filter(({ title }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(title))}`) : true); - groupListMap.unshift({ title: "Public" });//, { title: "ALL" }); + const groupListMap: (Doc | { title: string })[] = groups.filter(({ title }) => (docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(title))}`) : true)); + groupListMap.unshift({ title: 'Public' }); //, { title: "ALL" }); const groupListContents = groupListMap.map(group => { const groupKey = `acl-${StrCast(group.title)}`; - const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]); - const permissions = uniform ? StrCast(targetDoc?.[`acl-${StrCast(group.title)}`]) : "-multiple-"; - - return !permissions ? (null) : ( -
-
{group.title}
- {group instanceof Doc ? - (
GroupManager.Instance.currentGroup = group)}> - -
) - : (null)} + const uniform = docs.every(doc => (this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey])); + const permissions = uniform ? StrCast(targetDoc?.[`acl-${StrCast(group.title)}`]) : '-multiple-'; + + return !permissions ? null : ( +
+
{StrCast(group.title)}
+ {group instanceof Doc ? ( +
(GroupManager.Instance.currentGroup = group))}> + +
+ ) : null}
{admin || this.myDocAcls ? ( - this.setInternalGroupSharing(group, e.currentTarget.value)}> + {this.sharingOptions(uniform, group.title === 'Override')} ) : ( -
- {permissions} -
+
{permissions}
)}
@@ -632,102 +609,95 @@ export class SharingManager extends React.Component<{}> { }); return ( -
- {GroupManager.Instance?.currentGroup ? - GroupManager.Instance.currentGroup = undefined)} - /> : - null} +
+ {GroupManager.Instance?.currentGroup ? (GroupManager.Instance.currentGroup = undefined))} /> : null}
-

Share {this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, "this document") : "-multiple-")}

-
- +

+ Share + {this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')} +

+
+
{/* {this.linkVisible ?
{this.sharingUrl}
: (null)} */} - {
-
- - {this.sharingOptions(true)} - - -
-
- this.showUserOptions = !this.showUserOptions)} /> - this.showGroupOptions = !this.showGroupOptions)} /> -
+ { +
+
+ + {this.sharingOptions(true)} + + +
+
+ (this.showUserOptions = !this.showUserOptions))} /> + (this.showGroupOptions = !this.showGroupOptions))} /> +
-
- {Doc.noviceMode ? (null) : -
- this.layoutDocAcls = !this.layoutDocAcls)} checked={this.layoutDocAcls} /> -
} +
+ {Doc.noviceMode ? null : ( +
+ (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> +
+ )} +
-
}
-
-
this.individualSort = this.individualSort === "ascending" ? "descending" : this.individualSort === "descending" ? "none" : "ascending")}> - Individuals {this.individualSort === "ascending" ? - : this.individualSort === "descending" ? - : } -
-
- {userListContents} +
+
(this.individualSort = this.individualSort === 'ascending' ? 'descending' : this.individualSort === 'descending' ? 'none' : 'ascending'))}> + Individuals{' '} + {this.individualSort === 'ascending' ? ( + + ) : this.individualSort === 'descending' ? ( + + ) : ( + + )}
+
{userListContents}
-
-
this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}> - Groups {this.groupSort === "ascending" ? - : this.groupSort === "descending" ? - : } - -
-
- {groupListContents} +
+
(this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}> + Groups{' '} + {this.groupSort === 'ascending' ? ( + + ) : this.groupSort === 'descending' ? ( + + ) : ( + + )}
+
{groupListContents}
-
); } render() { - return ; + return ; } -} \ No newline at end of file +} diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 31fa5b157..542f85228 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -4,42 +4,46 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { AssignAllExtensions } from "../../extensions/General/Extensions"; -import { Docs } from "../documents/Documents"; -import { CurrentUserUtils } from "../util/CurrentUserUtils"; -import { LinkManager } from "../util/LinkManager"; +import { AssignAllExtensions } from '../../extensions/General/Extensions'; +import { Docs } from '../documents/Documents'; +import { CurrentUserUtils } from '../util/CurrentUserUtils'; +import { LinkManager } from '../util/LinkManager'; import { ReplayMovements } from '../util/ReplayMovements'; -import { TrackMovements } from "../util/TrackMovements"; -import { CollectionView } from "./collections/CollectionView"; -import { MainView } from "./MainView"; +import { TrackMovements } from '../util/TrackMovements'; +import { CollectionView } from './collections/CollectionView'; +import { MainView } from './MainView'; AssignAllExtensions(); (async () => { - MainView.Live = window.location.search.includes("live"); - window.location.search.includes("safe") && CollectionView.SetSafeMode(true); + MainView.Live = window.location.search.includes('live'); + window.location.search.includes('safe') && CollectionView.SetSafeMode(true); const info = await CurrentUserUtils.loadCurrentUser(); - if (info.id !== "__guest__") { + if (info.id !== '__guest__') { // a guest will not have an id registered await CurrentUserUtils.loadUserDocument(info.id); } else { await Docs.Prototypes.initialize(); new LinkManager(); } - document.getElementById('root')!.addEventListener('wheel', event => { - if (event.ctrlKey) { - event.preventDefault(); - } - }, true); + document.getElementById('root')!.addEventListener( + 'wheel', + event => { + if (event.ctrlKey) { + event.preventDefault(); + } + }, + true + ); const startload = (document as any).startLoad; - const loading = Date.now() - (startload ? Number(startload) : (Date.now() - 3000)); - console.log("Load Time = " + loading); + const loading = Date.now() - (startload ? Number(startload) : Date.now() - 3000); + console.log('Loading Time = ' + loading); const d = new Date(); - d.setTime(d.getTime() + (100 * 24 * 60 * 60 * 1000)); - const expires = "expires=" + d.toUTCString(); + d.setTime(d.getTime() + 100 * 24 * 60 * 60 * 1000); + const expires = 'expires=' + d.toUTCString(); document.cookie = `loadtime=${loading};${expires};path=/`; new LinkManager(); new TrackMovements(); new ReplayMovements(); ReactDOM.render(, document.getElementById('root')); -})(); \ No newline at end of file +})(); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4940c5f9d..6c0a67de2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -32,7 +32,7 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; import { CollectionViewType } from './collections/CollectionView'; -import "./collections/TreeView.scss"; +import './collections/TreeView.scss'; import { ComponentDecorations } from './ComponentDecorations'; import { ContextMenu } from './ContextMenu'; import { DashboardView } from './DashboardView'; @@ -45,7 +45,7 @@ import { KeyManager } from './GlobalKeyHandler'; import { InkTranscription } from './InkTranscription'; import { LightboxView } from './LightboxView'; import { LinkMenu } from './linking/LinkMenu'; -import "./MainView.scss"; +import './MainView.scss'; import { AudioBox } from './nodes/AudioBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; @@ -63,7 +63,7 @@ import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; -const _global = (window /* browser */ || global /* node */) as any; +const _global = (window /* browser */ || global) /* node */ as any; @observer export class MainView extends React.Component { @@ -73,30 +73,54 @@ export class MainView extends React.Component { @observable public LastButton: Opt; @observable private _windowWidth: number = 0; @observable private _windowHeight: number = 0; - @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) - @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons - @observable private _panelContent: string = "none"; + @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) + @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons + @observable private _panelContent: string = 'none'; @observable private _sidebarContent: any = CurrentUserUtils.MyLeftSidebarPanel; @observable private _leftMenuFlyoutWidth: number = 0; - @computed private get dashboardTabHeight() { return 27; } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js - @computed private get topOfDashUI() { return Number(DASHBOARD_SELECTOR_HEIGHT.replace("px", "")); } - @computed private get topOfHeaderBarDoc() { return this.topOfDashUI; } - @computed private get topOfSidebarDoc() { return this.topOfDashUI + this.topMenuHeight(); } - @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight() + this.headerBarDocHeight(); } - @computed private get topOfMainDocContent() { return this.topOfMainDoc + this.dashboardTabHeight; } - @computed private get leftScreenOffsetOfMainDocView() { return this.leftMenuWidth() - 2; } - @computed private get userDoc() { return Doc.UserDoc(); } - @computed private get colorScheme() { return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); } - @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } - @computed private get headerBarDoc() { return CurrentUserUtils.MyHeaderBar; } - @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } + @computed private get dashboardTabHeight() { + return 27; + } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js + @computed private get topOfDashUI() { + return Number(DASHBOARD_SELECTOR_HEIGHT.replace('px', '')); + } + @computed private get topOfHeaderBarDoc() { + return this.topOfDashUI; + } + @computed private get topOfSidebarDoc() { + return this.topOfDashUI + this.topMenuHeight(); + } + @computed private get topOfMainDoc() { + return this.topOfDashUI + this.topMenuHeight() + this.headerBarDocHeight(); + } + @computed private get topOfMainDocContent() { + return this.topOfMainDoc + this.dashboardTabHeight; + } + @computed private get leftScreenOffsetOfMainDocView() { + return this.leftMenuWidth() - 2; + } + @computed private get userDoc() { + return Doc.UserDoc(); + } + @computed private get colorScheme() { + return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); + } + @computed private get mainContainer() { + return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; + } + @computed private get headerBarDoc() { + return CurrentUserUtils.MyHeaderBar; + } + @computed public get mainFreeform(): Opt { + return (docs => (docs?.length > 1 ? docs[1] : undefined))(DocListCast(this.mainContainer!.data)); + } headerBarDocWidth = () => this.mainDocViewWidth(); headerBarDocHeight = () => CurrentUserUtils.headerBarHeight ?? 0; topMenuHeight = () => 35; topMenuWidth = returnZero; // value is ignored ... - leftMenuWidth = () => Number(LEFT_MENU_WIDTH.replace("px", "")); + leftMenuWidth = () => Number(LEFT_MENU_WIDTH.replace('px', '')); leftMenuHeight = () => this._dashUIHeight; leftMenuFlyoutWidth = () => this._leftMenuFlyoutWidth; leftMenuFlyoutHeight = () => this._dashUIHeight; @@ -106,89 +130,325 @@ export class MainView extends React.Component { mainDocViewHeight = () => this._dashUIHeight - this.headerBarDocHeight(); componentDidMount() { - document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!)); - const ele = document.getElementById("loader"); - const prog = document.getElementById("dash-progress"); + document.getElementById('root')?.addEventListener('scroll', e => (ele => (ele.scrollLeft = ele.scrollTop = 0))(document.getElementById('root')!)); + const ele = document.getElementById('loader'); + const prog = document.getElementById('dash-progress'); if (ele && prog) { // remove from DOM setTimeout(() => { clearTimeout(); - prog.style.transition = "1s"; - prog.style.width = "100%"; + prog.style.transition = '1s'; + prog.style.width = '100%'; }, 0); - setTimeout(() => ele.outerHTML = '', 1000); + setTimeout(() => (ele.outerHTML = ''), 1000); } this._sidebarContent.proto = undefined; if (!MainView.Live) { - DocServer.setPlaygroundFields(["dataTransition", "treeViewOpen", "showSidebar", "sidebarWidthPercent", "viewTransition", - "panX", "panY", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height", "hideMinimap", - "viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's + DocServer.setPlaygroundFields([ + 'dataTransition', + 'treeViewOpen', + 'showSidebar', + 'sidebarWidthPercent', + 'viewTransition', + 'panX', + 'panY', + 'nativeWidth', + 'nativeHeight', + 'text-scrollHeight', + 'text-height', + 'hideMinimap', + 'viewScale', + 'scrollTop', + 'hidden', + 'curPage', + 'viewType', + 'chromeHidden', + 'nativeWidth', + ]); // can play with these fields on someone else's } - DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg))); + DocServer.GetRefField('rtfProto').then( + proto => + proto instanceof Doc && + reaction( + () => StrCast(proto.BROADCAST_MESSAGE), + msg => msg && alert(msg) + ) + ); const tag = document.createElement('script'); - tag.src = "https://www.youtube.com/iframe_api"; + tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); - window.removeEventListener("keydown", KeyManager.Instance.handle); - window.addEventListener("keydown", KeyManager.Instance.handle); - window.removeEventListener("keyup", KeyManager.Instance.unhandle); - window.addEventListener("keyup", KeyManager.Instance.unhandle); - window.addEventListener("paste", KeyManager.Instance.paste as any); - document.addEventListener("dash", (e: any) => { // event used by chrome plugin to tell Dash which document to focus on + window.removeEventListener('keydown', KeyManager.Instance.handle); + window.addEventListener('keydown', KeyManager.Instance.handle); + window.removeEventListener('keyup', KeyManager.Instance.unhandle); + window.addEventListener('keyup', KeyManager.Instance.unhandle); + window.addEventListener('paste', KeyManager.Instance.paste as any); + document.addEventListener('dash', (e: any) => { + // event used by chrome plugin to tell Dash which document to focus on const id = FormattedTextBox.GetDocFromUrl(e.detail); - DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : (null)); + DocServer.GetRefField(id).then(doc => (doc instanceof Doc ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : null)); }); - document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener); + document.addEventListener('linkAnnotationToDash', Hypothesis.linkListener); this.initEventListeners(); } componentWillUnMount() { - window.removeEventListener("keyup", KeyManager.Instance.unhandle); - window.removeEventListener("keydown", KeyManager.Instance.handle); - window.removeEventListener("pointerdown", this.globalPointerDown); - window.removeEventListener("paste", KeyManager.Instance.paste as any); - document.removeEventListener("linkAnnotationToDash", Hypothesis.linkListener); + window.removeEventListener('keyup', KeyManager.Instance.unhandle); + window.removeEventListener('keydown', KeyManager.Instance.handle); + window.removeEventListener('pointerdown', this.globalPointerDown); + window.removeEventListener('paste', KeyManager.Instance.paste as any); + document.removeEventListener('linkAnnotationToDash', Hypothesis.linkListener); } constructor(props: Readonly<{}>) { super(props); MainView.Instance = this; - CurrentUserUtils._urlState = HistoryUtil.parseUrl(window.location) || {} as any; + CurrentUserUtils._urlState = HistoryUtil.parseUrl(window.location) || ({} as any); // causes errors to be generated when modifying an observable outside of an action - configure({ enforceActions: "observed" }); + configure({ enforceActions: 'observed' }); - if (window.location.pathname !== "/home") { - const pathname = window.location.pathname.substr(1).split("/"); - if (pathname.length > 1 && pathname[0] === "doc") { + if (window.location.pathname !== '/home') { + const pathname = window.location.pathname.substr(1).split('/'); + if (pathname.length > 1 && pathname[0] === 'doc') { CurrentUserUtils.MainDocId = pathname[1]; !this.userDoc && DocServer.GetRefField(pathname[1]).then(action(field => field instanceof Doc && (CurrentUserUtils.GuestTarget = field))); } } - library.add(...[fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar, - fa.faSquare, far.faSquare as any, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, - fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, - fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight, - fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow, - fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, - fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faChevronLeft, fa.faChevronDown, fa.faChevronUp, - fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt, - fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer, - fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote, fa.faArrowsAltV, - fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideoSlash, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes, fa.faFlag, - fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined, - fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, - fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any, - fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle as any, - fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleDoubleDown, fa.faAngleDoubleLeft, fa.faAngleDoubleUp, faBuffer as any, fa.faExpand, fa.faUndo, - fa.faSlidersH, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, - fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo, - fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical, - fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll, - fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines, - fa.faSave, fa.faBookmark, fa.faList, fa.faListOl, fa.faFolderPlus, fa.faLightbulb, fa.faBookOpen, fa.faMapMarkerAlt, fa.faSearchPlus, fa.faVolumeUp, fa.faVolumeDown, fa.faSquareRootAlt, fa.faVolumeMute]); + library.add( + ...[ + fa.faEdit, + fa.faTrash, + fa.faTrashAlt, + fa.faShare, + fa.faDownload, + fa.faExpandArrowsAlt, + fa.faLayerGroup, + fa.faExternalLinkAlt, + fa.faCalendar, + fa.faSquare, + far.faSquare as any, + fa.faConciergeBell, + fa.faWindowRestore, + fa.faFolder, + fa.faMapPin, + fa.faMapMarker, + fa.faFingerprint, + fa.faCrosshairs, + fa.faDesktop, + fa.faUnlock, + fa.faLock, + fa.faLaptopCode, + fa.faMale, + fa.faCopy, + fa.faHandPointLeft, + fa.faHandPointRight, + fa.faCompass, + fa.faSnowflake, + fa.faMicrophone, + fa.faKeyboard, + fa.faQuestion, + fa.faTasks, + fa.faPalette, + fa.faAngleLeft, + fa.faAngleRight, + fa.faBell, + fa.faCamera, + fa.faExpand, + fa.faCaretDown, + fa.faCaretLeft, + fa.faCaretRight, + fa.faCaretSquareDown, + fa.faCaretSquareRight, + fa.faArrowsAltH, + fa.faPlus, + fa.faMinus, + fa.faTerminal, + fa.faToggleOn, + fa.faFile, + fa.faLocationArrow, + fa.faSearch, + fa.faFileDownload, + fa.faFileUpload, + fa.faStop, + fa.faCalculator, + fa.faWindowMaximize, + fa.faAddressCard, + fa.faQuestionCircle, + fa.faArrowLeft, + fa.faArrowRight, + fa.faArrowDown, + fa.faArrowUp, + fa.faBolt, + fa.faBullseye, + fa.faCaretUp, + fa.faCat, + fa.faCheck, + fa.faChevronRight, + fa.faChevronLeft, + fa.faChevronDown, + fa.faChevronUp, + fa.faClone, + fa.faCloudUploadAlt, + fa.faCommentAlt, + fa.faCompressArrowsAlt, + fa.faCut, + fa.faEllipsisV, + fa.faEraser, + fa.faExclamation, + fa.faFileAlt, + fa.faFileAudio, + fa.faFileVideo, + fa.faFilePdf, + fa.faFilm, + fa.faFilter, + fa.faFont, + fa.faGlobeAmericas, + fa.faGlobeAsia, + fa.faHighlighter, + fa.faLongArrowAltRight, + fa.faMousePointer, + fa.faMusic, + fa.faObjectGroup, + fa.faPause, + fa.faPen, + fa.faPenNib, + fa.faPhone, + fa.faPlay, + fa.faPortrait, + fa.faRedoAlt, + fa.faStamp, + fa.faStickyNote, + fa.faArrowsAltV, + fa.faTimesCircle, + fa.faThumbtack, + fa.faTree, + fa.faTv, + fa.faUndoAlt, + fa.faVideoSlash, + fa.faVideo, + fa.faAsterisk, + fa.faBrain, + fa.faImage, + fa.faPaintBrush, + fa.faTimes, + fa.faFlag, + fa.faEye, + fa.faArrowsAlt, + fa.faQuoteLeft, + fa.faSortAmountDown, + fa.faAlignLeft, + fa.faAlignCenter, + fa.faAlignRight, + fa.faHeading, + fa.faRulerCombined, + fa.faFillDrip, + fa.faLink, + fa.faUnlink, + fa.faBold, + fa.faItalic, + fa.faClipboard, + fa.faUnderline, + fa.faStrikethrough, + fa.faSuperscript, + fa.faSubscript, + fa.faIndent, + fa.faEyeDropper, + fa.faPaintRoller, + fa.faBars, + fa.faBrush, + fa.faShapes, + fa.faEllipsisH, + fa.faHandPaper, + fa.faMap, + fa.faUser, + faHireAHelper as any, + fa.faTrashRestore, + fa.faUsers, + fa.faWrench, + fa.faCog, + fa.faMap, + fa.faBellSlash, + fa.faExpandAlt, + fa.faArchive, + fa.faBezierCurve, + fa.faCircle, + far.faCircle as any, + fa.faLongArrowAltRight, + fa.faPenFancy, + fa.faAngleDoubleRight, + fa.faAngleDoubleDown, + fa.faAngleDoubleLeft, + fa.faAngleDoubleUp, + faBuffer as any, + fa.faExpand, + fa.faUndo, + fa.faSlidersH, + fa.faAngleUp, + fa.faAngleDown, + fa.faPlayCircle, + fa.faClock, + fa.faRocket, + fa.faExchangeAlt, + fa.faHashtag, + fa.faAlignJustify, + fa.faCheckSquare, + fa.faListUl, + fa.faWindowMinimize, + fa.faWindowRestore, + fa.faTextWidth, + fa.faTextHeight, + fa.faClosedCaptioning, + fa.faInfoCircle, + fa.faTag, + fa.faSyncAlt, + fa.faPhotoVideo, + fa.faArrowAltCircleDown, + fa.faArrowAltCircleUp, + fa.faArrowAltCircleLeft, + fa.faArrowAltCircleRight, + fa.faStopCircle, + fa.faCheckCircle, + fa.faGripVertical, + fa.faSortUp, + fa.faSortDown, + fa.faTable, + fa.faTh, + fa.faThList, + fa.faProjectDiagram, + fa.faSignature, + fa.faColumns, + fa.faChevronCircleUp, + fa.faUpload, + fa.faBorderAll, + fa.faBraille, + fa.faChalkboard, + fa.faPencilAlt, + fa.faEyeSlash, + fa.faSmile, + fa.faIndent, + fa.faOutdent, + fa.faChartBar, + fa.faBan, + fa.faPhoneSlash, + fa.faGripLines, + fa.faSave, + fa.faBookmark, + fa.faList, + fa.faListOl, + fa.faFolderPlus, + fa.faLightbulb, + fa.faBookOpen, + fa.faMapMarkerAlt, + fa.faSearchPlus, + fa.faVolumeUp, + fa.faVolumeDown, + fa.faSquareRootAlt, + fa.faVolumeMute, + ] + ); this.initAuthenticationRouters(); } @@ -197,175 +457,211 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { const targClass = targets[0].className.toString(); - !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu(); - !["timeline-menu-desc", "timeline-menu-item", "timeline-menu-input"].includes(targClass) && TimelineMenu.Instance.closeMenu(); + !targClass.includes('contextMenu') && ContextMenu.Instance.closeMenu(); + !['timeline-menu-desc', 'timeline-menu-item', 'timeline-menu-input'].includes(targClass) && TimelineMenu.Instance.closeMenu(); } }); initEventListeners = () => { - window.addEventListener("drop", e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page - window.addEventListener("dragover", e => e.preventDefault(), false); + window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page + window.addEventListener('dragover', e => e.preventDefault(), false); // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined)); - document.addEventListener("pointerdown", this.globalPointerDown); - document.addEventListener("click", (e: MouseEvent) => { - if (!e.cancelBubble) { - const pathstr = (e as any)?.path?.map((p: any) => p.classList?.toString()).join(); - if (pathstr?.includes("libraryFlyout")) { - SelectionManager.DeselectAll(); + document.addEventListener('pointerdown', this.globalPointerDown); + document.addEventListener( + 'click', + (e: MouseEvent) => { + if (!e.cancelBubble) { + const pathstr = (e as any)?.path?.map((p: any) => p.classList?.toString()).join(); + if (pathstr?.includes('libraryFlyout')) { + SelectionManager.DeselectAll(); + } } - } - }, false); + }, + false + ); document.oncontextmenu = () => false; - } + }; initAuthenticationRouters = async () => { const received = CurrentUserUtils.MainDocId; if (received && !this.userDoc) { - reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(), { fireImmediately: true }); - } + reaction( + () => CurrentUserUtils.GuestTarget, + target => target && CurrentUserUtils.createNewDashboard(), + { fireImmediately: true } + ); + } // else { // PromiseValue(this.userDoc.activeDashboard).then(dash => { // if (dash instanceof Doc) CurrentUserUtils.openDashboard(dash); // else CurrentUserUtils.createNewDashboard(); // }); // } - } + }; @action createNewPresentation = async () => { - const pres = Docs.Create.PresDocument({ title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); - CollectionDockingView.AddSplit(pres, "left"); + const pres = Docs.Create.PresDocument({ title: 'Untitled Trail', _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: 'alias', _chromeHidden: true, boxShadow: '0 0' }); + CollectionDockingView.AddSplit(pres, 'left'); CurrentUserUtils.ActivePresentation = pres; - Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", pres); - } + Doc.AddDocToList(CurrentUserUtils.MyTrails, 'data', pres); + }; @action createNewFolder = async () => { - const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); - Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); - } + const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true }); + Doc.AddDocToList(CurrentUserUtils.MyFilesystem, 'data', folder); + }; @observable _exploreMode = false; @computed get exploreMode() { - return () => this._exploreMode ? ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", - { documentView: "any", clientX: "number", clientY: "number" })! : undefined; + return () => (this._exploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1); @computed get headerBarDocView() { - return
-
; + return ( +
+ +
+ ); } @computed get mainDocView() { - return <> - {this.headerBarDocView} - ; + return ( + <> + {this.headerBarDocView} + + + ); } @computed get dockingContent() { - return
{ e.stopPropagation(); e.preventDefault(); }} - style={{ - minWidth: `calc(100% - ${this._leftMenuFlyoutWidth + this.leftMenuWidth() + this.propertiesWidth()}px)`, - transform: LightboxView.LightboxDoc ? "scale(0.0001)" : undefined, - }}> - {!this.mainContainer ? (null) : this.mainDocView} -
; + return ( +
{ + e.stopPropagation(); + e.preventDefault(); + }} + style={{ + minWidth: `calc(100% - ${this._leftMenuFlyoutWidth + this.leftMenuWidth() + this.propertiesWidth()}px)`, + transform: LightboxView.LightboxDoc ? 'scale(0.0001)' : undefined, + }}> + {!this.mainContainer ? null : this.mainDocView} +
+ ); } @action onPropertiesPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, - action(e => (CurrentUserUtils.propertiesWidth = Math.max(0, this._dashUIWidth - e.clientX)) ? false : false), + setupMoveUpEvents( + this, + e, + action(e => ((CurrentUserUtils.propertiesWidth = Math.max(0, this._dashUIWidth - e.clientX)) ? false : false)), action(() => CurrentUserUtils.propertiesWidth < 5 && (CurrentUserUtils.propertiesWidth = 0)), - action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._dashUIWidth - 50, 250) : 0), false); - } + action(() => (CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._dashUIWidth - 50, 250) : 0)), + false + ); + }; @action onFlyoutPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, - action(e => (this._leftMenuFlyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false), + setupMoveUpEvents( + this, + e, + action(e => ((this._leftMenuFlyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false)), () => this._leftMenuFlyoutWidth < 5 && this.closeFlyout(), - this.closeFlyout); - } + this.closeFlyout + ); + }; sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); addDocTabFunc = (doc: Doc, location: string): boolean => { - const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); - const locationParams = locationFields.length > 1 ? locationFields[1] : ""; + const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':'); + const locationParams = locationFields.length > 1 ? locationFields[1] : ''; if (doc.dockingConfig) return CurrentUserUtils.openDashboard(doc); switch (locationFields[0]) { - case "dashboard": return CurrentUserUtils.openDashboard(doc); - case "close": return CollectionDockingView.CloseSplit(doc, locationParams); - case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); - case "lightbox": return LightboxView.AddDocTab(doc, location); - case "toggle": return CollectionDockingView.ToggleSplit(doc, locationParams); - case "inPlace": - case "add": + case 'dashboard': + return CurrentUserUtils.openDashboard(doc); + case 'close': + return CollectionDockingView.CloseSplit(doc, locationParams); + case 'fullScreen': + return CollectionDockingView.OpenFullScreen(doc); + case 'lightbox': + return LightboxView.AddDocTab(doc, location); + case 'toggle': + return CollectionDockingView.ToggleSplit(doc, locationParams); + case 'inPlace': + case 'add': default: return CollectionDockingView.AddSplit(doc, locationParams); } - } - + }; @computed get flyout() { - return !this._leftMenuFlyoutWidth ?
- {this.docButtons} -
: -
-
+ return !this._leftMenuFlyoutWidth ? ( +
+ {this.docButtons} +
+ ) : ( +
+
{this.docButtons} -
; +
+ ); } @computed get leftMenuPanel() { - return
- -
; + return ( +
+ +
+ ); } @action @@ -432,69 +731,78 @@ export class MainView extends React.Component { const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title; this.closeFlyout(); if (willOpen) { - switch (this._panelContent = title) { - case "Settings": + switch ((this._panelContent = title)) { + case 'Settings': SettingsManager.Instance.open(); break; - case "Help": + case 'Help': break; default: this.expandFlyout(button); } } return true; - } + }; @computed get mainInnerContent() { const leftMenuFlyoutWidth = this._leftMenuFlyoutWidth + this.leftMenuWidth(); const width = this.propertiesWidth() + leftMenuFlyoutWidth; - return <> - {this.leftMenuPanel} -
- {this.flyout} -
- -
-
- - {this.dockingContent} - -
- + return ( + <> + {this.leftMenuPanel} +
+ {this.flyout} +
+
-
- {this.propertiesWidth() < 10 ? (null) : } +
+ {this.dockingContent} + +
+ +
+
+ {this.propertiesWidth() < 10 ? null : } +
-
- ; + + ); } - @computed get mainDashboardArea() { - return !this.userDoc ? (null) : -
{ - r && new _global.ResizeObserver(action(() => { - this._dashUIWidth = r.getBoundingClientRect().width; - this._dashUIHeight = r.getBoundingClientRect().height; - })).observe(r); - }} style={{ - color: this.colorScheme === ColorScheme.Dark ? "rgb(205,205,205)" : "black", - height: `calc(100% - ${this.topOfDashUI + this.topMenuHeight()}px)`, - width: "100%", - }} > + return !this.userDoc ? null : ( +
{ + r && + new _global.ResizeObserver( + action(() => { + this._dashUIWidth = r.getBoundingClientRect().width; + this._dashUIHeight = r.getBoundingClientRect().height; + }) + ).observe(r); + }} + style={{ + color: this.colorScheme === ColorScheme.Dark ? 'rgb(205,205,205)' : 'black', + height: `calc(100% - ${this.topOfDashUI + this.topMenuHeight()}px)`, + width: '100%', + }}> {this.mainInnerContent} -
; +
+ ); } - expandFlyout = action((button: Doc) => { - // bcz: What's going on here!? + // bcz: What's going on here!? // Chrome(not firefox) seems to have a bug when the flyout expands and there's a zoomed freeform tab. All of the div below the CollectionFreeFormView's main div // generate the wrong value from getClientRectangle() -- specifically they return an 'x' that is the flyout's width greater than it should be. // interactively adjusting the flyout fixes the problem. So does programmatically changing the value after a timeout to something *fractionally* different (ie, 1.5, not 1);) - this._leftMenuFlyoutWidth = (this._leftMenuFlyoutWidth || 250); - setTimeout(action(() => this._leftMenuFlyoutWidth += 0.5), 0); + this._leftMenuFlyoutWidth = this._leftMenuFlyoutWidth || 250; + setTimeout( + action(() => (this._leftMenuFlyoutWidth += 0.5)), + 0 + ); this._sidebarContent.proto = button.target as any; this.LastButton = button; @@ -502,29 +810,29 @@ export class MainView extends React.Component { closeFlyout = action(() => { this.LastButton = undefined; - this._panelContent = "none"; + this._panelContent = 'none'; this._sidebarContent.proto = undefined; this._leftMenuFlyoutWidth = 0; }); - remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(CurrentUserUtils.MyDockedBtns, "data", doc), true); + remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(CurrentUserUtils.MyDockedBtns, 'data', doc), true); moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); - addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(CurrentUserUtils.MyDockedBtns, "data", doc), true); + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(CurrentUserUtils.MyDockedBtns, 'data', doc), true); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current); return new Transform(-translateX, -translateY, 1 / scale); - } + }; @computed get docButtons() { - return !CurrentUserUtils.MyDockedBtns ? (null) : -
+ return !CurrentUserUtils.MyDockedBtns ? null : ( +
- {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ?
{this.userDoc?.presentationMode}
: <>} -
; + ContainingCollectionDoc={undefined} + /> + {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ?
{StrCast(this.userDoc?.presentationMode)}
: <>} +
+ ); } @computed get snapLines() { - return !SnappingManager.GetShowSnapLines() ? (null) :
- - {SnappingManager.horizSnapLines().map(l => )} - {SnappingManager.vertSnapLines().map(l => )} - -
; + return !SnappingManager.GetShowSnapLines() ? null : ( +
+ + {SnappingManager.horizSnapLines().map(l => ( + + ))} + {SnappingManager.vertSnapLines().map(l => ( + + ))} + +
+ ); } @computed get inkResources() { - return - - - + - - - - - - - - - - - ; + 0 0 0 1 0"> + + + + + + + + + + + ); } - @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts - return !DocumentLinksButton.invisibleWebDoc ? null : + @computed get invisibleWebBox() { + // see note under the makeLink method in HypothesisUtils.ts + return !DocumentLinksButton.invisibleWebDoc ? null : (
-
; +
+ ); } render() { - return (
((ele) => ele.scrollTop = ele.scrollLeft = 0)(document.getElementById("root")!)} - ref={r => { - r && new _global.ResizeObserver(action(() => { this._windowWidth = r.getBoundingClientRect().width; this._windowHeight = r.getBoundingClientRect().height; })).observe(r); - }}> - {this.inkResources} - - - - - - - - - - {LinkDescriptionPopup.descriptionPopup ? : null} - {DocumentLinksButton.LinkEditorDocView ? DocumentLinksButton.LinkEditorDocView = undefined)} docView={DocumentLinksButton.LinkEditorDocView} /> : (null)} - {LinkDocPreview.LinkInfo ? : (null)} - - {((page:string) => { - switch (page) { - case "dashboard": - default:return <> -
- -
- {this.mainDashboardArea} - ; - case "home": return ; - } })(CurrentUserUtils.ActivePage) - } - - - - - - - - - - - - - {this.snapLines} -
- -
); + return ( +
(ele => (ele.scrollTop = ele.scrollLeft = 0))(document.getElementById('root')!)} + ref={r => { + r && + new _global.ResizeObserver( + action(() => { + this._windowWidth = r.getBoundingClientRect().width; + this._windowHeight = r.getBoundingClientRect().height; + }) + ).observe(r); + }}> + {this.inkResources} + + + + + + + + + + {LinkDescriptionPopup.descriptionPopup ? : null} + {DocumentLinksButton.LinkEditorDocView ? (DocumentLinksButton.LinkEditorDocView = undefined))} docView={DocumentLinksButton.LinkEditorDocView} /> : null} + {LinkDocPreview.LinkInfo ? : null} + + {((page: string) => { + switch (page) { + case 'dashboard': + default: + return ( + <> +
+ +
+ {this.mainDashboardArea} + + ); + case 'home': + return ; + } + })(CurrentUserUtils.ActivePage)} + + + + + + + + + + + + + {this.snapLines} +
+ +
+ ); } makeWebRef = (ele: HTMLDivElement) => { - reaction(() => DocumentLinksButton.invisibleWebDoc, + reaction( + () => DocumentLinksButton.invisibleWebDoc, invisibleDoc => { ReactDOM.unmountComponentAtNode(ele); - invisibleDoc && ReactDOM.render( -
- 500} - PanelHeight={() => 800} - docFilters={returnEmptyFilter} - docRangeFilters={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - /> -
; -
, ele); + invisibleDoc && + ReactDOM.render( + +
+ 500} + PanelHeight={() => 800} + docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} + /> +
+ ; +
, + ele + ); let success = false; const onSuccess = () => { success = true; clearTimeout(interval); - document.removeEventListener("editSuccess", onSuccess); + document.removeEventListener('editSuccess', onSuccess); }; // For some reason, Hypothes.is annotations don't load until a click is registered on the page, // so we keep simulating clicks until annotations have loaded and editing is successful const interval = setInterval(() => !success && simulateMouseClick(ele, 50, 50, 50, 50), 500); setTimeout(() => !success && clearInterval(interval), 10000); // give up if no success after 10s - document.addEventListener("editSuccess", onSuccess); - }); - } + document.addEventListener('editSuccess', onSuccess); + } + ); + }; } -ScriptingGlobals.add(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); }); \ No newline at end of file +ScriptingGlobals.add(function selectMainMenu(doc: Doc, title: string) { + MainView.Instance.selectMenu(doc); +}); diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 789756a78..436cb688f 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -4,7 +4,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; const HOLD_DURATION = 1000; -export abstract class Touchable extends React.Component { +export abstract class Touchable extends React.Component> { //private holdTimer: NodeJS.Timeout | undefined; private moveDisposer?: InteractionUtils.MultiTouchEventDisposer; private endDisposer?: InteractionUtils.MultiTouchEventDisposer; @@ -25,7 +25,6 @@ export abstract class Touchable extends React.Component { */ @action protected onTouchStart = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { - const actualPts: React.Touch[] = []; const te = me.touchEvent; // loop through all touches on screen @@ -60,7 +59,7 @@ export abstract class Touchable extends React.Component { case 1: this.handle1PointerDown(te, me); te.persist(); - // -- code for radial menu -- + // -- code for radial menu -- // if (this.holdTimer) { // clearTimeout(this.holdTimer) // this.holdTimer = undefined; @@ -71,11 +70,11 @@ export abstract class Touchable extends React.Component { break; } } - } + }; /** - * Handle touch move event - */ + * Handle touch move event + */ @action protected onTouch = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { const te = me.touchEvent; @@ -85,8 +84,12 @@ export abstract class Touchable extends React.Component { if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return; this._touchDrag = true; switch (myTouches.length) { - case 1: this.handle1PointerMove(te, me); break; - case 2: this.handle2PointersMove(te, me); break; + case 1: + this.handle1PointerMove(te, me); + break; + case 2: + this.handle2PointersMove(te, me); + break; } for (const pt of me.touches) { @@ -94,7 +97,7 @@ export abstract class Touchable extends React.Component { this.prevPoints.set(pt.identifier, pt); } } - } + }; @action protected onTouchEnd = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { @@ -110,7 +113,6 @@ export abstract class Touchable extends React.Component { this._touchDrag = false; te.stopPropagation(); - // if (e.targetTouches.length === 0) { // this.prevPoints.clear(); // } @@ -119,36 +121,36 @@ export abstract class Touchable extends React.Component { this.cleanUpInteractions(); } e.stopPropagation(); - } + }; cleanUpInteractions = (): void => { this.removeMoveListeners(); this.removeEndListeners(); - } + }; handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent): any => { e.stopPropagation(); e.preventDefault(); - } + }; handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent): any => { e.stopPropagation(); e.preventDefault(); - } + }; handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent): any => { this.removeMoveListeners(); this.addMoveListeners(); this.removeEndListeners(); this.addEndListeners(); - } + }; handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent): any => { this.removeMoveListeners(); this.addMoveListeners(); this.removeEndListeners(); this.addEndListeners(); - } + }; handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent): any => { e.stopPropagation(); @@ -159,30 +161,30 @@ export abstract class Touchable extends React.Component { this.removeHoldEndListeners(); this.addHoldMoveListeners(); this.addHoldEndListeners(); - } + }; addMoveListeners = () => { const handler = (e: Event) => this.onTouch(e, (e as CustomEvent>).detail); - document.addEventListener("dashOnTouchMove", handler); - this.moveDisposer = () => document.removeEventListener("dashOnTouchMove", handler); - } + document.addEventListener('dashOnTouchMove', handler); + this.moveDisposer = () => document.removeEventListener('dashOnTouchMove', handler); + }; addEndListeners = () => { const handler = (e: Event) => this.onTouchEnd(e, (e as CustomEvent>).detail); - document.addEventListener("dashOnTouchEnd", handler); - this.endDisposer = () => document.removeEventListener("dashOnTouchEnd", handler); - } + document.addEventListener('dashOnTouchEnd', handler); + this.endDisposer = () => document.removeEventListener('dashOnTouchEnd', handler); + }; addHoldMoveListeners = () => { const handler = (e: Event) => this.handle1PointerHoldMove(e, (e as CustomEvent>).detail); - document.addEventListener("dashOnTouchHoldMove", handler); - this.holdMoveDisposer = () => document.removeEventListener("dashOnTouchHoldMove", handler); - } + document.addEventListener('dashOnTouchHoldMove', handler); + this.holdMoveDisposer = () => document.removeEventListener('dashOnTouchHoldMove', handler); + }; addHoldEndListeners = () => { const handler = (e: Event) => this.handle1PointerHoldEnd(e, (e as CustomEvent>).detail); - document.addEventListener("dashOnTouchHoldEnd", handler); - this.holdEndDisposer = () => document.removeEventListener("dashOnTouchHoldEnd", handler); - } + document.addEventListener('dashOnTouchHoldEnd', handler); + this.holdEndDisposer = () => document.removeEventListener('dashOnTouchHoldEnd', handler); + }; removeMoveListeners = () => this.moveDisposer?.(); removeEndListeners = () => this.endDisposer?.(); @@ -192,7 +194,7 @@ export abstract class Touchable extends React.Component { handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { // e.stopPropagation(); // me.touchEvent.stopPropagation(); - } + }; handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { e.stopPropagation(); @@ -202,10 +204,10 @@ export abstract class Touchable extends React.Component { me.touchEvent.stopPropagation(); me.touchEvent.preventDefault(); - } + }; handleHandDown = (e: React.TouchEvent) => { // e.stopPropagation(); // e.preventDefault(); - } -} \ No newline at end of file + }; +} diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e80ba6f36..7a393a4f7 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -1,19 +1,19 @@ -import { faBackward, faForward, faGripLines, faPauseCircle, faPlayCircle } from "@fortawesome/free-solid-svg-icons"; +import { faBackward, faForward, faGripLines, faPauseCircle, faPlayCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, runInAction, trace } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { Doc, DocListCast } from "../../../fields/Doc"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; -import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils"; -import { FieldViewProps } from "../nodes/FieldView"; -import { KeyframeFunc } from "./Keyframe"; -import "./Timeline.scss"; -import { TimelineOverview } from "./TimelineOverview"; -import { Track } from "./Track"; -import clamp from "../../util/clamp"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { IconLookup } from "@fortawesome/fontawesome-svg-core"; +import { action, computed, observable, runInAction, trace } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; +import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from '../../../Utils'; +import { FieldViewProps } from '../nodes/FieldView'; +import { KeyframeFunc } from './Keyframe'; +import './Timeline.scss'; +import { TimelineOverview } from './TimelineOverview'; +import { Track } from './Track'; +import clamp from '../../util/clamp'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { IconLookup } from '@fortawesome/fontawesome-svg-core'; /** * Timeline class controls most of timeline functions besides individual keyframe and track mechanism. Main functions are @@ -35,10 +35,8 @@ import { IconLookup } from "@fortawesome/fontawesome-svg-core"; @author Andrew Kim */ - @observer export class Timeline extends React.Component { - //readonly constants private readonly DEFAULT_TICK_SPACING: number = 50; private readonly MAX_TITLE_HEIGHT = 75; @@ -57,8 +55,7 @@ export class Timeline extends React.Component { @observable private _roundToggleRef = React.createRef(); @observable private _roundToggleContainerRef = React.createRef(); - - //boolean vars and instance vars + //boolean vars and instance vars @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing @@ -73,13 +70,13 @@ export class Timeline extends React.Component { @observable private _titleHeight = 0; /** - * collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit. + * collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit. */ @computed private get children(): Doc[] { const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this.props.Document.type) as any); if (annotatedDoc) { - return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + "-annotations"]); + return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + '-annotations']); } return DocListCast(this.props.Document[this.props.fieldKey]); } @@ -91,7 +88,8 @@ export class Timeline extends React.Component { this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //check if relHeight is less than Maxheight. Else, just set relheight to max this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; //offset this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; //twice the titleheight + offset - if (!this.props.Document.AnimationLength) { //if animation length did not exist + if (!this.props.Document.AnimationLength) { + //if animation length did not exist this.props.Document.AnimationLength = this._time; //set it to default time } else { this._time = NumCast(this.props.Document.AnimationLength); //else, set time to animationlength stored from before @@ -116,24 +114,29 @@ export class Timeline extends React.Component { drawTicks = () => { const ticks = []; for (let i = 0; i < this._time / this._tickIncrement; i++) { - ticks.push(

{this.toReadTime(i * this._tickIncrement)}

); + ticks.push( +
+ {' '} +

{this.toReadTime(i * this._tickIncrement)}

+
+ ); } return ticks; - } + }; /** * changes the scrubber to actual pixel position */ @action changeCurrentBarX = (pixel: number) => { - pixel <= 0 ? this._currentBarX = 0 : pixel >= this._totalLength ? this._currentBarX = this._totalLength : this._currentBarX = pixel; - } + pixel <= 0 ? (this._currentBarX = 0) : pixel >= this._totalLength ? (this._currentBarX = this._totalLength) : (this._currentBarX = pixel); + }; //for playing onPlay = (e: React.MouseEvent) => { e.stopPropagation(); this.play(); - } + }; /** * when playbutton is clicked @@ -149,8 +152,7 @@ export class Timeline extends React.Component { this._isPlaying = !this._isPlaying; this._playButton = this._isPlaying ? faPauseCircle : faPlayCircle; this._isPlaying && playTimeline(); - } - + }; /** * fast forward the timeline scrubbing @@ -159,30 +161,32 @@ export class Timeline extends React.Component { windForward = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - if (this._windSpeed < 64) { //max speed is 32 + if (this._windSpeed < 64) { + //max speed is 32 this._windSpeed = this._windSpeed * 2; } - } + }; /** - * rewind the timeline scrubbing + * rewind the timeline scrubbing */ @action windBackward = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - if (this._windSpeed > 1 / 16) { // min speed is 1/8 + if (this._windSpeed > 1 / 16) { + // min speed is 1/8 this._windSpeed = this._windSpeed / 2; } - } + }; /** - * scrubber down + * scrubber down */ @action onScrubberDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, this.onScrubberMove, emptyFunction, emptyFunction); - } + }; /** * when there is any scrubber movement @@ -194,16 +198,15 @@ export class Timeline extends React.Component { const offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position return false; - } + }; /** * when panning the timeline (in editing mode) */ @action onPanDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, this.onPanMove, emptyFunction, (e) => - this.changeCurrentBarX(this._trackbox.current!.scrollLeft + e.clientX - this._trackbox.current!.getBoundingClientRect().left)); - } + setupMoveUpEvents(this, e, this.onPanMove, emptyFunction, e => this.changeCurrentBarX(this._trackbox.current!.scrollLeft + e.clientX - this._trackbox.current!.getBoundingClientRect().left)); + }; /** * when moving the timeline (in editing mode) @@ -218,29 +221,34 @@ export class Timeline extends React.Component { if (this._visibleStart + this._visibleLength + 20 >= this._totalLength) { this._visibleStart -= e.movementX; this._totalLength -= e.movementX; - this._time -= KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this._tickSpacing, this._tickIncrement); + this._time -= KeyframeFunc.convertPixelTime(e.movementX, 'mili', 'time', this._tickSpacing, this._tickIncrement); this.props.Document.AnimationLength = this._time; } return false; - } - + }; @action movePanX = (pixel: number) => { this._infoContainer.current!.scrollLeft = pixel; this._visibleStart = this._infoContainer.current!.scrollLeft; - } + }; /** * resizing timeline (in editing mode) (the hamburger drag icon) */ onResizeDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e) => { - const offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; - this._containerHeight = clamp(this.MIN_CONTAINER_HEIGHT, this._containerHeight + offset, this.MAX_CONTAINER_HEIGHT); - return false; - }), emptyFunction, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action(e => { + const offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; + this._containerHeight = clamp(this.MIN_CONTAINER_HEIGHT, this._containerHeight + offset, this.MAX_CONTAINER_HEIGHT); + return false; + }), + emptyFunction, + emptyFunction + ); + }; /** * for displaying time to standard min:sec @@ -251,19 +259,18 @@ export class Timeline extends React.Component { const inSeconds = Math.round(time * 100) / 100; const min = Math.floor(inSeconds / 60); - const sec = (Math.round((inSeconds % 60) * 100) / 100); + const sec = Math.round((inSeconds % 60) * 100) / 100; let secString = sec.toFixed(2); if (Math.floor(sec / 10) === 0) { - secString = "0" + secString; + secString = '0' + secString; } return `${min}:${secString}`; - } - + }; /** - * timeline zoom function + * timeline zoom function * use mouse middle button to zoom in/out the timeline */ @action @@ -271,17 +278,16 @@ export class Timeline extends React.Component { e.preventDefault(); e.stopPropagation(); const offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; - const prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); - const prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + const prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, 'mili', 'time', this._tickSpacing, this._tickIncrement); + const prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, 'mili', 'time', this._tickSpacing, this._tickIncrement); this.zoom(e.deltaY < 0); - const currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); - const currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); + const currPixel = KeyframeFunc.convertPixelTime(prevTime, 'mili', 'pixel', this._tickSpacing, this._tickIncrement); + const currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, 'mili', 'pixel', this._tickSpacing, this._tickIncrement); this._infoContainer.current!.scrollLeft = currPixel - offset; this._visibleStart = currPixel - offset > 0 ? currPixel - offset : 0; this._visibleStart += this._visibleLength + this._visibleStart > this._totalLength ? this._totalLength - (this._visibleStart + this._visibleLength) : 0; this.changeCurrentBarX(currCurrent); - } - + }; resetView(doc: Doc) { doc._panX = doc._customOriginX ?? 0; @@ -324,7 +330,7 @@ export class Timeline extends React.Component { this._tickSpacing = spacingChange; this._tickIncrement = incrementChange; } - } + }; /** * tool box includes the toggle buttons at the top of the timeline (both editing mode and play mode) @@ -333,60 +339,90 @@ export class Timeline extends React.Component { const size = 40 * scale; //50 is default const iconSize = 25; const width: number = this.props.PanelWidth(); - const modeType = this.props.Document.isATOn ? "Author" : "Play"; + const modeType = this.props.Document.isATOn ? 'Author' : 'Play'; //decides if information should be omitted because the timeline is very small // if its less than 950 pixels then it's going to be overlapping - let modeString = modeType, overviewString = "", lengthString = ""; + let modeString = modeType, + overviewString = '', + lengthString = ''; if (width < 850) { - modeString = "Mode: " + modeType; - overviewString = "Overview:"; - lengthString = "Length: "; + modeString = 'Mode: ' + modeType; + overviewString = 'Overview:'; + lengthString = 'Length: '; } return (
-
-
-
+
+ {' '} + {' '} +
+
+ {' '} + {' '} +
+
+ {' '} + {' '} +
-
{overviewString}
- +
+ {overviewString} +
+
-
{modeString}
+
+ {modeString} +
-
+
+ {' '} +
-
+
{this.timeIndicator(lengthString, totalTime)} -
this.resetView(this.props.Document)}>
-
this.setView(this.props.Document)}>
+
this.resetView(this.props.Document)}> + +
+
this.setView(this.props.Document)}> + +
); - } + }; timeIndicator(lengthString: string, totalTime: number) { if (this.props.Document.isATOn) { - return ( -
{`Total: ${this.toReadTime(totalTime)}`}
- ); - } - else { + return
{`Total: ${this.toReadTime(totalTime)}`}
; + } else { const ctime = `Current: ${this.getCurrentTime()}`; const ttime = `Total: ${this.toReadTime(this._time)}`; return ( -
-
+
+
{ctime}
-
+
{ttime}
@@ -402,7 +438,7 @@ export class Timeline extends React.Component { e.preventDefault(); e.stopPropagation(); this.toggleHandle(); - } + }; /** * turns on the toggle button (the purple slide button that changes from editing mode and play mode @@ -415,23 +451,22 @@ export class Timeline extends React.Component { this.props.Document.isATOn = !this.props.Document.isATOn; if (!BoolCast(this.props.Document.isATOn)) { //turning on playmode... - roundToggle.style.transform = "translate(0px, 0px)"; - roundToggle.style.animationName = "turnoff"; - roundToggleContainer.style.animationName = "turnoff"; - roundToggleContainer.style.backgroundColor = "white"; + roundToggle.style.transform = 'translate(0px, 0px)'; + roundToggle.style.animationName = 'turnoff'; + roundToggleContainer.style.animationName = 'turnoff'; + roundToggleContainer.style.backgroundColor = 'white'; timelineContainer.style.top = `${-this._containerHeight}px`; this.toPlay(); } else { //turning on authoring mode... - roundToggle.style.transform = "translate(20px, 0px)"; - roundToggle.style.animationName = "turnon"; - roundToggleContainer.style.animationName = "turnon"; - roundToggleContainer.style.backgroundColor = "#9acedf"; - timelineContainer.style.top = "0px"; + roundToggle.style.transform = 'translate(20px, 0px)'; + roundToggle.style.animationName = 'turnon'; + roundToggleContainer.style.animationName = 'turnon'; + roundToggleContainer.style.backgroundColor = '#9acedf'; + timelineContainer.style.top = '0px'; this.toAuthoring(); } - } - + }; @action.bound changeLengths() { @@ -443,9 +478,9 @@ export class Timeline extends React.Component { // @computed getCurrentTime = () => { - const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + const current = KeyframeFunc.convertPixelTime(this._currentBarX, 'mili', 'time', this._tickSpacing, this._tickIncrement); return this.toReadTime(current > this._time ? this._time : current); - } + }; @observable private mapOfTracks: (Track | null)[] = []; @@ -465,22 +500,22 @@ export class Timeline extends React.Component { } }); return longestTime; - } + }; @action toAuthoring = () => { this._time = Math.ceil((this.findLongestTime() ?? 1) / 100000) * 100000; - this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); - } + this._totalLength = KeyframeFunc.convertPixelTime(this._time, 'mili', 'pixel', this._tickSpacing, this._tickIncrement); + }; @action toPlay = () => { this._time = this.findLongestTime(); - this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); - } + this._totalLength = KeyframeFunc.convertPixelTime(this._time, 'mili', 'pixel', this._tickSpacing, this._tickIncrement); + }; /** - * if you have any question here, just shoot me an email or text. + * if you have any question here, just shoot me an email or text. * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { @@ -488,23 +523,46 @@ export class Timeline extends React.Component { // change visible and total width return ( -
-
+
+
{this.drawTicks()}
-
+
- {this.children.map(doc => - this.mapOfTracks.push(ref)} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={true} /> - )} + {this.children.map(doc => ( + this.mapOfTracks.push(ref)} + node={doc} + currentBarX={this._currentBarX} + changeCurrentBarX={this.changeCurrentBarX} + transform={this.props.ScreenToLocalTransform()} + time={this._time} + tickSpacing={this._tickSpacing} + tickIncrement={this._tickIncrement} + collection={this.props.Document} + timelineVisible={true} + /> + ))}
Current: {this.getCurrentTime()}
- {this.children.map(doc =>
{ Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

{doc.title}

)} + {this.children.map(doc => ( +
{ + Doc.BrushDoc(doc); + }} + onPointerOut={() => { + Doc.UnBrushDoc(doc); + }}> +

{StrCast(doc.title)}

+
+ ))}
@@ -515,4 +573,4 @@ export class Timeline extends React.Component {
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 37589974b..7d40cab8c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,37 +1,36 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { CursorProperty } from "csstype"; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { List } from "../../../fields/List"; -import { listSpec } from "../../../fields/Schema"; -import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; -import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; -import { Docs, DocUtils } from "../../documents/Documents"; -import { DragManager, dropActionType } from "../../util/DragManager"; -import { SnappingManager } from "../../util/SnappingManager"; -import { Transform } from "../../util/Transform"; -import { undoBatch } from "../../util/UndoManager"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { EditableView } from "../EditableView"; -import { LightboxView } from "../LightboxView"; -import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView"; -import { StyleProp } from "../StyleProvider"; -import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; -import "./CollectionStackingView.scss"; -import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; -import { CollectionSubView } from "./CollectionSubView"; -import { CollectionViewType } from "./CollectionView"; -import { FieldViewProps } from "../nodes/FieldView"; -import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; -const _global = (window /* browser */ || global /* node */) as any; - +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { CursorProperty } from 'csstype'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { listSpec } from '../../../fields/Schema'; +import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { TraceMobx } from '../../../fields/util'; +import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; +import { Docs, DocUtils } from '../../documents/Documents'; +import { DragManager, dropActionType } from '../../util/DragManager'; +import { SnappingManager } from '../../util/SnappingManager'; +import { Transform } from '../../util/Transform'; +import { undoBatch } from '../../util/UndoManager'; +import { ContextMenu } from '../ContextMenu'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { EditableView } from '../EditableView'; +import { LightboxView } from '../LightboxView'; +import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { StyleProp } from '../StyleProvider'; +import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; +import './CollectionStackingView.scss'; +import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn'; +import { CollectionSubView } from './CollectionSubView'; +import { CollectionViewType } from './CollectionView'; +import { FieldViewProps } from '../nodes/FieldView'; +import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; +const _global = (window /* browser */ || global) /* node */ as any; export type collectionStackingViewProps = { chromeHidden?: boolean; @@ -46,27 +45,50 @@ export class CollectionStackingView extends CollectionSubView(); _pivotFieldDisposer?: IReactionDisposer; _autoHeightDisposer?: IReactionDisposer; - _docXfs: { height: () => number, width: () => number, stackedDocTransform: () => Transform }[] = []; + _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = []; _columnStart: number = 0; @observable _heightMap = new Map(); - @observable _cursor: CursorProperty = "grab"; + @observable _cursor: CursorProperty = 'grab'; @observable _scroll = 0; // used to force the document decoration to update when scrolling - @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); } - @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); } - @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); } - @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); } - @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); } - @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } - @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); } - @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); } - @computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking; } - @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } - @computed get showAddAGroup() { return this.pivotField && !this.chromeHidden; } + @computed get chromeHidden() { + return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); + } + @computed get columnHeaders() { + return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); + } + @computed get pivotField() { + return StrCast(this.layoutDoc._pivotField); + } + @computed get filteredChildren() { + return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout); + } + @computed get headerMargin() { + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); + } + @computed get xMargin() { + return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, 0.05 * this.props.PanelWidth())); + } + @computed get yMargin() { + return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); + } // 2 * this.gridGap)); } + @computed get gridGap() { + return NumCast(this.layoutDoc._gridGap, 10); + } + @computed get isStackingView() { + return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking; + } + @computed get numGroupColumns() { + return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; + } + @computed get showAddAGroup() { + return this.pivotField && !this.chromeHidden; + } @computed get columnWidth() { - return Math.min(this.props.PanelWidth() - 2 * this.xMargin, - this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250)); + return Math.min(this.props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250)); + } + @computed get NodeWidth() { + return this.props.PanelWidth() - this.gridGap; } - @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } constructor(props: any) { super(props); @@ -84,21 +106,23 @@ export class CollectionStackingView extends CollectionSubView this.getDocWidth(d); const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` }; - return
- {this.getDisplayDoc(d, width)} -
; + return ( +
+ {this.getDisplayDoc(d, width)} +
+ ); }); - } + }; @action setDocHeight = (key: string, sectionHeight: number) => { this._heightMap.set(key, sectionHeight); - } + }; get Sections() { if (!this.pivotField || this.columnHeaders instanceof Promise) return new Map(); if (this.columnHeaders === undefined) { - setTimeout(() => this.layoutDoc._columnHeaders = new List(), 0); + setTimeout(() => (this.layoutDoc._columnHeaders = new List()), 0); return new Map(); } const columnHeaders = Array.from(this.columnHeaders); @@ -114,8 +138,7 @@ export class CollectionStackingView extends CollectionSubView sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`)); if (existingHeader) { fields.get(existingHeader)!.push(d); - } - else { + } else { const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`); fields.set(newSchemaHeader, [d]); columnHeaders.push(newSchemaHeader); @@ -124,13 +147,19 @@ export class CollectionStackingView extends CollectionSubView !fields.get(key)!.length).map(header => { - fields.delete(header); - columnHeaders.splice(columnHeaders.indexOf(header), 1); - changed = true; - }); + Array.from(fields.keys()) + .filter(key => !fields.get(key)!.length) + .map(header => { + fields.delete(header); + columnHeaders.splice(columnHeaders.indexOf(header), 1); + changed = true; + }); } - changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0); + changed && + setTimeout( + action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), + 0 + ); return fields; } @@ -140,13 +169,19 @@ export class CollectionStackingView extends CollectionSubView this.pivotField, - () => this.layoutDoc._columnHeaders = new List() + () => (this.layoutDoc._columnHeaders = new List()) + ); + this._autoHeightDisposer = reaction( + () => this.layoutDoc._autoHeight, + autoHeight => + autoHeight && + this.props.setHeight?.( + Math.min( + NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), + this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0)) + ) + ) ); - this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, - autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), - this.headerMargin + (this.isStackingView ? - Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) : - this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0))))); } componentWillUnmount() { @@ -158,45 +193,50 @@ export class CollectionStackingView extends CollectionSubView boolean): boolean => { return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; - } + }; createRef = (ele: HTMLDivElement | null) => { this._masonryGridRef = ele; this.createDashEventsTarget(ele!); //so the whole grid is the drop target? - } + }; - @computed get onChildClickHandler() { return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); } - @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } + @computed get onChildClickHandler() { + return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); + } + @computed get onChildDoubleClickHandler() { + return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); + } addDocTab = (doc: Doc, where: string) => { - if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { + if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; } return this.props.addDocTab(doc, where); - } + }; scrollToBottom = () => { smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); - } + }; focusDocument = (doc: Doc, options?: DocFocusOptions) => { Doc.BrushDoc(doc); let focusSpeed = 0; - const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]); + const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const top = found.getBoundingClientRect().top; const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0) { - smoothScroll(focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); + smoothScroll((focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop); } } const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing; this.props.focus(this.rootDoc, { - willZoom: options?.willZoom, scale: options?.scale, afterFocus: (didFocus: boolean) => - new Promise(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)) + willZoom: options?.willZoom, + scale: options?.scale, + afterFocus: (didFocus: boolean) => new Promise(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)), }); - } + }; styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === StyleProp.Opacity && doc) { @@ -208,85 +248,88 @@ export class CollectionStackingView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && ["Enter"].includes(e.key) && e.ctrlKey) { + if (docView && ['Enter'].includes(e.key) && e.ctrlKey) { e.stopPropagation?.(); - const below = !e.altKey && e.key !== "Tab"; + const below = !e.altKey && e.key !== 'Tab'; const layoutKey = StrCast(docView.LayoutFieldKey); const newDoc = Doc.MakeCopy(docView.rootDoc, true); const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) { + if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) { newDoc[layoutKey] = docView.rootDoc[layoutKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SelectOnLoad = newDoc[Id]; return this.addDocument?.(newDoc); } - } + }; isContentActive = () => this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined; + isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); getDisplayDoc(doc: Doc, width: () => number) { - const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc; + const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); let dref: Opt; const stackedDocTransform = () => this.getDocTransform(doc, dref); this._docXfs.push({ stackedDocTransform, width, height }); - return dref = r || undefined} - Document={doc} - DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])} - renderDepth={this.props.renderDepth + 1} - PanelWidth={width} - PanelHeight={height} - styleProvider={this.styleProvider} - docViewPath={this.props.docViewPath} - fitWidth={this.props.childFitWidth} - isContentActive={this.isChildContentActive} - onKey={this.onKeyDown} - isDocumentActive={this.isContentActive} - LayoutTemplate={this.props.childLayoutTemplate} - LayoutTemplateString={this.props.childLayoutString} - NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox - NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined} - dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined} - dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} - rootSelected={this.rootSelected} - showTitle={this.props.childShowTitle} - dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} - ScreenToLocalTransform={stackedDocTransform} - focus={this.focusDocument} - docFilters={this.childDocFilters} - hideDecorationTitle={this.props.childHideDecorationTitle?.()} - hideResizeHandles={this.props.childHideResizeHandles?.()} - hideTitle={this.props.childHideTitle?.()} - docRangeFilters={this.childDocRangeFilters} - searchFilterDocs={this.searchFilterDocs} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} - addDocument={this.props.addDocument} - moveDocument={this.props.moveDocument} - removeDocument={this.props.removeDocument} - contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} - whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.addDocTab} - bringToFront={returnFalse} - scriptContext={this.props.scriptContext} - pinToPres={this.props.pinToPres} - />; + return ( + (dref = r || undefined)} + Document={doc} + DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])} + renderDepth={this.props.renderDepth + 1} + PanelWidth={width} + PanelHeight={height} + styleProvider={this.styleProvider} + docViewPath={this.props.docViewPath} + fitWidth={this.props.childFitWidth} + isContentActive={this.isChildContentActive} + onKey={this.onKeyDown} + isDocumentActive={this.isContentActive} + LayoutTemplate={this.props.childLayoutTemplate} + LayoutTemplateString={this.props.childLayoutString} + NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox + NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined} + dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined} + dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} + rootSelected={this.rootSelected} + showTitle={this.props.childShowTitle} + dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType} + onClick={this.onChildClickHandler} + onDoubleClick={this.onChildDoubleClickHandler} + ScreenToLocalTransform={stackedDocTransform} + focus={this.focusDocument} + docFilters={this.childDocFilters} + hideDecorationTitle={this.props.childHideDecorationTitle?.()} + hideResizeHandles={this.props.childHideResizeHandles?.()} + hideTitle={this.props.childHideTitle?.()} + docRangeFilters={this.childDocRangeFilters} + searchFilterDocs={this.searchFilterDocs} + ContainingCollectionDoc={this.props.CollectionView?.props.Document} + ContainingCollectionView={this.props.CollectionView} + addDocument={this.props.addDocument} + moveDocument={this.props.moveDocument} + removeDocument={this.props.removeDocument} + contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} + whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} + addDocTab={this.addDocTab} + bringToFront={returnFalse} + scriptContext={this.props.scriptContext} + pinToPres={this.props.pinToPres} + /> + ); } getDocTransform(doc: Doc, dref?: DocumentView) { const y = this._scroll; // required for document decorations to update when the text box container is scrolled const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined); - // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off - return new Transform(- translateX + (dref?.centeringX || 0), - translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale); + // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off + return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale); } getDocWidth(d?: Doc) { if (!d) return 0; @@ -300,37 +343,42 @@ export class CollectionStackingView extends CollectionSubView lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1)); + const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS ? undefined : this.props.DataDoc; + const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0); const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0); if (nw && nh) { const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); - return Math.min( - maxHeight, - docWid * nh / nw); + return Math.min(maxHeight, (docWid * nh) / nw); } const childHeight = NumCast(childLayoutDoc._height); - const panelHeight = (childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; + const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; return Math.min(childHeight, maxHeight, panelHeight); } columnDividerDown = (e: React.PointerEvent) => { - runInAction(() => this._cursor = "grabbing"); - setupMoveUpEvents(this, e, this.onDividerMove, action(() => this._cursor = "grab"), emptyFunction); - } + runInAction(() => (this._cursor = 'grabbing')); + setupMoveUpEvents( + this, + e, + this.onDividerMove, + action(() => (this._cursor = 'grab')), + emptyFunction + ); + }; @action onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => { this.layoutDoc._columnWidth = Math.max(10, this.columnWidth + delta[0]); return false; - } + }; @computed get columnDragger() { - return
- -
; + return ( +
+ +
+ ); } @undoBatch @@ -341,7 +389,10 @@ export class CollectionStackingView extends CollectionSubView { - const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + const pos = cd + .stackedDocTransform() + .inverse() + .transformPoint(-2 * this.gridGap, -2 * this.gridGap); const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height()); if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { dropInd = i; @@ -358,21 +409,19 @@ export class CollectionStackingView extends CollectionSubView this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0); + const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0); newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1)); docs.splice(insertInd - offset, 0, ...newDocs); } } - } - else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { - const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, _fitWidth: true, title: "dropped annotation" }); + } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { + const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' }); this.props.addDocument?.(source); - de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed + de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, 'doc annotation', ''); // TODODO this is where in text links get passed e.stopPropagation(); - } - else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); + } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); return false; - } + }; @undoBatch internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) { @@ -390,7 +439,10 @@ export class CollectionStackingView extends CollectionSubView { - const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + const pos = cd + .stackedDocTransform() + .inverse() + .transformPoint(-2 * this.gridGap, -2 * this.gridGap); const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height()); if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { targInd = i; @@ -406,98 +458,103 @@ export class CollectionStackingView extends CollectionSubView Array.from(this.Sections); refList: any[] = []; sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { const key = this.pivotField; - let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined; if (this.pivotField) { const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { type = types[0]; } } - return this.refList.splice(this.refList.indexOf(ref), 1)} - observeHeight={ref => { - if (ref) { - this.refList.push(ref); - this.observer = new _global.ResizeObserver(action((entries: any) => { - if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { - const height = this.headerMargin + - Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), - Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))))); - if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) { - this.props.setHeight?.(height); - } - } - })); - this.observer.observe(ref); - } - }} - addDocument={this.addDocument} - chromeHidden={this.chromeHidden} - columnHeaders={this.columnHeaders} - Document={this.props.Document} - DataDoc={this.props.DataDoc} - renderChildren={this.children} - columnWidth={this.columnWidth} - numGroupColumns={this.numGroupColumns} - gridGap={this.gridGap} - pivotField={this.pivotField} - key={heading?.heading ?? ""} - headings={this.headings} - heading={heading?.heading ?? ""} - headingObject={heading} - docList={docList} - yMargin={this.yMargin} - type={type} - createDropTarget={this.createDashEventsTarget} - screenToLocalTransform={this.props.ScreenToLocalTransform} - />; - } + return ( + this.refList.splice(this.refList.indexOf(ref), 1)} + observeHeight={ref => { + if (ref) { + this.refList.push(ref); + this.observer = new _global.ResizeObserver( + action((entries: any) => { + if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); + if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) { + this.props.setHeight?.(height); + } + } + }) + ); + this.observer.observe(ref); + } + }} + addDocument={this.addDocument} + chromeHidden={this.chromeHidden} + columnHeaders={this.columnHeaders} + Document={this.props.Document} + DataDoc={this.props.DataDoc} + renderChildren={this.children} + columnWidth={this.columnWidth} + numGroupColumns={this.numGroupColumns} + gridGap={this.gridGap} + pivotField={this.pivotField} + key={heading?.heading ?? ''} + headings={this.headings} + heading={heading?.heading ?? ''} + headingObject={heading} + docList={docList} + yMargin={this.yMargin} + type={type} + createDropTarget={this.createDashEventsTarget} + screenToLocalTransform={this.props.ScreenToLocalTransform} + /> + ); + }; sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => { const key = this.pivotField; - let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined; const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { type = types[0]; } - const rows = () => !this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, - Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); - return this.refList.splice(this.refList.indexOf(ref), 1)} - observeHeight={(ref) => { - if (ref) { - this.refList.push(ref); - this.observer = new _global.ResizeObserver(action((entries: any) => { - if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { - const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0); - this.props.setHeight?.(this.headerMargin + height); - } - })); - this.observer.observe(ref); - } - }} - key={heading ? heading.heading : ""} - rows={rows} - headings={this.headings} - heading={heading ? heading.heading : ""} - headingObject={heading} - docList={docList} - parent={this} - type={type} - createDropTarget={this.createDashEventsTarget} - screenToLocalTransform={this.props.ScreenToLocalTransform} - setDocHeight={this.setDocHeight} - />; - } + const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))))); + return ( + this.refList.splice(this.refList.indexOf(ref), 1)} + observeHeight={ref => { + if (ref) { + this.refList.push(ref); + this.observer = new _global.ResizeObserver( + action((entries: any) => { + if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0); + this.props.setHeight?.(this.headerMargin + height); + } + }) + ); + this.observer.observe(ref); + } + }} + key={heading ? heading.heading : ''} + rows={rows} + headings={this.headings} + heading={heading ? heading.heading : ''} + headingObject={heading} + docList={docList} + parent={this} + type={type} + createDropTarget={this.createDashEventsTarget} + screenToLocalTransform={this.props.ScreenToLocalTransform} + setDocHeight={this.setDocHeight} + /> + ); + }; @action addGroup = (value: string) => { @@ -507,25 +564,25 @@ export class CollectionStackingView extends CollectionSubView { - const descending = StrCast(this.layoutDoc._columnsSort) === "descending"; + const descending = StrCast(this.layoutDoc._columnsSort) === 'descending'; const firstEntry = descending ? b : a; const secondEntry = descending ? a : b; return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1; - } + }; onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!e.isPropagationStopped()) { const subItems: ContextMenuProps[] = []; - subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" }); - subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); + subItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' }); + subItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' }); + subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' }); + ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' }); } - } + }; @computed get renderedSections() { TraceMobx(); @@ -534,7 +591,7 @@ export class CollectionStackingView extends CollectionSubView this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0)); + return sections.map((section, i) => (this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0))); } @computed get buttonMenu() { @@ -544,85 +601,90 @@ export class CollectionStackingView extends CollectionSubView - 35} - PanelHeight={() => 35} - renderDepth={this.props.renderDepth} - focus={emptyFunction} - styleProvider={this.props.styleProvider} - docViewPath={returnEmptyDoclist} - whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} - docFilters={this.props.docFilters} - docRangeFilters={this.props.docRangeFilters} - searchFilterDocs={this.props.searchFilterDocs} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - /> -
+ return ( +
+ 35} + PanelHeight={() => 35} + renderDepth={this.props.renderDepth} + focus={emptyFunction} + styleProvider={this.props.styleProvider} + docViewPath={returnEmptyDoclist} + whenChildContentsActiveChanged={emptyFunction} + bringToFront={emptyFunction} + docFilters={this.props.docFilters} + docRangeFilters={this.props.docRangeFilters} + searchFilterDocs={this.props.searchFilterDocs} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + /> +
); } } + @computed get nativeWidth() { + return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); + } + @computed get nativeHeight() { + return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); + } - @computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); } - @computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); } - - @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; } + @computed get scaling() { + return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; + } - @computed get backgroundEvents() { return SnappingManager.GetIsDragging(); } + @computed get backgroundEvents() { + return SnappingManager.GetIsDragging(); + } observer: any; render() { TraceMobx(); const editableViewProps = { - GetValue: () => "", + GetValue: () => '', SetValue: this.addGroup, - contents: "+ ADD A GROUP" + contents: '+ ADD A GROUP', }; const buttonMenu = this.rootDoc.buttonMenu; const noviceExplainer = this.rootDoc.explainer; return ( <> - {buttonMenu || noviceExplainer ?
- {buttonMenu ? this.buttonMenu : null} - {Doc.noviceMode && noviceExplainer ? -
- {noviceExplainer} -
- : null - } -
: null} -
-
+ {buttonMenu ? this.buttonMenu : null} + {Doc.noviceMode && noviceExplainer ?
{StrCast(noviceExplainer)}
: null} +
+ ) : null} +
+
this._scroll = e.currentTarget.scrollTop)} + onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} - onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > + onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}> {this.renderedSections} - {!this.showAddAGroup ? (null) : -
+ {!this.showAddAGroup ? null : ( +
-
} +
+ )} {/* {this.chromeHidden || !this.props.isSelected() ? (null) :
- ); } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ba72fb7b9..f5b9162d3 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,5 @@ -import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; -import { observer } from "mobx-react"; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -11,27 +11,27 @@ import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnF import { DocUtils } from '../../documents/Documents'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DocumentManager } from '../../util/DocumentManager'; -import { DragManager, dropActionType } from "../../util/DragManager"; +import { DragManager, dropActionType } from '../../util/DragManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { EditableView } from "../EditableView"; +import { EditableView } from '../EditableView'; import { DocumentView } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView } from "./CollectionSubView"; -import "./CollectionTreeView.scss"; -import { TreeView } from "./TreeView"; -import React = require("react"); -import { FieldViewProps } from "../nodes/FieldView"; -const _global = (window /* browser */ || global /* node */) as any; +import { CollectionSubView } from './CollectionSubView'; +import './CollectionTreeView.scss'; +import { TreeView } from './TreeView'; +import React = require('react'); +import { FieldViewProps } from '../nodes/FieldView'; +const _global = (window /* browser */ || global) /* node */ as any; export type collectionTreeViewProps = { - treeViewExpandedView?: "fields" | "layout" | "links" | "data"; + treeViewExpandedView?: 'fields' | 'layout' | 'links' | 'data'; treeViewOpen?: boolean; treeViewHideTitle?: boolean; treeViewHideHeaderFields?: boolean; @@ -45,9 +45,9 @@ export type collectionTreeViewProps = { }; export enum TreeViewType { - outline = "outline", - fileSystem = "fileSystem", - default = "default" + outline = 'outline', + fileSystem = 'fileSystem', + default = 'default', } @observer @@ -61,13 +61,28 @@ export class CollectionTreeView extends CollectionSubView this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); - isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.ActiveTool !== InkTool.None || - (this.props.isContentActive?.() || this.props.Document.forceActive || - this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || - this.props.rootSelected(outsideReaction)) ? true : false) + whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); + isContentActive = (outsideReaction?: boolean) => + CurrentUserUtils.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction) + ? true + : false; componentWillUnmount() { this._isDisposing = true; @@ -89,47 +104,51 @@ export class CollectionTreeView extends CollectionSubView this.rootDoc.autoHeight, + this._disposers.autoheight = reaction( + () => this.rootDoc.autoHeight, auto => auto && this.computeHeight(), - { fireImmediately: true }); + { fireImmediately: true } + ); } computeHeight = () => { if (!this._isDisposing) { - const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace("px", "")); - const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), this.marginBot()); + const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', '')); + const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()); this.layoutDoc._autoHeightMargins = bodyHeight; this.props.setHeight?.(bodyHeight + titleHeight); } - } + }; unobserveHeight = (ref: any) => { this.refList.delete(ref); this.rootDoc.autoHeight && this.computeHeight(); - } + }; observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); - this.observer = new _global.ResizeObserver(action((entries: any) => { - if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { - this.computeHeight(); - } - })); + this.observer = new _global.ResizeObserver( + action((entries: any) => { + if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { + this.computeHeight(); + } + }) + ); this.rootDoc.autoHeight && this.computeHeight(); this.observer.observe(ref); } - } + }; protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer?.(); - if (this._mainEle = ele) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this)); - } + if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this)); + }; protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { const dragData = de.complete.docDragData; if (dragData) { const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); - dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction; + dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction; } - } + }; @action remove = (doc: Doc | Doc[]): boolean => { @@ -149,7 +168,7 @@ export class CollectionTreeView extends CollectionSubView, before?: boolean): boolean => { @@ -161,81 +180,85 @@ export class CollectionTreeView extends CollectionSubView { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!Doc.noviceMode) { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: "Make tree state " + (this.doc.treeViewOpenIsTransient ? "persistent" : "transient"), event: () => this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient, icon: "paint-brush" }); - layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields, icon: "paint-brush" }); - layoutItems.push({ description: (this.doc.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle, icon: "paint-brush" }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); - const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); - const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - onClicks.push({ description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" }); - !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); + layoutItems.push({ description: 'Make tree state ' + (this.doc.treeViewOpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeViewHideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle), icon: 'paint-brush' }); + ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); + const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); + const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; + onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' }); + !existingOnClick && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } - } + }; onTreeDrop = (e: React.DragEvent, addDocs?: (docs: Doc[]) => void) => this.onExternalDrop(e, {}, addDocs); @undoBatch makeTextCollection = (childDocs: Doc[]) => { this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true); - } + }; get editableTitle() { - return StrCast(this.dataDoc.title)} - SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); - this.dataDoc.title = value; - return true; - })} />; + return ( + StrCast(this.dataDoc.title)} + SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { + if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); + this.dataDoc.title = value; + return true; + })} + /> + ); } - onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - if (this.outlineMode && e.key === "Enter") { + if (this.outlineMode && e.key === 'Enter') { e.stopPropagation(); this.makeTextCollection(this.treeChildren); return true; } - } + }; get documentTitle() { - return ; + return ( + + ); } childContextMenuItems = () => { const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []); const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []); const icons = StrListCast(this.doc.childContextMenuIcons); return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); - } + }; @computed get treeViewElements() { TraceMobx(); const dropAction = StrCast(this.doc.childDropAction) as dropActionType; @@ -266,36 +289,34 @@ export class CollectionTreeView extends CollectionSubView this._titleRef = r}> + return this.dataDoc === null ? null : ( +
(this._titleRef = r)}> {this.outlineMode ? this.documentTitle : this.editableTitle} -
; +
+ ); } @computed get noviceExplainer() { - return !Doc.noviceMode || !this.rootDoc.explainer ? (null) : -
{this.rootDoc.explainer}
; + return !Doc.noviceMode || !this.rootDoc.explainer ? null :
{StrCast(this.rootDoc.explainer)}
; } return35 = () => 35; @computed get buttonMenu() { const menuDoc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); // To create a multibutton menu add a CollectionLinearView - return !menuDoc ? null : - (
+ return !menuDoc ? null : ( +
-
); +
+ ); } - @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); } - @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); } + @computed get nativeWidth() { + return Doc.NativeWidth(this.Document, undefined, true); + } + @computed get nativeHeight() { + return Doc.NativeHeight(this.Document, undefined, true); + } @computed get contentScaling() { const nw = this.nativeWidth; @@ -347,68 +373,73 @@ export class CollectionTreeView extends CollectionSubView this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => - this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false + this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false; contentFunc = () => { const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); - const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined; - const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? (null) : this.titleBar; + const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined); + const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; return [ -
+
{titleBar} -
- {!this.buttonMenu && !this.noviceExplainer ? (null) : + {!this.buttonMenu && !this.noviceExplainer ? null : (
r && (this._explainerHeight = r.getBoundingClientRect().height))}> {this.buttonMenu} {this.noviceExplainer}
- } -
e.stopPropagation()} onDrop={this.onTreeDrop} ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}> -
    - {this.treeViewElements} -
-
+
    {this.treeViewElements}
+
-
+
, ]; - } + }; render() { TraceMobx(); - return !(this.doc instanceof Doc) || !this.treeChildren ? (null) : - this.doc.treeViewHasOverlay ? - - {this.contentFunc} - : - this.contentFunc(); + return !(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( + + {this.contentFunc} + + ) : ( + this.contentFunc() + ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2ae0c01ef..d788f9a77 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,5 +1,5 @@ import { computed, observable, runInAction } from 'mobx'; -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; import * as React from 'react'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app import { Doc, DocListCast } from '../../../fields/Doc'; @@ -14,66 +14,65 @@ import { BranchCreate, BranchTask } from '../../documents/Gitlike'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { InteractionUtils } from '../../util/InteractionUtils'; -import { ContextMenu } from "../ContextMenu"; +import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; -import { CollectionDockingView } from "./CollectionDockingView"; +import { CollectionDockingView } from './CollectionDockingView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionGridView } from './collectionGrid/CollectionGridView'; import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; import { CollectionPileView } from './CollectionPileView'; -import { CollectionSchemaView } from "./collectionSchema/CollectionSchemaView"; +import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; import { CollectionStackingView } from './CollectionStackingView'; import { SubCollectionViewProps } from './CollectionSubView'; import { CollectionTimeView } from './CollectionTimeView'; -import { CollectionTreeView } from "./CollectionTreeView"; +import { CollectionTreeView } from './CollectionTreeView'; import './CollectionView.scss'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); export enum CollectionViewType { - Invalid = "invalid", - Freeform = "freeform", - Schema = "schema", - Docking = "docking", + Invalid = 'invalid', + Freeform = 'freeform', + Schema = 'schema', + Docking = 'docking', Tree = 'tree', - Stacking = "stacking", - Masonry = "masonry", - Multicolumn = "multicolumn", - Multirow = "multirow", - Time = "time", - Carousel = "carousel", - Carousel3D = "3D Carousel", - Linear = "linear", + Stacking = 'stacking', + Masonry = 'masonry', + Multicolumn = 'multicolumn', + Multirow = 'multirow', + Time = 'time', + Carousel = 'carousel', + Carousel3D = '3D Carousel', + Linear = 'linear', //Staff = "staff", - Map = "map", - Grid = "grid", - Pile = "pileup", - StackedTimeline = "stacked timeline" + Map = 'map', + Grid = 'grid', + Pile = 'pileup', + StackedTimeline = 'stacked timeline', } -export interface CollectionViewProps extends FieldViewProps { - isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) +interface CollectionViewProps_ extends FieldViewProps { + isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently) layoutEngine?: () => string; setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; // property overrides for child documents - children?: never | (() => JSX.Element[]) | React.ReactNode; childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) - childDocumentsActive?: () => boolean;// whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) + childDocumentsActive?: () => boolean; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) childFitWidth?: (child: Doc) => boolean; childShowTitle?: () => string; childOpacity?: () => number; - childContextMenuItems?: () => { script: ScriptField, label: string }[]; + childContextMenuItems?: () => { script: ScriptField; label: string }[]; childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children childHideDecorationTitle?: () => boolean; childHideResizeHandles?: () => boolean; - childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection + childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection childLayoutString?: string; childIgnoreNativeSize?: boolean; childClickScript?: ScriptField; @@ -81,20 +80,25 @@ export interface CollectionViewProps extends FieldViewProps { //TODO: [AL] add these fields AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; - hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) + hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) } +export interface CollectionViewProps extends React.PropsWithChildren {} @observer export class CollectionView extends ViewBoxAnnotatableComponent() { - public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } + public static LayoutString(fieldStr: string) { + return FieldView.LayoutString(CollectionView, fieldStr); + } @observable private static _safeMode = false; - public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; } + public static SetSafeMode(safeMode: boolean) { + this._safeMode = safeMode; + } protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; constructor(props: any) { super(props); - runInAction(() => this._annotationKeySuffix = returnEmptyString); + runInAction(() => (this._annotationKeySuffix = returnEmptyString)); } get collectionViewType(): CollectionViewType | undefined { @@ -102,15 +106,17 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - return (null); + return null; // this section would display an icon in the bototm right of a collection to indicate that all // photos had been processed through Google's content analysis API and Google's tags had been // assigned to the documents googlePhotosTags field. @@ -119,136 +125,171 @@ export class CollectionView extends ViewBoxAnnotatableComponent 0 && imageProtos.every(image => image.googlePhotosTags); // return !allTagged ? (null) : ; //this.isContentActive(); - } + }; - screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()); + screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth())); private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => { TraceMobx(); if (type === undefined) return null; switch (type) { default: - case CollectionViewType.Freeform: return ; - case CollectionViewType.Schema: return ; - case CollectionViewType.Docking: return ; - case CollectionViewType.Tree: return ; - case CollectionViewType.Multicolumn: return ; - case CollectionViewType.Multirow: return ; - case CollectionViewType.Linear: return ; - case CollectionViewType.Pile: return ; - case CollectionViewType.Carousel: return ; - case CollectionViewType.Carousel3D: return ; - case CollectionViewType.Stacking: return ; - case CollectionViewType.Masonry: return ; - case CollectionViewType.Time: return ; - case CollectionViewType.Grid: return ; + case CollectionViewType.Freeform: + return ; + case CollectionViewType.Schema: + return ; + case CollectionViewType.Docking: + return ; + case CollectionViewType.Tree: + return ; + case CollectionViewType.Multicolumn: + return ; + case CollectionViewType.Multirow: + return ; + case CollectionViewType.Linear: + return ; + case CollectionViewType.Pile: + return ; + case CollectionViewType.Carousel: + return ; + case CollectionViewType.Carousel3D: + return ; + case CollectionViewType.Stacking: + return ; + case CollectionViewType.Masonry: + return ; + case CollectionViewType.Time: + return ; + case CollectionViewType.Grid: + return ; //case CollectionViewType.Staff: return ; } - } + }; setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) { const subItems: ContextMenuProps[] = []; - subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" }); + subItems.push({ description: 'Freeform', event: () => func(CollectionViewType.Freeform), icon: 'signature' }); if (addExtras && CollectionView._safeMode) { - ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" }); + ContextMenu.Instance.addItem({ description: 'Test Freeform', event: () => func(CollectionViewType.Invalid), icon: 'project-diagram' }); } - subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" }); - subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" }); - subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" }); - subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" }); - subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" }); - subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" }); - subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); - subItems.push({ description: "3D Carousel", event: () => func(CollectionViewType.Carousel3D), icon: "columns" }); - !Doc.noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); - !Doc.noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); - subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); + subItems.push({ description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' }); + subItems.push({ description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' }); + subItems.push({ description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' }); + subItems.push({ description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' }); + subItems.push({ description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' }); + subItems.push({ description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' }); + subItems.push({ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' }); + subItems.push({ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' }); + !Doc.noviceMode && subItems.push({ description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' }); + !Doc.noviceMode && subItems.push({ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' }); + subItems.push({ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' }); if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { const existingVm = ContextMenu.Instance.findByDescription(category); - const catItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; - catItems.push({ description: "Add a Perspective...", addDivider: true, noexpand: true, subitems: subItems, icon: "eye" }); - !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: catItems, icon: "eye" }); + const catItems = existingVm && 'subitems' in existingVm ? existingVm.subitems : []; + catItems.push({ description: 'Add a Perspective...', addDivider: true, noexpand: true, subitems: subItems, icon: 'eye' }); + !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: catItems, icon: 'eye' }); } } onContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; if (e.nativeEvent.cancelBubble) return; // nested calls to React to render can cause the same event to trigger in the outer view even if the inner view has handled it. This avoid CollectionDockingView menu options from being added when the event has been handled by a sub-document. - if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - this.setupViewTypes("UI Controls...", vtype => { - const newRendition = Doc.MakeAlias(this.rootDoc); - newRendition._viewType = vtype; - this.props.addDocTab(newRendition, "add:right"); - return newRendition; - }, false); + if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== CurrentUserUtils.MainDocId) { + // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + this.setupViewTypes( + 'UI Controls...', + vtype => { + const newRendition = Doc.MakeAlias(this.rootDoc); + newRendition._viewType = vtype; + this.props.addDocTab(newRendition, 'add:right'); + return newRendition; + }, + false + ); - const options = cm.findByDescription("Options..."); - const optionItems = options && "subitems" in options ? options.subitems : []; - !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; + const options = cm.findByDescription('Options...'); + const optionItems = options && 'subitems' in options ? options.subitems : []; + !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.rootDoc.forceActive = !this.rootDoc.forceActive), icon: 'project-diagram' }) : null; if (this.rootDoc.childLayout instanceof Doc) { - optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" }); + optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, 'add:right'), icon: 'project-diagram' }); } if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { - optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" }); + optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, 'add:right'), icon: 'project-diagram' }); } - !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); + !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' }); if (!Doc.noviceMode) { optionItems.push({ - description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram" + description: 'Create Branch', + event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), 'add:right'), + icon: 'project-diagram', }); optionItems.push({ - description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram" + description: 'Pull Master', + event: () => BranchTask(this.rootDoc, 'pull'), + icon: 'project-diagram', }); optionItems.push({ - description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram" + description: 'Merge Branches', + event: () => BranchTask(this.rootDoc, 'merge'), + icon: 'project-diagram', }); } if (this.Document._viewType === CollectionViewType.Docking) { - optionItems.push({ description: "Create Dashboard", event: () => CurrentUserUtils.createNewDashboard(), icon: "project-diagram" }); + optionItems.push({ description: 'Create Dashboard', event: () => CurrentUserUtils.createNewDashboard(), icon: 'project-diagram' }); } - !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" }); + !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' }); if (!Doc.noviceMode && !this.rootDoc.annotationOn) { - const existingOnClick = cm.findByDescription("OnClick..."); - const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - const funcs = [{ key: "onChildClick", name: "On Child Clicked" }, { key: "onChildDoubleClick", name: "On Child Double Clicked" }]; - funcs.map(func => onClicks.push({ - description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => { - const alias = Doc.MakeAlias(this.rootDoc); - DocUtils.makeCustomViewClicked(alias, undefined, func.key); - this.props.addDocTab(alias, "add:right"); - } - })); - DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick => + const existingOnClick = cm.findByDescription('OnClick...'); + const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; + const funcs = [ + { key: 'onChildClick', name: 'On Child Clicked' }, + { key: 'onChildDoubleClick', name: 'On Child Double Clicked' }, + ]; + funcs.map(func => + onClicks.push({ + description: `Edit ${func.name} script`, + icon: 'edit', + event: (obj: any) => { + const alias = Doc.MakeAlias(this.rootDoc); + DocUtils.makeCustomViewClicked(alias, undefined, func.key); + this.props.addDocTab(alias, 'add:right'); + }, + }) + ); + DocListCast(Cast(Doc.UserDoc()['clickFuncs-child'], Doc, null).data).forEach(childClick => onClicks.push({ description: `Set child ${childClick.title}`, - icon: "edit", - event: () => Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), - })); - !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); + icon: 'edit', + event: () => (Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))), + }) + ); + !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } if (!Doc.noviceMode) { - const more = cm.findByDescription("More..."); - const moreItems = more && "subitems" in more ? more.subitems : []; - moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); - !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); + const more = cm.findByDescription('More...'); + const moreItems = more && 'subitems' in more ? more.subitems : []; + moreItems.push({ description: 'Export Image Hierarchy', icon: 'columns', event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); + !more && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'hand-point-right' }); } } - } + }; bodyPanelWidth = () => this.props.PanelWidth(); childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles); childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle); childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); - @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); } + @computed get childLayoutString() { + return StrCast(this.rootDoc.childLayoutString); + } isContentActive = (outsideReaction?: boolean) => { return this.props.isContentActive(); - } + }; render() { TraceMobx(); const props: SubCollectionViewProps = { @@ -268,10 +309,11 @@ export class CollectionView extends ViewBoxAnnotatableComponent - {this.showIsTagged()} - {this.renderSubView(this.collectionViewType, props)} -
); + return ( +
+ {this.showIsTagged()} + {this.renderSubView(this.collectionViewType, props)} +
+ ); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index dacbb3508..8720c9097 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,25 +1,23 @@ -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import { Id } from "../../../../fields/FieldSymbols"; -import { DocumentManager } from "../../../util/DocumentManager"; -import "./CollectionFreeFormLinksView.scss"; -import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; -import React = require("react"); +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import { Id } from '../../../../fields/FieldSymbols'; +import { DocumentManager } from '../../../util/DocumentManager'; +import './CollectionFreeFormLinksView.scss'; +import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; +import React = require('react'); @observer -export class CollectionFreeFormLinksView extends React.Component { +export class CollectionFreeFormLinksView extends React.Component> { @computed get uniqueConnections() { - return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c => - - ); + return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c => ); } render() { - return
- - {this.uniqueConnections} - - {this.props.children} -
; + return ( +
+ {this.uniqueConnections} + {this.props.children} +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 3d2ed0cf9..3d1d87aa0 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -1,14 +1,13 @@ import * as React from 'react'; -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; -import "../../../../../node_modules/react-grid-layout/css/styles.css"; -import "../../../../../node_modules/react-resizable/css/styles.css"; +import '../../../../../node_modules/react-grid-layout/css/styles.css'; +import '../../../../../node_modules/react-resizable/css/styles.css'; import * as GridLayout from 'react-grid-layout'; import { Layout } from 'react-grid-layout'; export { Layout } from 'react-grid-layout'; - interface GridProps { width: number; nodeList: JSX.Element[] | null; @@ -29,9 +28,10 @@ interface GridProps { @observer export default class Grid extends React.Component { render() { - const compactType = this.props.compactType === "vertical" || this.props.compactType === "horizontal" ? this.props.compactType : null; + const compactType = this.props.compactType === 'vertical' || this.props.compactType === 'horizontal' ? this.props.compactType : null; return ( - { useCSSTransforms={true} onLayoutChange={this.props.setLayout} preventCollision={this.props.preventCollision} - transformScale={1 / this.props.transformScale} // still doesn't work :( - margin={[this.props.margin, this.props.margin]} - > + transformScale={1 / this.props.transformScale} // still doesn't work :( ?? + margin={[this.props.margin, this.props.margin]}> {this.props.nodeList} ); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index c31267e87..8adfdc70b 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -9,7 +9,7 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils'; import { DocUtils } from '../../../documents/Documents'; import { CurrentUserUtils } from '../../../util/CurrentUserUtils'; -import { DocumentManager } from "../../../util/DocumentManager"; +import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { Colors, Shadows } from '../../global/globalEnums'; @@ -21,13 +21,12 @@ import { StyleProp } from '../../StyleProvider'; import { CollectionStackedTimeline } from '../CollectionStackedTimeline'; import { CollectionSubView } from '../CollectionSubView'; import { CollectionViewType } from '../CollectionView'; -import "./CollectionLinearView.scss"; - +import './CollectionLinearView.scss'; /** - * CollectionLinearView is the class for rendering the horizontal collection + * CollectionLinearView is the class for rendering the horizontal collection * of documents, it useful for horizontal menus. It can either be expandable - * or not using the linearViewExpandable field. + * or not using the linearViewExpandable field. * It is used in the following locations: * - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx) * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx) @@ -48,45 +47,47 @@ export class CollectionLinearView extends CollectionSubView() { } componentDidMount() { - this._widthDisposer = reaction(() => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * (this.rootDoc[HeightSym]()) : 10), + this._widthDisposer = reaction( + () => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * this.rootDoc[HeightSym]() : 10), width => this.childDocs.length && (this.layoutDoc._width = width), { fireImmediately: true } ); this._selectedDisposer = reaction( () => NumCast(this.layoutDoc.selectedIndex), - (i) => runInAction(() => { - this._selectedIndex = i; - let selected: any = undefined; - this.childLayoutPairs.map(async (pair, ind) => { - const isSelected = this._selectedIndex === ind; - if (isSelected) { - selected = pair; - } - else { - ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log); + i => + runInAction(() => { + this._selectedIndex = i; + let selected: any = undefined; + this.childLayoutPairs.map(async (pair, ind) => { + const isSelected = this._selectedIndex === ind; + if (isSelected) { + selected = pair; + } else { + ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log); + } + }); + if (selected && selected.layout) { + ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log); } - }); - if (selected && selected.layout) { - ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log); - } - }), + }), { fireImmediately: true } ); } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { + //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } - } + }; dimension = () => NumCast(this.rootDoc._height); // 2 * the padding getTransform = (ele: Opt) => { if (!ele) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ele); return new Transform(-translateX, -translateY, 1); - } + }; @action exitLongLinks = () => { @@ -99,28 +100,27 @@ export class CollectionLinearView extends CollectionSubView() { } DocumentLinksButton.StartLink = undefined; DocumentLinksButton.StartLinkView = undefined; - } + }; @action changeDescriptionSetting = () => { if (LinkDescriptionPopup.showDescriptions) { - if (LinkDescriptionPopup.showDescriptions === "ON") { - LinkDescriptionPopup.showDescriptions = "OFF"; + if (LinkDescriptionPopup.showDescriptions === 'ON') { + LinkDescriptionPopup.showDescriptions = 'OFF'; LinkDescriptionPopup.descriptionPopup = false; } else { - LinkDescriptionPopup.showDescriptions = "ON"; + LinkDescriptionPopup.showDescriptions = 'ON'; } } else { - LinkDescriptionPopup.showDescriptions = "OFF"; + LinkDescriptionPopup.showDescriptions = 'OFF'; LinkDescriptionPopup.descriptionPopup = false; } - } + }; myContextMenu = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); - } - + }; getDisplayDoc = (doc: Doc, preview: boolean = false) => { const nested = doc._viewType === CollectionViewType.Linear; @@ -129,44 +129,50 @@ export class CollectionLinearView extends CollectionSubView() { let dref: Opt; const docXf = () => this.getTransform(dref); // const scalable = pair.layout.onClick || pair.layout.onDragStart; - return hidden ? (null) :
dref = r || undefined} - style={{ - pointerEvents: "all", - width: nested ? undefined : NumCast(doc._width), - height: nested ? undefined : NumCast(doc._height), - marginLeft: !nested ? 2.5 : 0, - marginRight: !nested ? 2.5 : 0, - // width: NumCast(pair.layout._width), - // height: NumCast(pair.layout._height), - }} > - -
; - } + return hidden ? null : ( +
(dref = r || undefined)} + style={{ + pointerEvents: 'all', + width: nested ? undefined : NumCast(doc._width), + height: nested ? undefined : NumCast(doc._height), + marginLeft: !nested ? 2.5 : 0, + marginRight: !nested ? 2.5 : 0, + // width: NumCast(pair.layout._width), + // height: NumCast(pair.layout._height), + }}> + +
+ ); + }; render() { const guid = Utils.GenerateGuid(); // Generate a unique ID to use as the label @@ -178,66 +184,99 @@ export class CollectionLinearView extends CollectionSubView() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); const icon: string = StrCast(this.props.Document.icon); // Menu opener toggle - const menuOpener = ; - - return
-
- {!expandable ? (null) :
{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close" : "Open"}
} placement="top"> - {menuOpener} -
} - this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} /> - -
- {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} -
- {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : - e.stopPropagation()} > - - Creating link from: {DocumentLinksButton.AnnotationId ? "Annotation in " : " "} {StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...'} - + const menuOpener = ( + + ); -
{"Toggle description pop-up"}
} placement="top"> - - Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"} - + return ( +
+
+ {!expandable ? null : ( + +
{BoolCast(this.props.Document.linearViewIsExpanded) ? 'Close' : 'Open'}
+ + } + placement="top"> + {menuOpener}
+ )} + (this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked))} + /> -
Exit linking mode
} placement="top"> - - Stop +
+ {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} +
+ {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : ( + e.stopPropagation()}> + + Creating link from:{' '} + + {(DocumentLinksButton.AnnotationId ? 'Annotation in ' : ' ') + + (StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...')} + -
- } - {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? (null) : - - - Currently playing: - {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => - DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}> - {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")} - )} - - } + +
{'Toggle description pop-up'}
+ + } + placement="top"> + + Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'} + +
+ + +
Exit linking mode
+ + } + placement="top"> + + Stop + +
+ + )} + {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : ( + + + Currently playing: + {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => ( + DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}> + {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '' : ',')} + + ))} + + + )} +
-
; + ); } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 1414bfdf7..ba301962b 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -1,15 +1,14 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from "@material-ui/core"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, NumListCast, StrListCast, Field } from "../../../fields/Doc"; -import { DateCast, StrCast, Cast } from "../../../fields/Types"; -import { LinkManager } from "../../util/LinkManager"; -import { undoBatch } from "../../util/UndoManager"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Tooltip } from '@material-ui/core'; +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc, NumListCast, StrListCast, Field } from '../../../fields/Doc'; +import { DateCast, StrCast, Cast } from '../../../fields/Types'; +import { LinkManager } from '../../util/LinkManager'; +import { undoBatch } from '../../util/UndoManager'; import './LinkEditor.scss'; -import { LinkRelationshipSearch } from "./LinkRelationshipSearch"; -import React = require("react"); - +import { LinkRelationshipSearch } from './LinkRelationshipSearch'; +import React = require('react'); interface LinkEditorProps { sourceDoc: Doc; @@ -19,16 +18,20 @@ interface LinkEditorProps { } @observer export class LinkEditor extends React.Component { - @observable description = Field.toString(LinkManager.currentLink?.description as any as Field); @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship); @observable zoomFollow = StrCast(this.props.sourceDoc.followLinkZoom); @observable openDropdown: boolean = false; @observable showInfo: boolean = false; - @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; } - @observable private buttonColor: string = ""; - @observable private relationshipButtonColor: string = ""; - @observable private relationshipSearchVisibility: string = "none"; + @computed get infoIcon() { + if (this.showInfo) { + return 'chevron-up'; + } + return 'chevron-down'; + } + @observable private buttonColor: string = ''; + @observable private relationshipButtonColor: string = ''; + @observable private relationshipSearchVisibility: string = 'none'; @observable private searchIsActive: boolean = false; //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION"; @@ -37,7 +40,7 @@ export class LinkEditor extends React.Component { deleteLink = (): void => { LinkManager.Instance.deleteLink(this.props.linkDoc); this.props.showLinks(); - } + }; @undoBatch setRelationshipValue = action((value: string) => { @@ -49,11 +52,11 @@ export class LinkEditor extends React.Component { const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); - // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color + // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color if (!linkRelationshipList?.includes(value)) { linkRelationshipList.push(value); linkRelationshipSizes.push(1); - const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")"; + const randColor = 'rgb(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ')'; linkColorList.push(randColor); // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes } else if (linkRelationshipList && value !== prevRelationship) { @@ -61,20 +64,22 @@ export class LinkEditor extends React.Component { //increment size of new relationship size if (index !== -1 && index < linkRelationshipSizes.length) { const pvalue = linkRelationshipSizes[index]; - linkRelationshipSizes[index] = (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1); + linkRelationshipSizes[index] = pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1; } //decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation) if (linkRelationshipList.includes(prevRelationship)) { const pindex = linkRelationshipList.indexOf(prevRelationship); if (pindex !== -1 && pindex < linkRelationshipSizes.length) { const pvalue = linkRelationshipSizes[pindex]; - linkRelationshipSizes[pindex] = Math.max(0, (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue - 1)); + linkRelationshipSizes[pindex] = Math.max(0, pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue - 1); } } - } - this.relationshipButtonColor = "rgb(62, 133, 55)"; - setTimeout(action(() => this.relationshipButtonColor = ""), 750); + this.relationshipButtonColor = 'rgb(62, 133, 55)'; + setTimeout( + action(() => (this.relationshipButtonColor = '')), + 750 + ); return true; } }); @@ -89,144 +94,143 @@ export class LinkEditor extends React.Component { if (linkRelationshipList) { return linkRelationshipList.filter(rel => rel.includes(query)); } - } + }; /** * toggles visibility of the relationship search results when the input field is focused on */ @action toggleRelationshipResults = () => { - this.relationshipSearchVisibility = this.relationshipSearchVisibility === "none" ? "block" : "none"; - } + this.relationshipSearchVisibility = this.relationshipSearchVisibility === 'none' ? 'block' : 'none'; + }; @undoBatch setDescripValue = action((value: string) => { if (LinkManager.currentLink) { Doc.GetProto(LinkManager.currentLink).description = value; - this.buttonColor = "rgb(62, 133, 55)"; - setTimeout(action(() => this.buttonColor = ""), 750); + this.buttonColor = 'rgb(62, 133, 55)'; + setTimeout( + action(() => (this.buttonColor = '')), + 750 + ); return true; } }); onDescriptionKey = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { + if (e.key === 'Enter') { this.setDescripValue(this.description); document.getElementById('input')?.blur(); } e.stopPropagation(); - } + }; onRelationshipKey = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { + if (e.key === 'Enter') { this.setRelationshipValue(this.relationship); document.getElementById('input')?.blur(); } e.stopPropagation(); - } + }; onDescriptionDown = () => this.setDescripValue(this.description); onRelationshipDown = () => this.setRelationshipValue(this.relationship); onBlur = () => { - //only hide the search results if the user clicks out of the input AND not on any of the search results + //only hide the search results if the user clicks out of the input AND not on any of the search results // i.e. if search is not active if (!this.searchIsActive) { this.toggleRelationshipResults(); } - } + }; onFocus = () => { this.toggleRelationshipResults(); - } + }; toggleSearchIsActive = () => { this.searchIsActive = !this.searchIsActive; - } + }; @action - handleDescriptionChange = (e: React.ChangeEvent) => { this.description = e.target.value; } + handleDescriptionChange = (e: React.ChangeEvent) => { + this.description = e.target.value; + }; @action - handleRelationshipChange = (e: React.ChangeEvent) => { this.relationship = e.target.value; } + handleRelationshipChange = (e: React.ChangeEvent) => { + this.relationship = e.target.value; + }; @action - handleZoomFollowChange = (e: React.ChangeEvent) => { this.props.sourceDoc.followLinkZoom = e.target.checked; } + handleZoomFollowChange = (e: React.ChangeEvent) => { + this.props.sourceDoc.followLinkZoom = e.target.checked; + }; @action handleRelationshipSearchChange = (result: string) => { this.setRelationshipValue(result); this.toggleRelationshipResults(); this.relationship = result; - } + }; @computed get editRelationship() { //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS - return
-
Link Relationship:
-
-
- - + return ( +
+
Link Relationship:
+
+
+ + +
+
+ Set +
-
Set
-
; + ); } @computed get editZoomFollow() { //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS - return
-
Zoom To Link Target:
-
-
- + return ( +
+
Zoom To Link Target:
+
+
+ +
-
; + ); } @computed get editDescription() { - return
-
Link Description:
-
-
- + return ( +
+
Link Description:
+
+
+ +
+
+ Set +
-
Set
-
; + ); } @action - changeDropdown = () => { this.openDropdown = !this.openDropdown; } + changeDropdown = () => { + this.openDropdown = !this.openDropdown; + }; @undoBatch changeFollowBehavior = action((follow: string) => { @@ -236,94 +240,114 @@ export class LinkEditor extends React.Component { @computed get followingDropdown() { - return
-
Follow Behavior:
-
-
- {StrCast(this.props.linkDoc.followLinkLocation, "default")} - -
-
-
this.changeFollowBehavior("default")}> - Default + return ( +
+
Follow Behavior:
+
+
+ {StrCast(this.props.linkDoc.followLinkLocation, 'default')} +
-
this.changeFollowBehavior("add:left")}> - Always open in new left pane -
-
this.changeFollowBehavior("add:right")}> - Always open in new right pane -
-
this.changeFollowBehavior("replace:right")}> - Always replace right tab -
-
this.changeFollowBehavior("replace:left")}> - Always replace left tab -
-
this.changeFollowBehavior("fullScreen")}> - Always open full screen -
-
this.changeFollowBehavior("add")}> - Always open in a new tab -
-
this.changeFollowBehavior("replace")}> - Replace Tab -
- {this.props.linkDoc.linksToAnnotation ? -
this.changeFollowBehavior("openExternal")}> - Always open in external page +
+
this.changeFollowBehavior('default')}> + Default +
+
this.changeFollowBehavior('add:left')}> + Always open in new left pane +
+
this.changeFollowBehavior('add:right')}> + Always open in new right pane +
+
this.changeFollowBehavior('replace:right')}> + Always replace right tab +
+
this.changeFollowBehavior('replace:left')}> + Always replace left tab
- : null} +
this.changeFollowBehavior('fullScreen')}> + Always open full screen +
+
this.changeFollowBehavior('add')}> + Always open in a new tab +
+
this.changeFollowBehavior('replace')}> + Replace Tab +
+ {this.props.linkDoc.linksToAnnotation ? ( +
this.changeFollowBehavior('openExternal')}> + Always open in external page +
+ ) : null} +
-
; + ); } @action - changeInfo = () => { this.showInfo = !this.showInfo; } + changeInfo = () => { + this.showInfo = !this.showInfo; + }; render() { const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc); - return !destination ? (null) : ( + return !destination ? null : (
e.stopPropagation()}>
-
Return to link menu
} placement="top"> - + +
Return to link menu
+ + } + placement="top"> +
-

Editing Link to: { - destination.proto?.title ?? destination.title ?? "untitled"}

-
Show more link information
} placement="top"> -
+

+ Editing Link to: {StrCast(destination.proto?.title, StrCast(destination.title, 'untitled'))} +

+ +
Show more link information
+ + } + placement="top"> +
+ +
- {this.showInfo ?
-
{this.props.linkDoc.author ?
Author: {this.props.linkDoc.author}
: null}
-
{this.props.linkDoc.creationDate ?
Creation Date: - {DateCast(this.props.linkDoc.creationDate).toString()}
: null}
-
: null} + {this.showInfo ? ( +
+
+ {this.props.linkDoc.author ? ( +
+ {' '} + Author: {StrCast(this.props.linkDoc.author)} +
+ ) : null} +
+
+ {this.props.linkDoc.creationDate ? ( +
+ {' '} + Creation Date: + {DateCast(this.props.linkDoc.creationDate).toString()} +
+ ) : null} +
+
+ ) : null} {this.editDescription} {this.editRelationship} {this.editZoomFollow} {this.followingDropdown}
- ); } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index a75e7a0c4..1e7f4f10b 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, observable } from 'mobx'; -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { Cast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; @@ -16,8 +16,7 @@ import { undoBatch } from '../../util/UndoManager'; import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import React = require("react"); - +import React = require('react'); interface LinkMenuItemProps { groupType: string; @@ -50,22 +49,21 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume }; const containingView = docView.props.ContainingCollectionView; const finishDrag = (e: DragManager.DragCompleteEvent) => - e.docDragData && (e.docDragData.droppedDocuments = - dragData.draggedDocuments.reduce((droppedDocs, d) => { - const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView); - if (dvs.length) { - dvs.forEach(dv => droppedDocs.push(dv.props.Document)); - } else { - droppedDocs.push(Doc.MakeAlias(d)); - } - return droppedDocs; - }, [] as Doc[])); + e.docDragData && + (e.docDragData.droppedDocuments = dragData.draggedDocuments.reduce((droppedDocs, d) => { + const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView); + if (dvs.length) { + dvs.forEach(dv => droppedDocs.push(dv.props.Document)); + } else { + droppedDocs.push(Doc.MakeAlias(d)); + } + return droppedDocs; + }, [] as Doc[])); DragManager.StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag); } } - @observer export class LinkMenuItem extends React.Component { private _drag = React.createRef(); @@ -74,20 +72,31 @@ export class LinkMenuItem extends React.Component { _buttonRef = React.createRef(); @observable private _showMore: boolean = false; - @action toggleShowMore(e: React.PointerEvent) { e.stopPropagation(); this._showMore = !this._showMore; } + @action toggleShowMore(e: React.PointerEvent) { + e.stopPropagation(); + this._showMore = !this._showMore; + } onEdit = (e: React.PointerEvent): void => { LinkManager.currentLink = this.props.linkDoc; - setupMoveUpEvents(this, e, e => { - const dragData = new DragManager.DocumentDragData([this.props.linkDoc], "alias"); - dragData.removeDropProperties = ["hidden"]; - DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y); - return true; - }, emptyFunction, () => this.props.showEditor(this.props.linkDoc)); - } + setupMoveUpEvents( + this, + e, + e => { + const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'alias'); + dragData.removeDropProperties = ['hidden']; + DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y); + return true; + }, + emptyFunction, + () => this.props.showEditor(this.props.linkDoc) + ); + }; onLinkButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, + setupMoveUpEvents( + this, + e, e => { const eleClone: any = this._drag.current!.cloneNode(true); eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`; @@ -99,109 +108,170 @@ export class LinkMenuItem extends React.Component { () => { this.props.clearLinkEditor(); if (this.props.itemHandler) { - this.props.itemHandler?.(this.props.linkDoc); } else { - const focusDoc = Cast(this.props.linkDoc.anchor1, Doc, null)?.annotationOn === this.props.sourceDoc ? Cast(this.props.linkDoc.anchor1, Doc, null) : - Cast(this.props.linkDoc.anchor2, Doc, null)?.annotationOn === this.props.sourceDoc ? Cast(this.props.linkDoc.anchor12, Doc, null) : undefined; + const focusDoc = + Cast(this.props.linkDoc.anchor1, Doc, null)?.annotationOn === this.props.sourceDoc + ? Cast(this.props.linkDoc.anchor1, Doc, null) + : Cast(this.props.linkDoc.anchor2, Doc, null)?.annotationOn === this.props.sourceDoc + ? Cast(this.props.linkDoc.anchor12, Doc, null) + : undefined; if (focusDoc) this.props.docView.ComponentView?.scrollFocus?.(focusDoc, true); LinkManager.FollowLink(this.props.linkDoc, this.props.sourceDoc, this.props.docView.props, false); } - }); - } + } + ); + }; deleteLink = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => { - this.props.linkDoc.linksToAnnotation && Hypothesis.deleteLink(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc); - LinkManager.Instance.deleteLink(this.props.linkDoc); - }))); - } + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoBatch( + action(() => { + this.props.linkDoc.linksToAnnotation && Hypothesis.deleteLink(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc); + LinkManager.Instance.deleteLink(this.props.linkDoc); + }) + ) + ); + }; autoMove = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove))); - } + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove)))); + }; showLink = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.props.linkDoc.linkDisplay = !this.props.linkDoc.linkDisplay))); - } + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkDisplay = !this.props.linkDoc.linkDisplay)))); + }; showAnchor = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.props.linkDoc.hidden = !this.props.linkDoc.hidden))); - } + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.hidden = !this.props.linkDoc.hidden)))); + }; render() { const destinationIcon = Doc.toIcon(this.props.destinationDoc) as any as IconProp; - const title = StrCast(this.props.destinationDoc.title).length > 18 ? - StrCast(this.props.destinationDoc.title).substr(0, 14) + "..." : this.props.destinationDoc.title; + const title = StrCast(this.props.destinationDoc.title).length > 18 ? StrCast(this.props.destinationDoc.title).substr(0, 14) + '...' : this.props.destinationDoc.title; // ... // from anika to bob: here's where the text that is specifically linked would show up (linkDoc.storedText) // ... - const source = this.props.sourceDoc.type === DocumentType.RTF ? this.props.linkDoc.storedText ? - StrCast(this.props.linkDoc.storedText).length > 17 ? - StrCast(this.props.linkDoc.storedText).substr(0, 18) - : this.props.linkDoc.storedText : undefined : undefined; + const source = + this.props.sourceDoc.type === DocumentType.RTF + ? this.props.linkDoc.storedText + ? StrCast(this.props.linkDoc.storedText).length > 17 + ? StrCast(this.props.linkDoc.storedText).substr(0, 18) + : this.props.linkDoc.storedText + : undefined + : undefined; return (
-
- -
+
this.props.linkDoc && LinkDocPreview.SetLinkInfo({ - docProps: this.props.docView.props, - linkSrc: this.props.sourceDoc, - linkDoc: this.props.linkDoc, - showHeader: false, - location: [e.clientX, e.clientY + 20] - })} + onPointerEnter={e => + this.props.linkDoc && + LinkDocPreview.SetLinkInfo({ + docProps: this.props.docView.props, + linkSrc: this.props.sourceDoc, + linkDoc: this.props.linkDoc, + showHeader: false, + location: [e.clientX, e.clientY + 20], + }) + } onPointerDown={this.onLinkButtonDown}> -
- {source ?

Source: {source}

: null} + {source ? ( +

+ {' '} + Source: {StrCast(source)} +

+ ) : null}
-
+

- {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? "Annotation in" : ""} {title} + {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}

- {!this.props.linkDoc.description ? (null) :

{StrCast(this.props.linkDoc.description)}

} + {!this.props.linkDoc.description ? null :

{StrCast(this.props.linkDoc.description)}

}
-
- -
{this.props.linkDoc.hidden ? "Show Link Anchor" : "Hide Link Anchor"}
}> -
e.stopPropagation()}> -
+
+ +
{this.props.linkDoc.hidden ? 'Show Link Anchor' : 'Hide Link Anchor'}
+ + }> +
e.stopPropagation()}> + +
-
{this.props.linkDoc.linkDisplay ? "Hide Link Line" : "Show Link Line"}
}> -
e.stopPropagation()}> -
+ +
{this.props.linkDoc.linkDisplay ? 'Hide Link Line' : 'Show Link Line'}
+ + }> +
e.stopPropagation()}> + +
-
{this.props.linkDoc.linkAutoMove ? "Click to freeze link anchor position" : "Click to auto move link anchor"}
}> -
e.stopPropagation()}> -
+ +
{this.props.linkDoc.linkAutoMove ? 'Click to freeze link anchor position' : 'Click to auto move link anchor'}
+ + }> +
e.stopPropagation()}> + +
-
Edit Link
}> + +
Edit Link
+ + }>
e.stopPropagation()}> -
+ +
-
Delete Link
}> + +
Delete Link
+ + }>
e.stopPropagation()}> -
+ +
- -
+
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 96ac3e332..f1d8123da 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,48 +1,48 @@ -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import { AclPrivate, Doc, Opt } from "../../../fields/Doc"; -import { ScriptField } from "../../../fields/ScriptField"; -import { Cast, StrCast } from "../../../fields/Types"; -import { GetEffectiveAcl, TraceMobx } from "../../../fields/util"; -import { emptyPath, OmitKeys, Without } from "../../../Utils"; -import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import { CollectionSchemaView } from "../collections/collectionSchema/CollectionSchemaView"; -import { CollectionView } from "../collections/CollectionView"; -import { InkingStroke } from "../InkingStroke"; -import { PresElementBox } from "../nodes/trails/PresElementBox"; -import { SearchBox } from "../search/SearchBox"; -import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo"; -import { YoutubeBox } from "./../../apis/youtube/YoutubeBox"; -import { AudioBox } from "./AudioBox"; -import { FontIconBox } from "./button/FontIconBox"; -import { ColorBox } from "./ColorBox"; -import { ComparisonBox } from "./ComparisonBox"; -import { DataVizBox } from "./DataVizBox/DataVizBox"; -import { DocumentViewProps } from "./DocumentView"; -import "./DocumentView.scss"; -import { EquationBox } from "./EquationBox"; -import { FieldView, FieldViewProps } from "./FieldView"; -import { FilterBox } from "./FilterBox"; -import { FormattedTextBox, FormattedTextBoxProps } from "./formattedText/FormattedTextBox"; -import { FunctionPlotBox } from "./FunctionPlotBox"; -import { ImageBox } from "./ImageBox"; -import { KeyValueBox } from "./KeyValueBox"; -import { LabelBox } from "./LabelBox"; -import { LinkAnchorBox } from "./LinkAnchorBox"; -import { LinkBox } from "./LinkBox"; -import { MapBox } from "./MapBox/MapBox"; -import { PDFBox } from "./PDFBox"; -import { RecordingBox } from "./RecordingBox"; -import { ScreenshotBox } from "./ScreenshotBox"; -import { ScriptingBox } from "./ScriptingBox"; -import { SliderBox } from "./SliderBox"; -import { PresBox } from "./trails/PresBox"; -import { VideoBox } from "./VideoBox"; -import { WebBox } from "./WebBox"; -import React = require("react"); -import XRegExp = require("xregexp"); +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import { AclPrivate, Doc, Opt } from '../../../fields/Doc'; +import { ScriptField } from '../../../fields/ScriptField'; +import { Cast, StrCast } from '../../../fields/Types'; +import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; +import { emptyPath, OmitKeys, Without } from '../../../Utils'; +import { DirectoryImportBox } from '../../util/Import & Export/DirectoryImportBox'; +import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { CollectionSchemaView } from '../collections/collectionSchema/CollectionSchemaView'; +import { CollectionView } from '../collections/CollectionView'; +import { InkingStroke } from '../InkingStroke'; +import { PresElementBox } from '../nodes/trails/PresElementBox'; +import { SearchBox } from '../search/SearchBox'; +import { DashWebRTCVideo } from '../webcam/DashWebRTCVideo'; +import { YoutubeBox } from './../../apis/youtube/YoutubeBox'; +import { AudioBox } from './AudioBox'; +import { FontIconBox } from './button/FontIconBox'; +import { ColorBox } from './ColorBox'; +import { ComparisonBox } from './ComparisonBox'; +import { DataVizBox } from './DataVizBox/DataVizBox'; +import { DocumentViewProps } from './DocumentView'; +import './DocumentView.scss'; +import { EquationBox } from './EquationBox'; +import { FieldView, FieldViewProps } from './FieldView'; +import { FilterBox } from './FilterBox'; +import { FormattedTextBox, FormattedTextBoxProps } from './formattedText/FormattedTextBox'; +import { FunctionPlotBox } from './FunctionPlotBox'; +import { ImageBox } from './ImageBox'; +import { KeyValueBox } from './KeyValueBox'; +import { LabelBox } from './LabelBox'; +import { LinkAnchorBox } from './LinkAnchorBox'; +import { LinkBox } from './LinkBox'; +import { MapBox } from './MapBox/MapBox'; +import { PDFBox } from './PDFBox'; +import { RecordingBox } from './RecordingBox'; +import { ScreenshotBox } from './ScreenshotBox'; +import { ScriptingBox } from './ScriptingBox'; +import { SliderBox } from './SliderBox'; +import { PresBox } from './trails/PresBox'; +import { VideoBox } from './VideoBox'; +import { WebBox } from './WebBox'; +import React = require('react'); +import XRegExp = require('xregexp'); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -60,7 +60,6 @@ class ObserverJsxParser1 extends JsxParser { const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; - interface HTMLtagProps { Document: Doc; RootDoc: Doc; @@ -68,16 +67,17 @@ interface HTMLtagProps { onClick?: ScriptField; onInput?: ScriptField; scaling: number; + children?: JSX.Element[]; } //" {this.title}" -//" // -// // {this.title} // @@ -87,45 +87,51 @@ export class HTMLtag extends React.Component { click = (e: React.MouseEvent) => { const clickScript = (this.props as any).onClick as Opt; clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, scale: this.props.scaling }); - } + }; onInput = (e: React.FormEvent) => { const onInputScript = (this.props as any).onInput as Opt; onInputScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, value: (e.target as any).textContent }); - } + }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "scaling", "Document", "key", "onInput", "onClick", "__proto__"]).omit; - const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value - return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string || ""; + const divKeys = OmitKeys(this.props, ['children', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; + const replacer = (match: any, expr: string, offset: any, string: any) => { + // bcz: this executes a script to convert a propery expression string: { script } into a value + return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer); }); const Tag = this.props.htmltag as keyof JSX.IntrinsicElements; - return - {this.props.children} - ; + return ( + + {this.props.children} + + ); } } @observer -export class DocumentContentsView extends React.Component boolean, - select: (ctrl: boolean) => void, - scaling?: () => number, - setHeight?: (height: number) => void, - layoutKey: string, -}> { +export class DocumentContentsView extends React.Component< + DocumentViewProps & + FormattedTextBoxProps & { + isSelected: (outsideReaction: boolean) => boolean; + select: (ctrl: boolean) => void; + scaling?: () => number; + setHeight?: (height: number) => void; + layoutKey: string; + } +> { @computed get layout(): string { TraceMobx(); if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString; - if (!this.layoutDoc) return "

awaiting layout

"; - if (this.props.layoutKey === "layout_keyValue") return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data")); - const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, "layout")], "string"); - if (layout === undefined) return this.props.Document.data ? "" : KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : ""); - if (typeof layout === "string") return layout; - return "

Loading layout

"; + if (!this.layoutDoc) return '

awaiting layout

'; + if (this.props.layoutKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString('data')); + const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, 'layout')], 'string'); + if (layout === undefined) return this.props.Document.data ? "" : KeyValueBox.LayoutString(this.layoutDoc.proto ? 'proto' : ''); + if (typeof layout === 'string') return layout; + return '

Loading layout

'; } get dataDoc() { @@ -136,36 +142,39 @@ export class DocumentContentsView extends React.Component, onInput: Opt): JsxBindings { - const docOnlyProps = [ // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews - "hideResizeHandles", - "hideTitle", - "treeViewDoc", - "contentPointerEvents", - "radialMenu", - "LayoutTemplateString", - "LayoutTemplate", - "dontCenter", - "ContentScaling", - "contextMenuItems", - "onClick", - "onDoubleClick", - "onPointerDown", - "onPointerUp", + const docOnlyProps = [ + // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews + 'hideResizeHandles', + 'hideTitle', + 'treeViewDoc', + 'contentPointerEvents', + 'radialMenu', + 'LayoutTemplateString', + 'LayoutTemplate', + 'dontCenter', + 'ContentScaling', + 'contextMenuItems', + 'onClick', + 'onDoubleClick', + 'onPointerDown', + 'onPointerUp', ]; const list = { - ...OmitKeys(this.props, [...docOnlyProps], "").omit, + ...OmitKeys(this.props, [...docOnlyProps], '').omit, RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, onClick: onClick, - onInput: onInput + onInput: onInput, }; return { props: list }; } @@ -180,17 +189,17 @@ export class DocumentContentsView extends React.Component{content}< as in {this.title} const replacer = (match: any, prefix: string, expr: string, postfix: string, offset: any, string: any) => { - return prefix + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + postfix; + return prefix + ((ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string) || '') + postfix; }; layoutFrame = layoutFrame.replace(/(>[^{]*)[^=]\{([^.'][^<}]+)\}([^}]*<)/g, replacer); - // replace HTML with corresponding HTML tag as in: becomes + // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { return ` with as in: becomes + // replace /HTML with
as in: becomes const replacer3 = (match: any, p1: string, offset: any, string: any) => { return ` { const splits = layoutFrame.split(`${func}=`); if (splits.length > 1) { - const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] }); + const code = XRegExp.matchRecursive(splits[1], '{', '}', '', { valueNames: ['between', 'left', 'match', 'right', 'between'] }); layoutFrame = splits[0] + ` ${func}={props.${func}} ` + splits[1].substring(code[1].end + 1); - const script = code[1].value.replace(/^‘/, "").replace(/’$/, ""); // ‘’ are not valid quotes in javascript so get rid of them -- they may be present to make it easier to write complex scripts - see headerTemplate in currentUserUtils.ts - return ScriptField.MakeScript(script, { this: Doc.name, self: Doc.name, scale: "number", value: "string" }); + const script = code[1].value.replace(/^‘/, '').replace(/’$/, ''); // ‘’ are not valid quotes in javascript so get rid of them -- they may be present to make it easier to write complex scripts - see headerTemplate in currentUserUtils.ts + return ScriptField.MakeScript(script, { this: Doc.name, self: Doc.name, scale: 'number', value: 'string' }); } return undefined; // add input function to props }; - const onClick = makeFuncProp("onClick"); - const onInput = makeFuncProp("onInput"); + const onClick = makeFuncProp('onClick'); + const onInput = makeFuncProp('onInput'); const bindings = this.CreateBindings(onClick, onInput); return { bindings, layoutFrame }; } @@ -218,23 +227,55 @@ export class DocumentContentsView extends React.Component 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate) ? (null) : + return this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate ? null : ( { console.log("DocumentContentsView:" + test); }} - />; + onError={(test: any) => { + console.log('DocumentContentsView:' + test); + }} + /> + ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 6c7e174f7..47d5c662e 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -1,19 +1,19 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; -import { observer } from "mobx-react"; -import wiki from "wikijs"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocCastAsync } from "../../../fields/Doc"; -import { NumCast, StrCast, Cast } from "../../../fields/Types"; -import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, setupMoveUpEvents, Utils } from "../../../Utils"; +import { observer } from 'mobx-react'; +import wiki from 'wikijs'; +import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocCastAsync } from '../../../fields/Doc'; +import { NumCast, StrCast, Cast } from '../../../fields/Types'; +import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils'; import { DocServer } from '../../DocServer'; -import { Docs, DocUtils } from "../../documents/Documents"; +import { Docs, DocUtils } from '../../documents/Documents'; import { LinkManager } from '../../util/LinkManager'; -import { Transform } from "../../util/Transform"; +import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; -import { DocumentView, DocumentViewSharedProps } from "./DocumentView"; +import { DocumentView, DocumentViewSharedProps } from './DocumentView'; import './LinkDocPreview.scss'; -import React = require("react"); +import React = require('react'); import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; @@ -27,15 +27,19 @@ interface LinkDocPreviewProps { } @observer export class LinkDocPreview extends React.Component { - @action public static Clear() { LinkDocPreview.LinkInfo = undefined; } - @action public static SetLinkInfo(info?: LinkDocPreviewProps) { LinkDocPreview.LinkInfo !== info && (LinkDocPreview.LinkInfo = info); } + @action public static Clear() { + LinkDocPreview.LinkInfo = undefined; + } + @action public static SetLinkInfo(info?: LinkDocPreviewProps) { + LinkDocPreview.LinkInfo !== info && (LinkDocPreview.LinkInfo = info); + } _infoRef = React.createRef(); @observable public static LinkInfo: Opt; @observable _targetDoc: Opt; @observable _linkDoc: Opt; @observable _linkSrc: Opt; - @observable _toolTipText = ""; + @observable _toolTipText = ''; @observable _hrefInd = 0; @action init() { @@ -47,113 +51,136 @@ export class LinkDocPreview extends React.Component { if (anchor1 && anchor2) { linkTarget = Doc.AreProtosEqual(anchor1, this._linkSrc) || Doc.AreProtosEqual(anchor1?.annotationOn as Doc, this._linkSrc) ? anchor2 : anchor1; } - if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { // want to show annotation context document if annotation is not text - linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => this._targetDoc = anno)); + if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { + // want to show annotation context document if annotation is not text + linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._targetDoc = anno))); } else { this._targetDoc = linkTarget; } - this._toolTipText = ""; + this._toolTipText = ''; } componentDidUpdate(props: any) { if (props.linkSrc !== this.props.linkSrc || props.linkDoc !== this.props.linkDoc || props.hrefs !== this.props.hrefs) this.init(); } componentDidMount() { this.init(); - document.addEventListener("pointerdown", this.onPointerDown); + document.addEventListener('pointerdown', this.onPointerDown); } componentWillUnmount() { LinkDocPreview.SetLinkInfo(undefined); - document.removeEventListener("pointerdown", this.onPointerDown); + document.removeEventListener('pointerdown', this.onPointerDown); } onPointerDown = (e: PointerEvent) => { !this._infoRef.current?.contains(e.target as any) && LinkDocPreview.Clear(); // close preview when not clicking anywhere other than the info bar of the preview - } + }; @computed get href() { if (this.props.hrefs?.length) { const href = this.props.hrefs[this._hrefInd]; - if (href.indexOf(Doc.localServerPath()) !== 0) { // link to a web page URL -- try to show a preview - if (href.startsWith("https://en.wikipedia.org/wiki/")) { - wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500)))); + if (href.indexOf(Doc.localServerPath()) !== 0) { + // link to a web page URL -- try to show a preview + if (href.startsWith('https://en.wikipedia.org/wiki/')) { + wiki() + .page(href.replace('https://en.wikipedia.org/wiki/', '')) + .then(page => page.summary().then(action(summary => (this._toolTipText = summary.substring(0, 500))))); } else { - setTimeout(action(() => this._toolTipText = "url => " + href)); + setTimeout(action(() => (this._toolTipText = 'url => ' + href))); } - } else { // hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated - const anchorDoc = href.replace(Doc.localServerPath(), "").split("?")[0]; - anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => { - if (anchor instanceof Doc && DocListCast(anchor.links).length) { - this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0]; - const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords; - if (automaticLink) { // automatic links specify the target in the link info, not the source - const linkTarget = anchor; - this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget); - this._targetDoc = linkTarget; - } else { - this._linkSrc = anchor; - const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); - this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; - } - this._toolTipText = ""; - } - })); + } else { + // hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated + const anchorDoc = href.replace(Doc.localServerPath(), '').split('?')[0]; + anchorDoc && + DocServer.GetRefField(anchorDoc).then( + action(anchor => { + if (anchor instanceof Doc && DocListCast(anchor.links).length) { + this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0]; + const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords; + if (automaticLink) { + // automatic links specify the target in the link info, not the source + const linkTarget = anchor; + this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget); + this._targetDoc = linkTarget; + } else { + this._linkSrc = anchor; + const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); + this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; + } + this._toolTipText = ''; + } + }) + ); } return href; } return undefined; } deleteLink = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(() => this._linkDoc && LinkManager.Instance.deleteLink(this._linkDoc))); - } + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoBatch(() => this._linkDoc && LinkManager.Instance.deleteLink(this._linkDoc)) + ); + }; nextHref = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => { - const nextHrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1); - if (nextHrefInd !== this._hrefInd) { - this._linkDoc = undefined; - this._hrefInd = nextHrefInd; - } - }), true); - } + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + action(() => { + const nextHrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1); + if (nextHrefInd !== this._hrefInd) { + this._linkDoc = undefined; + this._hrefInd = nextHrefInd; + } + }), + true + ); + }; followLink = (e: React.PointerEvent) => { if (this._linkDoc && this._linkSrc) { LinkDocPreview.Clear(); LinkManager.FollowLink(this._linkDoc, this._linkSrc, this.props.docProps, false); } else if (this.props.hrefs?.length) { - this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), "add:right"); + this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), 'add:right'); } - } + }; width = () => { if (!this._targetDoc) return 225; if (this._targetDoc[WidthSym]() < this._targetDoc?.[HeightSym]()) { - return Math.min(225, this._targetDoc[HeightSym]()) * this._targetDoc[WidthSym]() / this._targetDoc[HeightSym](); + return (Math.min(225, this._targetDoc[HeightSym]()) * this._targetDoc[WidthSym]()) / this._targetDoc[HeightSym](); } return Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225)); - } + }; height = () => { if (!this._targetDoc) return 225; if (this._targetDoc[WidthSym]() > this._targetDoc?.[HeightSym]()) { - return Math.min(225, this._targetDoc[WidthSym]()) * this._targetDoc[HeightSym]() / this._targetDoc[WidthSym](); + return (Math.min(225, this._targetDoc[WidthSym]()) * this._targetDoc[HeightSym]()) / this._targetDoc[WidthSym](); } return Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)); - } + }; @computed get previewHeader() { - return !this._linkDoc || !this._targetDoc || !this._linkSrc ? (null) : + return !this._linkDoc || !this._targetDoc || !this._linkSrc ? null : (
-
{ - DragManager.StartDocumentDrag([this._infoRef.current!], - new DragManager.DocumentDragData([this._targetDoc!]), e.pageX, e.pageY); + DragManager.StartDocumentDrag([this._infoRef.current!], new DragManager.DocumentDragData([this._targetDoc!]), e.pageX, e.pageY); e.stopPropagation(); LinkDocPreview.Clear(); }}> - {StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + "..." : this._targetDoc.title} + {StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + '...' : StrCast(this._targetDoc.title)}

{StrCast(this._linkDoc.description)}

-
+
Next Link
} placement="top"> -
+
@@ -164,20 +191,24 @@ export class LinkDocPreview extends React.Component {
-
; +
+ ); } @computed get docPreview() { const href = this.href; // needs to be here to trigger lookup of web pages and docs on server - return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? (null) : + return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? null : (
- {!this.props.showHeader ? (null) : this.previewHeader} -
- {this._toolTipText ? this._toolTipText : - { - const targetanchor = this._linkDoc && this._linkSrc && LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); - targetanchor && this._targetDoc !== targetanchor && r?.focus(targetanchor); - }} + {!this.props.showHeader ? null : this.previewHeader} +
+ {this._toolTipText ? ( + this._toolTipText + ) : ( + { + const targetanchor = this._linkDoc && this._linkSrc && LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); + targetanchor && this._targetDoc !== targetanchor && r?.focus(targetanchor); + }} Document={this._targetDoc!} moveDocument={returnFalse} rootSelected={returnFalse} @@ -206,16 +237,19 @@ export class LinkDocPreview extends React.Component { bringToFront={returnFalse} NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined} NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined} - />} + /> + )}
-
; +
+ ); } render() { const borders = 16; // 8px border on each side - return
- {this.docPreview} -
; + return ( +
+ {this.docPreview} +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 0b7264d79..18a6b5453 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api'; import { action, computed, IReactionDisposer, observable, ObservableMap } from 'mobx'; -import { observer } from "mobx-react"; -import * as React from "react"; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; @@ -22,17 +22,17 @@ import { Annotation } from '../../pdf/Annotation'; import { SidebarAnnos } from '../../SidebarAnnos'; import { StyleProp } from '../../StyleProvider'; import { FieldView, FieldViewProps } from '../FieldView'; -import "./MapBox.scss"; +import './MapBox.scss'; import { MapBoxInfoWindow } from './MapBoxInfoWindow'; /** * MapBox architecture: * Main component: MapBox.tsx * Supporting Components: SidebarAnnos, CollectionStackingView - * - * MapBox is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content. - * The main body of MapBox uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view. - * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available, + * + * MapBox is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content. + * The main body of MapBox uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view. + * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available, * sidebarAddDocument function checks if the document contains lat & lng information, if it does, then the document is added to both the sidebar and the infowindow (a pop up corresponding to a map marker--pin on map). * The lat and lng field of the document is filled when importing (spec see ConvertDMSToDD method and processFileUpload method in Documents.ts). * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps @@ -77,26 +77,30 @@ document.head.appendChild(script); // }, // }); - // options for searchbox in Google Maps Places Autocomplete API const options = { - fields: ["formatted_address", "geometry", "name"], // note: level of details is charged by item per retrieval, not recommended to return all fields + fields: ['formatted_address', 'geometry', 'name'], // note: level of details is charged by item per retrieval, not recommended to return all fields strictBounds: false, - types: ["establishment"], // type pf places, subject of change according to user need + types: ['establishment'], // type pf places, subject of change according to user need } as google.maps.places.AutocompleteOptions; @observer export class MapBox extends ViewBoxAnnotatableComponent>() { - private _dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [name: string]: IReactionDisposer } = {}; private _annotationLayer: React.RefObject = React.createRef(); @observable private _overlayAnnoInfo: Opt; - showInfo = action((anno: Opt) => this._overlayAnnoInfo = anno); - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBox, fieldKey); } - public get SidebarKey() { return this.fieldKey + "-sidebar"; } + showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(MapBox, fieldKey); + } + public get SidebarKey() { + return this.fieldKey + '-sidebar'; + } private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); - @computed get inlineTextAnnotations() { return this.allMapMarkers.filter(a => a.textInlineAnnotations); } + @computed get inlineTextAnnotations() { + return this.allMapMarkers.filter(a => a.textInlineAnnotations); + } @observable private _map: google.maps.Map = null as unknown as google.maps.Map; @observable private selectedPlace: Doc | undefined; @@ -108,14 +112,19 @@ export class MapBox extends ViewBoxAnnotatableComponent(); - @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); } - @computed get allMapMarkers() { return DocListCast(this.dataDoc[this.annotationKey]); } + @computed get allSidebarDocs() { + return DocListCast(this.dataDoc[this.SidebarKey]); + } + @computed get allMapMarkers() { + return DocListCast(this.dataDoc[this.annotationKey]); + } @observable private toggleAddMarker = false; private _mainCont: React.RefObject = React.createRef(); - @observable _showSidebar = false; - @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } + @computed get SidebarShown() { + return this._showSidebar || this.layoutDoc._showSidebar ? true : false; + } static _canAnnotate = true; static _hadSelection: boolean = false; @@ -129,109 +138,106 @@ export class MapBox extends ViewBoxAnnotatableComponent { this.searchBox = searchBox; - } + }; // iterate allMarkers to size, center, and zoom map to contain all markers private fitBounds = (map: google.maps.Map) => { const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds(); - const isFitting = this.allMapMarkers.reduce((fits, place) => - fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean); - !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => - bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), - new window.google.maps.LatLngBounds())); - } + const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean); + !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds())); + }; /** * Custom control for add marker button - * @param controlDiv - * @param map + * @param controlDiv + * @param map */ private CenterControl = () => { - const controlDiv = document.createElement("div"); - controlDiv.className = "mapBox-addMarker"; + const controlDiv = document.createElement('div'); + controlDiv.className = 'mapBox-addMarker'; // Set CSS for the control border. - const controlUI = document.createElement("div"); - controlUI.style.backgroundColor = "#fff"; - controlUI.style.borderRadius = "3px"; - controlUI.style.cursor = "pointer"; - controlUI.style.marginTop = "10px"; - controlUI.style.borderRadius = "4px"; - controlUI.style.marginBottom = "22px"; - controlUI.style.textAlign = "center"; - controlUI.style.position = "absolute"; - controlUI.style.width = "32px"; - controlUI.style.height = "32px"; - controlUI.title = "Click to toggle marker mode. In marker mode, click on map to place a marker."; - - const plIcon = document.createElement("img"); - plIcon.src = "https://cdn4.iconfinder.com/data/icons/wirecons-free-vector-icons/32/add-256.png"; - plIcon.style.color = "rgb(25,25,25)"; - plIcon.style.fontFamily = "Roboto,Arial,sans-serif"; - plIcon.style.fontSize = "16px"; - plIcon.style.lineHeight = "32px"; - plIcon.style.left = "18"; - plIcon.style.top = "15"; - plIcon.style.position = "absolute"; + const controlUI = document.createElement('div'); + controlUI.style.backgroundColor = '#fff'; + controlUI.style.borderRadius = '3px'; + controlUI.style.cursor = 'pointer'; + controlUI.style.marginTop = '10px'; + controlUI.style.borderRadius = '4px'; + controlUI.style.marginBottom = '22px'; + controlUI.style.textAlign = 'center'; + controlUI.style.position = 'absolute'; + controlUI.style.width = '32px'; + controlUI.style.height = '32px'; + controlUI.title = 'Click to toggle marker mode. In marker mode, click on map to place a marker.'; + + const plIcon = document.createElement('img'); + plIcon.src = 'https://cdn4.iconfinder.com/data/icons/wirecons-free-vector-icons/32/add-256.png'; + plIcon.style.color = 'rgb(25,25,25)'; + plIcon.style.fontFamily = 'Roboto,Arial,sans-serif'; + plIcon.style.fontSize = '16px'; + plIcon.style.lineHeight = '32px'; + plIcon.style.left = '18'; + plIcon.style.top = '15'; + plIcon.style.position = 'absolute'; plIcon.width = 14; plIcon.height = 14; - plIcon.innerHTML = "Add"; + plIcon.innerHTML = 'Add'; controlUI.appendChild(plIcon); // Set CSS for the control interior. - const markerIcon = document.createElement("img"); - markerIcon.src = "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-1024.png"; - markerIcon.style.color = "rgb(25,25,25)"; - markerIcon.style.fontFamily = "Roboto,Arial,sans-serif"; - markerIcon.style.fontSize = "16px"; - markerIcon.style.lineHeight = "32px"; - markerIcon.style.left = "-2"; - markerIcon.style.top = "1"; + const markerIcon = document.createElement('img'); + markerIcon.src = 'https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-1024.png'; + markerIcon.style.color = 'rgb(25,25,25)'; + markerIcon.style.fontFamily = 'Roboto,Arial,sans-serif'; + markerIcon.style.fontSize = '16px'; + markerIcon.style.lineHeight = '32px'; + markerIcon.style.left = '-2'; + markerIcon.style.top = '1'; markerIcon.width = 30; markerIcon.height = 30; - markerIcon.style.position = "absolute"; - markerIcon.innerHTML = "Add"; + markerIcon.style.position = 'absolute'; + markerIcon.innerHTML = 'Add'; controlUI.appendChild(markerIcon); // Setup the click event listeners - controlUI.addEventListener("click", () => { + controlUI.addEventListener('click', () => { if (this.toggleAddMarker === true) { this.toggleAddMarker = false; - console.log("add marker button status:" + this.toggleAddMarker); - controlUI.style.backgroundColor = "#fff"; - markerIcon.style.color = "rgb(25,25,25)"; + console.log('add marker button status:' + this.toggleAddMarker); + controlUI.style.backgroundColor = '#fff'; + markerIcon.style.color = 'rgb(25,25,25)'; } else { this.toggleAddMarker = true; - console.log("add marker button status:" + this.toggleAddMarker); - controlUI.style.backgroundColor = "#4476f7"; - markerIcon.style.color = "rgb(255,255,255)"; + console.log('add marker button status:' + this.toggleAddMarker); + controlUI.style.backgroundColor = '#4476f7'; + markerIcon.style.color = 'rgb(255,255,255)'; } }); controlDiv.appendChild(controlUI); return controlDiv; - } + }; /** * Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list * @param position - the LatLng position where the marker is placed - * @param map + * @param map */ @action private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => { const marker = new google.maps.Marker({ position: position, - map: map + map: map, }); map.panTo(position); const mapMarker = Docs.Create.MapMarkerDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {}); this.addDocument(mapMarker, this.annotationKey); - } + }; _loadPending = true; /** * store a reference to google map instance * setup the drawing manager on the top right corner of map - * fit map bounds to contain all markers - * @param map + * fit map bounds to contain all markers + * @param map */ @action private loadHandler = (map: google.maps.Map) => { @@ -256,7 +262,6 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (this._loadPending && this._map.getBounds()) { this._loadPending = false; this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); @@ -268,7 +273,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { @@ -278,7 +283,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { @@ -287,64 +292,64 @@ export class MapBox extends ViewBoxAnnotatableComponent { - place[Id] ? this.markerMap[place[Id]] = marker : null; - } + place[Id] ? (this.markerMap[place[Id]] = marker) : null; + }; /** * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true - * @param e - * @param place + * @param e + * @param place */ @action private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => { // set which place was clicked this.selectedPlace = place; place.infoWindowOpen = true; - } + }; /** * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts - * @param doc - * @param sidebarKey - * @returns + * @param doc + * @param sidebarKey + * @returns */ sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { - console.log("print all sidebar Docs"); + console.log('print all sidebar Docs'); console.log(this.allSidebarDocs); if (!this.layoutDoc._showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { if (doc.lat !== undefined && doc.lng !== undefined) { const existingMarker = this.allMapMarkers.find(marker => marker.lat === doc.lat && marker.lng === doc.lng); - doc.onClickBehavior = "enterPortal"; + doc.onClickBehavior = 'enterPortal'; if (existingMarker) { - Doc.AddDocToList(existingMarker, "data", doc); + Doc.AddDocToList(existingMarker, 'data', doc); } else { const marker = Docs.Create.MapMarkerDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {}); this.addDocument(marker, this.annotationKey); } } }); //add to annotation list - console.log("sidebaraddDocument"); + console.log('sidebaraddDocument'); console.log(doc); return this.addDocument(doc, sidebarKey); // add to sidebar list - } + }; /** * Removing documents from the sidebar - * @param doc - * @param sidebarKey - * @returns + * @param doc + * @param sidebarKey + * @returns */ sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => { if (this.layoutDoc._showSidebar) this.toggleSidebar(); @@ -354,31 +359,43 @@ export class MapBox extends ViewBoxAnnotatableComponent { - setupMoveUpEvents(this, e, (e, down, delta) => { - const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); - const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; - if (ratio >= 1) { - this.layoutDoc.nativeWidth = nativeWidth * ratio; - this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; - this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; - } - return false; - }, emptyFunction, this.toggleSidebar); - } - - sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); - @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); } - @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); } + setupMoveUpEvents( + this, + e, + (e, down, delta) => { + const localDelta = this.props + .ScreenToLocalTransform() + .scale(this.props.scaling?.() || 1) + .transformDirection(delta[0], delta[1]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']); + const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); + const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; + if (ratio >= 1) { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } + return false; + }, + emptyFunction, + this.toggleSidebar + ); + }; + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + @computed get sidebarWidthPercent() { + return StrCast(this.layoutDoc._sidebarWidthPercent, '0%'); + } + @computed get sidebarColor() { + return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4')); + } /** * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted; @@ -414,7 +431,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { + this.searchMarkers.forEach(marker => { marker.setMap(null); }); this.searchMarkers = []; @@ -426,7 +443,7 @@ export class MapBox extends ViewBoxAnnotatableComponent d?.author).length; const color = !annotated ? Colors.WHITE : Colors.BLACK; - const backgroundColor = !annotated ? this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK : this.props.styleProvider?.(this.rootDoc, this.props as any, StyleProp.WidgetColor + (annotated ? ":annotated" : "")); - return (!annotated) ? (null) : -
- -
; + opacity: annotated ? 1 : undefined, + }}> + +
+ ); } // TODO: Adding highlight box layer to Maps @action toggleSidebar = () => { const prevWidth = this.sidebarWidth(); - this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%"; + this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%'; this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); - } + }; sidebarDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), false); - } + }; sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => { const bounds = this._ref.current!.getBoundingClientRect(); - this.layoutDoc._sidebarWidthPercent = "" + 100 * Math.max(0, (1 - (e.clientX - bounds.left) / bounds.width)) + "%"; - this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== "0%"; + this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; + this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%'; e.preventDefault(); return false; - } + }; - setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func; + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); @action onMarqueeDown = (e: React.PointerEvent) => { if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { - setupMoveUpEvents(this, e, action(e => { - MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; - return true; - }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); + setupMoveUpEvents( + this, + e, + action(e => { + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); + this._marqueeing = [e.clientX, e.clientY]; + return true; + }), + returnFalse, + () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), + false + ); } - } + }; @action finishMarquee = (x?: number, y?: number) => { this._marqueeing = undefined; this._isAnnotating = false; x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false); - } + }; addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => { return this.addDocument(doc, annotationKey); - } + }; pointerEvents = () => { - return this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? - "all" : - SnappingManager.GetIsDragging() ? - undefined : "none"; - } + return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'; + }; @computed get annotationLayer() { - return
- {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - )} -
; + return ( +
+ {this.inlineTextAnnotations + .sort((a, b) => NumCast(a.y) - NumCast(b.y)) + .map(anno => ( + + ))} +
+ ); } getAnchor = () => { - const anchor = - AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? - this.rootDoc; + const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? this.rootDoc; return anchor; - } + }; /** * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker - * @returns + * @returns */ private renderMarkers = () => { return this.allMapMarkers.map(place => ( - this.markerLoadHandler(marker, place)} - onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} - /> + this.markerLoadHandler(marker, place)} onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} /> )); - } + }; // TODO: auto center on select a document in the sidebar private handleMapCenter = (map: google.maps.Map) => { @@ -531,7 +552,7 @@ export class MapBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); @@ -543,7 +564,7 @@ export class MapBox extends ViewBoxAnnotatableComponent this._sidebarRef.current?.anchorMenuClick; savedAnnotations = () => this._savedAnnotations; render() { - const renderAnnotations = (docFilters?: () => string[]) => (null); + const renderAnnotations = (docFilters?: () => string[]) => null; // bcz: commmented this out. Otherwise, any documents that are rendered with an InfoWindow of a marker // will also be rendered as freeform annotations on the map. However, it doesn't seem that rendering // freeform documents on the map does anything anyway, so getting rid of it for now. Also, since documents @@ -571,88 +592,88 @@ export class MapBox extends ViewBoxAnnotatableComponent; - return
- {/*console.log(apiKey)*/} - {/* + {/*console.log(apiKey)*/} + {/* */} -
e.stopPropagation()} - onPointerDown={e => (e.button === 0 && !e.ctrlKey) && e.stopPropagation()} - style={{ width: `calc(100% - ${this.sidebarWidthPercent})` }}> - -
- {renderAnnotations(this.transparentFilter)} +
e.stopPropagation()} onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} style={{ width: `calc(100% - ${this.sidebarWidthPercent})` }}> +
{renderAnnotations(this.transparentFilter)}
+ {renderAnnotations(this.opaqueFilter)} + {SnappingManager.GetIsDragging() ? null : renderAnnotations()} + {this.annotationLayer} + + + + + + {this.renderMarkers()} + {this.allMapMarkers + .filter(marker => marker.infoWindowOpen) + .map(marker => ( + + ))} + {/* {this.handleMapCenter(this._map)} */} + + {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + + )}
- {renderAnnotations(this.opaqueFilter)} - {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()} - {this.annotationLayer} - - - - - - {this.renderMarkers()} - {this.allMapMarkers.filter(marker => marker.infoWindowOpen).map(marker => */} +
+ )} - {this.handleMapCenter(this._map)} - - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) : - } -
- {/* */} -
- -
-
- + PanelWidth={this.sidebarWidth} + sidebarAddDocument={this.sidebarAddDocument} + moveDocument={this.moveDocument} + removeDocument={this.sidebarRemoveDocument} + /> +
+
+ +
-
; + ); } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 1fb3cef2a..5b9d90780 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,12 +1,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; -import { observer } from "mobx-react"; -import * as Pdfjs from "pdfjs-dist"; -import "pdfjs-dist/web/pdf_viewer.css"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { observer } from 'mobx-react'; +import * as Pdfjs from 'pdfjs-dist'; +import 'pdfjs-dist/web/pdf_viewer.css'; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; -import { ImageField, PdfField } from "../../../fields/URLField"; +import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -15,25 +15,27 @@ import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { Colors } from '../global/globalEnums'; -import { CreateImage } from "../nodes/WebBoxRenderer"; +import { CreateImage } from '../nodes/WebBoxRenderer'; import { AnchorMenu } from '../pdf/AnchorMenu'; -import { PDFViewer } from "../pdf/PDFViewer"; +import { PDFViewer } from '../pdf/PDFViewer'; import { SidebarAnnos } from '../SidebarAnnos'; import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; -import "./PDFBox.scss"; +import './PDFBox.scss'; import { VideoBox } from './VideoBox'; -import React = require("react"); +import React = require('react'); import { CollectionFreeFormView } from '../collections/collectionFreeForm'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(PDFBox, fieldKey); + } public static openSidebarWidth = 250; public static sidebarResizerWidth = 5; - private _searchString: string = ""; + private _searchString: string = ''; private _initialScrollTarget: Opt; private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef(); @@ -44,8 +46,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent; @observable private _pageControls = false; - @computed get pdfUrl() { return Cast(this.dataDoc[this.props.fieldKey], PdfField); } - @computed get pdfThumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url; } + @computed get pdfUrl() { + return Cast(this.dataDoc[this.props.fieldKey], PdfField); + } + @computed get pdfThumb() { + return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url; + } constructor(props: any) { super(props); @@ -53,8 +59,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href)); - else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => this._pdf = pdf)); + if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) runInAction(() => (this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href))); + else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => (this._pdf = pdf))); } } @@ -65,15 +71,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = "region:" + this.rootDoc.title; + Doc.GetProto(region).title = 'region:' + this.rootDoc.title; Doc.GetProto(region).isPushpin = true; this.addDocument(region); const docViewContent = this.props.docViewPath().lastElement().ContentDiv!; const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; - newDiv.style.width = (this.layoutDoc[WidthSym]()).toString(); - newDiv.style.height = (this.layoutDoc[HeightSym]()).toString(); + newDiv.style.width = this.layoutDoc[WidthSym]().toString(); + newDiv.style.height = this.layoutDoc[HeightSym]().toString(); this.replaceCanvases(docViewContent, newDiv); const htmlString = this._pdfViewer?._mainCont.current && new XMLSerializer().serializeToString(newDiv); @@ -103,7 +108,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - VideoBox.convertDataUri(data_url, region[Id]).then( - returnedfilename => setTimeout(action(() => { - croppingProto.data = new ImageField(returnedfilename); - }), 500)); + ) + .then((data_url: any) => { + VideoBox.convertDataUri(data_url, region[Id]).then(returnedfilename => + setTimeout( + action(() => { + croppingProto.data = new ImageField(returnedfilename); + }), + 500 + ) + ); }) .catch(function (error: any) { console.error('oops, something went wrong!', error); }); - return cropping; - } + }; updateIcon = () => { // currently we render pdf icons as text labels const docViewContent = this.props.docViewPath().lastElement().ContentDiv!; - const filename = this.layoutDoc[Id] + "-icon" + (new Date()).getTime(); - this._pdfViewer?._mainCont.current && CollectionFreeFormView.UpdateIcon( - filename, docViewContent, - this.layoutDoc[WidthSym](), this.layoutDoc[HeightSym](), - this.props.PanelWidth(), this.props.PanelHeight(), - NumCast(this.layoutDoc._scrollTop), - NumCast(this.rootDoc[this.fieldKey + "-nativeHeight"], 1), - true, - this.layoutDoc[Id] + "-icon", - (iconFile:string, nativeWidth:number, nativeHeight:number) => { - setTimeout(() => { - this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc["icon-nativeWidth"] = nativeWidth; - this.dataDoc["icon-nativeHeight"] = nativeHeight; - }, 500); - }); - } + const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime(); + this._pdfViewer?._mainCont.current && + CollectionFreeFormView.UpdateIcon( + filename, + docViewContent, + this.layoutDoc[WidthSym](), + this.layoutDoc[HeightSym](), + this.props.PanelWidth(), + this.props.PanelHeight(), + NumCast(this.layoutDoc._scrollTop), + NumCast(this.rootDoc[this.fieldKey + '-nativeHeight'], 1), + true, + this.layoutDoc[Id] + '-icon', + (iconFile: string, nativeWidth: number, nativeHeight: number) => { + setTimeout(() => { + this.dataDoc.icon = new ImageField(iconFile); + this.dataDoc['icon-nativeWidth'] = nativeWidth; + this.dataDoc['icon-nativeHeight'] = nativeHeight; + }, 500); + } + ); + }; - componentWillUnmount() { this._selectReactionDisposer?.(); } + componentWillUnmount() { + this._selectReactionDisposer?.(); + } componentDidMount() { this.props.setContentView?.(this); - this._selectReactionDisposer = reaction(() => this.props.isSelected(), + this._selectReactionDisposer = reaction( + () => this.props.isSelected(), () => { - document.removeEventListener("keydown", this.onKeyDown); - this.props.isSelected(true) && document.addEventListener("keydown", this.onKeyDown); - }, { fireImmediately: true }); + document.removeEventListener('keydown', this.onKeyDown); + this.props.isSelected(true) && document.addEventListener('keydown', this.onKeyDown); + }, + { fireImmediately: true } + ); } scrollFocus = (doc: Doc, smooth: boolean) => { let didToggle = false; - if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { + if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); didToggle = true; } if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; this._initialScrollTarget = doc; return this._pdfViewer?.scrollFocus(doc, smooth) ?? (didToggle ? 1 : undefined); - } + }; getAnchor = () => { const anchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ?? Docs.Create.TextanchorDocument({ - title: StrCast(this.rootDoc.title + "@" + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)), + title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)), y: NumCast(this.layoutDoc._scrollTop), - unrendered: true + unrendered: true, }); this.addDocument(anchor); return anchor; - } + }; @action loaded = (nw: number, nh: number, np: number) => { - this.dataDoc[this.props.fieldKey + "-numPages"] = np; - Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), nw * 96 / 72)); - Doc.SetNativeHeight(this.dataDoc, nh * 96 / 72); + this.dataDoc[this.props.fieldKey + '-numPages'] = np; + Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), (nw * 96) / 72)); + Doc.SetNativeHeight(this.dataDoc, (nh * 96) / 72); this.layoutDoc._height = this.layoutDoc[WidthSym]() / (Doc.NativeAspect(this.dataDoc) || 1); !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); - } + }; public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => { if (!this._searching && !clear) { @@ -225,19 +243,23 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this.Document._curPage = Math.max(1, (NumCast(this.Document._curPage) || 1) - 1); return true; - } + }; public forwardPage = () => { - this.Document._curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + "-numPages"]), (NumCast(this.Document._curPage) || 1) + 1); + this.Document._curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + '-numPages']), (NumCast(this.Document._curPage) || 1) + 1); return true; - } - public gotoPage = (p: number) => this.Document._curPage = p; + }; + public gotoPage = (p: number) => (this.Document._curPage = p); @undoBatch onKeyDown = action((e: KeyboardEvent) => { let processed = false; switch (e.key) { - case "PageDown": processed = this.forwardPage(); break; - case "PageUp": processed = this.backPage(); break; + case 'PageDown': + processed = this.forwardPage(); + break; + case 'PageUp': + processed = this.backPage(); + break; } if (processed) { e.stopImmediatePropagation(); @@ -251,131 +273,163 @@ export class PDFBox extends ViewBoxAnnotatableComponent) => this._searchString = e.currentTarget.value; + }; + searchStringChanged = (e: React.ChangeEvent) => (this._searchString = e.currentTarget.value); // adding external documents; to sidebar key // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"-annotation") sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); - } - sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => { // onButton determines whether the width of the pdf box changes, or just the ratio of the sidebar to the pdf - const batch = UndoManager.StartBatch("sidebar"); - setupMoveUpEvents(this, e, (e, down, delta) => { - const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); - const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - const ratio = (curNativeWidth + (onButton ? 1 : -1) * localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; - if (ratio >= 1) { - this.layoutDoc.nativeWidth = nativeWidth * ratio; - onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); - this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; - } - return false; - }, () => batch.end(), () => this.toggleSidebar()); - } + }; + sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => { + // onButton determines whether the width of the pdf box changes, or just the ratio of the sidebar to the pdf + const batch = UndoManager.StartBatch('sidebar'); + setupMoveUpEvents( + this, + e, + (e, down, delta) => { + const localDelta = this.props + .ScreenToLocalTransform() + .scale(this.props.scaling?.() || 1) + .transformDirection(delta[0], delta[1]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']); + const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); + const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.scaling?.() || 1)) / nativeWidth; + if (ratio >= 1) { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } + return false; + }, + () => batch.end(), + () => this.toggleSidebar() + ); + }; @observable _previewNativeWidth: Opt = undefined; @observable _previewWidth: Opt = undefined; toggleSidebar = action((preview: boolean = false) => { - const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']); const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { this._previewNativeWidth = nativeWidth * sideratio; - this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * sideratio / curNativeWidth; + this._previewWidth = (this.layoutDoc[WidthSym]() * nativeWidth * sideratio) / curNativeWidth; this._showSidebar = true; - } - else { + } else { this.layoutDoc.nativeWidth = nativeWidth * pdfratio; - this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * pdfratio / curNativeWidth; + this.layoutDoc._width = (this.layoutDoc[WidthSym]() * nativeWidth * pdfratio) / curNativeWidth; this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } }); settingsPanel() { - const pageBtns = <> - - - ; - const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; + const pageBtns = ( + <> + + + + ); + const searchTitle = `${!this._searching ? 'Open' : 'Close'} Search Bar`; const curPage = NumCast(this.Document._curPage) || 1; - return !this.props.isContentActive() || this._pdfViewer?.isAnnotating ? (null) : -
[KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true} - onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}> -
e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}> + return !this.props.isContentActive() || this._pdfViewer?.isAnnotating ? null : ( +
([KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true)} + onPointerDown={e => e.stopPropagation()} + style={{ display: this.props.isContentActive() ? 'flex' : 'none' }}> +
e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}> - -
-
- 99 ? 4 : 3}ch`, pointerEvents: "all" }} - onChange={e => this.Document._curPage = Number(e.currentTarget.value)} + 99 ? 4 : 3}ch`, pointerEvents: 'all' }} + onChange={e => (this.Document._curPage = Number(e.currentTarget.value))} onKeyDown={e => e.stopPropagation()} - onClick={action(() => this._pageControls = !this._pageControls)} /> - {this._pageControls ? pageBtns : (null)} + onClick={action(() => (this._pageControls = !this._pageControls))} + /> + {this._pageControls ? pageBtns : null}
-
this.sidebarBtnDown(e, true)} > - + onPointerDown={e => this.sidebarBtnDown(e, true)}> +
-
; +
+ ); } - sidebarWidth = () => !this.SidebarShown ? 0 : - PDFBox.sidebarResizerWidth + (this._previewWidth ? PDFBox.openSidebarWidth : - (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth)) + sidebarWidth = () => + !this.SidebarShown ? 0 : PDFBox.sidebarResizerWidth + (this._previewWidth ? PDFBox.openSidebarWidth : ((NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth()) / NumCast(this.layoutDoc.nativeWidth)); specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Copy path", event: () => this.pdfUrl && Utils.CopyText(Utils.prepend("") + this.pdfUrl.url.pathname), icon: "expand-arrows-alt" }); - funcs.push({ description: "update icon", event: () => this.pdfUrl && this.updateIcon(), icon: "expand-arrows-alt" }); + funcs.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); + funcs.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' }); //funcs.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); - } + ContextMenu.Instance.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); + }; @computed get renderTitleBox() { - const classname = "pdfBox" + (this.props.isContentActive() ? "-interactive" : ""); - return
-
- {this.props.Document.title} + const classname = 'pdfBox' + (this.props.isContentActive() ? '-interactive' : ''); + return ( +
+
+ {StrCast(this.props.Document.title)} +
-
; + ); } anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; @observable _showSidebar = false; - @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } + @computed get SidebarShown() { + return this._showSidebar || this.layoutDoc._showSidebar ? true : false; + } contentScaling = () => 1; isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected(); @@ -383,54 +437,60 @@ export class PDFBox extends ViewBoxAnnotatableComponent 600) ? - NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined - }}> -
this.sidebarBtnDown(e, false)} /> -
- 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined, + }}> +
this.sidebarBtnDown(e, false)} /> +
+ +
+ + {this.settingsPanel()}
- - {this.settingsPanel()} -
; + ); } static pdfcache = new Map(); @@ -446,13 +506,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdf = PDFBox.pdfcache.get(href))); + if (PDFBox.pdfcache.get(href)) setTimeout(action(() => (this._pdf = PDFBox.pdfcache.get(href)))); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); - PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, this._pdf = pdf))); + PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, (this._pdf = pdf)))); } } return this.renderTitleBox; } } - diff --git a/src/client/views/nodes/formattedText/schema_rts.ts b/src/client/views/nodes/formattedText/schema_rts.ts index 83561073c..d6e0e6002 100644 --- a/src/client/views/nodes/formattedText/schema_rts.ts +++ b/src/client/views/nodes/formattedText/schema_rts.ts @@ -1,8 +1,7 @@ -import { Schema, Slice } from "prosemirror-model"; - -import { nodes } from "./nodes_rts"; -import { marks } from "./marks_rts"; +import { Schema, Slice } from 'prosemirror-model'; +import { nodes } from './nodes_rts'; +import { marks } from './marks_rts'; // :: Schema // This schema rougly corresponds to the document schema used by @@ -20,7 +19,9 @@ const fromJson = schema.nodeFromJSON; schema.nodeFromJSON = (json: any) => { const node = fromJson(json); if (json.type === schema.nodes.summary.name) { - node.attrs.text = Slice.fromJSON(schema, node.attrs.textslice); + // bcz: this is a hacky way to convert the JSON that's serialized for a summary node into the Slice that the summary node wants at run-time. + // since attrs are readonly, assigning the text field like this violates the way prosemirror works, but I think we can get away with it. + (node.attrs.text as any) = Slice.fromJSON(schema, node.attrs.textslice); } return node; -}; \ No newline at end of file +}; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 7045d6d5d..91f8d1efc 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,55 +1,57 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from "@material-ui/core"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { ColorState, SketchPicker } from "react-color"; +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Tooltip } from '@material-ui/core'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { ColorState, SketchPicker } from 'react-color'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; -import { Doc, DocListCast, DocListCastAsync, FieldResult } from "../../../../fields/Doc"; -import { InkTool } from "../../../../fields/InkField"; -import { List } from "../../../../fields/List"; -import { PrefetchProxy } from "../../../../fields/Proxy"; -import { listSpec } from "../../../../fields/Schema"; -import { BoolCast, Cast, DocCast, NumCast, StrCast } from "../../../../fields/Types"; +import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc'; +import { InkTool } from '../../../../fields/InkField'; +import { List } from '../../../../fields/List'; +import { PrefetchProxy } from '../../../../fields/Proxy'; +import { listSpec } from '../../../../fields/Schema'; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; -import { Docs } from "../../../documents/Documents"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { SelectionManager } from "../../../util/SelectionManager"; -import { undoBatch, UndoManager } from "../../../util/UndoManager"; -import { CollectionDockingView } from "../../collections/CollectionDockingView"; -import { MarqueeViewBounds } from "../../collections/collectionFreeForm"; -import { CollectionView, CollectionViewType } from "../../collections/CollectionView"; -import { TabDocView } from "../../collections/TabDocView"; -import { ViewBoxBaseComponent } from "../../DocComponent"; -import { Colors } from "../../global/globalEnums"; -import { LightboxView } from "../../LightboxView"; -import { CollectionFreeFormDocumentView } from "../CollectionFreeFormDocumentView"; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { CurrentUserUtils } from '../../../util/CurrentUserUtils'; +import { DocumentManager } from '../../../util/DocumentManager'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { CollectionDockingView } from '../../collections/CollectionDockingView'; +import { MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionView, CollectionViewType } from '../../collections/CollectionView'; +import { TabDocView } from '../../collections/TabDocView'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { Colors } from '../../global/globalEnums'; +import { LightboxView } from '../../LightboxView'; +import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import "./PresBox.scss"; -import { PresEffect, PresMovement, PresStatus } from "./PresEnums"; -import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; -import { PresElementBox } from "."; +import './PresBox.scss'; +import { PresEffect, PresMovement, PresStatus } from './PresEnums'; +import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; +import { PresElementBox } from '.'; export interface PinProps { audioRange?: boolean; setPosition?: boolean; hidePresBox?: boolean; pinWithView?: PinViewProps; - pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document - panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area) - panelHeight?: number + pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document + panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area) + panelHeight?: number; } export interface PinViewProps { - bounds: MarqueeViewBounds; - scale: number; + bounds: MarqueeViewBounds; + scale: number; } @observer export class PresBox extends ViewBoxBaseComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(PresBox, fieldKey); + } /** * transitions & effects for documents @@ -67,22 +69,27 @@ export class PresBox extends ViewBoxBaseComponent() { // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, }; switch (presDoc.presEffect) { - case PresEffect.Zoom: return ({renderDoc}); - case PresEffect.Fade: return ({renderDoc}); - case PresEffect.Flip: return ({renderDoc}); - case PresEffect.Rotate: return ({renderDoc}); - case PresEffect.Bounce: return ({renderDoc}); - case PresEffect.Roll: return ({renderDoc}); - case PresEffect.Lightspeed: return ({renderDoc}); + case PresEffect.Zoom: + return {renderDoc}; + case PresEffect.Fade: + return {renderDoc}; + case PresEffect.Flip: + return {renderDoc}; + case PresEffect.Rotate: + return {renderDoc}; + case PresEffect.Bounce: + return {renderDoc}; + case PresEffect.Roll: + return {renderDoc}; + case PresEffect.Lightspeed: + return {renderDoc}; case PresEffect.None: - default: return renderDoc; + default: + return renderDoc; } } public static EffectsProvider(layoutDoc: Doc, renderDoc: any) { - return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? - PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) - : - renderDoc; + return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc; } @observable public static Instance: PresBox; @@ -107,10 +114,18 @@ export class PresBox extends ViewBoxBaseComponent() { @observable private openMovementDropdown: boolean = false; @observable private openEffectDropdown: boolean = false; @observable private presentTools: boolean = false; - @computed get isTreeOrStack() {return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any) } - @computed get isTree() { return this.layoutDoc._viewType === CollectionViewType.Tree;} - @computed get presFieldKey() { return StrCast(this.layoutDoc.presFieldKey, "data"); } - @computed get childDocs() { return DocListCast(this.rootDoc[this.presFieldKey]); } + @computed get isTreeOrStack() { + return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any); + } + @computed get isTree() { + return this.layoutDoc._viewType === CollectionViewType.Tree; + } + @computed get presFieldKey() { + return StrCast(this.layoutDoc.presFieldKey, 'data'); + } + @computed get childDocs() { + return DocListCast(this.rootDoc[this.presFieldKey]); + } @observable _treeViewMap: Map = new Map(); @computed get tagDocs() { @@ -121,9 +136,15 @@ export class PresBox extends ViewBoxBaseComponent() { } return tagDocs; } - @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); } - @computed get activeItem() { return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null); } - @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); } + @computed get itemIndex() { + return NumCast(this.rootDoc._itemIndex); + } + @computed get activeItem() { + return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null); + } + @computed get targetDoc() { + return Cast(this.activeItem?.presentationTargetDoc, Doc, null); + } @computed get scrollable(): boolean { if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true; else return false; @@ -134,7 +155,7 @@ export class PresBox extends ViewBoxBaseComponent() { } constructor(props: any) { super(props); - if (CurrentUserUtils.ActivePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); + if ((CurrentUserUtils.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this)); this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox } @computed get selectedDocumentView() { @@ -142,21 +163,23 @@ export class PresBox extends ViewBoxBaseComponent() { if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc); } @computed get isPres(): boolean { - document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); + document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); if (this.selectedDoc?.type === DocumentType.PRES) { - document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); - document.addEventListener("keydown", PresBox.keyEventsWrapper, true); + document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); + document.addEventListener('keydown', PresBox.keyEventsWrapper, true); return true; } return false; } - @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } + @computed get selectedDoc() { + return this.selectedDocumentView?.rootDoc; + } _unmounting = false; @action componentWillUnmount() { this._unmounting = true; - document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); + document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); this._presKeyEventsActive = false; this.resetPresentation(); // Turn of progressivize editors @@ -167,37 +190,38 @@ export class PresBox extends ViewBoxBaseComponent() { @action componentDidMount() { this._unmounting = false; - this.rootDoc._forceRenderEngine = "timeline"; + this.rootDoc._forceRenderEngine = 'timeline'; this.layoutDoc.presStatus = PresStatus.Edit; this.layoutDoc._gridGap = 0; this.layoutDoc._yMargin = 0; this.turnOffEdit(true); - DocListCastAsync(CurrentUserUtils.MyTrails.data).then(pres => - !pres?.includes(this.rootDoc) && Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", this.rootDoc)); - this._disposers.selection = reaction(() => SelectionManager.Views(), - views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()); + DocListCastAsync(CurrentUserUtils.MyTrails.data).then(pres => !pres?.includes(this.rootDoc) && Doc.AddDocToList(CurrentUserUtils.MyTrails, 'data', this.rootDoc)); + this._disposers.selection = reaction( + () => SelectionManager.Views(), + views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation() + ); } @action updateCurrentPresentation = (pres?: Doc) => { if (pres) CurrentUserUtils.ActivePresentation = pres; else CurrentUserUtils.ActivePresentation = this.rootDoc; - document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); - document.addEventListener("keydown", PresBox.keyEventsWrapper, true); + document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); + document.addEventListener('keydown', PresBox.keyEventsWrapper, true); this._presKeyEventsActive = true; PresBox.Instance = this; - } + }; // There are still other internal frames and should go through all frames before going to next slide nextInternalFrame = (targetDoc: Doc, activeItem: Doc) => { - const currentFrame = Cast(targetDoc?._currentFrame, "number", null); + const currentFrame = Cast(targetDoc?._currentFrame, 'number', null); const childDocs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - targetDoc._viewTransition = "all 1s"; - setTimeout(() => targetDoc._viewTransition = undefined, 1010); + targetDoc._viewTransition = 'all 1s'; + setTimeout(() => (targetDoc._viewTransition = undefined), 1010); this.nextKeyframe(targetDoc, activeItem); if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc); else targetDoc.keyFrameEditing = true; - } + }; _mediaTimer!: [NodeJS.Timeout, Doc]; // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played @@ -207,7 +231,7 @@ export class PresBox extends ViewBoxBaseComponent() { const targMedia = DocumentManager.Instance.getDocumentView(targetDoc); targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration); } - } + }; stopTempMedia = (targetDocField: FieldResult) => { const targetDoc = Cast(targetDocField, Doc, null); @@ -215,11 +239,11 @@ export class PresBox extends ViewBoxBaseComponent() { const targMedia = DocumentManager.Instance.getDocumentView(targetDoc); targMedia?.ComponentView?.Pause?.(); } - } + }; - //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time + //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time // TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions - // No more frames in current doc and next slide is defined, therefore move to next slide + // No more frames in current doc and next slide is defined, therefore move to next slide nextSlide = (activeNext: Doc) => { const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null); console.info('nextSlide', activeNext.title, targetNext?.title); @@ -229,11 +253,11 @@ export class PresBox extends ViewBoxBaseComponent() { if (!this.childDocs[nextSelected].groupWithUp) { break; } else { - console.log("Title: " + this.childDocs[nextSelected].title); + console.log('Title: ' + this.childDocs[nextSelected].title); this.gotoDocument(nextSelected, this.activeItem, true); } } - } + }; // Called when the user activates 'next' - to move to the next part of the pres. trail @action @@ -241,7 +265,7 @@ export class PresBox extends ViewBoxBaseComponent() { const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null); const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const lastFrame = Cast(targetDoc?.lastFrame, "number", null); + const lastFrame = Cast(targetDoc?.lastFrame, 'number', null); const curFrame = NumCast(targetDoc?._currentFrame); let internalFrames: boolean = false; if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true; @@ -249,13 +273,13 @@ export class PresBox extends ViewBoxBaseComponent() { // Case 1: There are still other frames and should go through all frames before going to next slide this.nextInternalFrame(targetDoc, activeItem); } else if (this.childDocs[this.itemIndex + 1] !== undefined) { - // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide + // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide this.nextSlide(activeNext); } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode this.gotoDocument(0, this.activeItem); } - } + }; // Called when the user activates 'back' - to move to the previous part of the pres. trail @action @@ -264,7 +288,7 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null); const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null); - const lastFrame = Cast(targetDoc.lastFrame, "number", null); + const lastFrame = Cast(targetDoc.lastFrame, 'number', null); const curFrame = NumCast(targetDoc._currentFrame); let prevSelected = this.itemIndex; // Functionality for group with up @@ -284,7 +308,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Case 3: Pres loop is on so it should go to the last slide this.gotoDocument(this.childDocs.length - 1, activeItem); } - } + }; //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. @@ -297,20 +321,21 @@ export class PresBox extends ViewBoxBaseComponent() { if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } - if (from?.mediaStop === "auto" && this.layoutDoc.presStatus !== PresStatus.Edit) { + if (from?.mediaStop === 'auto' && this.layoutDoc.presStatus !== PresStatus.Edit) { this.stopTempMedia(from.presentationTargetDoc); } // If next slide is audio / video 'Play automatically' then the next slide should be played - if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && (activeItem.mediaStart === "auto")) { + if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') { this.startTempMedia(targetDoc, activeItem); } if (targetDoc) { - Doc.linkFollowHighlight((targetDoc.annotationOn instanceof Doc) ? [targetDoc, targetDoc.annotationOn] : targetDoc); - targetDoc && runInAction(() => { - if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0; - else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500; - }); - setTimeout(() => targetDoc.focusSpeed = 500, this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510); + Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc); + targetDoc && + runInAction(() => { + if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0; + else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500; + }); + setTimeout(() => (targetDoc.focusSpeed = 500), this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510); } if (targetDoc?.lastFrame !== undefined) { targetDoc._currentFrame = 0; @@ -327,14 +352,14 @@ export class PresBox extends ViewBoxBaseComponent() { clearTimeout(this._navTimer); const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document; if (bestTarget) console.log(bestTarget.title, bestTarget.type); - else console.log("no best target"); - if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false); - } + else console.log('no best target'); + if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false); + }; // navigates to the bestTarget document by making sure it is on screen, - // then it applies the view specs stored in activeItem to + // then it applies the view specs stored in activeItem to @action - static navigateToDoc(bestTarget:Doc, activeItem:Doc, jumpToDoc:boolean) { + static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) { if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) { bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s'; bestTarget._scrollTop = activeItem.presPinViewScroll; @@ -343,32 +368,31 @@ export class PresBox extends ViewBoxBaseComponent() { } else if ([DocumentType.AUDIO, DocumentType.VID].includes(bestTarget.type as any)) { bestTarget._currentTimecode = activeItem.presStartTime; } else { - const contentBounds= Cast(activeItem.contentBounds, listSpec("number")); + const contentBounds = Cast(activeItem.contentBounds, listSpec('number')); bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s'; if (contentBounds) { - bestTarget._panX = (contentBounds[0] + contentBounds[2])/2; - bestTarget._panY = (contentBounds[1] + contentBounds[3])/2; + bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2; + bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2; const dv = DocumentManager.Instance.getDocumentView(bestTarget); if (dv) { - bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), - dv.props.PanelWidth() / (contentBounds[2]- contentBounds[0])); - }; + bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0])); + } } else { bestTarget._panX = activeItem.presPinViewX; bestTarget._panY = activeItem.presPinViewY; bestTarget._viewScale = activeItem.presPinViewScale; } } - return setTimeout(() => bestTarget._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510); + return setTimeout(() => (bestTarget._viewTransition = undefined), activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510); } /** * This method makes sure that cursor navigates to the element that - * has the option open and last in the group. - * Design choice: If the next document is not in presCollection or + * has the option open and last in the group. + * Design choice: If the next document is not in presCollection or * presCollection itself then if there is a presCollection it will add * a new tab. If presCollection is undefined it will open the document - * on the right. + * on the right. */ navigateToElement = async (curDoc: Doc) => { const activeItem: Doc = this.activeItem; @@ -401,7 +425,7 @@ export class PresBox extends ViewBoxBaseComponent() { self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); const openInTab = (doc: Doc, finished?: () => void) => { - collectionDocView ? collectionDocView.props.addDocTab(doc, "") : this.props.addDocTab(doc, ""); + collectionDocView ? collectionDocView.props.addDocTab(doc, '') : this.props.addDocTab(doc, ''); this.layoutDoc.presCollection = targetDoc; // this still needs some fixing setTimeout(resetSelection, 500); @@ -417,21 +441,21 @@ export class PresBox extends ViewBoxBaseComponent() { // openInTab(targetDoc); } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { LightboxView.SetLightboxDoc(undefined); - await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext]:[], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right + await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) { LightboxView.SetLightboxDoc(undefined); - //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext]:[], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right + //awaiting jump so that new scale can be found, since jumping is async + await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right } // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. if (activeItem.presPinView) { console.log(targetDoc.title); - console.log("presPinView in PresBox.tsx:420"); + console.log('presPinView in PresBox.tsx:420'); // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target this.navigateToView(targetDoc, activeItem); } - } + }; /** * Uses the viewfinder to progressivize through the different views of a single collection. @@ -441,10 +465,10 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; const srcContext = Cast(targetDoc?.context, Doc, null); const docView = DocumentManager.Instance.getDocumentView(targetDoc); - const vfLeft = this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]); - const vfWidth = this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]); - const vfTop = this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]); - const vfHeight = this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]); + const vfLeft = this.checkList(targetDoc, activeItem['viewfinder-left-indexed']); + const vfWidth = this.checkList(targetDoc, activeItem['viewfinder-width-indexed']); + const vfTop = this.checkList(targetDoc, activeItem['viewfinder-top-indexed']); + const vfHeight = this.checkList(targetDoc, activeItem['viewfinder-height-indexed']); // Case 1: document that is not a Golden Layout tab if (srcContext) { const srcDocView = DocumentManager.Instance.getDocumentView(srcContext); @@ -455,8 +479,8 @@ export class PresBox extends ViewBoxBaseComponent() { const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2; const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2; const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - srcContext._panX = newPanX + (vfLeft + (vfWidth / 2)); - srcContext._panY = newPanY + (vfTop + (vfHeight / 2)); + srcContext._panX = newPanX + (vfLeft + vfWidth / 2); + srcContext._panY = newPanY + (vfTop + vfHeight / 2); srcContext._viewScale = newScale; } } @@ -465,8 +489,8 @@ export class PresBox extends ViewBoxBaseComponent() { const panelWidth: number = docView.props.PanelWidth(); const panelHeight: number = docView.props.PanelHeight(); const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - targetDoc._panX = vfLeft + (vfWidth / 2); - targetDoc._panY = vfTop + (vfWidth / 2); + targetDoc._panX = vfLeft + vfWidth / 2; + targetDoc._panY = vfTop + vfWidth / 2; targetDoc._viewScale = newScale; } const resize = document.getElementById('resizable'); @@ -476,7 +500,7 @@ export class PresBox extends ViewBoxBaseComponent() { resize.style.top = vfTop + 'px'; resize.style.left = vfLeft + 'px'; } - } + }; /** * For 'Hide Before' and 'Hide After' buttons making sure that @@ -490,18 +514,19 @@ export class PresBox extends ViewBoxBaseComponent() { if (tagDoc) tagDoc.opacity = 1; const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); const curInd: number = itemIndexes.indexOf(index); - if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; } - else { - if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) { } - else if (curDoc.presHideBefore) { + if (tagDoc === this.layoutDoc.presCollection) { + tagDoc.opacity = 1; + } else { + if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) { + } else if (curDoc.presHideBefore) { if (index > this.itemIndex) { tagDoc.opacity = 0; } else if (!curDoc.presHideAfter) { tagDoc.opacity = 1; } } - if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== (itemIndexes.length - 1)) { } - else if (curDoc.presHideAfter) { + if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== itemIndexes.length - 1) { + } else if (curDoc.presHideAfter) { if (index < this.itemIndex) { tagDoc.opacity = 0; } else if (!curDoc.presHideBefore) { @@ -510,9 +535,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } }); - } - - + }; //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc @action @@ -521,13 +544,16 @@ export class PresBox extends ViewBoxBaseComponent() { let activeItem: Doc = this.activeItem; let targetDoc: Doc = this.targetDoc; let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition); - const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); - const load = async () => { // Wrap the loop into an async function for this to work + const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms))); + const load = async () => { + // Wrap the loop into an async function for this to work for (var i = startSlide; i < this.childDocs.length; i++) { activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition); - if (duration < 100) { duration = 2500; } + if (duration < 100) { + duration = 2500; + } if (NumCast(targetDoc.lastFrame) > 0) { for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) { await timer(duration / NumCast(targetDoc.lastFrame)); @@ -535,7 +561,8 @@ export class PresBox extends ViewBoxBaseComponent() { } } - await timer(duration); this.next(); // then the created Promise can be awaited + await timer(duration); + this.next(); // then the created Promise can be awaited if (i === this.childDocs.length - 1) { setTimeout(() => { clearTimeout(this._presTimer); @@ -549,7 +576,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.startPresentation(startSlide); this.gotoDocument(startSlide, activeItem); load(); - } + }; // The function pauses the auto presentation @action @@ -560,20 +587,23 @@ export class PresBox extends ViewBoxBaseComponent() { this.layoutDoc.presLoop = false; this.childDocs.forEach(this.stopTempMedia); } - } + }; //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. resetPresentation = () => { this.rootDoc._itemIndex = 0; - this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)).filter(doc => doc instanceof Doc).forEach(doc => { - try { - doc.opacity = 1; - } catch (e) { - console.log("Reset presentation error: ", e); - } - }); - } + this.childDocs + .map(doc => Cast(doc.presentationTargetDoc, Doc, null)) + .filter(doc => doc instanceof Doc) + .forEach(doc => { + try { + doc.opacity = 1; + } catch (e) { + console.log('Reset presentation error: ', e); + } + }); + }; // The function allows for viewing the pres path on toggle @action togglePath = (srcContext: Doc, off?: boolean) => { @@ -581,19 +611,19 @@ export class PresBox extends ViewBoxBaseComponent() { this._pathBoolean = false; srcContext.presPathView = false; } else { - runInAction(() => this._pathBoolean = !this._pathBoolean); + runInAction(() => (this._pathBoolean = !this._pathBoolean)); srcContext.presPathView = this._pathBoolean; } - } + }; // The function allows for expanding the view of pres on toggle @action toggleExpandMode = () => { - runInAction(() => this._expandBoolean = !this._expandBoolean); + runInAction(() => (this._expandBoolean = !this._expandBoolean)); this.rootDoc.expandBoolean = this._expandBoolean; - this.childDocs.forEach((doc) => { + this.childDocs.forEach(doc => { doc.presExpandInlineButton = this._expandBoolean; }); - } + }; /** * The function that starts the presentation at the given index, also checking if actions should be applied @@ -611,7 +641,7 @@ export class PresBox extends ViewBoxBaseComponent() { tagDoc.opacity = 0; } }); - } + }; /** * The method called to open the presentation as a minimized view @@ -621,7 +651,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); - CollectionDockingView.AddSplit(this.rootDoc, "right"); + CollectionDockingView.AddSplit(this.rootDoc, 'right'); } else { this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); @@ -633,7 +663,7 @@ export class PresBox extends ViewBoxBaseComponent() { Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); this.props.removeDocument?.(this.layoutDoc); } - } + }; /** * Called when the user changes the view type @@ -643,7 +673,7 @@ export class PresBox extends ViewBoxBaseComponent() { viewChanged = action((e: React.ChangeEvent) => { //@ts-ignore const viewType = e.target.selectedOptions[0].value as CollectionViewType; - this.layoutDoc.presFieldKey = this.fieldKey+(viewType === CollectionViewType.Tree ?"-linearized":""); + this.layoutDoc.presFieldKey = this.fieldKey + (viewType === CollectionViewType.Tree ? '-linearized' : ''); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here [CollectionViewType.Tree || CollectionViewType.Stacking].includes(viewType) && (this.rootDoc._pivotField = undefined); this.rootDoc._viewType = viewType; @@ -677,20 +707,30 @@ export class PresBox extends ViewBoxBaseComponent() { } }); - setMovementName = action((movement: any, activeItem: Doc): string => { let output: string = 'none'; switch (movement) { - case PresMovement.Zoom: output = 'Pan & Zoom'; break; //Pan and zoom - case PresMovement.Pan: output = 'Pan'; break; //Pan - case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut - case PresMovement.None: output = 'None'; break; //None - default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom + case PresMovement.Zoom: + output = 'Pan & Zoom'; + break; //Pan and zoom + case PresMovement.Pan: + output = 'Pan'; + break; //Pan + case PresMovement.Jump: + output = 'Jump cut'; + break; //Jump Cut + case PresMovement.None: + output = 'None'; + break; //None + default: + output = 'Zoom'; + activeItem.presMovement = 'zoom'; + break; //default set as zoom } return output; }); - whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive)); + whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive))); // For dragging documents into the presentation trail addDocumentFilter = (docs: Doc[]) => { docs.forEach((doc, i) => { @@ -698,8 +738,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (doc.type === DocumentType.LABEL) { const audio = Cast(doc.annotationOn, Doc, null); if (audio) { - audio.mediaStart = "manual"; - audio.mediaStop = "manual"; + audio.mediaStart = 'manual'; + audio.mediaStop = 'manual'; audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); audio.presDuration = audio.presStartTime - audio.presEndTime; @@ -714,7 +754,7 @@ export class PresBox extends ViewBoxBaseComponent() { setTimeout(() => this.removeDocument(doc), 0); return false; } else { - if (!doc.presentationTargetDoc) doc.title = doc.title + " - Slide"; + if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide'; doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); doc.presMovement = PresMovement.Zoom; if (this._expandBoolean) doc.presExpandInlineButton = true; @@ -722,13 +762,13 @@ export class PresBox extends ViewBoxBaseComponent() { } }); return true; - } - childLayoutTemplate = () => !this.isTreeOrStack ? undefined : DocCast(Doc.UserDoc().presElement); + }; + childLayoutTemplate = () => (!this.isTreeOrStack ? undefined : DocCast(Doc.UserDoc().presElement)); removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); - getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight + getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition) && - (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) + isContentActive = (outsideReaction?: boolean) => + CurrentUserUtils.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false; /** * For sorting the array so that the order is maintained when it is dropped. @@ -736,7 +776,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action sortArray = (): Doc[] => { return this.childDocs.filter(doc => this._selectedArray.has(doc)); - } + }; /** * Method to get the list of selected items in the order in which they have been selected @@ -745,9 +785,26 @@ export class PresBox extends ViewBoxBaseComponent() { const list = Array.from(this._selectedArray.keys()).map((doc: Doc, index: any) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); - if (curDoc && curDoc === this.activeItem) return
{index + 1}. {curDoc.title}
; - else if (tagDoc) return
{index + 1}. {curDoc.title}
; - else if (curDoc) return
{index + 1}. {curDoc.title}
; + if (curDoc && curDoc === this.activeItem) + return ( +
+ + {index + 1}. {curDoc.title} + +
+ ); + else if (tagDoc) + return ( +
+ {index + 1}. {curDoc.title} +
+ ); + else if (curDoc) + return ( +
+ {index + 1}. {curDoc.title} +
+ ); }); return list; } @@ -756,7 +813,7 @@ export class PresBox extends ViewBoxBaseComponent() { selectPres = () => { const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc); presDocView && SelectionManager.SelectView(presDocView, false); - } + }; //Regular click @action @@ -766,12 +823,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0); else this.updateCurrentPresentation(context); - if (this.activeItem.setPosition && - this.activeItem.y !== undefined && - this.activeItem.x !== undefined && - this.targetDoc.x !== undefined && - this.targetDoc.y !== undefined) { - const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); + if (this.activeItem.setPosition && this.activeItem.y !== undefined && this.activeItem.x !== undefined && this.targetDoc.x !== undefined && this.targetDoc.y !== undefined) { + const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms))); const time = 10; const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y); const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x); @@ -782,7 +835,7 @@ export class PresBox extends ViewBoxBaseComponent() { await timer(0.1); } } - } + }; //Command click @action @@ -797,13 +850,13 @@ export class PresBox extends ViewBoxBaseComponent() { this.removeFromArray(this._dragArray, doc); } this.selectPres(); - } + }; removeFromArray = (arr: any[], val: any) => { const index: number = arr.indexOf(val); const ret: any[] = arr.splice(index, 1); arr = ret; - } + }; //Shift click @action @@ -818,7 +871,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } this.selectPres(); - } + }; //regular click @action @@ -829,17 +882,17 @@ export class PresBox extends ViewBoxBaseComponent() { this._dragArray.splice(0, this._dragArray.length, drag); focus && this.selectElement(doc); selectPres && this.selectPres(); - } + }; modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => { if (cmdClick) this.multiSelect(doc, ref, drag); else if (shiftClick) this.shiftSelect(doc, ref, drag); else this.regularSelect(doc, ref, drag, focus); - } + }; static keyEventsWrapper = (e: KeyboardEvent) => { PresBox.Instance.keyEvents(e); - } + }; // Key for when the presentaiton is active @action @@ -847,57 +900,75 @@ export class PresBox extends ViewBoxBaseComponent() { if (e.target instanceof HTMLInputElement) return; let handled = false; const anchorNode = document.activeElement as HTMLDivElement; - if (anchorNode && anchorNode.className?.includes("lm_title")) return; + if (anchorNode && anchorNode.className?.includes('lm_title')) return; switch (e.key) { - case "Backspace": - if (this.layoutDoc.presStatus === "edit") { - undoBatch(action(() => { - for (const doc of Array.from(this._selectedArray.keys())) { - this.removeDocument(doc); - } - this._selectedArray.clear(); - this._eleArray.length = 0; - this._dragArray.length = 0; - }))(); + case 'Backspace': + if (this.layoutDoc.presStatus === 'edit') { + undoBatch( + action(() => { + for (const doc of Array.from(this._selectedArray.keys())) { + this.removeDocument(doc); + } + this._selectedArray.clear(); + this._eleArray.length = 0; + this._dragArray.length = 0; + }) + )(); handled = true; } break; - case "Escape": - if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.updateMinimize(); } - else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; } - else this.layoutDoc.presStatus = "edit"; + case 'Escape': + if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { + this.updateMinimize(); + } else if (this.layoutDoc.presStatus === 'edit') { + this._selectedArray.clear(); + this._eleArray.length = this._dragArray.length = 0; + } else this.layoutDoc.presStatus = 'edit'; if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; - case "Down": case "ArrowDown": - case "Right": case "ArrowRight": - if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) { // TODO: update to work properly + case 'Down': + case 'ArrowDown': + case 'Right': + case 'ArrowRight': + if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) { + // TODO: update to work properly this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1; this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined); } else { this.next(); - if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } } handled = true; break; - case "Up": case "ArrowUp": - case "Left": case "ArrowLeft": - if (e.shiftKey && this.itemIndex !== 0) { // TODO: update to work properly + case 'Up': + case 'ArrowUp': + case 'Left': + case 'ArrowLeft': + if (e.shiftKey && this.itemIndex !== 0) { + // TODO: update to work properly this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1; this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined); } else { this.back(); - if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } } handled = true; break; - case "Spacebar": case " ": + case 'Spacebar': + case ' ': if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex); else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; - case "a": - if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === "edit") { + case 'a': + if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') { this._selectedArray.clear(); this.childDocs.forEach(doc => this._selectedArray.set(doc, undefined)); handled = true; @@ -909,10 +980,10 @@ export class PresBox extends ViewBoxBaseComponent() { e.stopPropagation(); e.preventDefault(); } - } + }; /** - * + * */ @action viewPaths = () => { @@ -920,7 +991,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (srcContext) { this.togglePath(srcContext); } - } + }; getAllIndexes = (arr: Doc[], val: Doc): number[] => { const indexes = []; @@ -928,7 +999,7 @@ export class PresBox extends ViewBoxBaseComponent() { arr[i] === val && indexes.push(i); } return indexes; - } + }; // Adds the index in the pres path graphically @computed get order() { @@ -936,61 +1007,64 @@ export class PresBox extends ViewBoxBaseComponent() { const docs: Doc[] = []; const presCollection = Cast(this.rootDoc.presCollection, Doc, null); const dv = DocumentManager.Instance.getDocumentView(presCollection); - this.childDocs.filter(doc => Cast(doc.presentationTargetDoc, Doc, null)).forEach((doc, index) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); - const srcContext = Cast(tagDoc.context, Doc, null); - const width = NumCast(tagDoc._width) / 10; - const height = Math.max(NumCast(tagDoc._height) / 10, 15); - const edge = Math.max(width, height); - const fontSize = edge * 0.8; - const gap = 2; - if (presCollection === srcContext) { - // Case A: Document is contained within the collection - if (docs.includes(tagDoc)) { - const prevOccurances: number = this.getAllIndexes(docs, tagDoc).length; - docs.push(tagDoc); - order.push( -
this.selectElement(doc)}> -
{index + 1}
-
); - } else { + this.childDocs + .filter(doc => Cast(doc.presentationTargetDoc, Doc, null)) + .forEach((doc, index) => { + const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const srcContext = Cast(tagDoc.context, Doc, null); + const width = NumCast(tagDoc._width) / 10; + const height = Math.max(NumCast(tagDoc._height) / 10, 15); + const edge = Math.max(width, height); + const fontSize = edge * 0.8; + const gap = 2; + if (presCollection === srcContext) { + // Case A: Document is contained within the collection + if (docs.includes(tagDoc)) { + const prevOccurances: number = this.getAllIndexes(docs, tagDoc).length; + docs.push(tagDoc); + order.push( +
this.selectElement(doc)}> +
{index + 1}
+
+ ); + } else { + docs.push(tagDoc); + order.push( +
this.selectElement(doc)}> +
{index + 1}
+
+ ); + } + } else if (doc.presPinView && presCollection === tagDoc && dv) { + // Case B: Document is presPinView and is presCollection + const scale: number = 1 / NumCast(doc.presPinViewScale); + const height: number = dv.props.PanelHeight() * scale; + const width: number = dv.props.PanelWidth() * scale; + const indWidth = width / 10; + const indHeight = Math.max(height / 10, 15); + const indEdge = Math.max(indWidth, indHeight); + const indFontSize = indEdge * 0.8; + const xLoc: number = NumCast(doc.presPinViewX) - width / 2; + const yLoc: number = NumCast(doc.presPinViewY) - height / 2; docs.push(tagDoc); order.push( -
this.selectElement(doc)}> -
{index + 1}
-
); + <> +
this.selectElement(doc)}> +
{index + 1}
+
+
+ + ); } - } else if (doc.presPinView && presCollection === tagDoc && dv) { - // Case B: Document is presPinView and is presCollection - const scale: number = 1 / NumCast(doc.presPinViewScale); - const height: number = dv.props.PanelHeight() * scale; - const width: number = dv.props.PanelWidth() * scale; - const indWidth = width / 10; - const indHeight = Math.max(height / 10, 15); - const indEdge = Math.max(indWidth, indHeight); - const indFontSize = indEdge * 0.8; - const xLoc: number = NumCast(doc.presPinViewX) - (width / 2); - const yLoc: number = NumCast(doc.presPinViewY) - (height / 2); - docs.push(tagDoc); - order.push( - <> -
this.selectElement(doc)} - > -
{index + 1}
-
-
- ); - } - }); + }); return order; } @@ -1003,37 +1077,39 @@ export class PresBox extends ViewBoxBaseComponent() { * collection) */ @computed get paths() { - let pathPoints = ""; + let pathPoints = ''; const presCollection = Cast(this.rootDoc.presCollection, Doc, null); this.childDocs.forEach((doc, index) => { const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); const srcContext = Cast(tagDoc?.context, Doc, null); if (tagDoc && presCollection === srcContext) { - const n1x = NumCast(tagDoc.x) + (NumCast(tagDoc._width) / 2); - const n1y = NumCast(tagDoc.y) + (NumCast(tagDoc._height) / 2); - if (index = 0) pathPoints = n1x + "," + n1y; - else pathPoints = pathPoints + " " + n1x + "," + n1y; + const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2; + const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2; + if ((index = 0)) pathPoints = n1x + ',' + n1y; + else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } else if (doc.presPinView && presCollection === tagDoc) { const n1x = NumCast(doc.presPinViewX); const n1y = NumCast(doc.presPinViewY); - if (index = 0) pathPoints = n1x + "," + n1y; - else pathPoints = pathPoints + " " + n1x + "," + n1y; + if ((index = 0)) pathPoints = n1x + ',' + n1y; + else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } }); - return (); + return ( + + ); } // Converts seconds to ms and updates presTransition @@ -1042,8 +1118,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - Array.from(this._selectedArray.keys()).forEach((doc) => doc.presTransition = timeInMS); - } + Array.from(this._selectedArray.keys()).forEach(doc => (doc.presTransition = timeInMS)); + }; // Converts seconds to ms and updates presTransition setZoom = (number: String, change?: number) => { @@ -1051,8 +1127,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) scale += change; if (scale < 0.01) scale = 0.01; if (scale > 1.5) scale = 1.5; - Array.from(this._selectedArray.keys()).forEach((doc) => doc.presZoom = scale); - } + Array.from(this._selectedArray.keys()).forEach(doc => (doc.presZoom = scale)); + }; // Converts seconds to ms and updates presDuration setDurationTime = (number: String, change?: number) => { @@ -1060,8 +1136,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; - Array.from(this._selectedArray.keys()).forEach((doc) => doc.presDuration = timeInMS); - } + Array.from(this._selectedArray.keys()).forEach(doc => (doc.presDuration = timeInMS)); + }; /** * When the movement dropdown is changes @@ -1069,7 +1145,7 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateMovement = action((movement: any, all?: boolean) => { const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach((doc) => { + array.forEach(doc => { switch (movement) { case PresMovement.Zoom: //Pan and zoom doc.presMovement = PresMovement.Zoom; @@ -1081,7 +1157,8 @@ export class PresBox extends ViewBoxBaseComponent() { doc.presJump = true; doc.presMovement = PresMovement.Jump; break; - case PresMovement.None: default: + case PresMovement.None: + default: doc.presMovement = PresMovement.None; break; } @@ -1092,31 +1169,31 @@ export class PresBox extends ViewBoxBaseComponent() { @action updateHideBefore = (activeItem: Doc) => { activeItem.presHideBefore = !activeItem.presHideBefore; - Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideBefore = activeItem.presHideBefore); - } + Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); + }; @undoBatch @action updateHideAfter = (activeItem: Doc) => { activeItem.presHideAfter = !activeItem.presHideAfter; - Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideAfter = activeItem.presHideAfter); - } + Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); + }; @undoBatch @action updateOpenDoc = (activeItem: Doc) => { activeItem.openDocument = !activeItem.openDocument; - Array.from(this._selectedArray.keys()).forEach((doc) => { + Array.from(this._selectedArray.keys()).forEach(doc => { doc.openDocument = activeItem.openDocument; }); - } + }; @undoBatch @action updateEffectDirection = (effect: any, all?: boolean) => { const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach((doc) => { - const tagDoc = doc;// Cast(doc.presentationTargetDoc, Doc, null); + array.forEach(doc => { + const tagDoc = doc; // Cast(doc.presentationTargetDoc, Doc, null); switch (effect) { case PresEffect.Left: tagDoc.presEffectDirection = PresEffect.Left; @@ -1130,19 +1207,20 @@ export class PresBox extends ViewBoxBaseComponent() { case PresEffect.Bottom: tagDoc.presEffectDirection = PresEffect.Bottom; break; - case PresEffect.Center: default: + case PresEffect.Center: + default: tagDoc.presEffectDirection = PresEffect.Center; break; } }); - } + }; @undoBatch @action updateEffect = (effect: any, all?: boolean) => { const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach((doc) => { - const tagDoc = doc;//Cast(doc.presentationTargetDoc, Doc, null); + array.forEach(doc => { + const tagDoc = doc; //Cast(doc.presentationTargetDoc, Doc, null); switch (effect) { case PresEffect.Bounce: tagDoc.presEffect = PresEffect.Bounce; @@ -1159,19 +1237,20 @@ export class PresBox extends ViewBoxBaseComponent() { case PresEffect.Rotate: tagDoc.presEffect = PresEffect.Rotate; break; - case PresEffect.None: default: + case PresEffect.None: + default: tagDoc.presEffect = PresEffect.None; break; } }); - } + }; _batch: UndoManager.Batch | undefined = undefined; @computed get transitionDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection); + const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection; const isPinWithView: boolean = BoolCast(activeItem.presPinView); if (activeItem && targetDoc) { const type = targetDoc.type; @@ -1182,155 +1261,301 @@ export class PresBox extends ViewBoxBaseComponent() { const effect = this.activeItem.presEffect ? this.activeItem.presEffect : 'None'; activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom'; return ( -
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}> +
e.stopPropagation()} + onPointerUp={e => e.stopPropagation()} + onClick={action(e => { + e.stopPropagation(); + this.openMovementDropdown = false; + this.openEffectDropdown = false; + })}>
Movement - {isPresCollection || (isPresCollection && isPinWithView) ? + {isPresCollection || (isPresCollection && isPinWithView) ? (
- {this.scrollable ? "Scroll to pinned view" : !isPinWithView ? "No movement" : "Pan & Zoom to pinned view"} + {this.scrollable ? 'Scroll to pinned view' : !isPinWithView ? 'No movement' : 'Pan & Zoom to pinned view'}
- : -
{ e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + ) : ( +
{ + e.stopPropagation(); + this.openMovementDropdown = !this.openMovementDropdown; + })} + style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> {this.setMovementName(activeItem.presMovement, activeItem)} - -
e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}> -
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut
+ +
e.stopPropagation()} style={{ display: this.openMovementDropdown ? 'grid' : 'none' }}> +
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}> + None +
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}> + Pan {'&'} Zoom +
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}> + Pan +
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}> + Jump cut +
- } -
+ )} +
Zoom (% screen filled)
- this.setZoom(e.target.value))} />% + this.setZoom(e.target.value))} />%
this.setZoom(String(zoom), 0.1))}> - +
this.setZoom(String(zoom), -0.1))}> - +
- this._batch = UndoManager.StartBatch("presZoom")} + onPointerDown={() => (this._batch = UndoManager.StartBatch('presZoom'))} onPointerUp={() => this._batch?.end()} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); this.setZoom(e.target.value); - }} /> -
+ }} + /> +
Movement Speed
- e.stopPropagation()} - onChange={action((e) => this.setTransitionTime(e.target.value))} /> s + e.stopPropagation()} onChange={action(e => this.setTransitionTime(e.target.value))} /> s
this.setTransitionTime(String(transitionSpeed), 1000))}> - +
this.setTransitionTime(String(transitionSpeed), -1000))}> - +
- this._batch = UndoManager.StartBatch("presTransition")} + onPointerDown={() => (this._batch = UndoManager.StartBatch('presTransition'))} onPointerUp={() => this._batch?.end()} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); this.setTransitionTime(e.target.value); - }} /> -
+ }} + /> +
Fast
Medium
Slow
- Visibility {"&"} Duration + Visibility {'&'} Duration
- {isPresCollection ? (null) :
{"Hide before presented"}
}>
this.updateHideBefore(activeItem)}>Hide before
} - {isPresCollection ? (null) :
{"Hide after presented"}
}>
this.updateHideAfter(activeItem)}>Hide after
} -
{"Open in lightbox view"}
}>
this.updateOpenDoc(activeItem)}>Lightbox
+ {isPresCollection ? null : ( + +
{'Hide before presented'}
+ + }> +
this.updateHideBefore(activeItem)}> + Hide before +
+
+ )} + {isPresCollection ? null : ( + +
{'Hide after presented'}
+ + }> +
this.updateHideAfter(activeItem)}> + Hide after +
+
+ )} + +
{'Open in lightbox view'}
+ + }> +
this.updateOpenDoc(activeItem)}> + Lightbox +
+
- {(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) : <> -
-
Slide Duration
-
- e.stopPropagation()} - onChange={action((e) => this.setDurationTime(e.target.value))} /> s + {type === DocumentType.AUDIO || type === DocumentType.VID ? null : ( + <> +
+
Slide Duration
+
+ e.stopPropagation()} onChange={action(e => this.setDurationTime(e.target.value))} /> s +
+
+
this.setDurationTime(String(duration), 1000))}> + +
+
this.setDurationTime(String(duration), -1000))}> + +
+
+
+ { + this._batch = UndoManager.StartBatch('presDuration'); + }} + onPointerUp={() => { + if (this._batch) this._batch.end(); + }} + onChange={(e: React.ChangeEvent) => { + e.stopPropagation(); + this.setDurationTime(e.target.value); + }} + /> +
+
Short
+
Medium
+
Long
-
-
this.setDurationTime(String(duration), 1000))}> - + + )} +
+ {isPresCollection ? null : ( +
+ Effects +
{ + e.stopPropagation(); + this.openEffectDropdown = !this.openEffectDropdown; + })} + style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + {effect.toString()} + +
e.stopPropagation()}> +
e.stopPropagation()} + onClick={() => this.updateEffect(PresEffect.None)}> + None
-
this.setDurationTime(String(duration), -1000))}> - +
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}> + Fade In +
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}> + Flip +
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}> + Rotate +
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}> + Bounce +
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}> + Roll
- { this._batch = UndoManager.StartBatch("presDuration"); }} - onPointerUp={() => { if (this._batch) this._batch.end(); }} - onChange={(e: React.ChangeEvent) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} - /> -
-
Short
-
Medium
-
Long
+
+
Effect direction
+
{this.effectDirection}
- } -
- {isPresCollection ? (null) :
- Effects -
{ e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> - {effect} - -
e.stopPropagation()}> -
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll
-
-
-
-
Effect direction
-
- {this.effectDirection} +
+ {'Enter from left'}
}> +
this.updateEffectDirection(PresEffect.Left)}> + +
+ + {'Enter from right'}
}> +
this.updateEffectDirection(PresEffect.Right)}> + +
+ + +
{'Enter from top'}
+ + }> +
this.updateEffectDirection(PresEffect.Top)}> + +
+
+ +
{'Enter from bottom'}
+ + }> +
this.updateEffectDirection(PresEffect.Bottom)}> + +
+
+ +
{'Enter from center'}
+ + }> +
this.updateEffectDirection(PresEffect.Center)}>
+
-
-
{"Enter from left"}
}>
this.updateEffectDirection(PresEffect.Left)}>
-
{"Enter from right"}
}>
this.updateEffectDirection(PresEffect.Right)}>
-
{"Enter from top"}
}>
this.updateEffectDirection(PresEffect.Top)}>
-
{"Enter from bottom"}
}>
this.updateEffectDirection(PresEffect.Bottom)}>
-
{"Enter from center"}
}>
this.updateEffectDirection(PresEffect.Center)}>
-
-
} + )}
this.applyTo(this.childDocs)}> Apply to all
-
+
); } } @@ -1338,11 +1563,21 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get effectDirection(): string { let effect = ''; switch (this.activeItem.presEffectDirection) { - case 'left': effect = "Enter from left"; break; - case 'right': effect = "Enter from right"; break; - case 'top': effect = "Enter from top"; break; - case 'bottom': effect = "Enter from bottom"; break; - default: effect = "Enter from center"; break; + case 'left': + effect = 'Enter from left'; + break; + case 'right': + effect = 'Enter from right'; + break; + case 'top': + effect = 'Enter from top'; + break; + case 'bottom': + effect = 'Enter from bottom'; + break; + default: + effect = 'Enter from center'; + break; } return effect; } @@ -1355,7 +1590,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.updateMovement(activeItem.presMovement, true); this.updateEffect(activeItem.presEffect, true); this.updateEffectDirection(activeItem.presEffectDirection, true); - array.forEach((doc) => { + array.forEach(doc => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); if (tagDoc && targetDoc) { @@ -1365,63 +1600,86 @@ export class PresBox extends ViewBoxBaseComponent() { curDoc.presHideAfter = activeItem.presHideAfter; } }); - } + }; @computed get presPinViewOptionsDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const presPinWithViewIcon = ; + const presPinWithViewIcon = ; return ( <> - {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)} + {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : null}
-
{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}
}>
{ - activeItem.presPinView = !activeItem.presPinView; - targetDoc.presPinView = activeItem.presPinView; - if (activeItem.presPinView) { - if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) { - const scroll = targetDoc._scrollTop; - activeItem.presPinView = true; - activeItem.presPinViewScroll = scroll; - } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { - activeItem.presStartTime = targetDoc._currentTimecode; - activeItem.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1; - } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) { - const x = targetDoc._panX; - const y = targetDoc._panY; - const scale = targetDoc._viewScale; - activeItem.presPinView = true; - activeItem.presPinViewX = x; - activeItem.presPinViewY = y; - activeItem.presPinViewScale = scale; - } else if (targetDoc.type === DocumentType.COMPARISON) { - const width = targetDoc._clipWidth; - activeItem.presPinClipWidth = width; - activeItem.presPinView = true; + +
{activeItem.presPinView ? 'Turn off pin with view' : 'Turn on pin with view'}
+ + }> +
{ + activeItem.presPinView = !activeItem.presPinView; + targetDoc.presPinView = activeItem.presPinView; + if (activeItem.presPinView) { + if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) { + const scroll = targetDoc._scrollTop; + activeItem.presPinView = true; + activeItem.presPinViewScroll = scroll; + } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { + activeItem.presStartTime = targetDoc._currentTimecode; + activeItem.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1; + } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) { + const x = targetDoc._panX; + const y = targetDoc._panY; + const scale = targetDoc._viewScale; + activeItem.presPinView = true; + activeItem.presPinViewX = x; + activeItem.presPinViewY = y; + activeItem.presPinViewScale = scale; + } else if (targetDoc.type === DocumentType.COMPARISON) { + const width = targetDoc._clipWidth; + activeItem.presPinClipWidth = width; + activeItem.presPinView = true; + } } - } - }}>{presPinWithViewIcon}
- {activeItem.presPinView ?
{"Update the pinned view with the view of the selected document"}
}>
{ - if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) { - const scroll = targetDoc._scrollTop; - activeItem.presPinViewScroll = scroll; - } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { - activeItem.presStartTime = targetDoc._currentTimecode; - activeItem.presStartTime = NumCast(targetDoc._currentTimecode) + 0.1; - } else if (targetDoc.type === DocumentType.COMPARISON) { - const clipWidth = targetDoc._clipWidth; - activeItem.presPinClipWidth = clipWidth; - } else { - const x = targetDoc._panX; - const y = targetDoc._panY; - const scale = targetDoc._viewScale; - activeItem.presPinViewX = x; - activeItem.presPinViewY = y; - activeItem.presPinViewScale = scale; - } - }}>Update
: (null)} + }}> + {presPinWithViewIcon} +
+
+ {activeItem.presPinView ? ( + +
{'Update the pinned view with the view of the selected document'}
+ + }> +
{ + if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) { + const scroll = targetDoc._scrollTop; + activeItem.presPinViewScroll = scroll; + } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { + activeItem.presStartTime = targetDoc._currentTimecode; + activeItem.presStartTime = NumCast(targetDoc._currentTimecode) + 0.1; + } else if (targetDoc.type === DocumentType.COMPARISON) { + const clipWidth = targetDoc._clipWidth; + activeItem.presPinClipWidth = clipWidth; + } else { + const x = targetDoc._panX; + const y = targetDoc._panY; + const scale = targetDoc._viewScale; + activeItem.presPinViewX = x; + activeItem.presPinViewY = y; + activeItem.presPinViewScale = scale; + } + }}> + Update +
+
+ ) : null}
); @@ -1432,38 +1690,58 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; return ( <> - {this.panable ?
-
-
Pan X
-
- e.stopPropagation()} - onChange={action((e: React.ChangeEvent) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} /> + {this.panable ? ( +
+
+
Pan X
+
+ e.stopPropagation()} + onChange={action((e: React.ChangeEvent) => { + const val = e.target.value; + activeItem.presPinViewX = Number(val); + })} + /> +
-
-
-
Pan Y
-
- e.stopPropagation()} - onChange={action((e: React.ChangeEvent) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} /> +
+
Pan Y
+
+ e.stopPropagation()} + onChange={action((e: React.ChangeEvent) => { + const val = e.target.value; + activeItem.presPinViewY = Number(val); + })} + /> +
-
-
-
Scale
-
- e.stopPropagation()} - onChange={action((e: React.ChangeEvent) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} /> +
+
Scale
+
+ e.stopPropagation()} + onChange={action((e: React.ChangeEvent) => { + const val = e.target.value; + activeItem.presPinViewScale = Number(val); + })} + /> +
-
: (null)} + ) : null} ); } @@ -1473,18 +1751,26 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; return ( <> - {this.scrollable ?
-
-
Scroll
-
- e.stopPropagation()} - onChange={action((e: React.ChangeEvent) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} /> + {this.scrollable ? ( +
+
+
Scroll
+
+ e.stopPropagation()} + onChange={action((e: React.ChangeEvent) => { + const val = e.target.value; + activeItem.presPinViewScroll = Number(val); + })} + /> +
-
: (null)} + ) : null} ); } @@ -1494,13 +1780,13 @@ export class PresBox extends ViewBoxBaseComponent() { const list = this.childDocs.map((doc, i) => { if (i > this.itemIndex) { return ( - + ); } }); - return ( - list - ); + return list; } @computed get mediaOptionsDropdown() { @@ -1510,25 +1796,29 @@ export class PresBox extends ViewBoxBaseComponent() { const clipEnd: number = NumCast(activeItem.clipEnd); const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10); const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc); - const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + ". " + this.childDocs[mediaStopDocInd - 1].title : ""; + const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + '. ' + this.childDocs[mediaStopDocInd - 1].title : ''; if (activeItem && targetDoc) { return (
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
- Start {"&"} End Time -
-
+ Start {'&'} End Time +
+
Start time (s)
-
- + e.stopPropagation()} - onChange={action((e: React.ChangeEvent) => { activeItem.presStartTime = Number(e.target.value); })} + onChange={action((e: React.ChangeEvent) => { + activeItem.presStartTime = Number(e.target.value); + })} />
@@ -1544,24 +1834,33 @@ export class PresBox extends ViewBoxBaseComponent() {
End time (s)
-
- + e.stopPropagation()} style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }} - type="number" value={NumCast(activeItem.presEndTime)} - onChange={action((e: React.ChangeEvent) => { activeItem.presEndTime = Number(e.target.value); })} + type="number" + value={NumCast(activeItem.presEndTime)} + onChange={action((e: React.ChangeEvent) => { + activeItem.presEndTime = Number(e.target.value); + })} />
- { - this._batch = UndoManager.StartBatch("presEndTime"); - const endBlock = document.getElementById("endTime"); + this._batch = UndoManager.StartBatch('presEndTime'); + const endBlock = document.getElementById('endTime'); if (endBlock) { endBlock.style.color = Colors.LIGHT_GRAY; endBlock.style.backgroundColor = Colors.MEDIUM_BLUE; @@ -1569,7 +1868,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onPointerUp={() => { this._batch?.end(); - const endBlock = document.getElementById("endTime"); + const endBlock = document.getElementById('endTime'); if (endBlock) { endBlock.style.color = Colors.BLACK; endBlock.style.backgroundColor = Colors.LIGHT_GRAY; @@ -1578,14 +1877,20 @@ export class PresBox extends ViewBoxBaseComponent() { onChange={(e: React.ChangeEvent) => { e.stopPropagation(); activeItem.presEndTime = Number(e.target.value); - }} /> - + { - this._batch = UndoManager.StartBatch("presStartTime"); - const startBlock = document.getElementById("startTime"); + this._batch = UndoManager.StartBatch('presStartTime'); + const startBlock = document.getElementById('startTime'); if (startBlock) { startBlock.style.color = Colors.LIGHT_GRAY; startBlock.style.backgroundColor = Colors.MEDIUM_BLUE; @@ -1593,7 +1898,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onPointerUp={() => { this._batch?.end(); - const startBlock = document.getElementById("startTime"); + const startBlock = document.getElementById('startTime'); if (startBlock) { startBlock.style.color = Colors.BLACK; startBlock.style.backgroundColor = Colors.LIGHT_GRAY; @@ -1602,9 +1907,10 @@ export class PresBox extends ViewBoxBaseComponent() { onChange={(e: React.ChangeEvent) => { e.stopPropagation(); activeItem.presStartTime = Number(e.target.value); - }} /> + }} + />
-
+
{clipStart} s
{clipEnd} s
@@ -1615,38 +1921,22 @@ export class PresBox extends ViewBoxBaseComponent() {
Start playing:
- activeItem.mediaStart = "manual"} - checked={activeItem.mediaStart === "manual"} - /> + (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} />
On click
- activeItem.mediaStart = "auto"} - checked={activeItem.mediaStart === "auto"} - /> + (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} />
Automatically
Stop playing:
- activeItem.mediaStop = "manual"} - checked={activeItem.mediaStop === "manual"} - /> + (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} />
At audio end time
- activeItem.mediaStop = "auto"} - checked={activeItem.mediaStop === "auto"} - /> + (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} />
On slide change
{/*
@@ -1670,7 +1960,7 @@ export class PresBox extends ViewBoxBaseComponent() {
-
+
); } } @@ -1678,84 +1968,137 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get newDocumentToolbarDropdown() { return (
-
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
e.stopPropagation()} + onPointerUp={e => e.stopPropagation()} + onPointerDown={e => e.stopPropagation()}>
-
{ this.layout = 'blank'; this.createNewSlide(this.layout); })} /> -
{ this.layout = 'title'; this.createNewSlide(this.layout); })}> +
{ + this.layout = 'blank'; + this.createNewSlide(this.layout); + })} + /> +
{ + this.layout = 'title'; + this.createNewSlide(this.layout); + })}>
Title
Subtitle
-
{ this.layout = 'header'; this.createNewSlide(this.layout); })}> -
Section header
+
{ + this.layout = 'header'; + this.createNewSlide(this.layout); + })}> +
+ Section header +
-
{ this.layout = 'content'; this.createNewSlide(this.layout); })}> -
Title
+
{ + this.layout = 'content'; + this.createNewSlide(this.layout); + })}> +
+ Title +
Text goes here
-
+
); } @observable openLayouts: boolean = false; @observable addFreeform: boolean = true; - @observable layout: string = ""; - @observable title: string = ""; + @observable layout: string = ''; + @observable title: string = ''; @computed get newDocumentDropdown() { return (
-
e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
Slide Title:

- { + { e.stopPropagation(); e.preventDefault(); - runInAction(() => this.title = e.target.value); - }}> - + runInAction(() => (this.title = e.target.value)); + }}>
Choose type:
-
this.addFreeform = !this.addFreeform)}>Text
-
this.addFreeform = !this.addFreeform)}>Freeform
+
(this.addFreeform = !this.addFreeform))}> + Text +
+
(this.addFreeform = !this.addFreeform))}> + Freeform +
-
+
Preset layouts:
-
this.layout = 'blank')} /> -
this.layout = 'title')}> +
(this.layout = 'blank'))} /> +
(this.layout = 'title'))}>
Title
Subtitle
-
this.layout = 'header')}> -
Section header
+
(this.layout = 'header'))}> +
+ Section header +
-
this.layout = 'content')}> -
Title
+
(this.layout = 'content'))}> +
+ Title +
Text goes here
-
this.layout = 'twoColumns')}> -
Title
-
Column one text
-
Column two text
+
(this.layout = 'twoColumns'))}> +
+ Title +
+
+ Column one text +
+
+ Column two text +
-
this.openLayouts = !this.openLayouts)}> - +
(this.openLayouts = !this.openLayouts))}> +
-
this.createNewSlide(this.layout, this.title, this.addFreeform)}> +
this.createNewSlide(this.layout, this.title, this.addFreeform)}> Create New Slide
-
+
); } @@ -1763,7 +2106,7 @@ export class PresBox extends ViewBoxBaseComponent() { let doc = undefined; if (layout) doc = this.createTemplate(layout); if (freeform && layout) doc = this.createTemplate(layout, title); - if (!freeform && !layout) doc = Docs.Create.TextDocument("", { _nativeWidth: 400, _width: 225, title: title }); + if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title }); if (doc) { const presCollection = Cast(this.layoutDoc.presCollection, Doc, null); const data = Cast(presCollection?.data, listSpec(Doc)); @@ -1773,10 +2116,10 @@ export class PresBox extends ViewBoxBaseComponent() { TabDocView.PinDoc(doc); this.gotoDocument(this.childDocs.length, this.activeItem); } else { - this.props.addDocTab(doc, "add:right"); + this.props.addDocTab(doc, 'add:right'); } } - } + }; createTemplate = (layout: string, input?: string) => { const activeItem: Doc = this.activeItem; @@ -1788,43 +2131,59 @@ export class PresBox extends ViewBoxBaseComponent() { y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20; } let doc = undefined; - const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24pt", }); - const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16pt" }); - const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20pt" }); - const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24pt" }); - const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14pt" }); - const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14pt" }); - const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" }); + const title = Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, _fontSize: '24pt' }); + const subtitle = Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, _fontSize: '16pt' }); + const header = Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, _fontSize: '20pt' }); + const contentTitle = Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, _fontSize: '24pt' }); + const content = Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, _fontSize: '14pt' }); + const content1 = Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, _fontSize: '14pt' }); + const content2 = Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _fontSize: '14pt' }); switch (layout) { case 'blank': - doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y }); + doc = Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x: x, y: y }); break; case 'title': - doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : 'Title slide', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'header': - doc = Docs.Create.FreeformDocument([header], { title: input ? input : "Section header", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([header], { title: input ? input : 'Section header', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'content': - doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : "Title and content", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : 'Title and content', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; case 'twoColumns': - doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : "Title and two columns", _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); + doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y }); break; default: break; } return doc; - } + }; // Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view) @computed get presentDropdown() { return ( -
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> -
{ this.updateMinimize(); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}> +
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
{ + this.updateMinimize(); + this.turnOffEdit(true); + this.gotoDocument(this.itemIndex, this.activeItem); + }) + )}> Mini-player
-
{ this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}> +
{ + this.layoutDoc.presStatus = 'manual'; + this.turnOffEdit(true); + this.gotoDocument(this.itemIndex, this.activeItem); + }) + )}> Sidebar player
@@ -1835,7 +2194,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => { const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]); - const currentFrame = Cast(tagDoc._currentFrame, "number", null); + const currentFrame = Cast(tagDoc._currentFrame, 'number', null); if (currentFrame === undefined) { tagDoc._currentFrame = 0; // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0); @@ -1845,19 +2204,19 @@ export class PresBox extends ViewBoxBaseComponent() { CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc); tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1); tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame)); - } + }; @action prevKeyframe = (tagDoc: Doc, actItem: Doc): void => { const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]); - const currentFrame = Cast(tagDoc._currentFrame, "number", null); + const currentFrame = Cast(tagDoc._currentFrame, 'number', null); if (currentFrame === undefined) { tagDoc._currentFrame = 0; // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); } CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice()); tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1); - } + }; /** * Returns the collection type as a string for headers @@ -1868,15 +2227,33 @@ export class PresBox extends ViewBoxBaseComponent() { let type: string = ''; if (activeItem) { switch (targetDoc.type) { - case DocumentType.PDF: type = "PDF"; break; - case DocumentType.RTF: type = "Text node"; break; - case DocumentType.COL: type = "Collection"; break; - case DocumentType.AUDIO: type = "Audio"; break; - case DocumentType.VID: type = "Video"; break; - case DocumentType.IMG: type = "Image"; break; - case DocumentType.WEB: type = "Web page"; break; - case DocumentType.MAP: type = "Map"; break; - default: type = "Other node"; break; + case DocumentType.PDF: + type = 'PDF'; + break; + case DocumentType.RTF: + type = 'Text node'; + break; + case DocumentType.COL: + type = 'Collection'; + break; + case DocumentType.AUDIO: + type = 'Audio'; + break; + case DocumentType.VID: + type = 'Video'; + break; + case DocumentType.IMG: + type = 'Image'; + break; + case DocumentType.WEB: + type = 'Web page'; + break; + case DocumentType.MAP: + type = 'Map'; + break; + default: + type = 'Other node'; + break; } } return type; @@ -1885,66 +2262,122 @@ export class PresBox extends ViewBoxBaseComponent() { @observable private openActiveColorPicker: boolean = false; @observable private openViewedColorPicker: boolean = false; - - @computed get progressivizeDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; if (activeItem && targetDoc) { - const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black"; - const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black"; + const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black'; + const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black'; return (
-
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
e.stopPropagation()} + onPointerUp={e => e.stopPropagation()} + onPointerDown={e => e.stopPropagation()}>
{this.stringType} selected -
-
Contents
-
Edit
+
+
+ Contents +
+
+ Edit +
-
+
Active text color
-
{ this.openActiveColorPicker = !this.openActiveColorPicker; })}> -
+
{ + this.openActiveColorPicker = !this.openActiveColorPicker; + })}>
{this.activeColorPicker} -
+
Viewed font color
-
this.openViewedColorPicker = !this.openViewedColorPicker)}> -
+
(this.openViewedColorPicker = !this.openViewedColorPicker))}>
{this.viewedColorPicker} -
-
Zoom
-
Edit
+
+
+ Zoom +
+
+ Edit +
-
-
Scroll
-
Edit
+
+
+ Scroll +
+
+ Edit +
Frames
-
{ e.stopPropagation(); this.prevKeyframe(targetDoc, activeItem); }}> - +
{ + e.stopPropagation(); + this.prevKeyframe(targetDoc, activeItem); + }}> +
-
targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing)} > +
(targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}> {NumCast(targetDoc._currentFrame)}
-
{ e.stopPropagation(); this.nextKeyframe(targetDoc, activeItem); }}> - +
{ + e.stopPropagation(); + this.nextKeyframe(targetDoc, activeItem); + }}> +
-
{"Last frame"}
}>
{NumCast(targetDoc.lastFrame)}
+ +
{'Last frame'}
+ + }> +
{NumCast(targetDoc.lastFrame)}
+
{this.frameListHeader} {this.frameList}
-
console.log(" TODO: play frames")}>Play
+
console.log(' TODO: play frames')}> + Play +
@@ -1958,37 +2391,41 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; const val = String(color.hex); - targetDoc["pres-text-color"] = val; + targetDoc['pres-text-color'] = val; return true; - } + }; @undoBatch @action switchPresented = (color: ColorState) => { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; const val = String(color.hex); - targetDoc["pres-text-viewed-color"] = val; + targetDoc['pres-text-viewed-color'] = val; return true; - } + }; @computed get activeColorPicker() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - return !this.openActiveColorPicker ? (null) : ; + return !this.openActiveColorPicker ? null : ( + + ); } @computed get viewedColorPicker() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - return !this.openViewedColorPicker ? (null) : ; + return !this.openViewedColorPicker ? null : ( + + ); } @action @@ -1999,7 +2436,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (srcContext) this.togglePath(srcContext, true); } // Turn off the progressivize editors for each document - this.childDocs.forEach((doc) => { + this.childDocs.forEach(doc => { doc.editSnapZoomProgressivize = false; doc.editZoomProgressivize = false; const targetDoc = Cast(doc.presentationTargetDoc, Doc, null); @@ -2008,7 +2445,7 @@ export class PresBox extends ViewBoxBaseComponent() { // targetDoc.editScrollProgressivize = false; } }); - } + }; //Toggle whether the user edits or not @action @@ -2016,14 +2453,15 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; if (!targetDoc.editZoomProgressivize) { - if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; targetDoc.zoomProgressivize = true; + if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; + targetDoc.zoomProgressivize = true; targetDoc.editZoomProgressivize = true; activeItem.editZoomProgressivize = true; } else { targetDoc.editZoomProgressivize = false; activeItem.editZoomProgressivize = false; } - } + }; //Toggle whether the user edits or not @action @@ -2031,12 +2469,15 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; if (!targetDoc.editScrollProgressivize) { - if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; activeItem.scrollProgressivize = true; } + if (!targetDoc.scrollProgressivize) { + targetDoc.scrollProgressivize = true; + activeItem.scrollProgressivize = true; + } targetDoc.editScrollProgressivize = true; } else { targetDoc.editScrollProgressivize = false; } - } + }; //Progressivize Zoom @action @@ -2052,7 +2493,7 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._currentFrame = 0; targetDoc.lastFrame = 0; } - } + }; //Progressivize Zoom @action @@ -2068,7 +2509,7 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._currentFrame = 0; targetDoc.lastFrame = 0; } - } + }; //Progressivize Child Docs @action @@ -2077,12 +2518,15 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; targetDoc._currentFrame = targetDoc.lastFrame; if (!targetDoc.editProgressivize) { - if (!activeItem.presProgressivize) { activeItem.presProgressivize = true; targetDoc.presProgressivize = true; } + if (!activeItem.presProgressivize) { + activeItem.presProgressivize = true; + targetDoc.presProgressivize = true; + } targetDoc.editProgressivize = true; } else { targetDoc.editProgressivize = false; } - } + }; @action progressivizeChild = (e: React.MouseEvent) => { @@ -2104,40 +2548,48 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._currentFrame = 0; targetDoc.keyFrameEditing = true; } - } + }; @action checkMovementLists = (doc: Doc, xlist: any, ylist: any) => { const x: List = xlist; const y: List = ylist; const tags: JSX.Element[] = []; - let pathPoints = ""; //List of all of the pathpoints that need to be added + let pathPoints = ''; //List of all of the pathpoints that need to be added for (let i = 0; i < x.length - 1; i++) { if (y[i] || x[i]) { - if (i === 0) pathPoints = (x[i] - 11) + "," + (y[i] + 33); - else pathPoints = pathPoints + " " + (x[i] - 11) + "," + (y[i] + 33); - tags.push(
{i}
); + if (i === 0) pathPoints = x[i] - 11 + ',' + (y[i] + 33); + else pathPoints = pathPoints + ' ' + (x[i] - 11) + ',' + (y[i] + 33); + tags.push( +
+ {i} +
+ ); } } - tags.push(); + tags.push( + + + + ); return tags; - } + }; @observable toggleDisplayMovement = (doc: Doc) => { if (doc.displayMovement) doc.displayMovement = false; else doc.displayMovement = true; - } + }; @action checkList = (doc: Doc, list: any): number => { @@ -2149,22 +2601,54 @@ export class PresBox extends ViewBoxBaseComponent() { x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1]; return x[NumCast(doc._currentFrame)]; } else return 100; - } + }; @computed get progressivizeChildDocs() { const targetDoc: Doc = this.targetDoc; const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); const tags: JSX.Element[] = []; docs.forEach((doc, index) => { - if (doc["x-indexed"] && doc["y-indexed"]) { - tags.push(
{this.checkMovementLists(doc, doc["x-indexed"], doc["y-indexed"])}
); + if (doc['x-indexed'] && doc['y-indexed']) { + tags.push(
{this.checkMovementLists(doc, doc['x-indexed'], doc['y-indexed'])}
); } tags.push( -
{ if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; }} onPointerOver={() => { if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; }} onClick={e => { this.toggleDisplayMovement(doc); e.stopPropagation(); }} style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : "#c8c8c8", top: NumCast(doc.y), left: NumCast(doc.x) }}> -
{ e.stopPropagation(); this.prevAppearFrame(doc, index); }} />
-
{doc.appearFrame}
-
{ e.stopPropagation(); this.nextAppearFrame(doc, index); }} />
-
); +
{ + if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; + }} + onPointerOver={() => { + if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; + }} + onClick={e => { + this.toggleDisplayMovement(doc); + e.stopPropagation(); + }} + style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : '#c8c8c8', top: NumCast(doc.y), left: NumCast(doc.x) }}> +
+ { + e.stopPropagation(); + this.prevAppearFrame(doc, index); + }} + /> +
+
{NumCast(doc.appearFrame)}
+
+ { + e.stopPropagation(); + this.nextAppearFrame(doc, index); + }} + /> +
+
+ ); }); return tags; } @@ -2173,25 +2657,25 @@ export class PresBox extends ViewBoxBaseComponent() { nextAppearFrame = (doc: Doc, i: number): void => { // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - const appearFrame = Cast(doc.appearFrame, "number", null); + const appearFrame = Cast(doc.appearFrame, 'number', null); if (appearFrame === undefined) { doc.appearFrame = 0; } doc.appearFrame = appearFrame + 1; - this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame)); - } + this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); + }; @action prevAppearFrame = (doc: Doc, i: number): void => { // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - const appearFrame = Cast(doc.appearFrame, "number", null); + const appearFrame = Cast(doc.appearFrame, 'number', null); if (appearFrame === undefined) { doc.appearFrame = 0; } doc.appearFrame = Math.max(0, appearFrame - 1); - this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame)); - } + this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); + }; @action updateOpacityList = (list: any, frame: number) => { @@ -2216,10 +2700,10 @@ export class PresBox extends ViewBoxBaseComponent() { } list = x; } - } + }; @computed get moreInfoDropdown() { - return (
); + return
; } @computed @@ -2235,28 +2719,36 @@ export class PresBox extends ViewBoxBaseComponent() { } else { CurrentUserUtils.propertiesWidth = 250; } - } + }; @computed get toolbar() { - const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left"; - const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel"; + const propIcon = CurrentUserUtils.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; + const propTitle = CurrentUserUtils.propertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel'; const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); + const presKeyEvents: boolean = this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation; const activeColor = Colors.LIGHT_BLUE; const inactiveColor = Colors.WHITE; - return (mode === CollectionViewType.Carousel3D) ? (null) : ( + return mode === CollectionViewType.Carousel3D ? null : (
{/*
{"Add new slide"}
}>
this.newDocumentTools = !this.newDocumentTools)}>
*/} -
{"View paths"}
}> -
1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}> - + +
{'View paths'}
+ + }> +
1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }} + className={'toolbar-button'} + onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}> +
- {isMini ? (null) : + {isMini ? null : ( <>
{/*
{this._expandBoolean ? "Minimize all" : "Expand all"}
}> @@ -2267,18 +2759,28 @@ export class PresBox extends ViewBoxBaseComponent() {
*/} -
{presKeyEvents ? "Keys are active" : "Keys are not active - click anywhere on the presentation trail to activate keys"}
}> + +
{presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}
+ + }>
- +
-
{propTitle}
}> + +
{propTitle}
+ + }>
- 0 ? activeColor : inactiveColor }} /> + 0 ? activeColor : inactiveColor }} />
- } + )}
); } @@ -2292,35 +2794,45 @@ export class PresBox extends ViewBoxBaseComponent() { const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; return ( -
- {isMini ? (null) : } +
+ {isMini ? null : ( + + )}
- -
+
{ if (this.childDocs.length) { - this.layoutDoc.presStatus = "manual"; + this.layoutDoc.presStatus = 'manual'; this.gotoDocument(this.itemIndex, this.activeItem); } })}> - -
200 ? "inline-flex" : "none" }}>  Present
+ +
200 ? 'inline-flex' : 'none' }}>  Present
- {(mode === CollectionViewType.Carousel3D || isMini) ? (null) :
{ - if (this.childDocs.length) this.presentTools = !this.presentTools; - }))}> - - {this.presentDropdown} -
} + {mode === CollectionViewType.Carousel3D || isMini ? null : ( +
{ + if (this.childDocs.length) this.presentTools = !this.presentTools; + })}> + + {this.presentDropdown} +
+ )} {this.playButtons}
@@ -2332,7 +2844,7 @@ export class PresBox extends ViewBoxBaseComponent() { getList = (list: any): List => { const x: List = list; return x; - } + }; @action updateList = (list: any): List => { @@ -2341,7 +2853,7 @@ export class PresBox extends ViewBoxBaseComponent() { x.length + 1; x[x.length - 1] = NumCast(targetDoc._scrollY); return x; - } + }; @action newFrame = () => { @@ -2350,7 +2862,7 @@ export class PresBox extends ViewBoxBaseComponent() { const type: string = StrCast(targetDoc.type); if (!activeItem.frameList) activeItem.frameList = new List(); switch (type) { - case (DocumentType.PDF || DocumentType.RTF || DocumentType.WEB): + case DocumentType.PDF || DocumentType.RTF || DocumentType.WEB: this.updateList(activeItem.frameList); break; case DocumentType.COL: @@ -2358,20 +2870,46 @@ export class PresBox extends ViewBoxBaseComponent() { default: break; } - } + }; @computed get frameListHeader() { - return (
-   Frames {this.panable ? Panable : this.scrollable ? Scrollable : (null)} -
-
{"Add frame by example"}
}>
{ e.stopPropagation(); this.newFrame(); }}> - e.stopPropagation()} /> -
-
{"Edit in collection"}
}>
{ e.stopPropagation(); console.log('New frame'); }}> - e.stopPropagation()} /> -
+ return ( +
+   Frames {this.panable ? Panable : this.scrollable ? Scrollable : null} +
+ +
{'Add frame by example'}
+ + }> +
{ + e.stopPropagation(); + this.newFrame(); + }}> + e.stopPropagation()} /> +
+
+ +
{'Edit in collection'}
+ + }> +
{ + e.stopPropagation(); + console.log('New frame'); + }}> + e.stopPropagation()} /> +
+
+
-
); + ); } @computed get frameList() { @@ -2379,66 +2917,118 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; const frameList: List = this.getList(activeItem.frameList); if (frameList) { - const frameItems = frameList.map((value) => -
- -
- ); - return ( - -
- {frameItems} -
- ); - } else return (null); - + const frameItems = frameList.map(value =>
); + return
{frameItems}
; + } else return null; } @computed get playButtonFrames() { const targetDoc: Doc = this.targetDoc; return ( <> - {this.targetDoc ?
= 0 ? "inline-flex" : "none" }}> -
{targetDoc._currentFrame}
-
-
{targetDoc.lastFrame}
-
: null} + {this.targetDoc ? ( +
= 0 ? 'inline-flex' : 'none' }}> +
{NumCast(targetDoc._currentFrame)}
+
+
{NumCast(targetDoc.lastFrame)}
+
+ ) : null} ); } @computed get playButtons() { - const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); - const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); + const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; + const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; // Case 1: There are still other frames and should go through all frames before going to next slide - return (
-
{"Loop"}
}>
this.layoutDoc.presLoop = !this.layoutDoc.presLoop}>
-
-
{ this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}>
-
{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}
}>
-
{ this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}>
-
-
{"Click to return to 1st slide"}
}>
this.gotoDocument(0, this.activeItem)}>1
-
this.gotoDocument(0, this.activeItem)} - style={{ display: this.props.PanelWidth() > 250 ? "inline-flex" : "none" }}> - Slide {this.itemIndex + 1} / {this.childDocs.length} - {this.playButtonFrames} + return ( +
+ +
{'Loop'}
+ + }> +
(this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}> + +
+
+
+
{ + this.back(); + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } + }}> + +
+ +
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
+ + }> +
+ +
+
+
{ + this.next(); + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } + }}> + +
+
+ +
{'Click to return to 1st slide'}
+ + }> +
this.gotoDocument(0, this.activeItem)}> + 1 +
+
+
this.gotoDocument(0, this.activeItem)} style={{ display: this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> + Slide {this.itemIndex + 1} / {this.childDocs.length} + {this.playButtonFrames} +
+
+ {this.props.PanelWidth() > 250 ? ( +
{ + this.layoutDoc.presStatus = 'edit'; + clearTimeout(this._presTimer); + }) + )}> + EXIT +
+ ) : ( +
(this.layoutDoc.presStatus = 'edit')))}> + +
+ )}
-
- {this.props.PanelWidth() > 250 ?
{ this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }))}>EXIT
- :
this.layoutDoc.presStatus = "edit"))}> - -
} -
); + ); } @action startOrPause = () => { if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex); else this.pauseAutoPres(); - } + }; @action prevClicked = (e: PointerEvent) => { @@ -2447,7 +3037,7 @@ export class PresBox extends ViewBoxBaseComponent() { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } - } + }; @action nextClicked = (e: PointerEvent) => { @@ -2456,35 +3046,35 @@ export class PresBox extends ViewBoxBaseComponent() { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } - } + }; @undoBatch @action exitClicked = (e: PointerEvent) => { this.updateMinimize(); this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); - } + }; @action startMarqueeCreateSlide = () => { PresBox.startMarquee = true; - } + }; AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => { var indexNum = 0; for (let i = 0; i < index.length; i++) { - indexNum += (index[i] * (10 ** (-i))); + indexNum += index[i] * 10 ** -i; } if (this._treeViewMap.get(treeViewDoc) !== indexNum) { this._treeViewMap.set(treeViewDoc, indexNum); const sorted = this.sort(this._treeViewMap); const curList = DocListCast(this.dataDoc[this.presFieldKey]); - if (sorted.length !== curList.length || sorted.some((doc,ind) => doc !== curList[ind])) { + if (sorted.length !== curList.length || sorted.some((doc, ind) => doc !== curList[ind])) { this.dataDoc[this.presFieldKey] = new List(sorted); // this is a flat array of Docs } } return this.childDocs; - } + }; RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => { if (!this._unmounting && this.isTree) { @@ -2492,10 +3082,10 @@ export class PresBox extends ViewBoxBaseComponent() { this.dataDoc[this.presFieldKey] = new List(this.sort(this._treeViewMap)); } return this.childDocs; - } + }; // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1]) - sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0).map(kv => kv[0]); + sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); render() { // calling this method for keyEvents @@ -2503,42 +3093,73 @@ export class PresBox extends ViewBoxBaseComponent() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); - const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); - const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); - return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.rootDoc) ? + const presKeyEvents: boolean = this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation; + const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; + const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; + return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.rootDoc) ? (
e.stopPropagation()}> -
-
{"Loop"}
}>
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.layoutDoc.presLoop = !this.layoutDoc.presLoop, false, false)}>
+
+ +
{'Loop'}
+ + }> +
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}> + +
+
-
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
-
{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}
}>
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
-
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}>
+
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}> + +
+ +
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
+ + }> +
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}> + +
+
+
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}> + +
-
{"Click to return to 1st slide"}
}>
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>1
+ +
{'Click to return to 1st slide'}
+ + }> +
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}> + 1 +
+
Slide {this.itemIndex + 1} / {this.childDocs.length} {this.playButtonFrames}
-
- setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}>EXIT
+
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}> + EXIT +
-
- : -
+
+ ) : ( +
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown}
- {mode !== CollectionViewType.Invalid ? - () { AddToMap={this.AddToMap} RemFromMap={this.RemFromMap} hierarchyIndex={[]} - /> : (null) - } + /> + ) : null}
- { // if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack - {"Click on document to pin to presentaiton or make a marquee selection to pin your desired view"}
}> + { + // if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack + {'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}
}> }
-
; +
+ ); } } -ScriptingGlobals.add(function navigateToDoc(bestTarget:Doc, activeItem:Doc) { +ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) { const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null); - const openInTab = (doc: Doc, finished?: () => void) => {CollectionDockingView.AddSplit(doc, "right"); finished?.(); }; - DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext]:[], - undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom)); -}); \ No newline at end of file + const openInTab = (doc: Doc, finished?: () => void) => { + CollectionDockingView.AddSplit(doc, 'right'); + finished?.(); + }; + DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom)); +}); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 574193614..c5177de90 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -1,4 +1,4 @@ -import { Tooltip } from "@material-ui/core"; +import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -6,13 +6,12 @@ import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field } from '../.. import { Id } from '../../../fields/FieldSymbols'; import { StrCast } from '../../../fields/Types'; import { DocUtils } from '../../documents/Documents'; -import { DocumentType } from "../../documents/DocumentTypes"; +import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; -import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { ViewBoxBaseComponent } from "../DocComponent"; +import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; -import "./SearchBox.scss"; - +import './SearchBox.scss'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; @@ -29,13 +28,15 @@ export interface SearchBoxProps extends FieldViewProps { */ @observer export class SearchBox extends ViewBoxBaseComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(SearchBox, fieldKey); + } public static Instance: SearchBox; private _inputRef = React.createRef(); - @observable _searchString = ""; - @observable _docTypeString = "all"; + @observable _searchString = ''; + @observable _docTypeString = 'all'; @observable _results: Map = new Map(); @observable _pageRanks: Map = new Map(); @observable _linkedDocsOut: Map> = new Map>(); @@ -52,7 +53,7 @@ export class SearchBox extends ViewBoxBaseComponent() { SearchBox.Instance = this; } - /** + /** * This method is called when the SearchBox component is first mounted. When the user opens * the search panel, the search input box is automatically selected. This allows the user to * type in the search input box immediately, without needing clicking on it first. @@ -75,7 +76,7 @@ export class SearchBox extends ViewBoxBaseComponent() { * This method is called when the text in the search input box is modified by the user. The * _searchString is updated to the new value of the text in the input box and submitSearch * is called to update the search results accordingly. - * + * * (Note: There is no longer a need to press enter to submit a search. Any update to the input * causes a search to be submitted automatically.) */ @@ -88,7 +89,7 @@ export class SearchBox extends ViewBoxBaseComponent() { * This method is called when the option in the select drop-down menu is changed. The * _docTypeString is updated to the new value of the option in the drop-down menu. This * is used to filter the results of the search to documents of a specific type. - * + * * (Note: This doesn't affect the results array, so there is no need to submit a new * search here. The results of the search on the _searchString query are simply filtered * by type directly before rendering them.) @@ -134,8 +135,8 @@ export class SearchBox extends ViewBoxBaseComponent() { docs.filter(d => d && !visited.includes(d)).forEach(d => { visited.push(d); const fieldKey = Doc.LayoutFieldKey(d); - const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); - const data = d[annos ? fieldKey + "-annotations" : fieldKey]; + const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView'); + const data = d[annos ? fieldKey + '-annotations' : fieldKey]; data && newarray.push(...DocListCast(data)); func(depth, d); }); @@ -156,14 +157,18 @@ export class SearchBox extends ViewBoxBaseComponent() { var depth = 0; while (docs.length > 0) { newarray = []; - await Promise.all(docs.filter(d => d).map(async d => { - const fieldKey = Doc.LayoutFieldKey(d); - const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); - const data = d[annos ? fieldKey + "-annotations" : fieldKey]; - const docs = await DocListCastAsync(data); - docs && newarray.push(...docs); - func(depth, d); - })); + await Promise.all( + docs + .filter(d => d) + .map(async d => { + const fieldKey = Doc.LayoutFieldKey(d); + const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView'); + const data = d[annos ? fieldKey + '-annotations' : fieldKey]; + const docs = await DocListCastAsync(data); + docs && newarray.push(...docs); + func(depth, d); + }) + ); docs = newarray; depth++; } @@ -177,11 +182,10 @@ export class SearchBox extends ViewBoxBaseComponent() { * right side of each search result. */ static formatType(type: String): String { - if (type === "pdf") { - return "PDF"; - } - else if (type === "image") { - return "Img"; + if (type === 'pdf') { + return 'PDF'; + } else if (type === 'image') { + return 'Img'; } return type.charAt(0).toUpperCase() + type.substring(1, 3); @@ -198,9 +202,40 @@ export class SearchBox extends ViewBoxBaseComponent() { @action searchCollection(query: string) { const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; - const blockedKeys = ["x", "y", "proto", "width", "autoHeight", "acl-Override", "acl-Public", "context", "zIndex", "height", "text-scrollHeight", "text-height", "cloneFieldFilter", "isPrototype", "text-annotations", - "dragFactory-count", "text-noTemplate", "aliases", "system", "layoutKey", "baseProto", "xMargin", "yMargin", "links", "layout", "layout_keyValue", "fitWidth", "viewType", "title-custom", - "panX", "panY", "viewScale"]; + const blockedKeys = [ + 'x', + 'y', + 'proto', + 'width', + 'autoHeight', + 'acl-Override', + 'acl-Public', + 'context', + 'zIndex', + 'height', + 'text-scrollHeight', + 'text-height', + 'cloneFieldFilter', + 'isPrototype', + 'text-annotations', + 'dragFactory-count', + 'text-noTemplate', + 'aliases', + 'system', + 'layoutKey', + 'baseProto', + 'xMargin', + 'yMargin', + 'links', + 'layout', + 'layout_keyValue', + 'fitWidth', + 'viewType', + 'title-custom', + 'panX', + 'panY', + 'viewScale', + ]; const collection = CollectionDockingView.Instance; query = query.toLowerCase(); @@ -211,10 +246,15 @@ export class SearchBox extends ViewBoxBaseComponent() { const docs = DocListCast(collection.rootDoc[Doc.LayoutFieldKey(collection.rootDoc)]); const docIDs: String[] = []; SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { - const dtype = StrCast(doc.type, "string") as DocumentType; + const dtype = StrCast(doc.type, 'string') as DocumentType; if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth > 0) { const hlights = new Set(); - SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); + SearchBox.documentKeys(doc).forEach( + key => + Field.toString(doc[key] as Field) + .toLowerCase() + .includes(query) && hlights.add(key) + ); blockedKeys.forEach(key => hlights.delete(key)); if (Array.from(hlights.keys()).length > 0) { @@ -250,18 +290,16 @@ export class SearchBox extends ViewBoxBaseComponent() { this._results.forEach((_, linkedDoc) => { this._linkedDocsIn.get(linkedDoc)?.add(doc); }); - } - else { + } else { const linkedDocSet = new Set(); - Doc.GetProto(doc)[DirectLinksSym].forEach((link) => { + Doc.GetProto(doc)[DirectLinksSym].forEach(link => { const d1 = link?.anchor1 as Doc; const d2 = link?.anchor2 as Doc; if (doc === d1 && this._results.has(d2)) { linkedDocSet.add(d2); this._linkedDocsIn.get(d2)?.add(doc); - } - else if (doc === d2 && this._results.has(d1)) { + } else if (doc === d2 && this._results.has(d1)) { linkedDocSet.add(d1); this._linkedDocsIn.get(d1)?.add(doc); } @@ -289,8 +327,8 @@ export class SearchBox extends ViewBoxBaseComponent() { this._results.forEach((_, doc) => { let nextPageRank = pageRankFromAll; - this._linkedDocsIn.get(doc)?.forEach((linkedDoc) => { - nextPageRank += DAMPENING_FACTOR * (this._pageRanks.get(linkedDoc) ?? 0) / (this._linkedDocsOut.get(linkedDoc)?.size ?? 1); + this._linkedDocsIn.get(doc)?.forEach(linkedDoc => { + nextPageRank += (DAMPENING_FACTOR * (this._pageRanks.get(linkedDoc) ?? 0)) / (this._linkedDocsOut.get(linkedDoc)?.size ?? 1); }); nextPageRanks.set(doc, nextPageRank); @@ -328,7 +366,7 @@ export class SearchBox extends ViewBoxBaseComponent() { */ static documentKeys(doc: Doc) { const keys: { [key: string]: boolean } = {}; - Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)); + Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false))); return Array.from(Object.keys(keys)); } @@ -342,15 +380,13 @@ export class SearchBox extends ViewBoxBaseComponent() { const query = StrCast(this._searchString); Doc.SetSearchQuery(query); - Array.from(this._results.keys()).forEach(doc => - DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true) - ); + Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); this._results.clear(); if (query) { this.searchCollection(query); } - } + }; /** * This method resets the search by iterating through each result and removing all @@ -372,7 +408,7 @@ export class SearchBox extends ViewBoxBaseComponent() { */ selectElement = async (doc: Doc, finishFunc: () => void) => { await DocumentManager.Instance.jumpToDocument(doc, true, undefined, [], undefined, undefined, undefined, finishFunc); - } + }; /** * This method returns a JSX list of the options in the select drop-down menu, which @@ -380,9 +416,13 @@ export class SearchBox extends ViewBoxBaseComponent() { */ @computed public get selectOptions() { - const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"]; + const selectValues = ['all', 'rtf', 'image', 'pdf', 'web', 'video', 'audio', 'collection']; - return selectValues.map(value => ); + return selectValues.map(value => ( + + )); } /** @@ -393,39 +433,37 @@ export class SearchBox extends ViewBoxBaseComponent() { const isLinkSearch: boolean = this.props.linkSearch; - const sortedResults = Array.from(this._results.entries()).sort((a, b) => (this._pageRanks.get(b[0]) ?? 0) - (this._pageRanks.get(a[0]) ?? 0)); // sorted by page rank + const sortedResults = Array.from(this._results.entries()).sort((a, b) => (this._pageRanks.get(b[0]) ?? 0) - (this._pageRanks.get(a[0]) ?? 0)); // sorted by page rank const resultsJSX = Array(); - sortedResults.forEach((result) => { - var className = "searchBox-results-scroll-view-result"; + sortedResults.forEach(result => { + var className = 'searchBox-results-scroll-view-result'; if (this._selectedResult === result[0]) { - className += " searchBox-results-scroll-view-result-selected"; + className += ' searchBox-results-scroll-view-result-selected'; } const formattedType = SearchBox.formatType(StrCast(result[0].type)); const title = result[0].title; - if (this._docTypeString === "all" || this._docTypeString === result[0].type) { + if (this._docTypeString === 'all' || this._docTypeString === result[0].type) { validResults++; resultsJSX.push( -
{title}
}> -
this.makeLink(result[0]) : - e => { - this.onResultClick(result[0]); - e.stopPropagation(); - }} className={className}> -
- {title} -
-
- {formattedType} -
-
- {result[1].join(", ")} -
+ {title as string}
}> +
this.makeLink(result[0]) + : e => { + this.onResultClick(result[0]); + e.stopPropagation(); + } + } + className={className}> +
{title as string}
+
{formattedType}
+
{result[1].join(', ')}
); @@ -433,22 +471,31 @@ export class SearchBox extends ViewBoxBaseComponent() { }); return ( -
-
- {isLinkSearch ? (null) : } - e.key === "Enter" ? this.submitSearch() : null} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{ width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined }} ref={this._inputRef} /> -
+
+
+ {isLinkSearch ? null : ( + + )} + (e.key === 'Enter' ? this.submitSearch() : null)} + type="text" + placeholder="Search..." + id="search-input" + className="searchBox-input" + style={{ width: isLinkSearch ? '100%' : undefined, borderRadius: isLinkSearch ? '5px' : undefined }} + ref={this._inputRef} + /> +
-
- {`${validResults}` + " result" + (validResults === 1 ? "" : "s")} -
-
- {resultsJSX} -
+
{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}
+
{resultsJSX}
-
+
); } -} \ No newline at end of file +} diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index bf06faeb9..e1360553a 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,52 +1,236 @@ - import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, - faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, - faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, - faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, - faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, - faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft, - faAlignRight, faAlignLeft + faTasks, + faReply, + faQuoteLeft, + faHandPointLeft, + faFolderOpen, + faAngleDoubleLeft, + faExternalLinkSquareAlt, + faMobile, + faThLarge, + faWindowClose, + faEdit, + faTrashAlt, + faPalette, + faAngleRight, + faBell, + faTrash, + faCamera, + faExpand, + faCaretDown, + faCaretLeft, + faCaretRight, + faCaretSquareDown, + faCaretSquareRight, + faArrowsAltH, + faPlus, + faMinus, + faTerminal, + faToggleOn, + faFile as fileSolid, + faExternalLinkAlt, + faLocationArrow, + faSearch, + faFileDownload, + faStop, + faCalculator, + faWindowMaximize, + faAddressCard, + faQuestionCircle, + faArrowLeft, + faArrowRight, + faArrowDown, + faArrowUp, + faBolt, + faBullseye, + faCaretUp, + faCat, + faCheck, + faChevronRight, + faClipboard, + faClone, + faCloudUploadAlt, + faCommentAlt, + faCompressArrowsAlt, + faCut, + faEllipsisV, + faEraser, + faExclamation, + faFileAlt, + faFileAudio, + faFilePdf, + faFilm, + faFilter, + faFont, + faGlobeAsia, + faHighlighter, + faLongArrowAltRight, + faMicrophone, + faMousePointer, + faMusic, + faObjectGroup, + faPause, + faPen, + faPenNib, + faPhone, + faPlay, + faPortrait, + faRedoAlt, + faStamp, + faStickyNote, + faThumbtack, + faTree, + faTv, + faBook, + faUndoAlt, + faVideo, + faAsterisk, + faBrain, + faImage, + faPaintBrush, + faTimes, + faEye, + faHome, + faLongArrowAltLeft, + faBars, + faTh, + faChevronLeft, + faAlignRight, + faAlignLeft, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from "react"; +import * as React from 'react'; import { Docs, DocumentOptions, DocUtils } from '../client/documents/Documents'; -import { DocumentType } from "../client/documents/DocumentTypes"; +import { DocumentType } from '../client/documents/DocumentTypes'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { SettingsManager, ColorScheme } from '../client/util/SettingsManager'; import { Transform } from '../client/util/Transform'; -import { UndoManager } from "../client/util/UndoManager"; +import { UndoManager } from '../client/util/UndoManager'; import { TabDocView } from '../client/views/collections/TabDocView'; -import { CollectionViewType } from "../client/views/collections/CollectionView"; -import { GestureOverlay } from "../client/views/GestureOverlay"; -import { AudioBox } from "../client/views/nodes/AudioBox"; +import { CollectionViewType } from '../client/views/collections/CollectionView'; +import { GestureOverlay } from '../client/views/GestureOverlay'; +import { AudioBox } from '../client/views/nodes/AudioBox'; import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RichTextMenu } from "../client/views/nodes/formattedText/RichTextMenu"; -import { RadialMenu } from "../client/views/nodes/RadialMenu"; +import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; +import { RadialMenu } from '../client/views/nodes/RadialMenu'; import { Doc, DocListCast } from '../fields/Doc'; import { InkTool } from '../fields/InkField'; -import { List } from "../fields/List"; -import { ScriptField } from "../fields/ScriptField"; -import { Cast, FieldValue } from '../fields/Types'; +import { List } from '../fields/List'; +import { ScriptField } from '../fields/ScriptField'; +import { Cast, FieldValue, StrCast } from '../fields/Types'; import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; -import { AudioUpload } from "./AudioUpload"; -import { Uploader } from "./ImageUpload"; -import "./AudioUpload.scss"; -import "./ImageUpload.scss"; -import "./MobileInterface.scss"; - -library.add(...[faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, - faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, - faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, - faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, - faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, - faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft, - faAlignLeft, faAlignRight].map(m => m as any)); - +import { AudioUpload } from './AudioUpload'; +import { Uploader } from './ImageUpload'; +import './AudioUpload.scss'; +import './ImageUpload.scss'; +import './MobileInterface.scss'; + +library.add( + ...[ + faTasks, + faReply, + faQuoteLeft, + faHandPointLeft, + faFolderOpen, + faAngleDoubleLeft, + faExternalLinkSquareAlt, + faMobile, + faThLarge, + faWindowClose, + faEdit, + faTrashAlt, + faPalette, + faAngleRight, + faBell, + faTrash, + faCamera, + faExpand, + faCaretDown, + faCaretLeft, + faCaretRight, + faCaretSquareDown, + faCaretSquareRight, + faArrowsAltH, + faPlus, + faMinus, + faTerminal, + faToggleOn, + fileSolid, + faExternalLinkAlt, + faLocationArrow, + faSearch, + faFileDownload, + faStop, + faCalculator, + faWindowMaximize, + faAddressCard, + faQuestionCircle, + faArrowLeft, + faArrowRight, + faArrowDown, + faArrowUp, + faBolt, + faBullseye, + faCaretUp, + faCat, + faCheck, + faChevronRight, + faClipboard, + faClone, + faCloudUploadAlt, + faCommentAlt, + faCompressArrowsAlt, + faCut, + faEllipsisV, + faEraser, + faExclamation, + faFileAlt, + faFileAudio, + faFilePdf, + faFilm, + faFilter, + faFont, + faGlobeAsia, + faHighlighter, + faLongArrowAltRight, + faMicrophone, + faMousePointer, + faMusic, + faObjectGroup, + faPause, + faPen, + faPenNib, + faPhone, + faPlay, + faPortrait, + faRedoAlt, + faStamp, + faStickyNote, + faThumbtack, + faTree, + faTv, + faUndoAlt, + faBook, + faVideo, + faAsterisk, + faBrain, + faImage, + faPaintBrush, + faTimes, + faEye, + faHome, + faLongArrowAltLeft, + faBars, + faTh, + faChevronLeft, + faAlignLeft, + faAlignRight, + ].map(m => m as any) +); @observer export class MobileInterface extends React.Component { @@ -64,36 +248,38 @@ export class MobileInterface extends React.Component { @observable private _homeDoc: Doc = this._mainDoc; // home menu as a document @observable private _parents: Array = []; // array of parent docs (for pathbar) - @computed private get mainContainer() { return Doc.UserDoc() ? FieldValue(Cast(Doc.UserDoc().activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } + @computed private get mainContainer() { + return Doc.UserDoc() ? FieldValue(Cast(Doc.UserDoc().activeMobile, Doc)) : CurrentUserUtils.GuestMobile; + } constructor(props: Readonly<{}>) { super(props); - this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc(), "myDashboards"); // to access documents in Dash Web + this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc(), 'myDashboards'); // to access documents in Dash Web MobileInterface.Instance = this; } @action componentDidMount = () => { // if the home menu is in list view -> adjust the menu toggle appropriately - this._menuListView = this._homeDoc._viewType === "stacking" ? true : false; + this._menuListView = this._homeDoc._viewType === 'stacking' ? true : false; CurrentUserUtils.ActiveTool = InkTool.None; // ink should intially be set to none Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home AudioBox.Enabled = true; // remove double click to avoid mobile zoom in - document.removeEventListener("dblclick", this.onReactDoubleClick); - document.addEventListener("dblclick", this.onReactDoubleClick); - } + document.removeEventListener('dblclick', this.onReactDoubleClick); + document.addEventListener('dblclick', this.onReactDoubleClick); + }; @action componentWillUnmount = () => { document.removeEventListener('dblclick', this.onReactDoubleClick); - } + }; // Prevent zooming in when double tapping the screen onReactDoubleClick = (e: MouseEvent) => { e.stopPropagation(); - } + }; // Switch the mobile view to the given doc @action @@ -110,7 +296,7 @@ export class MobileInterface extends React.Component { // Ensures that switching to home is not registed UndoManager.undoStack.length = 0; UndoManager.redoStack.length = 0; - } + }; // For toggling the hamburger menu @action @@ -120,29 +306,29 @@ export class MobileInterface extends React.Component { if (this._ink) { this.onSwitchInking(); } - } + }; /** * Method called when 'Library' button is pressed on the home screen */ switchToLibrary = async () => { this.switchCurrentView(this._library); - runInAction(() => this._homeMenu = false); + runInAction(() => (this._homeMenu = false)); this.toggleSidebar(); - } + }; /** * Back method for navigating through items */ @action back = () => { - const header = document.getElementById("header") as HTMLElement; + const header = document.getElementById('header') as HTMLElement; const doc = Cast(this._parents.pop(), Doc) as Doc; // Parent document // Case 1: Parent document is 'dashboards' - if (doc === Cast(this._library, Doc) as Doc) { + if (doc === (Cast(this._library, Doc) as Doc)) { this.dashboards = null; this.switchCurrentView(this._library); // Case 2: Parent document is the 'home' menu (root node) - } else if (doc === Cast(this._homeDoc, Doc) as Doc) { + } else if (doc === (Cast(this._homeDoc, Doc) as Doc)) { this._homeMenu = true; this._parents = []; this.dashboards = null; @@ -155,7 +341,7 @@ export class MobileInterface extends React.Component { header.textContent = String(doc.title); } this._ink = false; // turns ink off - } + }; /** * Return 'Home", which implies returning to 'Home' menu buttons @@ -171,7 +357,7 @@ export class MobileInterface extends React.Component { if (this._sidebarActive) { this.toggleSidebar(); } - } + }; /** * Return to primary Dashboard in library (Dashboards Doc) @@ -182,7 +368,7 @@ export class MobileInterface extends React.Component { this.switchCurrentView(this._library); this._homeMenu = false; this.dashboards = null; - } + }; /** * Note: window.innerWidth and window.screen.width compute different values. @@ -190,14 +376,14 @@ export class MobileInterface extends React.Component { * display resolution which computes differently. */ returnWidth = () => window.innerWidth; //The windows width - returnHeight = () => (window.innerHeight - 300); //Calculating the windows height (-300 to account for topbar) - whitebackground = () => "white"; + returnHeight = () => window.innerHeight - 300; //Calculating the windows height (-300 to account for topbar) + whitebackground = () => 'white'; /** * DocumentView for graphic display of all documents */ @computed get displayDashboards() { - return !this.mainContainer ? (null) : -
+ return !this.mainContainer ? null : ( +
-
; +
+ ); } /** @@ -233,20 +420,19 @@ export class MobileInterface extends React.Component { */ handleClick = async (doc: Doc) => { runInAction(() => { - if (doc.type !== "collection" && this._sidebarActive) { + if (doc.type !== 'collection' && this._sidebarActive) { this._parents.push(this._activeDoc); this.switchCurrentView(doc); this._homeMenu = false; this.toggleSidebar(); - } - else { + } else { this._parents.push(this._activeDoc); this.switchCurrentView(doc); this._homeMenu = false; this.dashboards = doc; } }); - } + }; /** * Called when an item in the library is clicked and should @@ -260,30 +446,31 @@ export class MobileInterface extends React.Component { this._homeMenu = false; this.dashboards = doc; this.toggleSidebar(); - } + }; // Renders the graphical pathbar renderPathbar = () => { const docPath = [...this._parents, this._activeDoc]; - const items = docPath.map((doc: Doc, index: any) => + const items = docPath.map((doc: Doc, index: any) => (
- {index === 0 ? (null) : } -
this.handlePathClick(doc, index)}>{doc.title} + {index === 0 ? null : } +
this.handlePathClick(doc, index)}> + {StrCast(doc.title)}
-
); - return (
-
- {items}
- {!this._parents.length ? (null) : -
- -
} -
-
); - } + )); + return ( +
+
{items}
+ {!this._parents.length ? null : ( +
+ +
+ )} +
+
+ ); + }; // Handles when user clicks on a document in the pathbar @action @@ -300,7 +487,7 @@ export class MobileInterface extends React.Component { this.switchCurrentView(doc); this._parents.length = index; } - } + }; // Renders the contents of the menu and sidebar @computed get renderDefaultContent() { @@ -309,7 +496,9 @@ export class MobileInterface extends React.Component {
- +
e.stopPropagation()}>