aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/CurrentUserUtils.ts6
-rw-r--r--src/client/views/DocumentButtonBar.tsx5
-rw-r--r--src/client/views/PropertiesButtons.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.scss31
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx370
-rw-r--r--src/client/views/collections/CollectionMenu.tsx10
-rw-r--r--src/client/views/collections/TabDocView.scss20
-rw-r--r--src/client/views/collections/TabDocView.tsx379
-rw-r--r--src/client/views/nodes/PresBox.tsx43
-rw-r--r--src/mobile/MobileInterface.tsx4
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);