diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 6 | ||||
-rw-r--r-- | src/client/views/DocumentButtonBar.tsx | 5 | ||||
-rw-r--r-- | src/client/views/PropertiesButtons.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.scss | 31 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 370 | ||||
-rw-r--r-- | src/client/views/collections/CollectionMenu.tsx | 10 | ||||
-rw-r--r-- | src/client/views/collections/TabDocView.scss | 20 | ||||
-rw-r--r-- | src/client/views/collections/TabDocView.tsx | 379 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.tsx | 43 | ||||
-rw-r--r-- | src/mobile/MobileInterface.tsx | 4 |
10 files changed, 437 insertions, 433 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2ca395164..260552879 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1031,11 +1031,7 @@ export class CurrentUserUtils { const dashboards = Cast(userDoc.myDashboards, Doc) as Doc; const dashboardCount = DocListCast(dashboards.data).length + 1; const emptyPane = Cast(userDoc.emptyPane, Doc, null); - try { - emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; - } catch (e) { - console.log(e) - } + emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; const freeformOptions: DocumentOptions = { x: 0, y: 400, diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 764a2547c..45336129a 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -15,7 +15,8 @@ import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DragManager } from '../util/DragManager'; import { SelectionManager } from '../util/SelectionManager'; import { SharingManager } from '../util/SharingManager'; -import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { TabDocView } from './collections/TabDocView'; import './DocumentButtonBar.scss'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; @@ -194,7 +195,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}> <div className="documentButtonBar-linker" style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white", border: isPinned ? "black 1px solid " : "" }} - onClick={e => this.props.views().map(view => view && DockedFrameRenderer.PinDoc(view.props.Document, isPinned))}> + onClick={e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, isPinned))}> <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" /> </div></Tooltip>; diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 6ac6571d3..dcd3d47cf 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -160,7 +160,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } - CollectionDockingView.AddRight(googleDoc, "right"); + CollectionDockingView.AddSplit(googleDoc, "right"); } else if (e.altKey) { e.preventDefault(); window.open(googleDocUrl); diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index f1a29bd13..d3be1636d 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -1,24 +1,5 @@ @import "../../views/globalCssVariables.scss"; -.miniMap { - position: absolute; - overflow: hidden; - right: 10; - bottom: 10; - border: solid 1px; - box-shadow: black 0.4vw 0.4vw 0.8vw; - - .miniOverlay { - width: 100%; - height: 100%; - position: absolute; - - .miniThumb { - background: #25252525; - position: absolute; - } - } -} .lm_title { margin-top: 3px; @@ -72,18 +53,6 @@ display: inline; } -.messageCounter { - width: 18px; - height: 20px; - text-align: center; - border-radius: 20px; - margin-left: 5px; - transform: translate(0px, -8px); - display: inline-block; - background: transparent; - border: 1px #999999 solid; -} - .collectiondockingview-container { width: 100%; height: 100%; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 93e77e0a2..d8e95bcdc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,37 +1,25 @@ import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; -import { clamp, pull } from 'lodash'; -import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx"; +import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import * as GoldenLayout from "../../../client/goldenLayout"; -import { DataSym, Doc, DocListCast, Opt } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; -import { FieldId } from "../../../fields/RefField"; -import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; -import { DocumentManager } from '../../util/DocumentManager'; -import { DragManager, dropActionType } from "../../util/DragManager"; +import { DragManager } from "../../util/DragManager"; import { InteractionUtils } from '../../util/InteractionUtils'; import { Scripting } from '../../util/Scripting'; -import { SelectionManager } from '../../util/SelectionManager'; -import { SnappingManager } from '../../util/SnappingManager'; -import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { DocumentView } from "../nodes/DocumentView"; -import { PresBox } from '../nodes/PresBox'; import "./CollectionDockingView.scss"; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { CollectionViewType } from './CollectionView'; -import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; +import { TabDocView } from './TabDocView'; import React = require("react"); const _global = (window /* browser */ || global /* node */) as any; @@ -249,7 +237,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { this._goldenLayout.on('tabCreated', this.tabCreated); this._goldenLayout.on('tabDestroyed', this.tabDestroyed); this._goldenLayout.on('stackCreated', this.stackCreated); - this._goldenLayout.registerComponent('DocumentFrameRenderer', DockedFrameRenderer); + this._goldenLayout.registerComponent('DocumentFrameRenderer', TabDocView); this._goldenLayout.container = this._containerRef.current; if (this._goldenLayout.config.maximisedItemId === '__glMaximised') { try { @@ -407,354 +395,6 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { } } -interface DockedFrameProps { - documentId: FieldId; - glContainer: any; -} -@observer -export class DockedFrameRenderer extends React.Component<DockedFrameProps> { - _mainCont: HTMLDivElement | null = null; - _tabReaction: IReactionDisposer | undefined; - @observable private _panelWidth = 0; - @observable private _panelHeight = 0; - @observable private _isActive: boolean = false; - @observable private _document: Doc | undefined; - @observable private _view: DocumentView | undefined; - - get stack(): any { return (this.props as any).glContainer.parent.parent; } - get tab() { return (this.props as any).glContainer.tab; } - get view() { return this._view; } - - @action - init = (tab: any, doc: Opt<Doc>) => { - if (tab.DashDoc !== doc && doc && tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") { - tab._disposers = {} as { [name: string]: IReactionDisposer }; - tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true); - tab.DashDoc = doc; - - CollectionDockingView.Instance.tabMap.add(tab); - tab.titleElement[0].onclick = (e: any) => { - if (Date.now() - tab.titleElement[0].lastClick < 1000) tab.titleElement[0].select(); - tab.titleElement[0].lastClick = Date.now(); - tab.titleElement[0].focus(); - }; - tab.titleElement[0].onchange = (e: any) => { - tab.titleElement[0].size = e.currentTarget.value.length + 1; - Doc.GetProto(doc).title = e.currentTarget.value; - }; - tab.titleElement[0].size = StrCast(doc.title).length + 1; - tab.titleElement[0].value = doc.title; - tab.titleElement[0].style["max-width"] = "100px"; - const gearSpan = document.createElement("span"); - gearSpan.className = "collectionDockingView-gear"; - gearSpan.style.position = "relative"; - gearSpan.style.paddingLeft = "0px"; - gearSpan.style.paddingRight = "12px"; - const stack = tab.contentItem.parent; - tab.element[0].onpointerdown = (e: any) => { - e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view, false); - }; - // shifts the focus to this tab when another tab is dragged over it - tab.element[0].onmouseenter = (e: MouseEvent) => { - if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) { - tab.header.parent.setActiveContentItem(tab.contentItem); - } - tab.setActive(true); - }; - const onDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, (e) => { - !e.defaultPrevented && DragManager.StartDocumentDrag([gearSpan], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY); - return !e.defaultPrevented; - }, returnFalse, emptyFunction); - }; - - tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc), - (selected) => { - selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && tab.header.parent.setActiveContentItem(tab.contentItem); - } - ); - tab._disposers.buttonDisposer = reaction(() => this.view, - (view) => { - if (view) { - ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} > - <CollectionDockingViewMenu views={() => [view]} Stack={stack} /> - </span>, - gearSpan); - tab._disposers.buttonDisposer?.(); - } - }, { fireImmediately: true }); - - tab.reactComponents = [gearSpan]; - tab.element.append(gearSpan); - tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => { - tab.titleElement[0].value = title; - tab.titleElement[0].style.padding = degree ? 0 : 2; - tab.titleElement[0].style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`; - }, { fireImmediately: true }); - tab.closeElement.off('click') //unbind the current click handler - .click(function () { - Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); - Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true); - SelectionManager.DeselectAll(); - tab.contentItem.remove(); - }); - } - } - /** - * Adds a document to the presentation view - **/ - @undoBatch - @action - public static PinDoc(doc: Doc, unpin = false) { - if (unpin) DockedFrameRenderer.UnpinDoc(doc); - else { - //add this new doc to props.Document - const curPres = CurrentUserUtils.ActivePresentation; - if (curPres) { - const pinDoc = Doc.MakeAlias(doc); - pinDoc.presentationTargetDoc = doc; - pinDoc.presZoomButton = true; - pinDoc.context = curPres; - Doc.AddDocToList(curPres, "data", pinDoc); - if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; - if (!DocumentManager.Instance.getDocumentView(curPres)) { - CollectionDockingView.AddSplit(curPres, "right"); - } - DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null)); - } - } - } - /** - * Adds a document to the presentation view - **/ - @undoBatch - @action - public static UnpinDoc(doc: Doc) { - //add this new doc to props.Document - const curPres = CurrentUserUtils.ActivePresentation; - if (curPres) { - const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)); - ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]); - } - } - - componentDidMount() { - const color = () => StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white"); - const selected = () => SelectionManager.SelectedDocuments().some(v => v.props.Document === this._document); - const updateTabColor = () => this.tab?.titleElement[0] && (this.tab.titleElement[0].style.backgroundColor = selected() ? color() : ""); - const observer = new _global.ResizeObserver(action((entries: any) => { - for (const entry of entries) { - this._panelWidth = entry.contentRect.width; - this._panelHeight = entry.contentRect.height; - } - updateTabColor(); - })); - observer.observe(this.props.glContainer._element[0]); - this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged); - this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged(); - this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), updateTabColor, { fireImmediately: true }); - } - - componentWillUnmount() { - this._tabReaction?.(); - this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged); - } - - @action.bound - private onActiveContentItemChanged() { - if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) { - this._isActive = this.props.glContainer.tab.isActive; - this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0); - (CollectionDockingView.Instance as any)._goldenLayout.isInitialised && CollectionDockingView.Instance.stateChanged(); - !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. - } - } - - get layoutDoc() { return this._document && Doc.Layout(this._document); } - nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0; - panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : - (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth) - panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight; - nativeWidth = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeWidth) || this._panelWidth : 0; - nativeHeight = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeHeight) || this._panelHeight : 0; - - contentScaling = () => { - const nativeH = this.nativeHeight(); - const nativeW = this.nativeWidth(); - let scaling = 1; - if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) { - scaling = 1; - } else if (NumCast(this.layoutDoc?._nativeWidth) && ((this.layoutDoc?._fitWidth) || - this._panelHeight / NumCast(this.layoutDoc?._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc?._nativeWidth))) { - scaling = this._panelWidth / NumCast(this.layoutDoc?._nativeWidth); - } else if (nativeW && nativeH) { - const wscale = this.panelWidth() / nativeW; - scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale; - } - return scaling; - } - - ScreenToLocalTransform = () => { - if (this._mainCont && this._mainCont.children) { - const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement); - const scale = Utils.GetScreenTransform(this._mainCont).scale; - return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); - } - return Transform.Identity(); - } - get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; } - - // adds a tab to the layout based on the locaiton parameter which can be: - // close[:{left,right,top,bottom}] - e.g., "close" will close the tab, "close:left" will close the left tab, - // add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right - // replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents, - // "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, - // "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right - // inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack - addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { - SelectionManager.DeselectAll(); - if (doc._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); - const locationFields = location.split(":"); - const locationParams = locationFields.length > 1 ? locationFields[1] : ""; - switch (locationFields[0]) { - case "close": return CollectionDockingView.CloseSplit(doc, locationParams); - case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); - case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); - case "inPlace": - case "add": - default: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); - } - } - - @computed get renderContentBounds() { - const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0]; - const xbounds = bounds[2] - bounds[0]; - const ybounds = bounds[3] - bounds[1]; - const dim = Math.max(xbounds, ybounds); - return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim }; - } - @computed get miniLeft() { return 50 + (NumCast(this._document?._panX) - this.renderContentBounds.cx) / this.renderContentBounds.dim * 100 - this.miniWidth / 2; } - @computed get miniTop() { return 50 + (NumCast(this._document?._panY) - this.renderContentBounds.cy) / this.renderContentBounds.dim * 100 - this.miniHeight / 2; } - @computed get miniWidth() { return this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; } - @computed get miniHeight() { return this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; } - childLayoutTemplate = () => Cast(this._document?.childLayoutTemplate, Doc, null); - returnMiniSize = () => NumCast(this._document?._miniMapSize, 150); - miniDown = (e: React.PointerEvent) => { - this._document && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - this._document!._panX = clamp(NumCast(this._document!._panX) + delta[0] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.l, this.renderContentBounds.l + this.renderContentBounds.dim); - this._document!._panY = clamp(NumCast(this._document!._panY) + delta[1] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.t, this.renderContentBounds.t + this.renderContentBounds.dim); - return false; - }), emptyFunction, emptyFunction); - } - getCurrentFrame = (): number => { - const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null); - return Cast(presTargetDoc._currentFrame, "number", null); - } - - renderMiniMap() { - return <div className="miniMap" style={{ - width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor, - StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))), - }}> - <CollectionFreeFormView - Document={this._document!} - LibraryPath={emptyPath} - CollectionView={undefined} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this. - noOverlay={true} // don't render overlay Docs since they won't scale - active={returnTrue} - select={emptyFunction} - dropAction={undefined} - isSelected={returnFalse} - dontRegisterView={true} - annotationsKey={""} - fieldKey={Doc.LayoutFieldKey(this._document!)} - bringToFront={emptyFunction} - rootSelected={returnTrue} - addDocument={returnFalse} - moveDocument={returnFalse} - removeDocument={returnFalse} - ContentScaling={returnOne} - PanelWidth={this.returnMiniSize} - PanelHeight={this.returnMiniSize} - NativeHeight={returnZero} - NativeWidth={returnZero} - ScreenToLocalTransform={this.ScreenToLocalTransform} - renderDepth={0} - whenActiveChanged={emptyFunction} - focus={emptyFunction} - backgroundColor={CollectionDockingView.Instance.props.backgroundColor} - addDocTab={this.addDocTab} - pinToPres={DockedFrameRenderer.PinDoc} - docFilters={CollectionDockingView.Instance.docFilters} - searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} - fitToBox={true} - /> - <div className="miniOverlay" onPointerDown={this.miniDown} > - <div className="miniThumb" style={{ - width: `${this.miniWidth}% `, - height: `${this.miniHeight}% `, - left: `${this.miniLeft}% `, - top: `${this.miniTop}% `, - }} - /> - </div> - </div>; - } - setView = action((view: DocumentView) => this._view = view); - @computed get docView() { - TraceMobx(); - return !this._document ? (null) : - <><DocumentView key={this._document[Id]} - LibraryPath={emptyPath} - Document={this._document} - getView={this.setView} - DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} - bringToFront={emptyFunction} - rootSelected={returnTrue} - addDocument={undefined} - removeDocument={undefined} - ContentScaling={this.contentScaling} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight} - NativeHeight={this.nativeHeight} - NativeWidth={this.nativeWidth} - ScreenToLocalTransform={this.ScreenToLocalTransform} - renderDepth={0} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - focus={emptyFunction} - backgroundColor={CollectionDockingView.Instance.props.backgroundColor} - addDocTab={this.addDocTab} - pinToPres={DockedFrameRenderer.PinDoc} - docFilters={CollectionDockingView.Instance.docFilters} - searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} /> - {this._document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)} - </>; - } - - render() { - return !this._isActive ? (null) : - (<div className="collectionDockingView-content" ref={ref => { - if (this._mainCont = ref) { - (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); - DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document))); - } - }} - style={{ - transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`, - height: this.layoutDoc?._fitWidth ? undefined : "100%", - width: this.widthpercent - }}> - {this.docView} - </div >); - } -} Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddSplit(doc, "right"); }, "opens up the inputted document on the right side of the screen", "(doc: any)"); Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a41b5eaca..eaada32b0 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -5,7 +5,7 @@ import { Tooltip } from "@material-ui/core"; import { action, computed, Lambda, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { ColorState } from "react-color"; -import { Doc, DocListCast, Opt, Field } from "../../../fields/Doc"; +import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc"; import { Document } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; import { InkTool } from "../../../fields/InkField"; @@ -29,10 +29,10 @@ import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { DocumentView } from "../nodes/DocumentView"; import { RichTextMenu } from "../nodes/formattedText/RichTextMenu"; +import { PresBox } from "../nodes/PresBox"; import "./CollectionMenu.scss"; import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView"; -import { DockedFrameRenderer } from "./CollectionDockingView"; -import { PresBox } from "../nodes/PresBox"; +import { TabDocView } from "./TabDocView"; @observer export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { @@ -379,7 +379,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp const isPinned = targetDoc && Doc.isDocPinned(targetDoc); return !targetDoc ? (null) : <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div>} placement="top"> <button className="antimodeMenu-button" style={{ backgroundColor: isPinned ? "121212" : undefined, borderRight: "1px solid gray" }} - onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}> + onClick={e => TabDocView.PinDoc(targetDoc, isPinned)}> <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin" /> </button> </Tooltip>; @@ -443,7 +443,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp <button className="antidmodeMenu-button" style={{ borderRight: "1px solid gray" }} onClick={e => { if (targetDoc) { - DockedFrameRenderer.PinDoc(targetDoc, false); + TabDocView.PinDoc(targetDoc, false); const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1]; const x = targetDoc._panX; const y = targetDoc._panY; diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss new file mode 100644 index 000000000..9a4b5cbd1 --- /dev/null +++ b/src/client/views/collections/TabDocView.scss @@ -0,0 +1,20 @@ + +.miniMap { + position: absolute; + overflow: hidden; + right: 10; + bottom: 10; + border: solid 1px; + box-shadow: black 0.4vw 0.4vw 0.8vw; + + .miniOverlay { + width: 100%; + height: 100%; + position: absolute; + + .miniThumb { + background: #25252525; + position: absolute; + } + } +}
\ No newline at end of file diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx new file mode 100644 index 000000000..36959f254 --- /dev/null +++ b/src/client/views/collections/TabDocView.tsx @@ -0,0 +1,379 @@ +import 'golden-layout/src/css/goldenlayout-base.css'; +import 'golden-layout/src/css/goldenlayout-dark-theme.css'; +import { clamp } from 'lodash'; +import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; +import { observer } from "mobx-react"; +import * as ReactDOM from 'react-dom'; +import { DataSym, Doc, DocListCast, Opt } from "../../../fields/Doc"; +import { Id } from '../../../fields/FieldSymbols'; +import { FieldId } from "../../../fields/RefField"; +import { listSpec } from '../../../fields/Schema'; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { TraceMobx } from '../../../fields/util'; +import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../../Utils"; +import { DocServer } from "../../DocServer"; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; +import { DocumentManager } from '../../util/DocumentManager'; +import { DragManager, dropActionType } from "../../util/DragManager"; +import { SelectionManager } from '../../util/SelectionManager'; +import { SnappingManager } from '../../util/SnappingManager'; +import { Transform } from '../../util/Transform'; +import { undoBatch } from "../../util/UndoManager"; +import { DocumentView } from "../nodes/DocumentView"; +import { PresBox } from '../nodes/PresBox'; +import { CollectionDockingView } from './CollectionDockingView'; +import "./TabDocView.scss"; +import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionViewType } from './CollectionView'; +import React = require("react"); +const _global = (window /* browser */ || global /* node */) as any; + +interface TabDocViewProps { + documentId: FieldId; + glContainer: any; +} +@observer +export class TabDocView extends React.Component<TabDocViewProps> { + _mainCont: HTMLDivElement | null = null; + _tabReaction: IReactionDisposer | undefined; + @observable private _panelWidth = 0; + @observable private _panelHeight = 0; + @observable private _isActive: boolean = false; + @observable private _document: Doc | undefined; + @observable private _view: DocumentView | undefined; + + get stack(): any { return (this.props as any).glContainer.parent.parent; } + get tab() { return (this.props as any).glContainer.tab; } + get view() { return this._view; } + + @action + init = (tab: any, doc: Opt<Doc>) => { + if (tab.DashDoc !== doc && doc && tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") { + tab._disposers = {} as { [name: string]: IReactionDisposer }; + tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true); + tab.DashDoc = doc; + + CollectionDockingView.Instance.tabMap.add(tab); + tab.titleElement[0].onclick = (e: any) => { + if (Date.now() - tab.titleElement[0].lastClick < 1000) tab.titleElement[0].select(); + tab.titleElement[0].lastClick = Date.now(); + tab.titleElement[0].focus(); + }; + tab.titleElement[0].onchange = (e: any) => { + tab.titleElement[0].size = e.currentTarget.value.length + 1; + Doc.GetProto(doc).title = e.currentTarget.value; + }; + tab.titleElement[0].size = StrCast(doc.title).length + 1; + tab.titleElement[0].value = doc.title; + tab.titleElement[0].style["max-width"] = "100px"; + const gearSpan = document.createElement("span"); + gearSpan.className = "collectionDockingView-gear"; + gearSpan.style.position = "relative"; + gearSpan.style.paddingLeft = "0px"; + gearSpan.style.paddingRight = "12px"; + const stack = tab.contentItem.parent; + tab.element[0].onpointerdown = (e: any) => { + e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view, false); + }; + // shifts the focus to this tab when another tab is dragged over it + tab.element[0].onmouseenter = (e: MouseEvent) => { + if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) { + tab.header.parent.setActiveContentItem(tab.contentItem); + } + tab.setActive(true); + }; + const onDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, (e) => { + !e.defaultPrevented && DragManager.StartDocumentDrag([gearSpan], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY); + return !e.defaultPrevented; + }, returnFalse, emptyFunction); + }; + + tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc), + (selected) => { + selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && tab.header.parent.setActiveContentItem(tab.contentItem); + } + ); + tab._disposers.buttonDisposer = reaction(() => this.view, + (view) => { + if (view) { + ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} > + <CollectionDockingViewMenu views={() => [view]} Stack={stack} /> + </span>, + gearSpan); + tab._disposers.buttonDisposer?.(); + } + }, { fireImmediately: true }); + + tab.reactComponents = [gearSpan]; + tab.element.append(gearSpan); + tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => { + tab.titleElement[0].value = title; + tab.titleElement[0].style.padding = degree ? 0 : 2; + tab.titleElement[0].style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`; + }, { fireImmediately: true }); + tab.closeElement.off('click') //unbind the current click handler + .click(function () { + Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); + Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true); + SelectionManager.DeselectAll(); + tab.contentItem.remove(); + }); + } + } + /** + * Adds a document to the presentation view + **/ + @undoBatch + @action + public static PinDoc(doc: Doc, unpin = false) { + if (unpin) TabDocView.UnpinDoc(doc); + else { + //add this new doc to props.Document + const curPres = CurrentUserUtils.ActivePresentation; + if (curPres) { + const pinDoc = Doc.MakeAlias(doc); + pinDoc.presentationTargetDoc = doc; + pinDoc.presZoomButton = true; + pinDoc.context = curPres; + Doc.AddDocToList(curPres, "data", pinDoc); + if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; + if (!DocumentManager.Instance.getDocumentView(curPres)) { + CollectionDockingView.AddSplit(curPres, "right"); + } + DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null)); + } + } + } + /** + * Adds a document to the presentation view + **/ + @undoBatch + @action + public static UnpinDoc(doc: Doc) { + //add this new doc to props.Document + const curPres = CurrentUserUtils.ActivePresentation; + if (curPres) { + const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)); + ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]); + } + } + + componentDidMount() { + const color = () => StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white"); + const selected = () => SelectionManager.SelectedDocuments().some(v => v.props.Document === this._document); + const updateTabColor = () => this.tab?.titleElement[0] && (this.tab.titleElement[0].style.backgroundColor = selected() ? color() : ""); + const observer = new _global.ResizeObserver(action((entries: any) => { + for (const entry of entries) { + this._panelWidth = entry.contentRect.width; + this._panelHeight = entry.contentRect.height; + } + updateTabColor(); + })); + observer.observe(this.props.glContainer._element[0]); + this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged); + this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged(); + this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), updateTabColor, { fireImmediately: true }); + } + + componentWillUnmount() { + this._tabReaction?.(); + this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged); + } + + @action.bound + private onActiveContentItemChanged() { + if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) { + this._isActive = this.props.glContainer.tab.isActive; + this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0); + (CollectionDockingView.Instance as any)._goldenLayout.isInitialised && CollectionDockingView.Instance.stateChanged(); + !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. + } + } + + get layoutDoc() { return this._document && Doc.Layout(this._document); } + nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0; + panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : + (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth) + panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight; + nativeWidth = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeWidth) || this._panelWidth : 0; + nativeHeight = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeHeight) || this._panelHeight : 0; + + contentScaling = () => { + const nativeH = this.nativeHeight(); + const nativeW = this.nativeWidth(); + let scaling = 1; + if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) { + scaling = 1; + } else if (NumCast(this.layoutDoc?._nativeWidth) && ((this.layoutDoc?._fitWidth) || + this._panelHeight / NumCast(this.layoutDoc?._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc?._nativeWidth))) { + scaling = this._panelWidth / NumCast(this.layoutDoc?._nativeWidth); + } else if (nativeW && nativeH) { + const wscale = this.panelWidth() / nativeW; + scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale; + } + return scaling; + } + + ScreenToLocalTransform = () => { + if (this._mainCont && this._mainCont.children) { + const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement); + const scale = Utils.GetScreenTransform(this._mainCont).scale; + return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); + } + return Transform.Identity(); + } + get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; } + + // adds a tab to the layout based on the locaiton parameter which can be: + // close[:{left,right,top,bottom}] - e.g., "close" will close the tab, "close:left" will close the left tab, + // add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right + // replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents, + // "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, + // "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right + // inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack + addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { + SelectionManager.DeselectAll(); + if (doc._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + const locationFields = location.split(":"); + const locationParams = locationFields.length > 1 ? locationFields[1] : ""; + switch (locationFields[0]) { + case "close": return CollectionDockingView.CloseSplit(doc, locationParams); + case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); + case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); + case "inPlace": + case "add": + default: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); + } + } + + @computed get renderContentBounds() { + const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0]; + const xbounds = bounds[2] - bounds[0]; + const ybounds = bounds[3] - bounds[1]; + const dim = Math.max(xbounds, ybounds); + return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim }; + } + @computed get miniLeft() { return 50 + (NumCast(this._document?._panX) - this.renderContentBounds.cx) / this.renderContentBounds.dim * 100 - this.miniWidth / 2; } + @computed get miniTop() { return 50 + (NumCast(this._document?._panY) - this.renderContentBounds.cy) / this.renderContentBounds.dim * 100 - this.miniHeight / 2; } + @computed get miniWidth() { return this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; } + @computed get miniHeight() { return this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; } + childLayoutTemplate = () => Cast(this._document?.childLayoutTemplate, Doc, null); + returnMiniSize = () => NumCast(this._document?._miniMapSize, 150); + miniDown = (e: React.PointerEvent) => { + this._document && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { + this._document!._panX = clamp(NumCast(this._document!._panX) + delta[0] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.l, this.renderContentBounds.l + this.renderContentBounds.dim); + this._document!._panY = clamp(NumCast(this._document!._panY) + delta[1] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.t, this.renderContentBounds.t + this.renderContentBounds.dim); + return false; + }), emptyFunction, emptyFunction); + } + getCurrentFrame = (): number => { + const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null); + return Cast(presTargetDoc._currentFrame, "number", null); + } + + renderMiniMap() { + return <div className="miniMap" style={{ + width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor, + StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))), + }}> + <CollectionFreeFormView + Document={this._document!} + LibraryPath={emptyPath} + CollectionView={undefined} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this. + noOverlay={true} // don't render overlay Docs since they won't scale + active={returnTrue} + select={emptyFunction} + dropAction={undefined} + isSelected={returnFalse} + dontRegisterView={true} + annotationsKey={""} + fieldKey={Doc.LayoutFieldKey(this._document!)} + bringToFront={emptyFunction} + rootSelected={returnTrue} + addDocument={returnFalse} + moveDocument={returnFalse} + removeDocument={returnFalse} + ContentScaling={returnOne} + PanelWidth={this.returnMiniSize} + PanelHeight={this.returnMiniSize} + NativeHeight={returnZero} + NativeWidth={returnZero} + ScreenToLocalTransform={this.ScreenToLocalTransform} + renderDepth={0} + whenActiveChanged={emptyFunction} + focus={emptyFunction} + backgroundColor={CollectionDockingView.Instance.props.backgroundColor} + addDocTab={this.addDocTab} + pinToPres={TabDocView.PinDoc} + docFilters={CollectionDockingView.Instance.docFilters} + searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} + fitToBox={true} + /> + <div className="miniOverlay" onPointerDown={this.miniDown} > + <div className="miniThumb" style={{ + width: `${this.miniWidth}% `, + height: `${this.miniHeight}% `, + left: `${this.miniLeft}% `, + top: `${this.miniTop}% `, + }} + /> + </div> + </div>; + } + setView = action((view: DocumentView) => this._view = view); + @computed get docView() { + TraceMobx(); + return !this._document ? (null) : + <><DocumentView key={this._document[Id]} + LibraryPath={emptyPath} + Document={this._document} + getView={this.setView} + DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} + bringToFront={emptyFunction} + rootSelected={returnTrue} + addDocument={undefined} + removeDocument={undefined} + ContentScaling={this.contentScaling} + PanelWidth={this.panelWidth} + PanelHeight={this.panelHeight} + NativeHeight={this.nativeHeight} + NativeWidth={this.nativeWidth} + ScreenToLocalTransform={this.ScreenToLocalTransform} + renderDepth={0} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + focus={emptyFunction} + backgroundColor={CollectionDockingView.Instance.props.backgroundColor} + addDocTab={this.addDocTab} + pinToPres={TabDocView.PinDoc} + docFilters={CollectionDockingView.Instance.docFilters} + searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} /> + {this._document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)} + </>; + } + + render() { + return !this._isActive ? (null) : + (<div className="collectionDockingView-content" ref={ref => { + if (this._mainCont = ref) { + (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); + DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document))); + } + }} + style={{ + transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`, + height: this.layoutDoc?._fitWidth ? undefined : "100%", + width: this.widthpercent + }}> + {this.docView} + </div >); + } +} diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index a03c45a53..07b2d51d1 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -1,34 +1,33 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from "@material-ui/core"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, DocCastAsync, WidthSym } from "../../../fields/Doc"; -import { InkTool } from "../../../fields/InkField"; -import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types"; -import { returnFalse, returnOne, numberRange, returnTrue } from "../../../Utils"; +import { ColorState, SketchPicker } from "react-color"; +import { Doc, DocCastAsync, DocListCast } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; -import { DocumentManager } from "../../util/DocumentManager"; -import { undoBatch } from "../../util/UndoManager"; -import { CollectionDockingView, DockedFrameRenderer } from "../collections/CollectionDockingView"; -import { CollectionView, CollectionViewType } from "../collections/CollectionView"; -import { FieldView, FieldViewProps } from './FieldView'; -import { DocumentType } from "../../documents/DocumentTypes"; -import "./PresBox.scss"; -import { ViewBoxBaseComponent } from "../DocComponent"; -import { makeInterface, listSpec } from "../../../fields/Schema"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { InkTool } from "../../../fields/InkField"; +import { List } from "../../../fields/List"; import { PrefetchProxy } from "../../../fields/Proxy"; +import { listSpec, makeInterface } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { returnFalse, returnOne } from "../../../Utils"; +import { Docs } from "../../documents/Documents"; +import { DocumentType } from "../../documents/DocumentTypes"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { DocumentManager } from "../../util/DocumentManager"; import { Scripting } from "../../util/Scripting"; -import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; -import { List } from "../../../fields/List"; -import { Tooltip } from "@material-ui/core"; -import { actionAsync } from "mobx-utils"; import { SelectionManager } from "../../util/SelectionManager"; +import { undoBatch } from "../../util/UndoManager"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionView, CollectionViewType } from "../collections/CollectionView"; +import { TabDocView } from "../collections/TabDocView"; +import { ViewBoxBaseComponent } from "../DocComponent"; import { AudioBox } from "./AudioBox"; -import { DocumentView } from "./DocumentView"; -import { SketchPicker, ColorState } from "react-color"; -import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./PresBox.scss"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -1112,7 +1111,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const presData = Cast(this.rootDoc.data, listSpec(Doc)); if (data && presData) { data.push(doc); - DockedFrameRenderer.PinDoc(doc, false); + TabDocView.PinDoc(doc, false); this.gotoDocument(this.childDocs.length, this.itemIndex); } else { this.props.addDocTab(doc, "add:right"); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index d4eb76ecd..b8633b06f 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -20,7 +20,7 @@ import { Scripting } from '../client/util/Scripting'; import { SettingsManager } from '../client/util/SettingsManager'; import { Transform } from '../client/util/Transform'; import { UndoManager } from "../client/util/UndoManager"; -import { DockedFrameRenderer } from '../client/views/collections/CollectionDockingView'; +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"; @@ -516,7 +516,7 @@ export class MobileInterface extends React.Component { return <div className="docButton" title={Doc.isDocPinned(this._activeDoc) ? "Unpin from presentation" : "Pin to presentation"} style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }} - onClick={e => DockedFrameRenderer.PinDoc(this._activeDoc, isPinned)}> + onClick={e => TabDocView.PinDoc(this._activeDoc, isPinned)}> <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" /> </div>; } else return (null); |