aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-10-04 16:53:24 -0400
committerbobzel <zzzman@gmail.com>2022-10-04 16:53:24 -0400
commitbb9ddc6aaf5860736b0bd07333a33876b0c1d7ef (patch)
tree35ec2a69d9d5d4f45d9e3ed21acb72527365c035
parent995ed33feef1eb663d65b1b1d3da8c91926013dc (diff)
parent6e22c212e288eb3e69740a78732f81485c97a577 (diff)
Merge branch 'master' into pres-pin-fixes
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/util/CurrentUserUtils.ts21
-rw-r--r--src/client/util/InteractionUtils.tsx53
-rw-r--r--src/client/views/DashboardView.tsx85
-rw-r--r--src/client/views/DocumentDecorations.tsx24
-rw-r--r--src/client/views/InkingStroke.tsx15
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx56
-rw-r--r--src/client/views/collections/CollectionView.tsx7
-rw-r--r--src/client/views/collections/TabDocView.tsx30
-rw-r--r--src/client/views/collections/TreeView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx5
-rw-r--r--src/fields/Doc.ts11
-rw-r--r--src/fields/ScriptField.ts2
13 files changed, 198 insertions, 116 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4ca9972f8..42291bf0a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -396,6 +396,7 @@ export namespace Docs {
_yMargin: 10,
nativeDimModifiable: true,
treeViewGrowsHorizontally: true,
+ nativeHeightUnfrozen: true,
forceReflow: true,
links: '@links(self)',
},
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6f9975be4..d62acd64e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -462,28 +462,33 @@ export class CurrentUserUtils {
static setupDashboards(doc: Doc, field:string) {
var myDashboards = DocCast(doc[field]);
+ const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
const newDashboard = `createNewDashboard()`;
+
const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true };
const reqdBtnScript = {onClick: newDashboard,}
const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
+ const contextMenuScripts = [/*newDashboard*/] as string[];
+ const contextMenuLabels = [/*"Create New Dashboard"*/] as string[];
+ const contextMenuIcons = [/*"plus"*/] as string[];
+ const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)', 'resetDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters
+ const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts
+ const childContextMenuLabels = ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
+ const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
const reqdOpts:DocumentOptions = {
title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 150, ignoreClick: true,
buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias",
_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
- contextMenuLabels: new List<string>(["Create New Dashboard"]),
- contextMenuIcons: new List<string>(["plus"]),
- childContextMenuLabels: new List<string>(["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]),// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
- childContextMenuIcons: new List<string>(["chalkboard", "tv", "camera", "users", "times"]), // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
+ contextMenuLabels:new List<string>(contextMenuLabels),
+ contextMenuIcons:new List<string>(contextMenuIcons),
+ childContextMenuLabels:new List<string>(childContextMenuLabels),
+ childContextMenuIcons:new List<string>(childContextMenuIcons),
explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
};
myDashboards = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
- const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
- const contextMenuScripts = [newDashboard];
- const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters
- const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts
if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
myDashboards.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
}
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 4af51b9a0..85700da37 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -230,58 +230,33 @@ export namespace InteractionUtils {
points.push({ X: right, Y: bottom });
points.push({ X: left, Y: bottom });
points.push({ X: left, Y: top });
+ break;
case 'triangle':
- // points.push({ X: left, Y: bottom });
- // points.push({ X: right, Y: bottom });
- // points.push({ X: (right + left) / 2, Y: top });
- // points.push({ X: left, Y: bottom });
-
- points.push({ X: left, Y: bottom });
points.push({ X: left, Y: bottom });
-
- points.push({ X: right, Y: bottom });
- points.push({ X: right, Y: bottom });
points.push({ X: right, Y: bottom });
- points.push({ X: right, Y: bottom });
-
- points.push({ X: (right + left) / 2, Y: top });
- points.push({ X: (right + left) / 2, Y: top });
points.push({ X: (right + left) / 2, Y: top });
- points.push({ X: (right + left) / 2, Y: top });
-
- points.push({ X: left, Y: bottom });
points.push({ X: left, Y: bottom });
+ break;
case 'circle':
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
- if (centerX - Math.min(left, right) < centerY - Math.min(top, bottom)) {
- for (var y = Math.min(top, bottom); y < Math.max(top, bottom); y++) {
- const x = Math.sqrt(Math.pow(radius, 2) - Math.pow(y - centerY, 2)) + centerX;
- points.push({ X: x, Y: y });
- }
- for (var y = Math.max(top, bottom); y > Math.min(top, bottom); y--) {
- const x = Math.sqrt(Math.pow(radius, 2) - Math.pow(y - centerY, 2)) + centerX;
- const newX = centerX - (x - centerX);
- points.push({ X: newX, Y: y });
- }
- points.push({ X: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(top, bottom) - centerY, 2)) + centerX, Y: Math.min(top, bottom) });
- } else {
- for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
- const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
- points.push({ X: x, Y: y });
- }
- for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
- const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
- const newY = centerY - (y - centerY);
- points.push({ X: x, Y: newY });
- }
- points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(left, right) - centerX, 2)) + centerY });
+ for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
+ const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
+ points.push({ X: x, Y: y });
}
+ for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
+ const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
+ const newY = centerY - (y - centerY);
+ points.push({ X: x, Y: newY });
+ }
+ points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(left, right) - centerX, 2)) + centerY });
+ break;
+
case 'line':
points.push({ X: left, Y: top });
points.push({ X: right, Y: bottom });
- return points;
+ break;
}
return points;
}
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 11bb0c6a8..192e55431 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -294,6 +294,88 @@ export class DashboardView extends React.Component {
}
};
+ public static resetDashboard = (dashboard: Doc) => {
+ const config = StrCast(dashboard.dockingConfig);
+ const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
+ const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
+
+ const components =
+ docids.map(docid => ({
+ type: 'component',
+ component: 'DocumentFrameRenderer',
+ title: 'Untitled Tab 1',
+ width: 600,
+ props: {
+ documentId: docid,
+ },
+ componentName: 'lm-react-component',
+ isClosable: true,
+ reorderEnabled: true,
+ componentState: null,
+ })) ?? [];
+ const reset = {
+ isClosable: true,
+ reorderEnabled: true,
+ title: '',
+ openPopouts: [],
+ maximisedItemId: null,
+ settings: {
+ hasHeaders: true,
+ constrainDragToContainer: true,
+ reorderEnabled: true,
+ selectionEnabled: false,
+ popoutWholeStack: false,
+ blockedPopoutsThrowError: true,
+ closePopoutsOnUnload: true,
+ showPopoutIcon: true,
+ showMaximiseIcon: true,
+ showCloseIcon: true,
+ responsiveMode: 'onload',
+ tabOverlapAllowance: 0,
+ reorderOnTabMenuClick: false,
+ tabControlOffset: 10,
+ },
+ dimensions: {
+ borderWidth: 3,
+ borderGrabWidth: 5,
+ minItemHeight: 10,
+ minItemWidth: 20,
+ headerHeight: 27,
+ dragProxyWidth: 300,
+ dragProxyHeight: 200,
+ },
+ labels: {
+ close: 'close',
+ maximise: 'maximise',
+ minimise: 'minimise',
+ popout: 'new tab',
+ popin: 'pop in',
+ tabDropdown: 'additional tabs',
+ },
+ content: [
+ {
+ type: 'row',
+ isClosable: true,
+ reorderEnabled: true,
+ title: '',
+ content: [
+ {
+ type: 'stack',
+ width: 100,
+ isClosable: true,
+ reorderEnabled: true,
+ title: '',
+ activeItemIndex: 0,
+ content: components,
+ },
+ ],
+ },
+ ],
+ };
+ Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
+ return reset;
+ };
+
public static createNewDashboard = (id?: string, name?: string, background?: string) => {
const dashboards = Doc.MyDashboards;
const dashboardCount = DocListCast(dashboards.data).length + 1;
@@ -393,6 +475,9 @@ ScriptingGlobals.add(function shareDashboard(dashboard: Doc) {
ScriptingGlobals.add(function removeDashboard(dashboard: Doc) {
DashboardView.removeDashboard(dashboard);
}, 'Remove Dashboard from Dashboards');
+ScriptingGlobals.add(function resetDashboard(dashboard: Doc) {
+ DashboardView.resetDashboard(dashboard);
+}, 'move all dashboard tabs to single stack');
ScriptingGlobals.add(function addToDashboards(dashboard: Doc) {
DashboardView.openDashboard(Doc.MakeAlias(dashboard));
}, 'adds Dashboard to set of Dashboards');
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3e0de6d15..1d6075606 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,8 +1,10 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
+import { IconButton } from 'browndash-components';
import { action, computed, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
+import { FaUndo } from 'react-icons/fa';
import { DateField } from '../../fields/DateField';
import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from '../../fields/Doc';
import { Document } from '../../fields/documentSchemas';
@@ -28,10 +30,8 @@ import { LightboxView } from './LightboxView';
import { DocumentView } from './nodes/DocumentView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { ImageBox } from './nodes/ImageBox';
-import React = require('react');
-import { IconButton } from 'browndash-components';
-import { FaUndo } from 'react-icons/fa';
import { VideoBox } from './nodes/VideoBox';
+import React = require('react');
@observer
export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -503,7 +503,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
}
let actualdW = Math.max(width + dW * scale, 20);
let actualdH = Math.max(height + dH * scale, 20);
- const fixedAspect = nwidth && nheight && (!doc._fitWidth || e.ctrlKey || doc.nativeHeightUnfrozen);
+ const fixedAspect = nwidth && nheight && (!doc._fitWidth || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
if (fixedAspect) {
if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) {
if (dragRight && modifyNativeDim) {
@@ -534,7 +534,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
} else doc._height = actualdH;
}
} else {
- const maxHeight = 0; //Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '-scrollHeight']))) * docView.NativeDimScaling();
+ const maxHeight = doc.nativHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '-scrollHeight']))) * docView.NativeDimScaling();
dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH);
dW && (doc._width = actualdW);
dH && (doc._autoHeight = false);
@@ -721,14 +721,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
width: bounds.r - bounds.x + this._resizeBorderWidth + 'px',
height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px',
}}>
- {hideResizers ? null : (
- <div className="documentDecorations-topbar">
- {hideDeleteButton ? <div /> : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
- {hideDeleteButton ? <div /> : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
- {titleArea}
- {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Tab (ctrl: as alias, shift: in new collection)')}
- </div>
- )}
+ <div className="documentDecorations-topbar">
+ {hideDeleteButton ? <div /> : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
+ {hideResizers || hideDeleteButton ? <div /> : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
+ {hideResizers ? <div /> : titleArea}
+ {hideOpenButton ? <div /> : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
+ </div>
{hideResizers ? null : (
<>
<div key="tl" className={`documentDecorations-topLeftResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index dae1c10bb..b83ba97e7 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -24,8 +24,8 @@ import React = require('react');
import { action, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, HeightSym, WidthSym } from '../../fields/Doc';
-import { InkData, InkField, InkTool } from '../../fields/InkField';
-import { BoolCast, Cast, FieldValue, NumCast, RTFCast, StrCast } from '../../fields/Types';
+import { InkData, InkField } from '../../fields/InkField';
+import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
import { TraceMobx } from '../../fields/util';
import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils';
import { CognitiveServices } from '../cognitive_services/CognitiveServices';
@@ -35,20 +35,17 @@ import { Transform } from '../util/Transform';
import { UndoManager } from '../util/UndoManager';
import { ContextMenu } from './ContextMenu';
import { ViewBoxBaseComponent } from './DocComponent';
+import { INK_MASK_SIZE } from './global/globalCssVariables.scss';
import { Colors } from './global/globalEnums';
import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles';
+import './InkStroke.scss';
import { InkStrokeProperties } from './InkStrokeProperties';
import { InkTangentHandles } from './InkTangentHandles';
import { DocComponentView } from './nodes/DocumentView';
import { FieldView, FieldViewProps } from './nodes/FieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { INK_MASK_SIZE } from './global/globalCssVariables.scss';
-import './InkStroke.scss';
-import Color = require('color');
-import { ComputedField } from '../../fields/ScriptField';
-import { listSpec } from '../../fields/Schema';
-import { List } from '../../fields/List';
import { StyleProp } from './StyleProvider';
+import Color = require('color');
@observer
export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -460,7 +457,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
width: this.layoutDoc[WidthSym](),
transform: `scale(${this.props.NativeDimScaling?.() || 1})`,
transformOrigin: 'top left',
- top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2,
+ //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2,
}}>
<FormattedTextBox
{...OmitKeys(this.props, ['children']).omit}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c6ac5ee0c..40a5876e0 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -281,38 +281,36 @@ export class CollectionDockingView extends CollectionSubView() {
this.stateChanged();
return true;
}
-
setupGoldenLayout = async () => {
- const config = StrCast(this.props.Document.dockingConfig);
- if (config) {
- const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
- const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
- await Promise.all(docids.map(id => DocServer.GetRefField(id)));
-
- if (this._goldenLayout) {
- if (config === JSON.stringify(this._goldenLayout.toConfig())) {
- return;
- } else {
- try {
- this._goldenLayout.unbind('tabCreated', this.tabCreated);
- this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
- this._goldenLayout.unbind('stackCreated', this.stackCreated);
- } catch (e) {}
- }
- this.tabMap.clear();
- this._goldenLayout.destroy();
+ const config = StrCast(this.props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.props.Document)));
+ const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
+ const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
+
+ await Promise.all(docids.map(id => DocServer.GetRefField(id)));
+
+ if (this._goldenLayout) {
+ if (config === JSON.stringify(this._goldenLayout.toConfig())) {
+ return;
+ } else {
+ try {
+ this._goldenLayout.unbind('tabCreated', this.tabCreated);
+ this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
+ this._goldenLayout.unbind('stackCreated', this.stackCreated);
+ } catch (e) {}
}
- const glay = (this._goldenLayout = new GoldenLayout(JSON.parse(config)));
- glay.on('tabCreated', this.tabCreated);
- glay.on('tabDestroyed', this.tabDestroyed);
- glay.on('stackCreated', this.stackCreated);
- glay.registerComponent('DocumentFrameRenderer', TabDocView);
- glay.container = this._containerRef.current;
- glay.init();
- glay.root.layoutManager.on('itemDropped', this.tabItemDropped);
- glay.root.layoutManager.on('dragStart', this.tabDragStart);
- glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
+ this.tabMap.clear();
+ this._goldenLayout.destroy();
}
+ const glay = (this._goldenLayout = new GoldenLayout(JSON.parse(config)));
+ glay.on('tabCreated', this.tabCreated);
+ glay.on('tabDestroyed', this.tabDestroyed);
+ glay.on('stackCreated', this.stackCreated);
+ glay.registerComponent('DocumentFrameRenderer', TabDocView);
+ glay.container = this._containerRef.current;
+ glay.init();
+ glay.root.layoutManager.on('itemDropped', this.tabItemDropped);
+ glay.root.layoutManager.on('dragStart', this.tabDragStart);
+ glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
};
componentDidMount: () => void = () => {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ee3f46818..d88d59205 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -155,7 +155,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
!Doc.noviceMode && subItems.push({ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' });
subItems.push({ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' });
- if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) {
+ if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) {
const existingVm = ContextMenu.Instance.findByDescription(category);
const catItems = existingVm && 'subitems' in existingVm ? existingVm.subitems : [];
catItems.push({ description: 'Add a Perspective...', addDivider: true, noexpand: true, subitems: subItems, icon: 'eye' });
@@ -189,7 +189,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
}
!Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' });
- if (!Doc.noviceMode) {
+ if (!Doc.noviceMode && false) {
optionItems.push({
description: 'Create Branch',
event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), 'add:right'),
@@ -206,9 +206,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
icon: 'project-diagram',
});
}
- if (this.Document._viewType === CollectionViewType.Docking) {
- optionItems.push({ description: 'Create Dashboard', event: () => DashboardView.createNewDashboard(), icon: 'project-diagram' });
- }
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index c4da70371..a6cfbd6b2 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -96,6 +96,18 @@ export class TabDocView extends React.Component<TabDocViewProps> {
const iconWrap = document.createElement('div');
const closeWrap = document.createElement('div');
+ const getChild = () => {
+ let child = this.view?.ContentDiv?.children[0];
+ while (child?.children.length) {
+ const next = Array.from(child.children).find(c => c.className?.toString().includes('SVGAnimatedString') || typeof c.className === 'string');
+ if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break;
+ if (next?.className?.toString().includes(DashFieldView.name)) break;
+ if (next) child = next;
+ else break;
+ }
+ return child;
+ };
+
titleEle.size = StrCast(doc.title).length + 3;
titleEle.value = doc.title;
titleEle.onkeydown = (e: KeyboardEvent) => {
@@ -119,14 +131,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
action(e => {
if (this.view) {
SelectionManager.SelectView(this.view, false);
- let child = this.view.ContentDiv!.children[0];
- while (child.children.length) {
- const next = Array.from(child.children).find(c => c.className?.toString().includes('SVGAnimatedString') || typeof c.className === 'string');
- if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break;
- if (next?.className?.toString().includes(DashFieldView.name)) break;
- if (next) child = next;
- else break;
- }
+ const child = getChild();
simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
} else {
this._activated = true;
@@ -165,6 +170,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
};
+ tab.element[0].oncontextmenu = (e: MouseEvent) => {
+ let child = getChild();
+ if (child) {
+ simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ };
+
// select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected
titleEle.onpointerdown = action((e: any) => {
if (e.target.className !== 'lm_iconWrap') {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 640984ad6..25f57b045 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1037,7 +1037,7 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderBorder() {
const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
- const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } };
+ const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } };
return (
<div className={`treeView-border${this.props.treeView.outlineMode ? TreeViewType.outline : ''}`} style={{ borderColor: sortings[sorting]?.color }}>
{!this.treeViewOpen ? null : this.renderContent}
@@ -1057,7 +1057,7 @@ export class TreeView extends React.Component<TreeViewProps> {
render() {
TraceMobx();
const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode;
- return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? (
+ return this.props.renderedIds?.indexOf(this.doc[Id]) !== -1 ? (
'<' + this.doc.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
) : (
<div
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8824c2b01..c19a5a05a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -156,7 +156,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
@computed get cachedCenteringShiftY(): number {
const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
- return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+ // if freeform has a native aspect, then the panel height needs to be adjusted to match it
+ const aspect = this.props.DocumentView?.().nativeHeight ? this.props.DocumentView?.().nativeHeight / this.props.DocumentView?.().nativeWidth : 1;
+ return this.props.isAnnotationOverlay ? 0 : (aspect * this.props.PanelHeight()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedGetLocalTransform(): Transform {
return Transform.Identity()
@@ -190,6 +192,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
elementFunc = () => this._layoutElements;
shrinkWrap = () => {
+ if (this.props.DocumentView?.().nativeWidth) return;
const vals = this.fitToContentVals;
this.layoutDoc._panX = vals.bounds.cx;
this.layoutDoc._panY = vals.bounds.cy;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index a3c742f28..0ceaff968 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -33,7 +33,10 @@ export namespace Field {
return !Field.IsField(field) ? '' : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field));
}
export function toScriptString(field: Field): string {
- if (typeof field === 'string') return `"${field}"`;
+ if (typeof field === 'string') {
+ if (field.startsWith('{"')) return `'${field}'`; // bcz: hack ... want to quote the string the right way. if there are nested "'s, then use ' instead of ". In this case, test for the start of a JSON string of the format {"property": ... } and use outer 's instead of "s
+ return `"${field}"`;
+ }
if (typeof field === 'number' || typeof field === 'boolean') return String(field);
if (field === undefined || field === null) return 'null';
return field[ToScriptString]();
@@ -1399,11 +1402,17 @@ export namespace Doc {
layoutDoc._viewScale = NumCast(layoutDoc._viewScale, 1) * contentScale;
layoutDoc._nativeWidth = undefined;
layoutDoc._nativeHeight = undefined;
+ layoutDoc._forceReflow = undefined;
+ layoutDoc._nativeHeightUnfrozen = undefined;
+ layoutDoc._nativeDimModifiable = undefined;
} else {
layoutDoc._autoHeight = false;
if (!Doc.NativeWidth(layoutDoc)) {
layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth);
layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight);
+ layoutDoc._forceReflow = true;
+ layoutDoc._nativeHeightUnfrozen = true;
+ layoutDoc._nativeDimModifiable = true;
}
}
});
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index 3cb50a4c0..4896c027d 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -104,7 +104,7 @@ export class ScriptField extends ObjectField {
}
this.rawscript = rawscript;
this.setterscript = setterscript;
- this.script = script ?? (CompileScript('false') as CompiledScript);
+ this.script = script ?? (CompileScript('false', { addReturn: true }) as CompiledScript);
}
// init(callback: (res: Field) => any) {