aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-12-10 20:19:27 -0500
committerbobzel <zzzman@gmail.com>2023-12-10 20:19:27 -0500
commit380ee1acac1c0b7972d7d423cf804af146dc0edf (patch)
tree1d77244a600e6eb1fb6d56356b3ce01ca6add89d /src/client/views/collections
parentb7b7105fac83ec11480204c5c7ac0ae6579774e1 (diff)
massive changes to use mobx 6 which means not accessing props directly in @computed functions.
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx45
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx101
-rw-r--r--src/client/views/collections/CollectionMenu.tsx45
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx1
-rw-r--r--src/client/views/collections/CollectionPileView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx217
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx187
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx139
-rw-r--r--src/client/views/collections/CollectionSubView.tsx92
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx192
-rw-r--r--src/client/views/collections/CollectionView.tsx53
-rw-r--r--src/client/views/collections/TabDocView.tsx91
-rw-r--r--src/client/views/collections/TreeView.tsx505
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx16
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx38
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx376
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx142
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx44
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx1
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx10
-rw-r--r--src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx4
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx141
26 files changed, 1320 insertions, 1131 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 858090c05..4ddf9e69b 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,4 +1,4 @@
-import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx';
import { observer } from 'mobx-react';
import * as ReactDOM from 'react-dom/client';
import * as GoldenLayout from '../../../client/goldenLayout';
@@ -10,7 +10,7 @@ import { List } from '../../../fields/List';
import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { GetEffectiveAcl, inheritParentAcls } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, incrementTitleCopy } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, copyProps, emptyFunction, incrementTitleCopy } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { Docs } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
@@ -36,7 +36,7 @@ const _global = (window /* browser */ || global) /* node */ as any;
@observer
export class CollectionDockingView extends CollectionSubView() {
- @observable public static Instance: CollectionDockingView | undefined;
+ @observable public static Instance: CollectionDockingView | undefined = undefined;
public static makeDocumentConfig(document: Doc, panelName?: string, width?: number, keyValue?: boolean) {
return {
type: 'react-component',
@@ -62,9 +62,14 @@ export class CollectionDockingView extends CollectionSubView() {
}
private _goldenLayout: any = null;
static _highlightStyleSheet: any = addStyleSheet();
+
+ _prevProps: SubCollectionViewProps;
+ @override _props: SubCollectionViewProps;
constructor(props: SubCollectionViewProps) {
super(props);
- if (this.props.renderDepth < 0) runInAction(() => (CollectionDockingView.Instance = this));
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ if (this._props.renderDepth < 0) runInAction(() => (CollectionDockingView.Instance = this));
//Why is this here?
(window as any).React = React;
(window as any).ReactDOM = ReactDOM;
@@ -72,6 +77,10 @@ export class CollectionDockingView extends CollectionSubView() {
this.Document.myTrails; // this is equivalent to having a prefetchProxy for myTrails which is needed for the My Trails button in the UI which assumes that Doc.ActiveDashboard.myTrails is legit...
}
+ componentDidUpdate() {
+ copyProps(this);
+ }
+
/**
* Switches from dragging a document around a freeform canvas to dragging it as a tab to be docked.
*
@@ -274,8 +283,8 @@ export class CollectionDockingView extends CollectionSubView() {
return true;
}
setupGoldenLayout = async () => {
- //const config = StrCast(this.props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.props.Document)));
- const config = StrCast(this.props.Document.dockingConfig);
+ //const config = StrCast(this._props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this._props.Document)));
+ 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('"', '')) ?? [];
@@ -318,7 +327,7 @@ export class CollectionDockingView extends CollectionSubView() {
);
new _global.ResizeObserver(this.onResize).observe(this._containerRef.current);
this._reactionDisposer = reaction(
- () => StrCast(this.props.Document.dockingConfig),
+ () => StrCast(this._props.Document.dockingConfig),
config => {
if (!this._goldenLayout || this._ignoreStateChange !== config) {
// bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one.
@@ -328,7 +337,7 @@ export class CollectionDockingView extends CollectionSubView() {
}
);
reaction(
- () => this.props.PanelWidth(),
+ () => this._props.PanelWidth(),
width => !this._goldenLayout && width > 20 && setTimeout(() => this.setupGoldenLayout()), // need to wait for the collectiondockingview-container to have it's width/height since golden layout reads that to configure its windows
{ fireImmediately: true }
);
@@ -375,7 +384,7 @@ export class CollectionDockingView extends CollectionSubView() {
.map(id => DocServer.GetCachedRefField(id))
.filter(f => f)
.map(f => f as Doc);
- const changesMade = this.props.Document.dockingConfig !== json;
+ const changesMade = this._props.Document.dockingConfig !== json;
if (changesMade) {
if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) {
this.layoutDoc.dockingConfig = json;
@@ -425,7 +434,7 @@ export class CollectionDockingView extends CollectionSubView() {
};
public CaptureThumbnail() {
- const content = this.props.DocumentView?.()?.ContentDiv;
+ const content = this._props.DocumentView?.()?.ContentDiv;
if (content) {
const _width = Number(getComputedStyle(content).width.replace('px', ''));
const _height = Number(getComputedStyle(content).height.replace('px', ''));
@@ -472,7 +481,7 @@ export class CollectionDockingView extends CollectionSubView() {
stateChanged = () => {
this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
const json = JSON.stringify(this._goldenLayout.toConfig());
- const changesMade = this.props.Document.dockingConfig !== json;
+ const changesMade = this._props.Document.dockingConfig !== json;
return changesMade;
};
@@ -506,8 +515,8 @@ export class CollectionDockingView extends CollectionSubView() {
if (dashboard && e.target === stack.header?.element[0] && e.button === 2) {
dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
const docToAdd = Docs.Create.FreeformDocument([], {
- _width: this.props.PanelWidth(),
- _height: this.props.PanelHeight(),
+ _width: this._props.PanelWidth(),
+ _height: this._props.PanelHeight(),
_freeform_backgroundGrid: true,
_layout_fitWidth: true,
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
@@ -524,8 +533,8 @@ export class CollectionDockingView extends CollectionSubView() {
if (dashboard) {
dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
const docToAdd = Docs.Create.FreeformDocument([], {
- _width: this.props.PanelWidth(),
- _height: this.props.PanelHeight(),
+ _width: this._props.PanelWidth(),
+ _height: this._props.PanelHeight(),
_layout_fitWidth: true,
_freeform_backgroundGrid: true,
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
@@ -573,14 +582,14 @@ export class CollectionDockingView extends CollectionSubView() {
render() {
const href = ImageCast(this.Document.thumb)?.url?.href;
- return this.props.renderDepth > -1 ? (
+ return this._props.renderDepth > -1 ? (
<div>
{href ? (
<img
style={{ background: 'white', top: 0, position: 'absolute' }}
src={href} // + '?d=' + (new Date()).getTime()}
- width={this.props.PanelWidth()}
- height={this.props.PanelHeight()}
+ width={this._props.PanelWidth()}
+ height={this._props.PanelHeight()}
/>
) : (
<p>nested dashboards has no thumbnail</p>
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 61a5738ec..1c6f97c14 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -1,10 +1,9 @@
import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
-import { Id } from '../../../fields/FieldSymbols';
import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { ScriptField } from '../../../fields/ScriptField';
import { emptyFunction, numberRange, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../../Utils';
@@ -49,14 +48,20 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@observable private color: string = '#f1efeb';
@observable private collapsed: boolean = false;
@observable private _paletteOn = false;
+ @observable _props: React.PropsWithChildren<CMVFieldRowProps>;
+ constructor(props: React.PropsWithChildren<CMVFieldRowProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
private set _heading(value: string) {
- runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value));
+ runInAction(() => this._props.headingObject && (this._props.headingObject.heading = this.heading = value));
}
private set _color(value: string) {
- runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value));
+ runInAction(() => this._props.headingObject && (this._props.headingObject.color = this.color = value));
}
private set _collapsed(value: boolean) {
- runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value));
+ runInAction(() => this._props.headingObject && (this._props.headingObject.collapsed = this.collapsed = value));
}
private _dropDisposer?: DragManager.DragDropDisposer;
@@ -68,28 +73,28 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
this._dropDisposer?.();
if (ele) {
this._ele = ele;
- this.props.observeHeight(ele);
+ this._props.observeHeight(ele);
this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
}
};
@action
componentDidMount() {
- this.heading = this.props.headingObject?.heading || '';
- this.color = this.props.headingObject?.color || '#f1efeb';
- this.collapsed = this.props.headingObject?.collapsed || false;
+ this.heading = this._props.headingObject?.heading || '';
+ this.color = this._props.headingObject?.color || '#f1efeb';
+ this.collapsed = this._props.headingObject?.collapsed || false;
}
componentWillUnmount() {
- this.props.unobserveHeight(this._ele);
+ this._props.unobserveHeight(this._ele);
}
getTrueHeight = () => {
if (this.collapsed) {
- this.props.setDocHeight(this.heading, 20);
+ this._props.setDocHeight(this.heading, 20);
} else {
const rawHeight = this._contRef.current!.getBoundingClientRect().height + 15; //+ 15 accounts for the group header
- const transformScale = this.props.screenToLocalTransform().Scale;
+ const transformScale = this._props.screenToLocalTransform().Scale;
const trueHeight = rawHeight * transformScale;
- this.props.setDocHeight(this.heading, trueHeight);
+ this._props.setDocHeight(this.heading, trueHeight);
}
};
@@ -97,10 +102,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
rowDrop = action((e: Event, de: DragManager.DropEvent) => {
this._createEmbeddingSelected = false;
if (de.complete.docDragData) {
- const key = this.props.pivotField;
+ const key = this._props.pivotField;
const castedValue = this.getValue(this.heading);
const onLayoutDoc = this.onLayoutDoc(key);
- if (this.props.parent.onInternalDrop(e, de)) {
+ if (this._props.parent.onInternalDrop(e, de)) {
de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc));
}
return true;
@@ -119,15 +124,15 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@action
headingChanged = (value: string, shiftDown?: boolean) => {
this._createEmbeddingSelected = false;
- const key = this.props.pivotField;
+ const key = this._props.pivotField;
const castedValue = this.getValue(value);
if (castedValue) {
- if (this.props.parent.colHeaderData) {
- if (this.props.parent.colHeaderData.map(i => i.heading).indexOf(castedValue.toString()) > -1) {
+ if (this._props.parent.colHeaderData) {
+ if (this._props.parent.colHeaderData.map(i => i.heading).indexOf(castedValue.toString()) > -1) {
return false;
}
}
- this.props.docList.forEach(d => Doc.SetInPlace(d, key, castedValue, true));
+ this._props.docList.forEach(d => Doc.SetInPlace(d, key, castedValue, true));
this._heading = castedValue.toString();
return true;
}
@@ -152,24 +157,24 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
if (!value && !forceEmptyNote) return false;
this._createEmbeddingSelected = false;
- const key = this.props.pivotField;
+ const key = this._props.pivotField;
const newDoc = Docs.Create.TextDocument('', { _layout_autoHeight: true, _width: 200, _layout_fitWidth: true, title: value });
const onLayoutDoc = this.onLayoutDoc(key);
FormattedTextBox.SetSelectOnLoad(newDoc);
FormattedTextBox.SelectOnLoadChar = value;
- (onLayoutDoc ? newDoc : newDoc[DocData])[key] = this.getValue(this.props.heading);
- const docs = this.props.parent.childDocList;
- return docs ? (docs.splice(0, 0, newDoc) ? true : false) : this.props.parent.props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list)
+ (onLayoutDoc ? newDoc : newDoc[DocData])[key] = this.getValue(this._props.heading);
+ const docs = this._props.parent.childDocList;
+ return docs ? (docs.splice(0, 0, newDoc) ? true : false) : this._props.parent._props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list)
};
deleteRow = undoBatch(
action(() => {
this._createEmbeddingSelected = false;
- const key = this.props.pivotField;
- this.props.docList.forEach(d => Doc.SetInPlace(d, key, undefined, true));
- if (this.props.parent.colHeaderData && this.props.headingObject) {
- const index = this.props.parent.colHeaderData.indexOf(this.props.headingObject);
- this.props.parent.colHeaderData.splice(index, 1);
+ const key = this._props.pivotField;
+ this._props.docList.forEach(d => Doc.SetInPlace(d, key, undefined, true));
+ if (this._props.parent.colHeaderData && this._props.headingObject) {
+ const index = this._props.parent.colHeaderData.indexOf(this._props.headingObject);
+ this._props.parent.colHeaderData.splice(index, 1);
}
})
);
@@ -182,8 +187,8 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
};
headerMove = (e: PointerEvent) => {
- const embedding = Doc.MakeEmbedding(this.props.Document);
- const key = this.props.pivotField;
+ const embedding = Doc.MakeEmbedding(this._props.Document);
+ const key = this._props.pivotField;
let value = this.getValue(this.heading);
value = typeof value === 'string' ? `"${value}"` : value;
const script = `return doc.${key} === ${value}`;
@@ -198,7 +203,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@action
headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
if (e.button === 0 && !e.ctrlKey) {
- setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !this.props.chromeHidden && this.collapseSection(e));
+ setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !this._props.chromeHidden && this.collapseSection(e));
this._createEmbeddingSelected = false;
}
};
@@ -207,7 +212,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
* Returns true if a key is on the layout doc of the documents in the collection.
*/
onLayoutDoc = (key: string): boolean => {
- DocListCast(this.props.parent.Document.data).forEach(doc => {
+ DocListCast(this._props.parent.Document.data).forEach(doc => {
if (Doc.Get(doc, key, true)) return true;
});
return false;
@@ -264,19 +269,19 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
};
@computed get contentLayout() {
- const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
- const showChrome = !this.props.chromeHidden;
- const stackPad = showChrome ? `0px ${this.props.parent.xMargin}px` : `${this.props.parent.yMargin}px ${this.props.parent.xMargin}px 0px ${this.props.parent.xMargin}px `;
+ const rows = Math.max(1, Math.min(this._props.docList.length, Math.floor((this._props.parent._props.PanelWidth() - 2 * this._props.parent.xMargin) / (this._props.parent.columnWidth + this._props.parent.gridGap))));
+ const showChrome = !this._props.chromeHidden;
+ const stackPad = showChrome ? `0px ${this._props.parent.xMargin}px` : `${this._props.parent.yMargin}px ${this._props.parent.xMargin}px 0px ${this._props.parent.xMargin}px `;
return this.collapsed ? null : (
<div style={{ position: 'relative' }}>
- {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : null}
+ {this._props.showHandle && this._props.parent._props.isContentActive() ? this._props.parent.columnDragger : null}
{showChrome ? (
<div
className="collectionStackingView-addDocumentButton"
style={
{
//width: style.columnWidth / style.numGroupColumns,
- //padding: `${NumCast(this.props.parent.layoutDoc._yPadding, this.props.parent.yMargin)}px 0px 0px 0px`,
+ //padding: `${NumCast(this._props.parent.layoutDoc._yPadding, this._props.parent.yMargin)}px 0px 0px 0px`,
}
}>
<EditableView GetValue={returnEmptyString} SetValue={this.addDocument} textCallback={this.textCallback} contents={'+ NEW'} />
@@ -287,25 +292,25 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
ref={this._contRef}
style={{
padding: stackPad,
- minHeight: this.props.showHandle && this.props.parent.props.isContentActive() ? '10px' : undefined,
- width: this.props.parent.NodeWidth,
- gridGap: this.props.parent.gridGap,
- gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this.props.parent.columnWidth}px`, ''),
+ minHeight: this._props.showHandle && this._props.parent._props.isContentActive() ? '10px' : undefined,
+ width: this._props.parent.NodeWidth,
+ gridGap: this._props.parent.gridGap,
+ gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this._props.parent.columnWidth}px`, ''),
}}>
- {this.props.parent.children(this.props.docList)}
+ {this._props.parent.children(this._props.docList)}
</div>
</div>
);
}
@computed get headingView() {
- const noChrome = this.props.chromeHidden;
- const key = this.props.pivotField;
- const evContents = this.heading ? this.heading : this.props.type && this.props.type === 'number' ? '0' : `NO ${key.toUpperCase()} VALUE`;
+ const noChrome = this._props.chromeHidden;
+ const key = this._props.pivotField;
+ const evContents = this.heading ? this.heading : this._props.type && this._props.type === 'number' ? '0' : `NO ${key.toUpperCase()} VALUE`;
const editableHeaderView = <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} />;
- return this.props.Document.miniHeaders ? (
+ return this._props.Document.miniHeaders ? (
<div className="collectionStackingView-miniHeader">{editableHeaderView}</div>
- ) : !this.props.headingObject ? null : (
+ ) : !this._props.headingObject ? null : (
<div className="collectionStackingView-sectionHeader" ref={this._headerRef}>
<div
className="collectionStackingView-sectionHeader-subCont"
@@ -352,7 +357,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
render() {
const background = this._background;
return (
- <div className="collectionStackingView-masonrySection" style={{ width: this.props.parent.NodeWidth, background }} ref={this.createRowDropRef} onPointerEnter={this.pointerEnteredRow} onPointerLeave={this.pointerLeaveRow}>
+ <div className="collectionStackingView-masonrySection" style={{ width: this._props.parent.NodeWidth, background }} ref={this.createRowDropRef} onPointerEnter={this.pointerEnteredRow} onPointerLeave={this.pointerLeaveRow}>
{this.headingView}
{this.contentLayout}
</div>
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 3edf4135f..f8e80ed87 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -33,7 +33,7 @@ interface CollectionMenuProps {
export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
@observable static Instance: CollectionMenu;
- @observable SelectedCollection: DocumentView | undefined;
+ @observable SelectedCollection: DocumentView | undefined = undefined;
@observable FieldKey: string;
private _docBtnRef = React.createRef<HTMLDivElement>();
@@ -41,7 +41,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
constructor(props: any) {
super(props);
this.FieldKey = '';
- runInAction(() => (CollectionMenu.Instance = this));
+ CollectionMenu.Instance = this;
this._canFade = false; // don't let the inking menu fade away
runInAction(() => (this.Pinned = Cast(Doc.UserDoc()['menuCollections-pinned'], 'boolean', true)));
this.jumpTo(300, 300);
@@ -69,19 +69,19 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
@action
toggleTopBar = () => {
- if (SettingsManager.headerBarHeight > 0) {
- SettingsManager.headerBarHeight = 0;
+ if (SettingsManager.Instance.headerBarHeight > 0) {
+ SettingsManager.Instance.headerBarHeight = 0;
} else {
- SettingsManager.headerBarHeight = 60;
+ SettingsManager.Instance.headerBarHeight = 60;
}
};
@action
toggleProperties = () => {
if (MainView.Instance.propertiesWidth() > 0) {
- SettingsManager.propertiesWidth = 0;
+ SettingsManager.Instance.propertiesWidth = 0;
} else {
- SettingsManager.propertiesWidth = 300;
+ SettingsManager.Instance.propertiesWidth = 300;
}
};
@@ -94,7 +94,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
@computed get contMenuButtons() {
const selDoc = Doc.MyContextMenuBtns;
return !(selDoc instanceof Doc) ? null : (
- <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this.props.panelHeight() }}>
+ <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this._props.panelHeight() }}>
<CollectionLinearView
Document={selDoc}
fieldKey="data"
@@ -113,8 +113,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
pinToPres={emptyFunction}
removeDocument={returnFalse}
ScreenToLocalTransform={this.buttonBarXf}
- PanelWidth={this.props.panelWidth}
- PanelHeight={this.props.panelHeight}
+ PanelWidth={this._props.panelWidth}
+ PanelHeight={this._props.panelHeight}
renderDepth={0}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
@@ -127,10 +127,10 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
}
render() {
- const headerIcon = SettingsManager.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
- const headerTitle = SettingsManager.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
- const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
- const propTitle = SettingsManager.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties';
+ const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
+ const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
+ const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
+ const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties';
const hardCodedButtons = (
<div className={`hardCodedButtons`}>
@@ -139,7 +139,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
type={Type.PRIM}
color={SettingsManager.userColor}
onClick={this.toggleTopBar}
- toggleStatus={SettingsManager.headerBarHeight > 0}
+ toggleStatus={SettingsManager.Instance.headerBarHeight > 0}
icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
tooltip={headerTitle}
/>
@@ -148,7 +148,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
type={Type.PRIM}
color={SettingsManager.userColor}
onClick={this.toggleProperties}
- toggleStatus={SettingsManager.propertiesWidth > 0}
+ toggleStatus={SettingsManager.Instance.propertiesWidth > 0}
icon={<FontAwesomeIcon icon={propIcon} size="lg" />}
tooltip={propTitle}
/>
@@ -185,7 +185,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
//(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\)
get document() {
- return this.props.docView?.props.Document;
+ return this.props.docView?.Document;
}
get target() {
return this.document;
@@ -577,13 +577,18 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
return this.props.docView.props.Document;
}
+ @computed get panelWidth() {
+ return this.props.docView.props.PanelWidth();
+ }
+
componentDidMount() {
runInAction(() => (this.resize = this.props.docView.props.PanelWidth() < 700));
// listener to reduce text on chrome resize (panel resize)
- this.resizeListenerDisposer = computed(() => this.props.docView.props.PanelWidth()).observe(({ newValue }) => {
- runInAction(() => (this.resize = newValue < 700));
- });
+ this.resizeListenerDisposer = reaction(
+ () => this.panelWidth,
+ newValue => (this.resize = newValue < 700)
+ );
}
componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index ba00c4fa0..f9d99f1e5 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -416,7 +416,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
// onInternalDrop is used when dragging and dropping a document within the view, such as dragging
// a document to a new column or changing its order within the column.
@undoBatch
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.docDragData) {
if (super.onInternalDrop(e, de)) {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index c5677e2ba..a0f8b9c89 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -43,7 +43,7 @@ export class CollectionPileView extends CollectionSubView() {
removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
(doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d));
const ret = this.props.moveDocument?.(doc, targetCollection, addDoc) || false;
- if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.().props.removeDocument?.(this.Document);
+ if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.()._props.removeDocument?.(this.Document);
return ret;
};
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 92b5470ae..28d15be71 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -1,7 +1,7 @@
-import * as React from 'react';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
+import * as React from 'react';
import { Doc, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { Cast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
-import { emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
+import { copyProps, emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
@@ -20,9 +20,9 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
-import { AudioWaveform } from '../AudioWaveform';
-import { CollectionSubView } from '../collections/CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from '../collections/CollectionSubView';
import { LightboxView } from '../LightboxView';
+import { AudioWaveform } from '../nodes/audio/AudioWaveform';
import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView';
import { LabelBox } from '../nodes/LabelBox';
import { VideoBox } from '../nodes/VideoBox';
@@ -53,17 +53,28 @@ export enum TrimScope {
}
@observer
-export class CollectionStackedTimeline extends CollectionSubView<CollectionStackedTimelineProps>() {
+export class CollectionStackedTimeline extends CollectionSubView<SubCollectionViewProps & CollectionStackedTimelineProps>() {
@observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined;
@observable public static CurrentlyPlaying: DocumentView[];
+ _prevProps: React.PropsWithChildren<SubCollectionViewProps & CollectionStackedTimelineProps>;
+ @override _props: React.PropsWithChildren<SubCollectionViewProps & CollectionStackedTimelineProps>;
+ constructor(props: React.PropsWithChildren<SubCollectionViewProps & CollectionStackedTimelineProps>) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ }
+ componentDidUpdate() {
+ copyProps(this);
+ }
+
static LabelScript: ScriptField;
static LabelPlayScript: ScriptField;
private _timeline: HTMLDivElement | null = null; // ref to actual timeline div
private _timelineWrapper: HTMLDivElement | null = null; // ref to timeline wrapper div for zooming and scrolling
private _markerStart: number = 0;
- @observable _markerEnd: number | undefined;
+ @observable _markerEnd: number | undefined = undefined;
@observable _trimming: number = TrimScope.None;
@observable _trimStart: number = 0; // trim controls start pos
@observable _trimEnd: number = 0; // trim controls end pos
@@ -73,14 +84,14 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
@observable _hoverTime: number = 0;
- @observable _thumbnail: string | undefined;
+ @observable _thumbnail: string | undefined = undefined;
// ensures that clip doesn't get trimmed so small that controls cannot be adjusted anymore
get minTrimLength() {
return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5);
}
@computed get thumbnails() {
- return this.props.thumbnails?.();
+ return this._props.thumbnails?.();
}
@computed get trimStart() {
@@ -100,7 +111,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
return this.clipEnd - this.clipStart;
}
@computed get clipEnd() {
- return this.IsTrimming === TrimScope.All ? this.props.rawDuration : NumCast(this.layoutDoc.clipEnd, this.props.rawDuration);
+ return this.IsTrimming === TrimScope.All ? this._props.rawDuration : NumCast(this.layoutDoc.clipEnd, this._props.rawDuration);
}
@computed get currentTime() {
@@ -115,11 +126,10 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
document.addEventListener('keydown', this.keyEvents, true);
}
- @action
componentWillUnmount() {
document.removeEventListener('keydown', this.keyEvents, true);
if (CollectionStackedTimeline.SelectingRegion === this) {
- CollectionStackedTimeline.SelectingRegion = undefined;
+ runInAction(() => (CollectionStackedTimeline.SelectingRegion = undefined));
}
}
@@ -149,8 +159,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._zoomFactor = zoom;
}
- anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]));
- anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this.props.endTag], val) ?? null);
+ anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this._props.startTag]));
+ anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null);
// converts screen pixel offset to time
toTimeline = (screen_delta: number, width: number) => {
@@ -177,13 +187,13 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
if (
// need to include range inputs because after dragging video time slider it becomes target element
!(e.target instanceof HTMLInputElement && !(e.target.type === 'range')) &&
- this.props.isContentActive()
+ this._props.isContentActive()
) {
// if shift pressed scrub 1 second otherwise 1/10th
const jump = e.shiftKey ? 1 : 0.1;
switch (e.key) {
case ' ':
- this.props.playing() ? this.props.Pause() : this.props.Play();
+ this._props.playing() ? this._props.Pause() : this._props.Play();
break;
case '^':
if (!CollectionStackedTimeline.SelectingRegion) {
@@ -191,7 +201,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
CollectionStackedTimeline.SelectingRegion = this;
} else {
this._markerEnd = this.currentTime;
- CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true);
+ CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this._props.fieldKey, this._markerStart, this._markerEnd, undefined, true);
this._markerEnd = undefined;
CollectionStackedTimeline.SelectingRegion = undefined;
}
@@ -204,11 +214,11 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._trimming = TrimScope.None;
break;
case 'ArrowLeft':
- this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime - jump), this.clipEnd));
+ this._props.setTime(Math.min(Math.max(this.clipStart, this.currentTime - jump), this.clipEnd));
e.stopPropagation();
break;
case 'ArrowRight':
- this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime + jump), this.clipEnd));
+ this._props.setTime(Math.min(Math.max(this.clipStart, this.currentTime + jump), this.clipEnd));
e.stopPropagation();
break;
}
@@ -218,7 +228,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
getLinkData(l: Doc) {
let la1 = l.link_anchor_1 as Doc;
let la2 = l.link_anchor_2 as Doc;
- const linkTime = NumCast(la2[this.props.startTag], NumCast(la1[this.props.startTag]));
+ const linkTime = NumCast(la2[this._props.startTag], NumCast(la1[this._props.startTag]));
if (Doc.AreProtosEqual(la1, this.dataDoc)) {
la1 = l.link_anchor_2 as Doc;
la2 = l.link_anchor_1 as Doc;
@@ -233,9 +243,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
const clientX = e.clientX;
const diff = rect ? clientX - rect?.x : null;
const shiftKey = e.shiftKey;
- if (rect && this.props.isContentActive()) {
- const wasPlaying = this.props.playing();
- if (wasPlaying) this.props.Pause();
+ if (rect && this._props.isContentActive()) {
+ const wasPlaying = this._props.playing();
+ if (wasPlaying) this._props.Pause();
var wasSelecting = this._markerEnd !== undefined;
setupMoveUpEvents(
this,
@@ -257,7 +267,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._markerEnd = tmp;
}
if (!isClick && Math.abs(movement[0]) > 15 && !this.IsTrimming) {
- const anchor = CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true);
+ const anchor = CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this._props.fieldKey, this._markerStart, this._markerEnd, undefined, true);
setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false));
}
(!isClick || !wasSelecting) && (this._markerEnd = undefined);
@@ -265,17 +275,17 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
}),
(e, doubleTap) => {
if (e.button !== 2) {
- this.props.select(false);
- !wasPlaying && doubleTap && this.props.Play();
+ this._props.select(false);
+ !wasPlaying && doubleTap && this._props.Play();
}
},
- this.props.isSelected() || this.props.isContentActive(),
+ this._props.isSelected() || this._props.isContentActive(),
undefined,
() => {
if (shiftKey) {
- CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true);
+ CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this._props.fieldKey, this.currentTime, undefined, undefined, true);
} else {
- !wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
+ !wasPlaying && this._props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
}
);
@@ -290,7 +300,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
if (rect) {
this._hoverTime = this.toTimeline(clientX - rect.x, rect.width);
if (this.thumbnails) {
- const nearest = Math.floor((this._hoverTime / this.props.rawDuration) * VideoBox.numThumbnails);
+ const nearest = Math.floor((this._hoverTime / this._props.rawDuration) * VideoBox.numThumbnails);
const imgField = this.thumbnails.length > 0 ? new ImageField(this.thumbnails[nearest]) : undefined;
this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_m.png') : undefined;
}
@@ -305,7 +315,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this,
e,
action((e, [], []) => {
- if (rect && this.props.isContentActive()) {
+ if (rect && this._props.isContentActive()) {
this._trimStart = Math.min(Math.max(this.trimStart + (e.movementX / rect.width) * this.clipDuration, this.clipStart), this.trimEnd - this.minTrimLength);
}
return false;
@@ -325,7 +335,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this,
e,
action((e, [], []) => {
- if (rect && this.props.isContentActive()) {
+ if (rect && this._props.isContentActive()) {
this._trimEnd = Math.max(Math.min(this.trimEnd + (e.movementX / rect.width) * this.clipDuration, this.clipEnd), this.trimStart + this.minTrimLength);
}
return false;
@@ -348,8 +358,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
@action
scrollToTime = (time: number) => {
if (this._timelineWrapper) {
- if (time > this.toTimeline(this._scroll + this.props.PanelWidth(), this.timelineContentWidth)) {
- this._scroll = Math.min(this._scroll + this.props.PanelWidth(), this.timelineContentWidth - this.props.PanelWidth());
+ if (time > this.toTimeline(this._scroll + this._props.PanelWidth(), this.timelineContentWidth)) {
+ this._scroll = Math.min(this._scroll + this._props.PanelWidth(), this.timelineContentWidth - this._props.PanelWidth());
smoothScrollHorizontal(200, this._timelineWrapper, this._scroll);
} else if (time < this.toTimeline(this._scroll, this.timelineContentWidth)) {
this._scroll = (time / this.timelineContentWidth) * this.clipDuration;
@@ -363,15 +373,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number) {
if (super.onInternalDrop(e, de)) {
// determine x coordinate of drop and assign it to the documents being dragged --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
- const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+ const localPt = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y);
const x = localPt[0] - docDragData.offset[0];
const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth);
docDragData.droppedDocuments.forEach(drop => {
const anchorEnd = this.anchorEnd(drop);
if (anchorEnd !== undefined) {
- Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
+ Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this._props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
}
- Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
+ Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this._props.startTag : 'timecodeToShow', timelinePt, false);
});
return true;
@@ -386,7 +396,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
// creates marker on timeline
@undoBatch
- @action
static createAnchor(doc: Doc, dataDoc: Doc, fieldKey: string, anchorStartTime: Opt<number>, anchorEndTime: Opt<number>, docAnchor: Opt<Doc>, addAsAnnotation: boolean) {
if (anchorStartTime === undefined) return doc;
const startTag = '_timecodeToShow';
@@ -422,20 +431,20 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
const endTime = this.anchorEnd(anchorDoc);
if (this.layoutDoc.autoPlayAnchors) {
- if (this.props.playing()) this.props.Pause();
+ if (this._props.playing()) this._props.Pause();
else {
- this.props.playFrom(seekTimeInSeconds, endTime);
+ this._props.playFrom(seekTimeInSeconds, endTime);
this.scrollToTime(seekTimeInSeconds);
}
} else {
if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) && endTime > NumCast(this.layoutDoc._layout_currentTimecode)) {
- if (!this.layoutDoc.autoPlayAnchors && this.props.playing()) {
- this.props.Pause();
+ if (!this.layoutDoc.autoPlayAnchors && this._props.playing()) {
+ this._props.Pause();
} else {
- this.props.Play();
+ this._props.Play();
}
} else {
- this.props.playFrom(seekTimeInSeconds, endTime);
+ this._props.playFrom(seekTimeInSeconds, endTime);
this.scrollToTime(seekTimeInSeconds);
}
}
@@ -450,17 +459,17 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
const endTime = this.anchorEnd(anchorDoc);
if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._layout_currentTimecode) - 1e-4) {
- if (this.props.playing()) this.props.Pause();
- else if (this.layoutDoc.autoPlayAnchors) this.props.Play();
+ if (this._props.playing()) this._props.Pause();
+ else if (this.layoutDoc.autoPlayAnchors) this._props.Play();
else if (!this.layoutDoc.autoPlayAnchors) {
const rect = this._timeline?.getBoundingClientRect();
- rect && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
+ rect && this._props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
} else {
if (this.layoutDoc.autoPlayAnchors) {
- this.props.playFrom(seekTimeInSeconds, endTime);
+ this._props.playFrom(seekTimeInSeconds, endTime);
} else {
- this.props.setTime(seekTimeInSeconds);
+ this._props.setTime(seekTimeInSeconds);
}
}
return { select: true };
@@ -490,18 +499,18 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
};
dictationHeightPercent = 50;
- dictationHeight = () => (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100;
+ dictationHeight = () => (this._props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100;
@computed get timelineContentHeight() {
- return (this.props.PanelHeight() * this.dictationHeightPercent) / 100;
+ return (this._props.PanelHeight() * this.dictationHeightPercent) / 100;
}
@computed get timelineContentWidth() {
- return this.props.PanelWidth() * this.zoomFactor;
+ return this._props.PanelWidth() * this.zoomFactor;
} // subtract size of container border
- dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight);
+ dictationScreenToLocalTransform = () => this._props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight);
- isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+ isContentActive = () => this._props.isSelected() || this._props.isContentActive();
currentTimecode = () => this.currentTime;
@@ -520,7 +529,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
}
@computed get timelineEvents() {
- return this.props.isContentActive() ? 'all' : this.props.isContentActive() === false ? 'none' : undefined;
+ return this._props.isContentActive() ? 'all' : this._props.isContentActive() === false ? 'none' : undefined;
}
render() {
const overlaps: {
@@ -537,7 +546,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
<div ref={this.createDashEventsTarget} style={{ pointerEvents: this.timelineEvents }}>
<div
className="collectionStackedTimeline-timelineContainer"
- style={{ width: this.props.PanelWidth(), cursor: SnappingManager.GetIsDragging() ? 'grab' : '' }}
+ style={{ width: this._props.PanelWidth(), cursor: SnappingManager.GetIsDragging() ? 'grab' : '' }}
onWheel={e => this.isContentActive() && e.stopPropagation()}
onScroll={this.setScroll}
onMouseMove={e => this.isContentActive() && this.onHover(e)}
@@ -553,11 +562,11 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
const end = this.anchorEnd(d.anchor, start + (10 / this.timelineContentWidth) * this.clipDuration);
if (end < this.clipStart || start > this.clipEnd) return null;
const left = Math.max(((start - this.clipStart) / this.clipDuration) * this.timelineContentWidth, 0);
- const top = (d.level / maxLevel) * this.props.PanelHeight();
+ const top = (d.level / maxLevel) * this._props.PanelHeight();
const timespan = Math.max(0, Math.min(end - this.clipStart, this.clipEnd)) - Math.max(0, start - this.clipStart);
const width = (timespan / this.clipDuration) * this.timelineContentWidth;
- const height = this.props.PanelHeight() / maxLevel;
- return this.props.Document.hideAnchors ? null : (
+ const height = this._props.PanelHeight() / maxLevel;
+ return this._props.Document.hideAnchors ? null : (
<div
className={'collectionStackedTimeline-marker-timeline'}
key={d.anchor[Id]}
@@ -569,7 +578,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
pointerEvents: 'none',
}}>
<StackedTimelineAnchor
- {...this.props}
+ {...this._props}
mark={d.anchor}
rangeClickScript={this.rangeClickScript}
rangePlayScript={this.rangePlayScript}
@@ -590,18 +599,19 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
);
})}
{!this.IsTrimming && this.selectionContainer}
- {!this.props.PanelHeight() ? null : (
+ {!this._props.PanelHeight() ? null : (
<AudioWaveform
- rawDuration={this.props.rawDuration}
- fieldKey={this.props.dataFieldKey}
+ rawDuration={this._props.rawDuration}
+ fieldKey={this._props.dataFieldKey}
duration={this.clipDuration}
- mediaPath={this.props.mediaPath}
+ mediaPath={this._props.mediaPath}
layoutDoc={this.layoutDoc}
clipStart={this.clipStart}
clipEnd={this.clipEnd}
zoomFactor={this.zoomFactor}
PanelHeight={this.timelineContentHeight}
PanelWidth={this.timelineContentWidth}
+ progress={(this.currentTime - this.clipStart) / this.clipDuration}
/>
)}
@@ -691,37 +701,44 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
_lastTimecode: number;
_disposer: IReactionDisposer | undefined;
- constructor(props: any) {
+ _prevProps: React.PropsWithChildren<StackedTimelineAnchorProps>;
+ @observable _props: React.PropsWithChildren<StackedTimelineAnchorProps>;
+ constructor(props: React.PropsWithChildren<StackedTimelineAnchorProps>) {
super(props);
- this._lastTimecode = this.props.currentTimecode();
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ this._lastTimecode = this._props.currentTimecode();
+ }
+ componentDidUpdate() {
+ copyProps(this);
}
// updates marker document title to reflect correct timecodes
computeTitle = () => {
- if (this.props.mark.type !== DocumentType.LABEL) return undefined;
- const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart;
- const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart;
+ if (this._props.mark.type !== DocumentType.LABEL) return undefined;
+ const start = Math.max(NumCast(this._props.mark[this._props.startTag]), this._props.trimStart) - this._props.trimStart;
+ const end = Math.min(NumCast(this._props.mark[this._props.endTag]), this._props.trimEnd) - this._props.trimStart;
return `#${formatTime(start)}-${formatTime(end)}`;
};
componentDidMount() {
this._disposer = reaction(
- () => this.props.currentTimecode(),
+ () => this._props.currentTimecode(),
time => {
- const dictationDoc = Cast(this.props.layoutDoc.data_dictation, Doc, null);
- const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.link_anchor_1, Doc, null)?.annotationOn === dictationDoc);
+ const dictationDoc = Cast(this._props.layoutDoc.data_dictation, Doc, null);
+ const isDictation = dictationDoc && LinkManager.Links(this._props.mark).some(link => Cast(link.link_anchor_1, Doc, null)?.annotationOn === dictationDoc);
if (
!LightboxView.LightboxDoc &&
// bcz: when should links be followed? we don't want to move away from the video to follow a link but we can open it in a sidebar/etc. But we don't know that upfront.
// for now, we won't follow any links when the lightbox is oepn to avoid "losing" the video.
- /*(isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this.props.layoutDoc))*/
- !this.props.layoutDoc.dontAutoFollowLinks &&
- LinkManager.Links(this.props.mark).length &&
- time > NumCast(this.props.mark[this.props.startTag]) &&
- time < NumCast(this.props.mark[this.props.endTag]) &&
- this._lastTimecode < NumCast(this.props.mark[this.props.startTag]) - 1e-5
+ /*(isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this._props.layoutDoc))*/
+ !this._props.layoutDoc.dontAutoFollowLinks &&
+ LinkManager.Links(this._props.mark).length &&
+ time > NumCast(this._props.mark[this._props.startTag]) &&
+ time < NumCast(this._props.mark[this._props.endTag]) &&
+ this._lastTimecode < NumCast(this._props.mark[this._props.startTag]) - 1e-5
) {
- LinkFollower.FollowLink(undefined, this.props.mark, false);
+ LinkFollower.FollowLink(undefined, this._props.mark, false);
}
this._lastTimecode = time;
}
@@ -736,16 +753,16 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
// starting the drag event for anchor resizing
@action
onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => {
- //this.props._timeline?.setPointerCapture(e.pointerId);
+ //this._props._timeline?.setPointerCapture(e.pointerId);
const newTime = (e: PointerEvent) => {
const rect = (e.target as any).getBoundingClientRect();
- return this.props.toTimeline(e.clientX - rect.x, rect.width);
+ return this._props.toTimeline(e.clientX - rect.x, rect.width);
};
const changeAnchor = (anchor: Doc, left: boolean, time: number | undefined) => {
- const timelineOnly = Cast(anchor[this.props.startTag], 'number', null) !== undefined;
+ const timelineOnly = Cast(anchor[this._props.startTag], 'number', null) !== undefined;
if (timelineOnly) {
- if (!left && time !== undefined && time <= NumCast(anchor[this.props.startTag])) time = undefined;
- Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
+ if (!left && time !== undefined && time <= NumCast(anchor[this._props.startTag])) time = undefined;
+ Doc.SetInPlace(anchor, left ? this._props.startTag : this._props.endTag, time, true);
if (!left) Doc.SetInPlace(anchor, 'layout_borderRounding', time !== undefined ? undefined : '100%', true);
} else {
anchor[left ? '_timecodeToShow' : '_timecodeToHide'] = time;
@@ -759,11 +776,11 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
e,
e => {
if (!undo) undo = UndoManager.StartBatch('drag anchor');
- this.props.setTime(newTime(e));
+ this._props.setTime(newTime(e));
return changeAnchor(anchor, left, newTime(e));
},
action(e => {
- this.props.setTime(newTime(e));
+ this._props.setTime(newTime(e));
undo?.end();
this.noEvents = false;
}),
@@ -774,7 +791,9 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
// context menu
contextMenuItems = () => {
const resetTitle = {
- script: ScriptField.MakeFunction(`this.title = this["${this.props.endTag}"] ? "#" + formatToTime(this["${this.props.startTag}"]) + "-" + formatToTime(this["${this.props.endTag}"]) : "#" + formatToTime(this["${this.props.startTag}"])`)!,
+ script: ScriptField.MakeFunction(
+ `this.title = this["${this._props.endTag}"] ? "#" + formatToTime(this["${this._props.startTag}"]) + "-" + formatToTime(this["${this._props.endTag}"]) : "#" + formatToTime(this["${this._props.startTag}"])`
+ )!,
icon: 'folder-plus',
label: 'Reset Title',
};
@@ -785,7 +804,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
const anchor = observable({ view: undefined as Opt<DocumentView> | null });
const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => {
- this.props.playLink(mark, options);
+ this._props.playLink(mark, options);
return undefined;
};
return {
@@ -793,7 +812,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
view: (
<DocumentView
key="view"
- {...this.props}
+ {...this._props}
NativeWidth={returnZero}
NativeHeight={returnZero}
ref={action((r: DocumentView | null) => (anchor.view = r))}
@@ -801,11 +820,11 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
TemplateDataDocument={undefined}
docViewPath={returnEmptyDoclist}
pointerEvents={this.noEvents ? returnNone : undefined}
- styleProvider={this.props.styleProvider}
- renderDepth={this.props.renderDepth + 1}
+ styleProvider={this._props.styleProvider}
+ renderDepth={this._props.renderDepth + 1}
LayoutTemplate={undefined}
LayoutTemplateString={LabelBox.LayoutStringWithTitle('data', this.computeTitle())}
- isDocumentActive={this.props.isDocumentActive}
+ isDocumentActive={this._props.isDocumentActive}
PanelWidth={width}
PanelHeight={height}
layout_fitWidth={returnTrue}
@@ -817,7 +836,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
onClick={script}
- onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
+ onDoubleClick={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
ignoreAutoHeight={false}
hideResizeHandles={true}
bringToFront={emptyFunction}
@@ -827,19 +846,19 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
};
});
- anchorScreenToLocalXf = () => this.props.ScreenToLocalTransform().translate(-this.props.left, -this.props.top);
- width = () => this.props.width;
- height = () => this.props.height;
+ anchorScreenToLocalXf = () => this._props.ScreenToLocalTransform().translate(-this._props.left, -this._props.top);
+ width = () => this._props.width;
+ height = () => this._props.height;
render() {
- const inner = this.renderInner(this.props.mark, this.props.rangeClickScript, this.props.rangePlayScript, this.anchorScreenToLocalXf, this.width, this.height);
+ const inner = this.renderInner(this._props.mark, this._props.rangeClickScript, this._props.rangePlayScript, this.anchorScreenToLocalXf, this.width, this.height);
return (
<div style={{ pointerEvents: this.noEvents ? 'none' : undefined }}>
{inner.view}
{!inner.anchor.view || !inner.anchor.view.SELECTED ? null : (
<>
- <div key="left" className="collectionStackedTimeline-left-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this.props.mark, true)} />
- <div key="right" className="collectionStackedTimeline-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this.props.mark, false)} />
+ <div key="left" className="collectionStackedTimeline-left-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this._props.mark, true)} />
+ <div key="right" className="collectionStackedTimeline-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this._props.mark, false)} />
</>
)}
</div>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index bc428c22f..984d6eedd 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as CSS from 'csstype';
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, Opt } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
@@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema';
import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
+import { copyProps, emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { CollectionViewType } from '../../documents/DocumentTypes';
import { DragManager, dropActionType } from '../../util/DragManager';
@@ -31,7 +31,7 @@ import { StyleProp } from '../StyleProvider';
import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
import './CollectionStackingView.scss';
import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
-import { CollectionSubView } from './CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
const _global = (window /* browser */ || global) /* node */ as any;
export type collectionStackingViewProps = {
@@ -64,7 +64,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
@observable _scroll = 0; // used to force the document decoration to update when scrolling
// does this mean whether the browser is hidden? Or is chrome something else entirely?
@computed get chromeHidden() {
- return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
+ return this._props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
}
// it looks like this gets the column headers that Mehek was showing just now
@computed get colHeaderData() {
@@ -77,18 +77,18 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
// filteredChildren is what you want to work with. It's the list of things that you're currently displaying
@computed get filteredChildren() {
const children = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout);
- if (this.props.sortFunc) children.sort(this.props.sortFunc);
+ if (this._props.sortFunc) children.sort(this._props.sortFunc);
return children;
}
// how much margin we give the header
@computed get headerMargin() {
- return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
+ return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin);
}
@computed get xMargin() {
- return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this.props.PanelWidth()));
+ return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
}
@computed get yMargin() {
- return this.props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this.props.PanelWidth()));
+ return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
}
@computed get gridGap() {
@@ -96,7 +96,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
// are we stacking or masonry?
@computed get isStackingView() {
- return (this.props.type_collection ?? this.layoutDoc._type_collection) === CollectionViewType.Stacking;
+ return (this._props.type_collection ?? this.layoutDoc._type_collection) === CollectionViewType.Stacking;
}
// this is the number of StackingViewFieldColumns that we have
@computed get numGroupColumns() {
@@ -108,15 +108,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
// columnWidth handles the margin on the left and right side of the documents
@computed get columnWidth() {
- return Math.min(this.props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
+ return Math.min(this._props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this._props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
}
@computed get NodeWidth() {
- return this.props.PanelWidth() - this.gridGap;
+ return this._props.PanelWidth() - this.gridGap;
}
+ _prevProps: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionStackingViewProps>>;
+ _props: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionStackingViewProps>>;
constructor(props: any) {
super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
if (this.colHeaderData === undefined) {
// TODO: what is a layout doc? Is it literally how this document is supposed to be layed out?
@@ -124,6 +128,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
this.dataDoc['_' + this.fieldKey + '_columnHeaders'] = new List<SchemaHeaderField>();
}
}
+ componentDidUpdate() {
+ copyProps(this);
+ }
// TODO: plj - these are the children
children = (docs: Doc[]) => {
@@ -203,7 +210,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
componentDidMount() {
super.componentDidMount?.();
- this.props.setContentView?.(this);
+ this._props.setContentView?.(this);
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
@@ -214,7 +221,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
() => this.layoutDoc._layout_autoHeight,
layout_autoHeight =>
layout_autoHeight &&
- this.props.setHeight?.(
+ this._props.setHeight?.(
Math.min(
NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0))
@@ -229,20 +236,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
this._layout_autoHeightDisposer?.();
}
- isAnyChildContentActive = () => this.props.isAnyChildContentActive();
+ isAnyChildContentActive = () => this._props.isAnyChildContentActive();
- @action
moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
- return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
+ return this._props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
};
createRef = (ele: HTMLDivElement | null) => {
this._masonryGridRef = ele;
this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
};
- onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
+ onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick);
@computed get onChildDoubleClickHandler() {
- return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
+ return () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
}
scrollToBottom = () => {
@@ -256,7 +262,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
const top = found.getBoundingClientRect().top;
- const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
+ const localTop = this._props.ScreenToLocalTransform().transformPoint(0, top);
if (Math.floor(localTop[1]) !== 0) {
let focusSpeed = options.zoomTime ?? 500;
smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
@@ -268,17 +274,16 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
if (property === StyleProp.Opacity && doc) {
- if (this.props.childOpacity) {
- return this.props.childOpacity();
+ if (this._props.childOpacity) {
+ return this._props.childOpacity();
}
if (this.Document._currentFrame !== undefined) {
return CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity;
}
}
- return this.props.styleProvider?.(doc, props, property);
+ return this._props.styleProvider?.(doc, props, property);
};
@undoBatch
- @action
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
const docView = fieldProps.DocumentView?.();
if (docView && ['Enter'].includes(e.key) && e.ctrlKey) {
@@ -296,26 +301,26 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return this.addDocument?.(newDoc);
}
};
- isContentActive = () => (this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
+ isContentActive = () => (this._props.isContentActive() ? true : this._props.isSelected() === false || this._props.isContentActive() === false ? false : undefined);
@observable _renderCount = 5;
isChildContentActive = () =>
- this.props.isContentActive?.() === false
+ this._props.isContentActive?.() === false
? false
- : this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
- ? true
- : this.props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
- ? false
- : undefined;
- isChildButtonContentActive = () => (this.props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false ? false : undefined);
+ : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
+ ? true
+ : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
+ ? false
+ : undefined;
+ isChildButtonContentActive = () => (this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false ? false : undefined);
@observable docRefs = new ObservableMap<Doc, DocumentView>();
- childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this.props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null));
+ childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this._props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null));
// this is what renders the document that you see on the screen
// called in Children: this actually adds a document to our children list
getDisplayDoc(doc: Doc, width: () => number, count: number) {
- const dataDoc = doc.isTemplateDoc || doc.isTemplateForField ? this.props.TemplateDataDocument : undefined;
+ const dataDoc = doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined;
const height = () => this.getDocHeight(doc);
- const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this.props.PanelHeight()));
+ const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this._props.PanelHeight()));
const panelWidth = () => (this.isStackingView ? width() : this.columnWidth);
const stackedDocTransform = () => this.getDocTransform(doc);
this._docXfs.push({ stackedDocTransform, width, height });
@@ -324,45 +329,45 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
ref={action((r: DocumentView) => r?.ContentDiv && this.docRefs.set(doc, r))}
Document={doc}
TemplateDataDocument={dataDoc ?? (Doc.AreProtosEqual(doc[DocData], doc) ? undefined : doc[DocData])}
- renderDepth={this.props.renderDepth + 1}
+ renderDepth={this._props.renderDepth + 1}
PanelWidth={panelWidth}
PanelHeight={panelHeight}
- pointerEvents={this.props.DocumentView?.().props.onClick?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
+ pointerEvents={this._props.DocumentView?.()._props.onClick?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
styleProvider={this.styleProvider}
- docViewPath={this.props.docViewPath}
+ docViewPath={this._props.docViewPath}
layout_fitWidth={this.childFitWidth}
isContentActive={doc.onClick ? this.isChildButtonContentActive : this.isChildContentActive}
onKey={this.onKeyDown}
- onBrowseClick={this.props.onBrowseClick}
+ onBrowseClick={this._props.onBrowseClick}
isDocumentActive={this.isContentActive}
- LayoutTemplate={this.props.childLayoutTemplate}
- LayoutTemplateString={this.props.childLayoutString}
- NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
- NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeHeight(doc)) ? height : undefined}
- dontCenter={this.props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as any)}
- dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ NativeWidth={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeHeight(doc)) ? height : undefined}
+ dontCenter={this._props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as any)}
+ dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this._props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
rootSelected={this.rootSelected}
- layout_showTitle={this.props.childlayout_showTitle}
- dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
+ layout_showTitle={this._props.childlayout_showTitle}
+ dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={stackedDocTransform}
focus={this.focusDocument}
childFilters={this.childDocFilters}
- hideDecorationTitle={this.props.childHideDecorationTitle}
- hideResizeHandles={this.props.childHideResizeHandles}
+ hideDecorationTitle={this._props.childHideDecorationTitle}
+ hideResizeHandles={this._props.childHideResizeHandles}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
- yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- removeDocument={this.props.removeDocument}
+ xPadding={NumCast(this.layoutDoc._childXPadding, this._props.childXPadding)}
+ yPadding={NumCast(this.layoutDoc._childYPadding, this._props.childYPadding)}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ removeDocument={this._props.removeDocument}
contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.props.addDocTab}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ addDocTab={this._props.addDocTab}
bringToFront={returnFalse}
- pinToPres={this.props.pinToPres}
+ pinToPres={this._props.pinToPres}
/>
);
}
@@ -372,11 +377,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
this._scroll; // must be referenced for document decorations to update when the text box container is scrolled
const { translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv);
// the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
- return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
+ return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this._props.ScreenToLocalTransform().Scale);
}
getDocWidth(d?: Doc) {
if (!d) return 0;
- const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const childLayoutDoc = Doc.Layout(d, this._props.childLayoutTemplate?.());
const maxWidth = this.columnWidth / this.numGroupColumns;
if (!this.layoutDoc._columnsFill && !this.childFitWidth(childLayoutDoc)) {
return Math.min(NumCast(d._width), maxWidth);
@@ -385,9 +390,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
getDocHeight(d?: Doc) {
if (!d || d.hidden) return 0;
- const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
- const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.TemplateDataDocument;
- const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
+ const childLayoutDoc = Doc.Layout(d, this._props.childLayoutTemplate?.());
+ const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this._props.TemplateDataDocument;
+ const maxHeight = (lim => (lim === 0 ? this._props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._width) : 0);
const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._height) : 0);
if (nw && nh) {
@@ -396,7 +401,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return Math.min(maxHeight, (docWid * nh) / nw);
}
const childHeight = NumCast(childLayoutDoc._height);
- const panelHeight = this.childFitWidth(childLayoutDoc) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
+ const panelHeight = this.childFitWidth(childLayoutDoc) ? Number.MAX_SAFE_INTEGER : this._props.PanelHeight() - 2 * this.yMargin;
return Math.min(childHeight, maxHeight, panelHeight);
}
@@ -434,7 +439,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
@undoBatch
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
// Fairly confident that this is where the swapping of nodes in the various arrays happens
const where = [de.x, de.y];
@@ -472,9 +476,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
return true;
}
- } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
+ } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
- if (!this.props.addDocument?.(source)) e.preventDefault();
+ if (!this._props.addDocument?.(source)) e.preventDefault();
de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
e.stopPropagation();
return true;
@@ -497,7 +501,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
/// an item from outside of Dash is being dropped onto this stacking view (e.g, a document from the file system)
@undoBatch
- @action
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
const where = [e.clientX, e.clientY];
let targInd = -1;
@@ -544,8 +547,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
- if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
- this.props.setHeight?.(height);
+ if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) {
+ this._props.setHeight?.(height);
}
}
})
@@ -556,8 +559,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this.addDocument}
chromeHidden={this.chromeHidden}
colHeaderData={this.colHeaderData}
- Document={this.props.Document}
- TemplateDataDocument={this.props.TemplateDataDocument}
+ Document={this._props.Document}
+ TemplateDataDocument={this._props.TemplateDataDocument}
renderChildren={this.children}
columnWidth={this.columnWidth}
numGroupColumns={this.numGroupColumns}
@@ -571,7 +574,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
yMargin={this.yMargin}
type={type}
createDropTarget={this.createDashEventsTarget}
- screenToLocalTransform={this.props.ScreenToLocalTransform}
+ screenToLocalTransform={this._props.ScreenToLocalTransform}
/>
);
};
@@ -584,11 +587,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
type = types[0];
}
- const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
+ const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
return (
<CollectionMasonryViewFieldRow
showHandle={first}
- Document={this.props.Document}
+ Document={this._props.Document}
chromeHidden={this.chromeHidden}
pivotField={this.pivotField}
unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
@@ -599,7 +602,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0);
- this.props.setHeight?.(2 * this.headerMargin + height); // bcz: added 2x for header to fix problem with scrollbars appearing in Tools panel
+ this._props.setHeight?.(2 * this.headerMargin + height); // bcz: added 2x for header to fix problem with scrollbars appearing in Tools panel
}
})
);
@@ -615,7 +618,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
parent={this}
type={type}
createDropTarget={this.createDashEventsTarget}
- screenToLocalTransform={this.props.ScreenToLocalTransform}
+ screenToLocalTransform={this._props.ScreenToLocalTransform}
setDocHeight={this.setDocHeight}
/>
);
@@ -672,43 +675,43 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
Document={menuDoc}
isContentActive={this.isContentActive}
isDocumentActive={this.isContentActive}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
- onBrowseClick={this.props.onBrowseClick}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ addDocTab={this._props.addDocTab}
+ onBrowseClick={this._props.onBrowseClick}
pinToPres={emptyFunction}
rootSelected={this.rootSelected}
- removeDocument={this.props.removeDocument}
+ removeDocument={this._props.removeDocument}
ScreenToLocalTransform={Transform.Identity}
PanelWidth={this.return35}
PanelHeight={this.return35}
- renderDepth={this.props.renderDepth}
+ renderDepth={this._props.renderDepth}
focus={emptyFunction}
- styleProvider={this.props.styleProvider}
+ styleProvider={this._props.styleProvider}
docViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
bringToFront={emptyFunction}
- childFilters={this.props.childFilters}
- childFiltersByRanges={this.props.childFiltersByRanges}
- searchFilterDocs={this.props.searchFilterDocs}
+ childFilters={this._props.childFilters}
+ childFiltersByRanges={this._props.childFiltersByRanges}
+ searchFilterDocs={this._props.searchFilterDocs}
/>
</div>
);
}
@computed get nativeWidth() {
- return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc);
+ return this._props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc);
}
@computed get nativeHeight() {
- return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc);
+ return this._props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc);
}
@computed get scaling() {
- return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight;
+ return !this.nativeWidth ? 1 : this._props.PanelHeight() / this.nativeHeight;
}
@computed get backgroundEvents() {
- return this.props.isContentActive() === false ? 'none' : undefined;
+ return this._props.isContentActive() === false ? 'none' : undefined;
}
observer: any;
render() {
@@ -734,8 +737,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
ref={this.createRef}
style={{
overflowY: this.isContentActive() ? 'auto' : 'hidden',
- background: this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor),
- pointerEvents: (this.props.pointerEvents?.() as any) ?? this.backgroundEvents,
+ background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor),
+ pointerEvents: (this._props.pointerEvents?.() as any) ?? this.backgroundEvents,
}}
onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
onDrop={this.onExternalDrop.bind(this)}
@@ -743,7 +746,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
onWheel={e => this.isContentActive() && e.stopPropagation()}>
{this.renderedSections}
{!this.showAddAGroup ? null : (
- <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
+ <div key={`${this._props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
<EditableView {...editableViewProps} />
</div>
)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 3282eb4b4..b8dcd6248 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, untracked } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { RichTextField } from '../../../fields/RichTextField';
@@ -50,15 +50,22 @@ interface CSVFieldColumnProps {
@observer
export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldColumnProps> {
- @observable private _background = 'inherit';
-
private dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
-
+ @observable private _background = 'inherit';
@observable _paletteOn = false;
- @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
- @observable _color = this.props.headingObject ? this.props.headingObject.color : '#f1efeb';
+ @observable _heading = '';
+ @observable _color = '';
+
+ @observable _props!: CSVFieldColumnProps;
+ constructor(props: CSVFieldColumnProps) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ this._heading = this._props.headingObject ? this._props.headingObject.heading : this._props.heading;
+ this._color = this._props.headingObject ? this._props.headingObject.color : '#f1efeb';
+ }
_ele: HTMLElement | null = null;
@@ -68,29 +75,33 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
this.dropDisposer?.();
if (ele) {
this._ele = ele;
- this.props.observeHeight(ele);
+ this._props.observeHeight(ele);
this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
}
};
+ componentDidUpdate() {
+ // untracked(() => (this._props = this.props));
+ }
+
@action
componentDidMount() {
this._disposers.collapser = reaction(
- () => this.props.headingObject?.collapsed,
+ () => this._props.headingObject?.collapsed,
collapsed => (this.collapsed = collapsed !== undefined ? BoolCast(collapsed) : false),
{ fireImmediately: true }
);
}
componentWillUnmount() {
this._disposers.collapser?.();
- this.props.unobserveHeight(this._ele);
+ this._props.unobserveHeight(this._ele);
}
//TODO: what is scripting? I found it in SetInPlace def but don't know what that is
@undoBatch
columnDrop = action((e: Event, de: DragManager.DropEvent) => {
const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
- this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+ this._props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this._props.pivotField, drop.val, false));
return true;
});
getValue = (value: string): any => {
@@ -105,13 +116,13 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
headingChanged = (value: string, shiftDown?: boolean) => {
const castedValue = this.getValue(value);
if (castedValue) {
- if (this.props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
+ if (this._props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
return false;
}
- this.props.docList.forEach(d => (d[this.props.pivotField] = castedValue));
- if (this.props.headingObject) {
- this.props.headingObject.setHeading(castedValue.toString());
- this._heading = this.props.headingObject.heading;
+ this._props.docList.forEach(d => (d[this._props.pivotField] = castedValue));
+ if (this._props.headingObject) {
+ this._props.headingObject.setHeading(castedValue.toString());
+ this._heading = this._props.headingObject.heading;
}
return true;
}
@@ -120,7 +131,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action
changeColumnColor = (color: string) => {
- this.props.headingObject?.setColor(color);
+ this._props.headingObject?.setColor(color);
this._color = color;
};
@@ -131,30 +142,30 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action
addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
if (!value && !forceEmptyNote) return false;
- const key = this.props.pivotField;
+ const key = this._props.pivotField;
const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true });
- newDoc[key] = this.getValue(this.props.heading);
- const maxHeading = this.props.docList.reduce((maxHeading, doc) => (NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading), 0);
- const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
+ newDoc[key] = this.getValue(this._props.heading);
+ const maxHeading = this._props.docList.reduce((maxHeading, doc) => (NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading), 0);
+ const heading = maxHeading === 0 || this._props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
newDoc.heading = heading;
FormattedTextBox.SetSelectOnLoad(newDoc);
FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
- return this.props.addDocument?.(newDoc) || false;
+ return this._props.addDocument?.(newDoc) || false;
};
@action
deleteColumn = () => {
- this.props.docList.forEach(d => (d[this.props.pivotField] = undefined));
- if (this.props.colHeaderData && this.props.headingObject) {
- const index = this.props.colHeaderData.indexOf(this.props.headingObject);
- this.props.colHeaderData.splice(index, 1);
+ this._props.docList.forEach(d => (d[this._props.pivotField] = undefined));
+ if (this._props.colHeaderData && this._props.headingObject) {
+ const index = this._props.colHeaderData.indexOf(this._props.headingObject);
+ this._props.colHeaderData.splice(index, 1);
}
};
@action
collapseSection = () => {
- this.props.headingObject?.setCollapsed(!this.props.headingObject.collapsed);
- this.collapsed = BoolCast(this.props.headingObject?.collapsed);
+ this._props.headingObject?.setCollapsed(!this._props.headingObject.collapsed);
+ this.collapsed = BoolCast(this._props.headingObject?.collapsed);
};
headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
@@ -162,12 +173,12 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
//TODO: I think this is where I'm supposed to edit stuff
startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
// is MakeEmbedding a way to make a copy of a doc without rendering it?
- const embedding = Doc.MakeEmbedding(this.props.Document);
- embedding._width = this.props.columnWidth / (this.props.colHeaderData?.length || 1);
+ const embedding = Doc.MakeEmbedding(this._props.Document);
+ embedding._width = this._props.columnWidth / (this._props.colHeaderData?.length || 1);
embedding._pivotField = undefined;
let value = this.getValue(this._heading);
value = typeof value === 'string' ? `"${value}"` : value;
- embedding.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name });
+ embedding.viewSpecScript = ScriptField.MakeFunction(`doc.${this._props.pivotField} === ${value}`, { doc: Doc.name });
if (embedding.viewSpecScript) {
DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([embedding]), e.clientX, e.clientY);
return true;
@@ -177,7 +188,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
renderColorPicker = () => {
const gray = '#f1efeb';
- const selected = this.props.headingObject ? this.props.headingObject.color : gray;
+ const selected = this._props.headingObject ? this._props.headingObject.color : gray;
const colors = ['pink2', 'purple4', 'bluegreen1', 'yellow4', 'gray', 'red2', 'bluegreen7', 'bluegreen5', 'orange1'];
return (
<div className="collectionStackingView-colorPicker">
@@ -211,15 +222,15 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
ContextMenu.Instance.clearItems();
const layoutItems: ContextMenuProps[] = [];
const docItems: ContextMenuProps[] = [];
- const dataDoc = this.props.TemplateDataDocument || this.props.Document;
+ const dataDoc = this._props.TemplateDataDocument || this._props.Document;
const width = this._ele ? Number(getComputedStyle(this._ele).width.replace('px', '')) : 0;
const height = this._ele ? Number(getComputedStyle(this._ele).height.replace('px', '')) : 0;
DocUtils.addDocumentCreatorMenuItems(
doc => {
FormattedTextBox.SetSelectOnLoad(doc);
- return this.props.addDocument?.(doc);
+ return this._props.addDocument?.(doc);
},
- this.props.addDocument,
+ this._props.addDocument,
0,
0,
true
@@ -231,12 +242,12 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
docItems.push({
description: ':' + fieldKey,
event: () => {
- const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document));
+ const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this._props.Document));
if (created) {
- if (this.props.Document.isTemplateDoc) {
- Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+ if (this._props.Document.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, this._props.Document);
}
- return this.props.addDocument?.(created);
+ return this._props.addDocument?.(created);
}
},
icon: 'compress-arrows-alt',
@@ -250,12 +261,12 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
event: () => {
const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey });
if (created) {
- const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document;
+ const container = this._props.Document.resolvedDataDoc ? Doc.GetProto(this._props.Document) : this._props.Document;
if (container.isTemplateDoc) {
Doc.MakeMetadataFieldTemplate(created, container);
return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
}
- return this.props.addDocument?.(created) || false;
+ return this._props.addDocument?.(created) || false;
}
},
icon: 'compress-arrows-alt',
@@ -264,16 +275,16 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
!Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' });
!Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
- Doc.GetProto(this.props.Document)[name] = '';
+ Doc.GetProto(this._props.Document)[name] = '';
const created = Docs.Create.TextDocument('', { title: name, _width: 250, _layout_autoHeight: true });
if (created) {
- if (this.props.Document.isTemplateDoc) {
- Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+ if (this._props.Document.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, this._props.Document);
}
- this.props.addDocument?.(created);
+ this._props.addDocument?.(created);
}
});
- const pt = this.props
+ const pt = this._props
.screenToLocalTransform()
.inverse()
.transformPoint(width - 30, height);
@@ -282,21 +293,21 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@computed get innards() {
TraceMobx();
- const key = this.props.pivotField;
- const headings = this.props.headings();
+ const key = this._props.pivotField;
+ const headings = this._props.headings();
const heading = this._heading;
- const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin;
+ const columnYMargin = this._props.headingObject ? 0 : this._props.yMargin;
const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
const noValueHeader = `NO ${key.toUpperCase()} VALUE`;
- const evContents = heading ? heading : this.props?.type === 'number' ? '0' : noValueHeader;
- const headingView = this.props.headingObject ? (
+ const evContents = heading ? heading : this._props?.type === 'number' ? '0' : noValueHeader;
+ const headingView = this._props.headingObject ? (
<div
key={heading}
className="collectionStackingView-sectionHeader"
ref={this._headerRef}
style={{
- marginTop: this.props.yMargin,
- width: this.props.columnWidth / (uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1) || 1),
+ marginTop: this._props.yMargin,
+ width: this._props.columnWidth / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1),
}}>
{/* the default bucket (no key value) has a tooltip that describes what it is.
Further, it does not have a color and cannot be deleted. */}
@@ -326,35 +337,35 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
)} */}
</div>
<div
- className={'collectionStackingView-collapseBar' + (this.props.headingObject.collapsed === true ? ' active' : '')}
- style={{ display: this.props.headingObject.collapsed === true ? 'block' : undefined }}
+ className={'collectionStackingView-collapseBar' + (this._props.headingObject.collapsed === true ? ' active' : '')}
+ style={{ display: this._props.headingObject.collapsed === true ? 'block' : undefined }}
onClick={this.collapseSection}
/>
</div>
) : null;
- const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `;
- const type = this.props.Document.type;
+ const templatecols = `${this._props.columnWidth / this._props.numGroupColumns}px `;
+ const type = this._props.Document.type;
return (
<>
- {this.props.Document._columnsHideIfEmpty ? null : headingView}
+ {this._props.Document._columnsHideIfEmpty ? null : headingView}
{this.collapsed ? null : (
<div>
<div
key={`${heading}-stack`}
className={`collectionStackingView-masonrySingle`}
style={{
- padding: `${columnYMargin}px ${0}px ${this.props.yMargin}px ${0}px`,
+ padding: `${columnYMargin}px ${0}px ${this._props.yMargin}px ${0}px`,
margin: 'auto',
width: 'max-content', //singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
height: 'max-content',
position: 'relative',
- gridGap: this.props.gridGap,
+ gridGap: this._props.gridGap,
gridTemplateColumns: templatecols,
gridAutoRows: '0px',
}}>
- {this.props.renderChildren(this.props.docList)}
+ {this._props.renderChildren(this._props.docList)}
</div>
- {!this.props.chromeHidden && type !== DocumentType.PRES ? (
+ {!this._props.chromeHidden && type !== DocumentType.PRES ? (
// TODO: this is the "new" button: see what you can work with here
// change cursor to pointer for this, and update dragging cursor
//TODO: there is a bug that occurs when adding a freeform document and trying to move it around
@@ -365,7 +376,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
key={`${heading}-add-document`}
onKeyDown={e => e.stopPropagation()}
className="collectionStackingView-addDocumentButton"
- style={{ width: 'calc(100% - 25px)', maxWidth: this.props.columnWidth / this.props.numGroupColumns - 25, marginBottom: 10 }}>
+ style={{ width: 'calc(100% - 25px)', maxWidth: this._props.columnWidth / this._props.numGroupColumns - 25, marginBottom: 10 }}>
<EditableView
GetValue={returnEmptyString}
SetValue={this.addNewTextDoc}
@@ -384,7 +395,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
render() {
TraceMobx();
- const headings = this.props.headings();
+ const headings = this._props.headings();
const heading = this._heading;
const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
return (
@@ -392,7 +403,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
className={'collectionStackingViewFieldColumn' + (SnappingManager.GetIsDragging() ? 'Dragging' : '')}
key={heading}
style={{
- width: `${100 / (uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1) || 1)}%`,
+ width: `${100 / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1)}%`,
height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined,
background: this._background,
}}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 40b2f9644..fd53e12da 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable } from 'mobx';
+import { action, computed, makeObservable, observable, override, runInAction, untracked } from 'mobx';
import * as rp from 'request-promise';
import CursorField from '../../../fields/CursorField';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
@@ -35,6 +35,17 @@ export function CollectionSubView<X>(moreProps?: X) {
private dropDisposer?: DragManager.DragDropDisposer;
private gestureDisposer?: GestureUtils.GestureEventDisposer;
protected _mainCont?: HTMLDivElement;
+ @override _props: X & SubCollectionViewProps;
+
+ constructor(props: any) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+ componentDidUpdate() {
+ // untracked(() => (this._props = this.props));
+ }
+
@observable _focusFilters: Opt<string[]>; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it
@observable _focusRangeFilters: Opt<string[]>; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it
protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
@@ -55,29 +66,29 @@ export function CollectionSubView<X>(moreProps?: X) {
this.gestureDisposer?.();
}
- @computed get dataDoc() {
- return this.props.TemplateDataDocument instanceof Doc && this.props.Document.isTemplateForField
- ? Doc.GetProto(this.props.TemplateDataDocument)
- : this.props.Document.resolvedDataDoc
- ? this.props.Document
- : Doc.GetProto(this.props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
+ get dataDoc() {
+ return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField
+ ? Doc.GetProto(this._props.TemplateDataDocument)
+ : this._props.Document.resolvedDataDoc
+ ? this._props.Document
+ : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
}
// this returns whether either the collection is selected, or the template that it is part of is selected
- rootSelected = () => this.props.isSelected() || BoolCast(this.props.TemplateDataDocument && this.props.rootSelected?.());
+ rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
- // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument.
+ // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument.
// When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@computed get dataField() {
- return this.dataDoc[this.props.fieldKey]; // this used to be 'layoutDoc', but then template fields will get ignored since the template is not a proto of the layout. hopefully nothing depending on the previous code.
+ return this.dataDoc[this._props.fieldKey]; // this used to be 'layoutDoc', but then template fields will get ignored since the template is not a proto of the layout. hopefully nothing depending on the previous code.
}
@computed get childLayoutPairs(): { layout: Doc; data: Doc }[] {
- const { Document, TemplateDataDocument } = this.props;
+ const { Document, TemplateDataDocument } = this._props;
const validPairs = this.childDocs
- .map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc))
+ .map(doc => Doc.GetLayoutDataDocPair(Document, !this._props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc))
.filter(pair => {
// filter out any documents that have a proto that we don't have permissions to
return !pair.layout?.hidden && pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
@@ -87,14 +98,14 @@ export function CollectionSubView<X>(moreProps?: X) {
@computed get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
- collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters);
- collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._childFiltersByRanges, listSpec('string'), []);
+ collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters);
+ collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []);
// child filters apply to the descendants of the documents in this collection
- childDocFilters = () => [...(this.props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+ childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
// unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack
- unrecursiveDocFilters = () => [...(this.props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
- childDocRangeFilters = () => [...(this.props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
- searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
+ unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
+ childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
+ searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -108,27 +119,27 @@ export function CollectionSubView<X>(moreProps?: X) {
// Finally, if it's not a doc or a list and the document is a template, we try to render the root doc.
// For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection.
// Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image.
- const templateRoot = this.props.TemplateDataDocument;
- rawdocs = templateRoot && !this.props.isAnnotationOverlay ? [Doc.GetProto(templateRoot)] : [];
+ const templateRoot = this._props.TemplateDataDocument;
+ rawdocs = templateRoot && !this._props.isAnnotationOverlay ? [Doc.GetProto(templateRoot)] : [];
}
- const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
+ const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this._props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
const childDocFilters = this.childDocFilters();
const childFiltersByRanges = this.childDocRangeFilters();
const searchDocs = this.searchFilterDocs();
- if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
+ if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
}
const docsforFilter: Doc[] = [];
childDocs.forEach(d => {
// dragging facets
- const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter));
+ const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter));
if (dragged && SnappingManager.GetCanEmbed() && DragManager.docsBeingDragged.includes(d)) return false;
- let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0;
+ let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0;
if (notFiltered) {
- notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.props.Document).length > 0;
+ notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0;
const fieldKey = Doc.LayoutFieldKey(d);
const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
const data = d[annos ? fieldKey + '_annotations' : fieldKey];
@@ -161,7 +172,7 @@ export function CollectionSubView<X>(moreProps?: X) {
@action
protected async setCursorPosition(position: [number, number]) {
let ind;
- const doc = this.props.Document;
+ const doc = this._props.Document;
const id = Doc.UserDoc()[Id];
const email = Doc.CurrentUserEmail;
const pos = { x: position[0], y: position[1] };
@@ -197,23 +208,23 @@ export function CollectionSubView<X>(moreProps?: X) {
const dropAction = this.layoutDoc.dropAction as dropActionType;
// if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding.
// so we check if our collection has a dropAction set on it and if so, we use that instead.
- if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
+ if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) {
de.complete.docDragData.dropAction = dropAction;
}
e.stopPropagation();
}
}
- addDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.addDocument?.(doc, annotationKey) || false;
- removeDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.removeDocument?.(doc, annotationKey) || false;
- moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string) => this.props.moveDocument?.(doc, targetCollection, addDocument);
- @action
+ addDocument = (doc: Doc | Doc[], annotationKey?: string) => this._props.addDocument?.(doc, annotationKey) || false;
+ removeDocument = (doc: Doc | Doc[], annotationKey?: string) => this._props.removeDocument?.(doc, annotationKey) || false;
+ moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string) => this._props.moveDocument?.(doc, targetCollection, addDocument);
+
protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const docDragData = de.complete.docDragData;
if (docDragData) {
let added = undefined;
const dropAction = docDragData.dropAction || docDragData.userDropAction;
- const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]);
+ const targetDocments = DocListCast(this.dataDoc[this._props.fieldKey]);
const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop));
if ((!dropAction || dropAction === 'inSame' || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) {
@@ -236,13 +247,13 @@ export function CollectionSubView<X>(moreProps?: X) {
added = this.addDocument(docDragData.droppedDocuments);
!added && alert('You cannot perform this move');
}
- added === false && !this.props.isAnnotationOverlay && e.preventDefault();
+ added === false && !this._props.isAnnotationOverlay && e.preventDefault();
added === true && e.stopPropagation();
return added ? true : false;
} else if (de.complete.annoDragData) {
const dropCreator = de.complete.annoDragData.dropDocCreator;
de.complete.annoDragData.dropDocCreator = () => {
- const dropped = dropCreator(this.props.isAnnotationOverlay ? this.Document : undefined);
+ const dropped = dropCreator(this._props.isAnnotationOverlay ? this.Document : undefined);
this.addDocument(dropped);
return dropped;
};
@@ -252,7 +263,6 @@ export function CollectionSubView<X>(moreProps?: X) {
}
@undoBatch
- @action
protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) {
if (e.ctrlKey) {
e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
@@ -463,15 +473,15 @@ export function CollectionSubView<X>(moreProps?: X) {
}
if (generatedDocuments.length) {
// Creating a dash document
- const isFreeformView = this.props.Document._type_collection === CollectionViewType.Freeform;
+ const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform;
const set = !isFreeformView
? generatedDocuments
: generatedDocuments.length > 1
- ? generatedDocuments.map(d => {
- DocUtils.iconify(d);
- return d;
- })
- : [];
+ ? generatedDocuments.map(d => {
+ DocUtils.iconify(d);
+ return d;
+ })
+ : [];
if (completed) completed(set);
else {
if (isFreeformView && generatedDocuments.length > 1) {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 5c165fe70..938af002f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
@@ -7,7 +7,7 @@ import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils';
+import { copyProps, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
@@ -23,7 +23,7 @@ import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormView } from './collectionFreeForm';
-import { CollectionSubView } from './CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import './CollectionTreeView.scss';
import { TreeView } from './TreeView';
import * as React from 'react';
@@ -59,27 +59,35 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
private refList: Set<any> = new Set(); // list of tree view items to monitor for height changes
private observer: any; // observer for monitoring tree view items.
- @computed get doc() {
- return this.props.Document;
+ _prevProps: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionTreeViewProps>>;
+ @override _props: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionTreeViewProps>>;
+ constructor(props: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionTreeViewProps>>) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
}
- @computed get dataDoc() {
- return this.props.TemplateDataDocument || this.doc;
+ componentDidUpdate() {
+ copyProps(this);
+ }
+
+ get dataDoc() {
+ return this._props.TemplateDataDocument || this.Document;
}
@computed get treeViewtruncateTitleWidth() {
- return NumCast(this.doc.treeView_TruncateTitleWidth, this.panelWidth());
+ return NumCast(this.Document.treeView_TruncateTitleWidth, this.panelWidth());
}
@computed get treeChildren() {
TraceMobx();
- return this.props.childDocuments || this.childDocs;
+ return this._props.childDocuments || this.childDocs;
}
@computed get outlineMode() {
- return this.doc.treeView_Type === TreeViewType.outline;
+ return this.Document.treeView_Type === TreeViewType.outline;
}
@computed get fileSysMode() {
- return this.doc.treeView_Type === TreeViewType.fileSystem;
+ return this.Document.treeView_Type === TreeViewType.fileSystem;
}
@computed get dashboardMode() {
- return this.doc === Doc.MyDashboards;
+ return this.Document === Doc.MyDashboards;
}
@observable _titleHeight = 0; // height of the title bar
@@ -88,8 +96,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
// these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
@observable _isAnyChildContentActive = false;
- whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
- isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this.props.isContentActive() ? true : false);
+ whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
+ isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this._props.isContentActive() ? true : false);
componentWillUnmount() {
this._isDisposing = true;
@@ -99,7 +107,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
}
componentDidMount() {
- //this.props.setContentView?.(this);
+ //this._props.setContentView?.(this);
this._disposers.autoheight = reaction(
() => this.layoutDoc.layout_autoHeight,
auto => auto && this.computeHeight(),
@@ -112,7 +120,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', ''));
const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6;
this.layoutDoc._layout_autoHeightMargins = bodyHeight;
- !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight);
+ !this._props.dontRegisterView && this._props.setHeight?.(bodyHeight + titleHeight);
}
};
unobserveHeight = (ref: any) => {
@@ -135,7 +143,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
};
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
+ if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this));
};
protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => {
@@ -143,7 +151,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
const dragData = de.complete.docDragData;
if (dragData) {
const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.Document) ? true : false;
- const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
+ const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d));
if (isAlreadyInTree() !== sameTree) {
console.log('WHAAAT');
}
@@ -152,22 +160,22 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
}
};
- screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this._headerHeight);
+ screenToLocalTransform = () => this._props.ScreenToLocalTransform().translate(0, -this._headerHeight);
@action
remove = (doc: Doc | Doc[]): boolean => {
const docs = doc instanceof Doc ? [doc] : doc;
- const targetDataDoc = this.doc[DocData];
- const value = DocListCast(targetDataDoc[this.props.fieldKey]);
+ const targetDataDoc = this.Document[DocData];
+ const value = DocListCast(targetDataDoc[this._props.fieldKey]);
const result = value.filter(v => !docs.includes(v));
if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll();
if (result.length !== value.length && doc instanceof Doc) {
- const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc);
- const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1];
- this.props.removeDocument?.(doc);
+ const ind = DocListCast(targetDataDoc[this._props.fieldKey]).indexOf(doc);
+ const prev = ind && DocListCast(targetDataDoc[this._props.fieldKey])[ind - 1];
+ this._props.removeDocument?.(doc);
if (ind > 0 && prev) {
FormattedTextBox.SetSelectOnLoad(prev);
- DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
+ DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false);
}
return true;
}
@@ -178,24 +186,28 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
const doAddDoc = (doc: Doc | Doc[]) =>
(doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
- const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before);
- res && Doc.SetContainer(doc, this.props.Document);
+ const res = flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before);
+ res && Doc.SetContainer(doc, this.Document);
return res;
}, true);
- if (this.doc.resolvedDataDoc instanceof Promise) return false;
- return relativeTo === undefined ? this.props.addDocument?.(docs) || false : doAddDoc(docs);
+ if (this.Document.resolvedDataDoc instanceof Promise) return false;
+ return relativeTo === undefined ? this._props.addDocument?.(docs) || false : doAddDoc(docs);
};
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
if (!Doc.noviceMode) {
const layoutItems: ContextMenuProps[] = [];
- layoutItems.push({ description: 'Make tree state ' + (this.doc.treeView_OpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeView_OpenIsTransient = !this.doc.treeView_OpenIsTransient), icon: 'paint-brush' });
- layoutItems.push({ description: (this.doc.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeView_HideHeaderFields = !this.doc.treeView_HideHeaderFields), icon: 'paint-brush' });
- layoutItems.push({ description: (this.doc.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeView_HideTitle = !this.doc.treeView_HideTitle), icon: 'paint-brush' });
+ layoutItems.push({
+ description: 'Make tree state ' + (this.Document.treeView_OpenIsTransient ? 'persistent' : 'transient'),
+ event: () => (this.Document.treeView_OpenIsTransient = !this.Document.treeView_OpenIsTransient),
+ icon: 'paint-brush',
+ });
+ layoutItems.push({ description: (this.Document.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.Document.treeView_HideHeaderFields = !this.Document.treeView_HideHeaderFields), icon: 'paint-brush' });
+ layoutItems.push({ description: (this.Document.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.Document.treeView_HideTitle = !this.Document.treeView_HideTitle), icon: 'paint-brush' });
ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...');
const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
- onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' });
+ onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' });
!existingOnClick && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
}
};
@@ -213,7 +225,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
height={'auto'}
GetValue={() => StrCast(this.dataDoc.title)}
SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => {
- if (enter && this.props.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren);
+ if (enter && this.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren);
this.dataDoc.title = value;
return true;
})}
@@ -231,9 +243,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
get documentTitle() {
return (
<FormattedTextBox
- {...this.props}
+ {...this._props}
fieldKey="text"
- renderDepth={this.props.renderDepth + 1}
+ renderDepth={this._props.renderDepth + 1}
isContentActive={this.isContentActive}
isDocumentActive={this.isContentActive}
forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not layout_autoHeight
@@ -253,52 +265,52 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
);
}
childContextMenuItems = () => {
- const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
- const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
- const icons = StrListCast(this.doc.childContextMenuIcons);
- return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
+ const customScripts = Cast(this.Document.childContextMenuScripts, listSpec(ScriptField), []);
+ const customFilters = Cast(this.Document.childContextMenuFilters, listSpec(ScriptField), []);
+ const icons = StrListCast(this.Document.childContextMenuIcons);
+ return StrListCast(this.Document.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
};
- headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeView_HideHeaderFields);
+ headerFields = () => this._props.treeViewHideHeaderFields || BoolCast(this.Document.treeView_HideHeaderFields);
@observable _renderCount = 1;
@computed get treeViewElements() {
TraceMobx();
- const dragAction = StrCast(this.doc.childDragAction) as dropActionType;
+ const dragAction = StrCast(this.Document.childDragAction) as dropActionType;
const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
- const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false;
+ const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this._props.moveDocument?.(d, target, addDoc) || false;
if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
return TreeView.GetChildElements(
this.treeChildren,
this,
this,
- this.doc,
- this.props.TemplateDataDocument,
+ this.Document,
+ this._props.TemplateDataDocument,
undefined,
undefined,
addDoc,
this.remove,
moveDoc,
dragAction,
- this.props.addDocTab,
- this.props.styleProvider,
+ this._props.addDocTab,
+ this._props.styleProvider,
this.screenToLocalTransform,
this.isContentActive,
this.panelWidth,
- this.props.renderDepth,
+ this._props.renderDepth,
this.headerFields,
[],
- this.props.onCheckedClick,
+ this._props.onCheckedClick,
this.onChildClick,
- this.props.treeViewSkipFields,
+ this._props.treeViewSkipFields,
true,
this.whenChildContentsActiveChanged,
- this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, 'boolean', null),
+ this._props.dontRegisterView || Cast(this.Document.childDontRegisterViews, 'boolean', null),
this.observeHeight,
this.unobserveHeight,
this.childContextMenuItems(),
//TODO: [AL] add these
- this.props.AddToMap,
- this.props.RemFromMap,
- this.props.hierarchyIndex,
+ this._props.AddToMap,
+ this._props.RemFromMap,
+ this._props.hierarchyIndex,
this._renderCount
);
}
@@ -306,8 +318,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
return this.dataDoc === null ? null : (
<div
className="collectionTreeView-titleBar"
- ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.props.ScreenToLocalTransform().Scale))}
- key={this.doc[Id]}
+ ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this._props.ScreenToLocalTransform().Scale))}
+ key={this.Document[Id]}
style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}>
{this.outlineMode ? this.documentTitle : this.editableTitle}
</div>
@@ -327,26 +339,26 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
<DocumentView
Document={menuDoc}
TemplateDataDocument={menuDoc}
- isContentActive={this.props.isContentActive}
+ isContentActive={this._props.isContentActive}
isDocumentActive={returnTrue}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- removeDocument={this.props.removeDocument}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ removeDocument={this._props.removeDocument}
+ addDocTab={this._props.addDocTab}
+ pinToPres={this._props.pinToPres}
rootSelected={this.rootSelected}
ScreenToLocalTransform={Transform.Identity}
PanelWidth={this.return35}
PanelHeight={this.return35}
- renderDepth={this.props.renderDepth + 1}
+ renderDepth={this._props.renderDepth + 1}
focus={emptyFunction}
- styleProvider={this.props.styleProvider}
+ styleProvider={this._props.styleProvider}
docViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
bringToFront={emptyFunction}
- childFilters={this.props.childFilters}
- childFiltersByRanges={this.props.childFiltersByRanges}
- searchFilterDocs={this.props.searchFilterDocs}
+ childFilters={this._props.childFilters}
+ childFiltersByRanges={this._props.childFiltersByRanges}
+ searchFilterDocs={this._props.searchFilterDocs}
/>
</div>
);
@@ -363,30 +375,30 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@computed get nativeDimScaling() {
const nw = this.nativeWidth;
const nh = this.nativeHeight;
- const hscale = nh ? this.props.PanelHeight() / nh : 1;
- const wscale = nw ? this.props.PanelWidth() / nw : 1;
+ const hscale = nh ? this._props.PanelHeight() / nh : 1;
+ const wscale = nw ? this._props.PanelWidth() / nw : 1;
return wscale < hscale ? wscale : hscale;
}
- marginX = () => NumCast(this.doc._xMargin);
- marginTop = () => NumCast(this.doc._yMargin);
- marginBot = () => NumCast(this.doc._yMargin);
+ marginX = () => NumCast(this.Document._xMargin);
+ marginTop = () => NumCast(this.Document._yMargin);
+ marginBot = () => NumCast(this.Document._yMargin);
documentTitleWidth = () => Math.min(NumCast(this.layoutDoc?._width), this.panelWidth());
documentTitleHeight = () => NumCast(this.layoutDoc?._height) - NumCast(this.layoutDoc.layout_autoHeightMargins);
truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
- onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
- panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1));
+ onChildClick = () => this._props.onChildClick?.() || ScriptCast(this.Document.onChildClick);
+ panelWidth = () => Math.max(0, this._props.PanelWidth() - 2 * this.marginX() * (this._props.NativeDimScaling?.() || 1));
- addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}_annotations`) || false;
- remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}_annotations`) || false;
+ addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this._props.fieldKey}_annotations`) || false;
+ remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this._props.fieldKey}_annotations`) || false;
moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) =>
- this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}_annotations`) || false;
+ this.moveDocument(doc, targetCollection, addDocument, `${this._props.fieldKey}_annotations`) || false;
@observable _headerHeight = 0;
@computed get content() {
- const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
- const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color);
- const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined);
- const titleBar = this.props.treeViewHideTitle || this.doc.treeView_HideTitle ? null : this.titleBar;
+ const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor);
+ const color = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.Color);
+ const pointerEvents = () => (this._props.isContentActive() === false ? 'none' : undefined);
+ const titleBar = this._props.treeViewHideTitle || this.Document.treeView_HideTitle ? null : this.titleBar;
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}>
{!this.buttonMenu && !this.noviceExplainer ? null : (
@@ -398,7 +410,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
<div
className="collectionTreeView-contents"
key="tree"
- ref={r => !this.doc.treeView_HasOverlay && r && this.createTreeDropTarget(r)}
+ ref={r => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r)}
style={{
...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
color: color(),
@@ -423,7 +435,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
minHeight: '100%',
}}
onWheel={e => e.stopPropagation()}
- onClick={e => (!this.layoutDoc.forceActive ? this.props.select(false) : SelectionManager.DeselectAll())}
+ onClick={e => (!this.layoutDoc.forceActive ? this._props.select(false) : SelectionManager.DeselectAll())}
onDrop={this.onTreeDrop}>
<ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul>
</div>
@@ -435,27 +447,27 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
render() {
TraceMobx();
- const scale = this.props.NativeDimScaling?.() || 1;
+ const scale = this._props.NativeDimScaling?.() || 1;
return (
<div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}>
- {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? (
+ {!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? (
<CollectionFreeFormView
- {...this.props}
+ {...this._props}
setContentView={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
- pointerEvents={this.props.isContentActive() && SnappingManager.GetIsDragging() ? returnAll : returnNone}
+ pointerEvents={this._props.isContentActive() && SnappingManager.GetIsDragging() ? returnAll : returnNone}
isAnnotationOverlay={true}
isAnnotationOverlayScrollable={true}
- childDocumentsActive={this.props.isDocumentActive}
- fieldKey={this.props.fieldKey + '_annotations'}
+ childDocumentsActive={this._props.isDocumentActive}
+ fieldKey={this._props.fieldKey + '_annotations'}
dropAction="move"
select={emptyFunction}
addDocument={this.addAnnotationDocument}
removeDocument={this.remAnnotationDocument}
moveDocument={this.moveAnnotationDocument}
bringToFront={emptyFunction}
- renderDepth={this.props.renderDepth + 1}>
+ renderDepth={this._props.renderDepth + 1}>
{this.content}
</CollectionFreeFormView>
) : (
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2e4c5af6b..e84c12e02 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
@@ -6,7 +6,7 @@ import { ObjectField } from '../../../fields/ObjectField';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { returnEmptyString } from '../../../Utils';
+import { copyProps, returnEmptyString } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { CollectionViewType } from '../../documents/DocumentTypes';
import { dropActionType } from '../../util/DragManager';
@@ -76,12 +76,19 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
this._safeMode = safeMode;
}
private reactionDisposer: IReactionDisposer | undefined;
- @observable _isContentActive: boolean | undefined;
+ @observable _isContentActive: boolean | undefined = undefined;
+ _prevProps: React.PropsWithChildren<ViewBoxAnnotatableProps & CollectionViewProps>;
+ @override _props: React.PropsWithChildren<ViewBoxAnnotatableProps & CollectionViewProps>;
constructor(props: any) {
super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
runInAction(() => (this._annotationKeySuffix = returnEmptyString));
}
+ componentDidUpdate() {
+ copyProps(this);
+ }
componentDidMount() {
// we use a reaction/observable instead of a computed value to reduce invalidations.
@@ -89,7 +96,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
// will cause downstream invalidations even if the computed value doesn't change. By making
// this a reaction, downstream invalidations only occur when the reaction value actually changes.
this.reactionDisposer = reaction(
- () => (this.isAnyChildContentActive() ? true : this.props.isContentActive()),
+ () => (this.isAnyChildContentActive() ? true : this._props.isContentActive()),
active => (this._isContentActive = active),
{ fireImmediately: true }
);
@@ -112,7 +119,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
return viewField as any as CollectionViewType;
}
- screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()));
+ screenToLocalTransform = () => (this._props.renderDepth ? this._props.ScreenToLocalTransform() : this._props.ScreenToLocalTransform().scale(this._props.PanelWidth() / this.bodyPanelWidth()));
// prettier-ignore
private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => {
TraceMobx();
@@ -172,7 +179,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
this.setupViewTypes('Appearance...', vtype => {
const newRendition = Doc.MakeEmbedding(this.Document);
newRendition._type_collection = vtype;
- this.props.addDocTab(newRendition, OpenWhere.addRight);
+ this._props.addDocTab(newRendition, OpenWhere.addRight);
return newRendition;
});
@@ -180,10 +187,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
const optionItems = options && 'subitems' in options ? options.subitems : [];
!Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.Document.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.Document.forceActive = !this.Document.forceActive), icon: 'project-diagram' }) : null;
if (this.Document.childLayout instanceof Doc) {
- optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.Document.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' });
+ optionItems.push({ description: 'View Child Layout', event: () => this._props.addDocTab(this.Document.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' });
}
if (this.Document.childClickedOpenTemplateView instanceof Doc) {
- optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.Document.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
+ optionItems.push({ description: 'View Child Detailed Layout', event: () => this._props.addDocTab(this.Document.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
}
!Doc.noviceMode && optionItems.push({ description: `${this.layoutDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.layoutDoc._isLightbox = !this.layoutDoc._isLightbox), icon: 'project-diagram' });
@@ -203,7 +210,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
event: (obj: any) => {
const embedding = Doc.MakeEmbedding(this.Document);
DocUtils.makeCustomViewClicked(embedding, undefined, func.key);
- this.props.addDocTab(embedding, OpenWhere.addRight);
+ this._props.addDocTab(embedding, OpenWhere.addRight);
},
})
);
@@ -226,34 +233,40 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
}
};
- bodyPanelWidth = () => this.props.PanelWidth();
+ bodyPanelWidth = () => this._props.PanelWidth();
- childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null);
+ childLayoutTemplate = () => this._props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null);
isContentActive = (outsideReaction?: boolean) => this._isContentActive;
+ pointerEvents = () => {
+ const viewPath = this._props.DocumentView?.()?._props.docViewPath();
+ return (
+ this.layoutDoc._lockedPosition && //
+ viewPath?.lastElement()?.Document?._type_collection === CollectionViewType.Freeform
+ );
+ };
+
render() {
TraceMobx();
+ const pointerEvents = this.pointerEvents() ? 'none' : undefined;
const props: SubCollectionViewProps = {
- ...this.props,
+ ...this._props,
addDocument: this.addDocument,
moveDocument: this.moveDocument,
removeDocument: this.removeDocument,
isContentActive: this.isContentActive,
isAnyChildContentActive: this.isAnyChildContentActive,
PanelWidth: this.bodyPanelWidth,
- PanelHeight: this.props.PanelHeight,
+ PanelHeight: this._props.PanelHeight,
ScreenToLocalTransform: this.screenToLocalTransform,
childLayoutTemplate: this.childLayoutTemplate,
whenChildContentsActiveChanged: this.whenChildContentsActiveChanged,
- childLayoutString: StrCast(this.Document.childLayoutString, this.props.childLayoutString),
- childHideResizeHandles: this.props.childHideResizeHandles ?? BoolCast(this.Document.childHideResizeHandles),
- childHideDecorationTitle: this.props.childHideDecorationTitle ?? BoolCast(this.Document.childHideDecorationTitle),
+ childLayoutString: StrCast(this.Document.childLayoutString, this._props.childLayoutString),
+ childHideResizeHandles: this._props.childHideResizeHandles ?? BoolCast(this.Document.childHideResizeHandles),
+ childHideDecorationTitle: this._props.childHideDecorationTitle ?? BoolCast(this.Document.childHideDecorationTitle),
};
return (
- <div
- className="collectionView"
- onContextMenu={this.onContextMenu}
- style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.Document?._type_collection === CollectionViewType.Freeform && this.layoutDoc._lockedPosition ? 'none' : undefined }}>
+ <div className="collectionView" onContextMenu={this.onContextMenu} style={{ pointerEvents }}>
{this.renderSubView(this.collectionViewType, props)}
</div>
);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4a1d702b8..dc7ee206c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Popup, Type } from 'browndash-components';
import { clamp } from 'lodash';
-import { action, computed, IReactionDisposer, observable, ObservableSet, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as ReactDOM from 'react-dom/client';
import { Doc, Opt } from '../../../fields/Doc';
@@ -11,7 +11,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { FieldId } from '../../../fields/RefField';
import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
-import { DashColor, emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
+import { copyProps, DashColor, emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
@@ -48,6 +48,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
static _allTabs = new ObservableSet<TabDocView>();
_mainCont: HTMLDivElement | null = null;
_tabReaction: IReactionDisposer | undefined;
+
+ _prevProps: React.PropsWithChildren<TabDocViewProps>;
+ @observable _props: React.PropsWithChildren<TabDocViewProps>;
+ constructor(props: React.PropsWithChildren<TabDocViewProps>) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ }
+
@observable _activated: boolean = false;
@observable _panelWidth = 0;
@observable _panelHeight = 0;
@@ -57,21 +66,21 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@computed get _isUserActivated() {
return SelectionManager.IsSelected(this._document) || this._isAnyChildContentActive;
}
- @computed get _isContentActive() {
+ get _isContentActive() {
return this._isUserActivated || this._hovering;
}
- @observable _document: Doc | undefined;
- @observable _view: DocumentView | undefined;
+ @observable _document: Doc | undefined = undefined;
+ @observable _view: DocumentView | undefined = undefined;
@computed get layoutDoc() {
return this._document && Doc.Layout(this._document);
}
get stack() {
- return (this.props as any).glContainer.parent.parent;
+ return this._props.glContainer.parent.parent;
}
get tab() {
- return (this.props as any).glContainer.tab;
+ return this._props.glContainer.tab;
}
get view() {
return this._view;
@@ -162,12 +171,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
this._isUserActivated
? 0
: this._hovering
- ? 0.25
- : degree === Doc.DocBrushStatus.selfBrushed
- ? 0.5
- : degree === Doc.DocBrushStatus.protoBrushed //
- ? 0.7
- : 0.9
+ ? 0.25
+ : degree === Doc.DocBrushStatus.selfBrushed
+ ? 0.5
+ : degree === Doc.DocBrushStatus.protoBrushed //
+ ? 0.7
+ : 0.9
)
.rgb()
.toString()
@@ -316,7 +325,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
- @action
componentDidMount() {
new _global.ResizeObserver(
action((entries: any) => {
@@ -325,25 +333,25 @@ export class TabDocView extends React.Component<TabDocViewProps> {
this._panelHeight = entry.contentRect.height;
}
})
- ).observe(this.props.glContainer._element[0]);
- this.props.glContainer.layoutManager.on('activeContentItemChanged', this.onActiveContentItemChanged);
- this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged(undefined);
+ ).observe(this._props.glContainer._element[0]);
+ this._props.glContainer.layoutManager.on('activeContentItemChanged', this.onActiveContentItemChanged);
+ this._props.glContainer.tab?.isActive && this.onActiveContentItemChanged(undefined);
// this._tabReaction = reaction(() => ({ selected: this.active(), title: this.tab?.titleElement[0] }),
// ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""),
// { fireImmediately: true });
- TabDocView._allTabs.add(this);
+ runInAction(() => TabDocView._allTabs.add(this));
}
componentDidUpdate() {
this._view && DocumentManager.Instance.AddView(this._view);
+ copyProps(this);
}
- @action
componentWillUnmount() {
this._tabReaction?.();
this._view && DocumentManager.Instance.RemoveView(this._view);
- TabDocView._allTabs.delete(this);
+ runInAction(() => TabDocView._allTabs.delete(this));
- this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
+ this._props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
}
// Flag indicating that when a tab is activated, it should not select it's document.
@@ -420,7 +428,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
ScreenToLocalTransform = () => {
this._forceInvalidateScreenToLocal;
const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
- return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY) ?? Transform.Identity();
+ return CollectionDockingView.Instance?._props.ScreenToLocalTransform().translate(-translateX, -translateY) ?? Transform.Identity();
};
PanelWidth = () => this._panelWidth;
PanelHeight = () => this._panelHeight;
@@ -441,8 +449,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
this._lastView = this._view;
})}
renderDepth={0}
- LayoutTemplateString={this.props.keyValue ? KeyValueBox.LayoutString() : undefined}
- hideTitle={this.props.keyValue}
+ LayoutTemplateString={this._props.keyValue ? KeyValueBox.LayoutString() : undefined}
+ hideTitle={this._props.keyValue}
Document={this._document}
TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
onBrowseClick={DocumentView.exploreMode}
@@ -489,7 +497,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
this._lastTab = this.tab;
(this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
- DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
+ DocServer.GetRefField(this._props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
}
}}>
@@ -547,8 +555,15 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
}
}
};
+
+ @observable _props: React.PropsWithChildren<TabMinimapViewProps>;
+ constructor(props: React.PropsWithChildren<TabMinimapViewProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
@computed get renderBounds() {
- const compView = this.props.tabView()?.ComponentView as CollectionFreeFormView;
+ const compView = this._props.tabView()?.ComponentView as CollectionFreeFormView;
const bounds = compView?.freeformData?.(true)?.bounds;
if (!bounds) return undefined;
const xbounds = bounds.r - bounds.x;
@@ -556,10 +571,10 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
const dim = Math.max(xbounds, ybounds);
return { l: bounds.x + xbounds / 2 - dim / 2, t: bounds.y + ybounds / 2 - dim / 2, cx: bounds.x + xbounds / 2, cy: bounds.y + ybounds / 2, dim };
}
- childLayoutTemplate = () => Cast(this.props.document.childLayoutTemplate, Doc, null);
- returnMiniSize = () => NumCast(this.props.document._miniMapSize, 150);
+ childLayoutTemplate = () => Cast(this._props.document.childLayoutTemplate, Doc, null);
+ returnMiniSize = () => NumCast(this._props.document._miniMapSize, 150);
miniDown = (e: React.PointerEvent) => {
- const doc = this.props.document;
+ const doc = this._props.document;
const miniSize = this.returnMiniSize();
doc &&
setupMoveUpEvents(
@@ -578,15 +593,15 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
popup = () => {
if (!this.renderBounds) return <></>;
const renderBounds = this.renderBounds;
- const miniWidth = () => (this.props.PanelWidth() / NumCast(this.props.document._freeform_scale, 1) / renderBounds.dim) * 100;
- const miniHeight = () => (this.props.PanelHeight() / NumCast(this.props.document._freeform_scale, 1) / renderBounds.dim) * 100;
- const miniLeft = () => 50 + ((NumCast(this.props.document._freeform_panX) - renderBounds.cx) / renderBounds.dim) * 100 - miniWidth() / 2;
- const miniTop = () => 50 + ((NumCast(this.props.document._freeform_panY) - renderBounds.cy) / renderBounds.dim) * 100 - miniHeight() / 2;
+ const miniWidth = () => (this._props.PanelWidth() / NumCast(this._props.document._freeform_scale, 1) / renderBounds.dim) * 100;
+ const miniHeight = () => (this._props.PanelHeight() / NumCast(this._props.document._freeform_scale, 1) / renderBounds.dim) * 100;
+ const miniLeft = () => 50 + ((NumCast(this._props.document._freeform_panX) - renderBounds.cx) / renderBounds.dim) * 100 - miniWidth() / 2;
+ const miniTop = () => 50 + ((NumCast(this._props.document._freeform_panY) - renderBounds.cy) / renderBounds.dim) * 100 - miniHeight() / 2;
const miniSize = this.returnMiniSize();
return (
- <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
+ <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this._props.background() }}>
<CollectionFreeFormView
- Document={this.props.document}
+ Document={this._props.document}
docViewPath={returnEmptyDoclist}
childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
noOverlay={true} // don't render overlay Docs since they won't scale
@@ -596,7 +611,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
select={emptyFunction}
isSelected={returnFalse}
dontRegisterView={true}
- fieldKey={Doc.LayoutFieldKey(this.props.document)}
+ fieldKey={Doc.LayoutFieldKey(this._props.document)}
bringToFront={emptyFunction}
addDocument={returnFalse}
moveDocument={returnFalse}
@@ -608,7 +623,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
whenChildContentsActiveChanged={emptyFunction}
focus={emptyFunction}
styleProvider={TabMinimapView.miniStyleProvider}
- addDocTab={this.props.addDocTab}
+ addDocTab={this._props.addDocTab}
pinToPres={TabDocView.PinDoc}
childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
@@ -622,7 +637,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
);
};
render() {
- return this.props.document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this.props.document)) || this.props.document?._type_collection !== CollectionViewType.Freeform ? null : (
+ return this._props.document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._props.document)) || this._props.document?._type_collection !== CollectionViewType.Freeform ? null : (
<div className="miniMap-hidden">
<Popup icon={<FontAwesomeIcon icon="globe-asia" size="lg" />} color={SettingsManager.userVariantColor} type={Type.TERT} onPointerDown={e => e.stopPropagation()} placement={'top-end'} popup={this.popup} />
</div>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ac79e4fef..27ff7166d 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,7 +1,7 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconButton, Size } from 'browndash-components';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
@@ -12,7 +12,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { copyProps, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
@@ -44,7 +44,7 @@ export interface TreeViewProps {
observeHeight: (ref: any) => void;
unobserveHeight: (ref: any) => void;
prevSibling?: Doc;
- document: Doc;
+ Document: Doc;
dataDoc?: Doc;
treeViewParent: Doc;
renderDepth: number;
@@ -100,57 +100,61 @@ export class TreeView extends React.Component<TreeViewProps> {
private _treedropDisposer?: DragManager.DragDropDisposer;
get treeViewOpenIsTransient() {
- return this.props.treeView.doc.treeView_OpenIsTransient || Doc.IsDataProto(this.doc);
+ return this.treeView.Document.treeView_OpenIsTransient || Doc.IsDataProto(this.Document);
}
set treeViewOpen(c: boolean) {
if (this.treeViewOpenIsTransient) this._transientOpenState = c;
else {
- this.doc.treeView_Open = c;
+ this.Document.treeView_Open = c;
this._transientOpenState = false;
}
}
@observable _transientOpenState = false; // override of the treeView_Open field allowing the display state to be independent of the document's state
@observable _editTitle: boolean = false;
- @observable _dref: DocumentView | undefined | null;
+ @observable _dref: DocumentView | undefined | null = undefined;
get displayName() {
- return 'TreeView(' + this.props.document.title + ')';
+ return 'TreeView(' + this.Document.title + ')';
} // this makes mobx trace() statements more descriptive
get defaultExpandedView() {
- return this.doc._type_collection === CollectionViewType.Docking
+ return this.Document._type_collection === CollectionViewType.Docking
? this.fieldKey
- : this.props.treeView.dashboardMode
+ : this.treeView.dashboardMode
? this.fieldKey
- : this.props.treeView.fileSysMode
- ? this.doc.isFolder
+ : this.treeView.fileSysMode
+ ? this.Document.isFolder
? this.fieldKey
: 'data' // file system folders display their contents (data). used to be they displayed their embeddings but now its a tree structure and not a flat list
- : this.props.treeView.outlineMode || this.childDocs
+ : this.treeView.outlineMode || this.childDocs
? this.fieldKey
: Doc.noviceMode
? 'layout'
- : StrCast(this.props.treeView.doc.treeView_ExpandedView, 'fields');
+ : StrCast(this.treeView.Document.treeView_ExpandedView, 'fields');
}
- @computed get doc() {
- return this.props.document;
+ @computed get treeView() {
+ return this._props.treeView;
+ }
+
+ @computed get Document() {
+ return this._props.Document;
}
@computed get treeViewOpen() {
- return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeView_Open', 'boolean', true)) || this._transientOpenState;
+ return (!this.treeViewOpenIsTransient && Doc.GetT(this.Document, 'treeView_Open', 'boolean', true)) || this._transientOpenState;
}
@computed get treeViewExpandedView() {
- return this.validExpandViewTypes.includes(StrCast(this.doc.treeView_ExpandedView)) ? StrCast(this.doc.treeView_ExpandedView) : this.defaultExpandedView;
+ return this.validExpandViewTypes.includes(StrCast(this.Document.treeView_ExpandedView)) ? StrCast(this.Document.treeView_ExpandedView) : this.defaultExpandedView;
}
@computed get MAX_EMBED_HEIGHT() {
- return NumCast(this.props.treeViewParent.maxEmbedHeight, 200);
+ return NumCast(this._props.treeViewParent.maxEmbedHeight, 200);
}
@computed get dataDoc() {
- return this.doc[DocData];
+ return this.Document[DocData];
}
@computed get layoutDoc() {
- return Doc.Layout(this.doc);
+ return Doc.Layout(this.Document);
}
@computed get fieldKey() {
- return StrCast(this.doc._treeView_FieldKey, Doc.LayoutFieldKey(this.doc));
+ return StrCast(this.Document._treeView_FieldKey, Doc.LayoutFieldKey(this.Document));
}
@computed get childDocs() {
return this.childDocList(this.fieldKey);
@@ -169,30 +173,30 @@ export class TreeView extends React.Component<TreeViewProps> {
}
childDocList(field: string) {
- const layout = Cast(Doc.LayoutField(this.doc), Doc, null);
- return DocListCast(this.props.dataDoc?.[field], DocListCast(layout?.[field], DocListCast(this.doc[field])));
+ const layout = Cast(Doc.LayoutField(this.Document), Doc, null);
+ return DocListCast(this._props.dataDoc?.[field], DocListCast(layout?.[field], DocListCast(this.Document[field])));
}
moving: boolean = false;
@undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
- if (this.doc !== target && addDoc !== returnFalse) {
- const canAdd1 = (this.props.parentTreeView as any).dropping || !(ComputedField.WithoutComputed(() => FieldValue(this.props.parentTreeView?.doc.data)) instanceof ComputedField);
+ if (this.Document !== target && addDoc !== returnFalse) {
+ const canAdd1 = (this._props.parentTreeView as any).dropping || !(ComputedField.WithoutComputed(() => FieldValue(this._props.parentTreeView?.Document.data)) instanceof ComputedField);
// bcz: this should all be running in a Temp undo batch instead of hackily testing for returnFalse
- if (canAdd1 && this.props.removeDoc?.(doc) === true) {
- this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.moving = true);
+ if (canAdd1 && this._props.removeDoc?.(doc) === true) {
+ this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.moving = true);
const res = addDoc(doc);
- this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.moving = false);
+ this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.moving = false);
return res;
}
}
return false;
};
- @undoBatch @action remove = (doc: Doc | Doc[], key: string) => {
- this.props.treeView.props.select(false);
+ @undoBatch remove = (doc: Doc | Doc[], key: string) => {
+ this.treeView._props.select(false);
const ind = DocListCast(this.dataDoc[key]).indexOf(doc instanceof Doc ? doc : doc.lastElement());
const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
- res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
+ res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView._props.DocumentView?.())?.select(false);
return res;
};
@@ -212,17 +216,16 @@ export class TreeView extends React.Component<TreeViewProps> {
};
@action
openLevel = (docView: DocumentView) => {
- if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
+ if (this.Document.isFolder || Doc.IsSystem(this.Document)) {
this.treeViewOpen = !this.treeViewOpen;
} else {
// choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns, (2) has no context field ... otherwise make a new embedding
- const bestEmbedding = docView.Document.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document) ? docView.Document : Doc.BestEmbedding(docView.Document);
- this.props.addDocTab(bestEmbedding, OpenWhere.lightbox);
+ const bestEmbedding = docView.Document.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.Document) ? docView.Document : Doc.BestEmbedding(docView.Document);
+ this._props.addDocTab(bestEmbedding, OpenWhere.lightbox);
}
};
@undoBatch
- @action
recurToggle = (childList: Doc[]) => {
if (childList.length > 0) {
childList.forEach(child => {
@@ -233,7 +236,6 @@ export class TreeView extends React.Component<TreeViewProps> {
};
@undoBatch
- @action
getRunningChildren = (childList: Doc[]) => {
if (childList.length === 0) {
return [];
@@ -253,23 +255,27 @@ export class TreeView extends React.Component<TreeViewProps> {
static GetRunningChildren = new Map<Doc, any>();
static ToggleChildrenRun = new Map<Doc, () => void>();
- constructor(props: any) {
+ _prevProps: TreeViewProps;
+ @observable _props: TreeViewProps;
+ constructor(props: TreeViewProps) {
super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
if (!TreeView._openLevelScript) {
TreeView._openTitleScript = ScriptField.MakeScript('scriptContext.setEditTitle(documentView)', { scriptContext: 'any', documentView: 'any' });
TreeView._openLevelScript = ScriptField.MakeScript(`scriptContext.openLevel(documentView)`, { scriptContext: 'any', documentView: 'any' });
}
- this._openScript = Doc.IsSystem(this.props.document) ? undefined : () => TreeView._openLevelScript!;
- this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
+ this._openScript = Doc.IsSystem(this.Document) ? undefined : () => TreeView._openLevelScript!;
+ this._editTitleScript = Doc.IsSystem(this.Document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
// set for child processing highligting
this.dataDoc.hasChildren = this.childDocs.length > 0;
// this.dataDoc.children = this.childDocs;
- TreeView.ToggleChildrenRun.set(this.doc, () => {
+ TreeView.ToggleChildrenRun.set(this.Document, () => {
this.recurToggle(this.childDocs);
});
- TreeView.GetRunningChildren.set(this.doc, () => {
+ TreeView.GetRunningChildren.set(this.Document, () => {
return this.getRunningChildren(this.childDocs);
});
}
@@ -277,31 +283,32 @@ export class TreeView extends React.Component<TreeViewProps> {
_treeEle: any;
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.doc);
- if (this._treeEle) this.props.unobserveHeight(this._treeEle);
- this.props.observeHeight((this._treeEle = ele));
+ ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.Document);
+ if (this._treeEle) this._props.unobserveHeight(this._treeEle);
+ this._props.observeHeight((this._treeEle = ele));
};
componentWillUnmount() {
this._renderTimer && clearTimeout(this._renderTimer);
Object.values(this._disposers).forEach(disposer => disposer?.());
- this._treeEle && this.props.unobserveHeight(this._treeEle);
+ this._treeEle && this._props.unobserveHeight(this._treeEle);
document.removeEventListener('pointermove', this.onDragMove, true);
document.removeEventListener('pointermove', this.onDragUp, true);
// TODO: [AL] add these
- this.props.hierarchyIndex !== undefined && this.props.RemFromMap?.(this.doc, this.props.hierarchyIndex);
+ this._props.hierarchyIndex !== undefined && this._props.RemFromMap?.(this.Document, this._props.hierarchyIndex);
}
componentDidUpdate() {
+ copyProps(this);
this._disposers.opening = reaction(
() => this.treeViewOpen,
open => !open && (this._renderCount = 20)
);
- this.props.hierarchyIndex !== undefined && this.props.AddToMap?.(this.doc, this.props.hierarchyIndex);
+ this._props.hierarchyIndex !== undefined && this._props.AddToMap?.(this.Document, this._props.hierarchyIndex);
}
componentDidMount() {
- this.props.hierarchyIndex !== undefined && this.props.AddToMap?.(this.doc, this.props.hierarchyIndex);
+ this._props.hierarchyIndex !== undefined && this._props.AddToMap?.(this.Document, this._props.hierarchyIndex);
}
onDragUp = (e: PointerEvent) => {
@@ -309,8 +316,8 @@ export class TreeView extends React.Component<TreeViewProps> {
document.removeEventListener('pointermove', this.onDragMove, true);
};
onPointerEnter = (e: React.PointerEvent): void => {
- this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
- if (e.buttons === 1 && SnappingManager.GetIsDragging() && this.props.isContentActive()) {
+ this._props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
+ if (e.buttons === 1 && SnappingManager.GetIsDragging() && this._props.isContentActive()) {
this._header.current!.className = 'treeView-header';
document.removeEventListener('pointermove', this.onDragMove, true);
document.removeEventListener('pointerup', this.onDragUp, true);
@@ -333,7 +340,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const before = pt[1] < rect.top + rect.height / 2;
const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length);
this._header.current!.className = 'treeView-header';
- if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.Document) {
+ if (!this.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.treeView.Document) {
if (inside) this._header.current!.className += ' treeView-header-inside';
else if (before) this._header.current!.className += ' treeView-header-above';
else if (!before) this._header.current!.className += ' treeView-header-below';
@@ -371,18 +378,18 @@ export class TreeView extends React.Component<TreeViewProps> {
makeTextCollection = () => {
const bullet = TreeView.makeTextBullet();
TreeView._editTitleOnLoad = { id: bullet[Id], parent: this };
- return this.props.addDocument(bullet);
+ return this._props.addDocument(bullet);
};
makeFolder = () => {
const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true });
- TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
- return this.props.addDocument(folder);
+ TreeView._editTitleOnLoad = { id: folder[Id], parent: this._props.parentTreeView };
+ return this._props.addDocument(folder);
};
preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
const dragData = de.complete.docDragData;
- dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
+ dragData && (dragData.dropAction = this.treeView.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
};
@undoBatch
@@ -391,17 +398,17 @@ export class TreeView extends React.Component<TreeViewProps> {
if (!this._header.current) return false;
const rect = this._header.current.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
- const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
+ const inside = this.treeView.fileSysMode && !this.Document.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
if (de.complete.linkDragData) {
const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
- const destDoc = this.doc;
+ const destDoc = this.Document;
DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' });
e.stopPropagation();
return true;
}
const docDragData = de.complete.docDragData;
if (docDragData && pt[0] < rect.left + rect.width) {
- if (docDragData.draggedDocuments[0] === this.doc) return true;
+ if (docDragData.draggedDocuments[0] === this.Document) return true;
const added = this.dropDocuments(
docDragData.droppedDocuments, //
before,
@@ -409,7 +416,7 @@ export class TreeView extends React.Component<TreeViewProps> {
docDragData.dropAction,
docDragData.removeDocument,
docDragData.moveDocument,
- docDragData.treeViewDoc === this.props.treeView.props.Document
+ docDragData.treeViewDoc === this.treeView.Document
);
e.stopPropagation();
!added && e.preventDefault();
@@ -420,40 +427,40 @@ export class TreeView extends React.Component<TreeViewProps> {
dropping: boolean = false;
dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
- const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, undefined, before);
+ const parentAddDoc = (doc: Doc | Doc[]) => this._props.addDocument(doc, undefined, undefined, before);
const localAdd = (doc: Doc | Doc[]) => {
const innerAdd = (doc: Doc) => {
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc);
- dataIsComputed && Doc.SetContainer(doc, DocCast(this.doc.embedContainer));
+ dataIsComputed && Doc.SetContainer(doc, DocCast(this.Document.embedContainer));
return added;
};
return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
};
const addDoc = inside ? localAdd : parentAddDoc;
const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
- const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
- if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this.props.parentTreeView?.doc))) {
- this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
+ const canAdd = (!this.treeView.outlineMode && !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
+ if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) {
+ this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true);
const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
- this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = false);
+ this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false);
return res;
}
return false;
}
refTransform = (ref: HTMLDivElement | undefined | null) => {
- if (!ref) return this.props.ScreenToLocalTransform();
+ if (!ref) return this._props.ScreenToLocalTransform();
const { scale, translateX, translateY } = Utils.GetScreenTransform(ref);
- const outerXf = Utils.GetScreenTransform(this.props.treeView.MainEle());
- const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
- return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
+ const outerXf = Utils.GetScreenTransform(this.treeView.MainEle());
+ const offset = this._props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
+ return this._props.ScreenToLocalTransform().translate(offset[0], offset[1]);
};
docTransform = () => this.refTransform(this._dref?.ContentRef?.current);
getTransform = () => this.refTransform(this._tref.current);
- embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1);
+ embeddedPanelWidth = () => this._props.panelWidth() / (this.treeView._props.NativeDimScaling?.() || 1);
embeddedPanelHeight = () => {
- const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+ const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.Document))(this.treeView._props.childLayoutTemplate?.()) || this.layoutDoc;
return Math.min(
NumCast(layoutDoc._height),
this.MAX_EMBED_HEIGHT,
@@ -463,7 +470,7 @@ export class TreeView extends React.Component<TreeViewProps> {
return layoutDoc._layout_fitWidth
? !Doc.NativeHeight(layoutDoc)
? NumCast(layoutDoc._height)
- : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
+ : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this._props.treeViewParent._height)))
: (this.embeddedPanelWidth() * NumCast(layoutDoc._height)) / NumCast(layoutDoc._width);
})()
);
@@ -471,16 +478,16 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get expandedField() {
const ids: { [key: string]: string } = {};
const rows: JSX.Element[] = [];
- const doc = this.doc;
+ const doc = this.Document;
doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
for (const key of Object.keys(ids).slice().sort()) {
- if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeView_Open') continue;
+ if (this._props.skipFields?.includes(key) || key === 'title' || key === 'treeView_Open') continue;
const contents = doc[key];
let contentElement: (JSX.Element | null)[] | JSX.Element = [];
let leftOffset = observable({ width: 0 });
- const expandedWidth = () => this.props.panelWidth() - leftOffset.width;
+ const expandedWidth = () => this._props.panelWidth() - leftOffset.width;
if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
const moveDoc = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.move(doc, target, addDoc);
@@ -488,44 +495,44 @@ export class TreeView extends React.Component<TreeViewProps> {
const innerAdd = (doc: Doc) => {
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
- dataIsComputed && Doc.SetContainer(doc, DocCast(this.doc.embedContainer));
+ dataIsComputed && Doc.SetContainer(doc, DocCast(this.Document.embedContainer));
return added;
};
return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
};
contentElement = TreeView.GetChildElements(
contents instanceof Doc ? [contents] : DocListCast(contents),
- this.props.treeView,
+ this.treeView,
this,
doc,
undefined,
- this.props.treeViewParent,
- this.props.prevSibling,
+ this._props.treeViewParent,
+ this._props.prevSibling,
addDoc,
remDoc,
moveDoc,
- this.props.dragAction,
- this.props.addDocTab,
+ this._props.dragAction,
+ this._props.addDocTab,
this.titleStyleProvider,
- this.props.ScreenToLocalTransform,
- this.props.isContentActive,
+ this._props.ScreenToLocalTransform,
+ this._props.isContentActive,
expandedWidth,
- this.props.renderDepth,
- this.props.treeViewHideHeaderFields,
- [...this.props.renderedIds, doc[Id]],
- this.props.onCheckedClick,
- this.props.onChildClick,
- this.props.skipFields,
+ this._props.renderDepth,
+ this._props.treeViewHideHeaderFields,
+ [...this._props.renderedIds, doc[Id]],
+ this._props.onCheckedClick,
+ this._props.onChildClick,
+ this._props.skipFields,
false,
- this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView,
+ this._props.whenChildContentsActiveChanged,
+ this._props.dontRegisterView,
emptyFunction,
emptyFunction,
this.childContextMenuItems(),
// TODO: [AL] Add these
- this.props.AddToMap,
- this.props.RemFromMap,
- this.props.hierarchyIndex
+ this._props.AddToMap,
+ this._props.RemFromMap,
+ this._props.hierarchyIndex
);
} else {
contentElement = (
@@ -573,9 +580,9 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderContent() {
TraceMobx();
const expandKey = this.treeViewExpandedView;
- const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {};
+ const sortings = (this._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {};
if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) {
- const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.WhenAdded);
+ const sorting = StrCast(this.Document.treeView_SortCriterion, TreeSort.WhenAdded);
const sortKeys = Object.keys(sortings);
const curSortIndex = Math.max(
0,
@@ -587,7 +594,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
// if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
// then the modification would be done here
- const ordering = StrCast(this.doc.treeView_SortCriterion);
+ const ordering = StrCast(this.Document.treeView_SortCriterion);
if (ordering === TreeSort.Zindex) {
const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
@@ -596,7 +603,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
- !dataIsComputed && added && Doc.SetContainer(doc, this.doc);
+ !dataIsComputed && added && Doc.SetContainer(doc, this.Document);
return added;
};
@@ -614,12 +621,12 @@ export class TreeView extends React.Component<TreeViewProps> {
}
return (
<div>
- {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : (
+ {!docs?.length || this._props.AddToMap /* hack to identify pres box trees */ ? null : (
<div className="treeView-sorting">
<IconButton
color={sortings[sorting]?.color}
size={Size.XSMALL}
- tooltip={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`}
+ tooltip={`Sorted by : ${this.Document.treeView_SortCriterion}. click to cycle`}
icon={sortings[sorting]?.icon}
onPointerDown={e => {
downX = e.clientX;
@@ -627,8 +634,8 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
}}
onClick={undoable(e => {
- if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
- !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
+ if (this._props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
+ !this.treeView.outlineMode && (this.Document.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
e.stopPropagation();
}
}, 'sort order')}
@@ -638,7 +645,7 @@ export class TreeView extends React.Component<TreeViewProps> {
<ul
style={{ cursor: 'inherit' }}
key={expandKey + 'more'}
- title={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`}
+ title={`Sorted by : ${this.Document.treeView_SortCriterion}. click to cycle`}
className="" //this.doc.treeView_HideTitle ? 'no-indent' : ''}
onPointerDown={e => {
downX = e.clientX;
@@ -646,8 +653,8 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
}}
onClick={undoable(e => {
- if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
- !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
+ if (this._props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
+ !this.treeView.outlineMode && (this.Document.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
e.stopPropagation();
}
}, 'sort order')}>
@@ -655,37 +662,37 @@ export class TreeView extends React.Component<TreeViewProps> {
? null
: TreeView.GetChildElements(
docs,
- this.props.treeView,
+ this.treeView,
this,
this.layoutDoc,
this.dataDoc,
- this.props.treeViewParent,
- this.props.prevSibling,
+ this._props.treeViewParent,
+ this._props.prevSibling,
addDoc,
remDoc,
moveDoc,
- StrCast(this.doc.childDragAction, this.props.dragAction) as dropActionType,
- this.props.addDocTab,
+ StrCast(this.Document.childDragAction, this._props.dragAction) as dropActionType,
+ this._props.addDocTab,
this.titleStyleProvider,
- this.props.ScreenToLocalTransform,
- this.props.isContentActive,
- this.props.panelWidth,
- this.props.renderDepth,
- this.props.treeViewHideHeaderFields,
- [...this.props.renderedIds, this.doc[Id]],
- this.props.onCheckedClick,
- this.props.onChildClick,
- this.props.skipFields,
+ this._props.ScreenToLocalTransform,
+ this._props.isContentActive,
+ this._props.panelWidth,
+ this._props.renderDepth,
+ this._props.treeViewHideHeaderFields,
+ [...this._props.renderedIds, this.Document[Id]],
+ this._props.onCheckedClick,
+ this._props.onChildClick,
+ this._props.skipFields,
false,
- this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView,
+ this._props.whenChildContentsActiveChanged,
+ this._props.dontRegisterView,
emptyFunction,
emptyFunction,
this.childContextMenuItems(),
// TODO: [AL] add these
- this.props.AddToMap,
- this.props.RemFromMap,
- this.props.hierarchyIndex,
+ this._props.AddToMap,
+ this._props.RemFromMap,
+ this._props.hierarchyIndex,
this._renderCount
)}
</ul>
@@ -693,7 +700,7 @@ export class TreeView extends React.Component<TreeViewProps> {
);
} else if (this.treeViewExpandedView === 'fields') {
return (
- <ul key={this.doc[Id] + this.doc.title} style={{ cursor: 'inherit' }}>
+ <ul key={this.Document[Id] + this.Document.title} style={{ cursor: 'inherit' }}>
<div>{this.expandedField}</div>
</ul>
);
@@ -705,13 +712,13 @@ export class TreeView extends React.Component<TreeViewProps> {
e.preventDefault();
e.stopPropagation();
}}>
- {this.renderEmbeddedDocument(false, this.props.treeView.props.childDocumentsActive ?? returnFalse)}
+ {this.renderEmbeddedDocument(false, this.treeView._props.childDocumentsActive ?? returnFalse)}
</ul>
); // "layout"
}
get onCheckedClick() {
- return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick);
+ return this.Document.type === DocumentType.COL ? undefined : this._props.onCheckedClick?.() ?? ScriptCast(this.Document.onCheckedClick);
}
@action
@@ -719,10 +726,10 @@ export class TreeView extends React.Component<TreeViewProps> {
if (this.onCheckedClick) {
this.onCheckedClick?.script.run(
{
- this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
- heading: this.props.treeViewParent.title,
- checked: this.doc.treeView_Checked === 'check' ? 'x' : this.doc.treeView_Checked === 'x' ? 'remove' : 'check',
- containingTreeView: this.props.treeView.props.Document,
+ this: this.Document.isTemplateForField && this._props.dataDoc ? this._props.dataDoc : this.Document,
+ heading: this._props.treeViewParent.title,
+ checked: this.Document.treeView_Checked === 'check' ? 'x' : this.Document.treeView_Checked === 'x' ? 'remove' : 'check',
+ containingTreeView: this.treeView.Document,
},
console.log
);
@@ -734,28 +741,28 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderBullet() {
TraceMobx();
- const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question';
+ const iconType = this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question';
const color = SettingsManager.userColor;
- const checked = this.onCheckedClick ? this.doc.treeView_Checked ?? 'unchecked' : undefined;
+ const checked = this.onCheckedClick ? this.Document.treeView_Checked ?? 'unchecked' : undefined;
return (
<div
- className={`bullet${this.props.treeView.outlineMode ? '-outline' : ''}`}
+ className={`bullet${this.treeView.outlineMode ? '-outline' : ''}`}
key="bullet"
- title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : `view ${this.props.document.type} content`}
+ title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : `view ${this.Document.type} content`}
onClick={this.bulletClick}
style={
- this.props.treeView.outlineMode
+ this.treeView.outlineMode
? {
- opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity),
+ opacity: this.titleStyleProvider?.(this.Document, this.treeView._props, StyleProp.Opacity),
}
: {
- pointerEvents: this.props.isContentActive() ? 'all' : undefined,
+ pointerEvents: this._props.isContentActive() ? 'all' : undefined,
opacity: checked === 'unchecked' || typeof iconType !== 'string' ? undefined : 0.4,
color: checked === 'unchecked' ? SettingsManager.userColor : 'inherit',
}
}>
- {this.props.treeView.outlineMode ? (
- !(this.doc.text as RichTextField)?.Text ? null : (
+ {this.treeView.outlineMode ? (
+ !(this.Document.text as RichTextField)?.Text ? null : (
<IconButton color={color} icon={<FontAwesomeIcon icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />} size={Size.XSMALL} />
)
) : (
@@ -775,28 +782,28 @@ export class TreeView extends React.Component<TreeViewProps> {
}
@computed get validExpandViewTypes() {
- const annos = () => (DocListCast(this.doc[this.fieldKey + '_annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : '');
- const links = () => (LinkManager.Links(this.doc).length && !this.props.treeView.dashboardMode ? 'links' : '');
- const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
- const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings');
+ const annos = () => (DocListCast(this.Document[this.fieldKey + '_annotations']).length && !this.treeView.dashboardMode ? 'annotations' : '');
+ const links = () => (LinkManager.Links(this.Document).length && !this.treeView.dashboardMode ? 'links' : '');
+ const data = () => (this.childDocs || this.treeView.dashboardMode ? this.fieldKey : '');
+ const embeddings = () => (this.treeView.dashboardMode ? '' : 'embeddings');
const fields = () => (Doc.noviceMode ? '' : 'fields');
- const layout = Doc.noviceMode || this.doc._type_collection === CollectionViewType.Docking ? [] : ['layout'];
- return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
+ const layout = Doc.noviceMode || this.Document._type_collection === CollectionViewType.Docking ? [] : ['layout'];
+ return [data(), ...layout, ...(this.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
}
@action
expandNextviewType = () => {
- if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeView_ExpandedViewLock) {
+ if (this.treeViewOpen && !this.Document.isFolder && !this.treeView.outlineMode && !this.Document.treeView_ExpandedViewLock) {
const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length];
- this.doc.treeView_ExpandedView = next(this.validExpandViewTypes);
+ this.Document.treeView_ExpandedView = next(this.validExpandViewTypes);
}
this.treeViewOpen = true;
};
@observable headerEleWidth = 0;
@computed get titleButtons() {
- const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations);
+ const customHeaderButtons = this._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.Decorations);
const color = SettingsManager.userColor;
- return this.props.treeViewHideHeaderFields() || this.doc.treeView_HideHeaderFields ? null : (
+ return this._props.treeViewHideHeaderFields() || this.Document.treeView_HideHeaderFields ? null : (
<>
{customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
<IconButton
@@ -808,7 +815,7 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
}}
/>
- {Doc.noviceMode ? null : this.doc.treeView_ExpandedViewLock || Doc.IsSystem(this.doc) ? null : (
+ {Doc.noviceMode ? null : this.Document.treeView_ExpandedViewLock || Doc.IsSystem(this.Document) ? null : (
<span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}>
{this.treeViewExpandedView}
</span>
@@ -829,50 +836,50 @@ export class TreeView extends React.Component<TreeViewProps> {
const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(this)`)!, icon: 'eye', label: 'Focus or Open' };
const reopenDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(this)`)!, icon: 'eye', label: 'Reopen' };
return [
- ...(this.props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result)),
- ...(this.doc.isFolder
+ ...(this._props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.Document })?.result)),
+ ...(this.Document.isFolder
? folderOp
- : Doc.IsSystem(this.doc)
+ : Doc.IsSystem(this.Document)
? []
- : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
+ : this.treeView.fileSysMode && this.Document === Doc.GetProto(this.Document)
? [openEmbedding, makeFolder]
- : this.doc._type_collection === CollectionViewType.Docking
+ : this.Document._type_collection === CollectionViewType.Docking
? []
- : this.props.treeView.Document === Doc.MyRecentlyClosed
+ : this.treeView.Document === Doc.MyRecentlyClosed
? [reopenDoc]
: [openEmbedding, focusDoc]),
];
};
childContextMenuItems = () => {
- const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
- const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
- const icons = StrListCast(this.doc.childContextMenuIcons);
- return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
+ const customScripts = Cast(this.Document.childContextMenuScripts, listSpec(ScriptField), []);
+ const customFilters = Cast(this.Document.childContextMenuFilters, listSpec(ScriptField), []);
+ const icons = StrListCast(this.Document.childContextMenuIcons);
+ return StrListCast(this.Document.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
};
- onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(this)`)!);
+ onChildClick = () => this._props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(this)`)!);
- onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeView_ChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null);
+ onChildDoubleClick = () => ScriptCast(this.treeView.Document.treeView_ChildDoubleClick, !this.treeView.outlineMode ? this._openScript?.() : null);
- refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document, {});
+ refocus = () => this.treeView._props.focus(this.treeView.Document, {});
ignoreEvent = (e: any) => {
- if (this.props.isContentActive(true)) {
+ if (this._props.isContentActive(true)) {
e.stopPropagation();
e.preventDefault();
}
};
titleStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
- if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
+ if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
- const treeView = this.props.treeView;
+ const treeView = this.treeView;
// prettier-ignore
switch (property.split(':')[0]) {
- case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1;
+ case StyleProp.Opacity: return this.treeView.outlineMode ? undefined : 1;
case StyleProp.BackgroundColor: return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
- case StyleProp.Highlighting: if (this.props.treeView.outlineMode) return undefined;
+ case StyleProp.Highlighting: if (this.treeView.outlineMode) return undefined;
case StyleProp.BoxShadow: return undefined;
case StyleProp.DocContents:
- const highlightIndex = this.props.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.GetBrushHighlightStatus(doc);
+ const highlightIndex = this.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.GetBrushHighlightStatus(doc);
const highlightColor = ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
return treeView.outlineMode ? null : (
<div
@@ -882,32 +889,32 @@ export class TreeView extends React.Component<TreeViewProps> {
maxWidth: props?.PanelWidth() || undefined,
background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor),
outline: SnappingManager.GetIsDragging() ? undefined: `solid ${highlightColor} ${highlightIndex}px`,
- paddingLeft: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)),
- paddingRight: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)),
- paddingTop: treeView.props.childYPadding,
- paddingBottom: treeView.props.childYPadding,
+ paddingLeft: NumCast(treeView.Document.childXPadding, NumCast(treeView._props.childXPadding, Doc.IsComicStyle(doc)?20:0)),
+ paddingRight: NumCast(treeView.Document.childXPadding, NumCast(treeView._props.childXPadding, Doc.IsComicStyle(doc)?20:0)),
+ paddingTop: treeView._props.childYPadding,
+ paddingBottom: treeView._props.childYPadding,
}}>
{StrCast(doc?.title)}
</div>
);
}
- return treeView.props.styleProvider?.(doc, props, property);
+ return treeView._props.styleProvider?.(doc, props, property);
};
embeddedStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (property.startsWith(StyleProp.Decorations)) return null;
- return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
+ return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
};
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- if (this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) {
+ if (this.Document.treeView_HideHeader || (this.Document.treeView_HideHeaderIfTemplate && this.treeView._props.childLayoutTemplate?.()) || this.treeView.outlineMode) {
switch (e.key) {
case 'Tab':
e.stopPropagation?.();
e.preventDefault?.();
setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
- UndoManager.RunInBatch(() => (e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true)), 'tab');
+ UndoManager.RunInBatch(() => (e.shiftKey ? this._props.outdentDocument?.(true) : this._props.indentDocument?.(true)), 'tab');
return true;
case 'Backspace':
- if (!(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc)) {
+ if (!(this.Document.text as RichTextField)?.Text && this._props.removeDoc?.(this.Document)) {
e.stopPropagation?.();
e.preventDefault?.();
return true;
@@ -921,7 +928,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
return false;
};
- titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - this.headerEleWidth - treeBulletWidth();
+ titleWidth = () => Math.max(20, Math.min(this.treeView.truncateTitleWidth(), this._props.panelWidth())) / (this.treeView._props.NativeDimScaling?.() || 1) - this.headerEleWidth - treeBulletWidth();
/**
* Renders the EditableView title element for placement into the tree.
@@ -936,21 +943,21 @@ export class TreeView extends React.Component<TreeViewProps> {
display={'inline-block'}
editing={this._editTitle}
background={'#7089bb'}
- contents={StrCast(this.doc.title)}
+ contents={StrCast(this.Document.title)}
height={12}
sizeToContent={true}
fontSize={12}
isEditingCallback={action(e => (this._editTitle = e))}
- GetValue={() => StrCast(this.doc.title)}
+ GetValue={() => StrCast(this.Document.title)}
OnTab={undoBatch((shift?: boolean) => {
- if (!shift) this.props.indentDocument?.(true);
- else this.props.outdentDocument?.(true);
+ if (!shift) this._props.indentDocument?.(true);
+ else this._props.outdentDocument?.(true);
})}
- OnEmpty={undoBatch(() => this.props.treeView.outlineMode && this.props.removeDoc?.(this.doc))}
- OnFillDown={val => this.props.treeView.fileSysMode && this.makeFolder()}
+ OnEmpty={undoBatch(() => this.treeView.outlineMode && this._props.removeDoc?.(this.Document))}
+ OnFillDown={val => this.treeView.fileSysMode && this.makeFolder()}
SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
- Doc.SetInPlace(this.doc, 'title', value, false);
- this.props.treeView.outlineMode && enterKey && this.makeTextCollection();
+ Doc.SetInPlace(this.Document, 'title', value, false);
+ this.treeView.outlineMode && enterKey && this.makeTextCollection();
})}
/>
) : (
@@ -958,29 +965,29 @@ export class TreeView extends React.Component<TreeViewProps> {
key="title"
ref={action((r: any) => {
this._docRef = r ? r : undefined;
- if (this._docRef && TreeView._editTitleOnLoad?.id === this.props.document[Id] && TreeView._editTitleOnLoad.parent === this.props.parentTreeView) {
+ if (this._docRef && TreeView._editTitleOnLoad?.id === this.Document[Id] && TreeView._editTitleOnLoad.parent === this._props.parentTreeView) {
this._docRef.select(false);
this.setEditTitle(this._docRef);
TreeView._editTitleOnLoad = undefined;
}
})}
- Document={this.doc}
+ Document={this.Document}
layout_fitWidth={returnTrue}
scriptContext={this}
- hideDecorationTitle={this.props.treeView.outlineMode}
- hideResizeHandles={this.props.treeView.outlineMode}
+ hideDecorationTitle={this.treeView.outlineMode}
+ hideResizeHandles={this.treeView.outlineMode}
styleProvider={this.titleStyleProvider}
onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
- docViewPath={this.props.treeView.props.docViewPath}
- treeViewDoc={this.props.treeView.props.Document}
+ docViewPath={this.treeView._props.docViewPath}
+ treeViewDoc={this.treeView.Document}
addDocument={undefined}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.treeView.props.pinToPres}
+ addDocTab={this._props.addDocTab}
+ pinToPres={this.treeView._props.pinToPres}
onClick={this.onChildClick}
onDoubleClick={this.onChildDoubleClick}
- dragAction={this.props.dragAction}
+ dragAction={this._props.dragAction}
moveDocument={this.move}
- removeDocument={this.props.removeDoc}
+ removeDocument={this._props.removeDoc}
ScreenToLocalTransform={this.getTransform}
NativeHeight={returnZero}
NativeWidth={returnZero}
@@ -988,16 +995,16 @@ export class TreeView extends React.Component<TreeViewProps> {
PanelHeight={return18}
contextMenuItems={this.contextMenuItems}
renderDepth={1}
- isContentActive={emptyFunction} //this.props.isContentActive}
- isDocumentActive={this.props.isContentActive}
+ isContentActive={emptyFunction} //this._props.isContentActive}
+ isDocumentActive={this._props.isContentActive}
focus={this.refocus}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
bringToFront={emptyFunction}
- disableBrushing={this.props.treeView.props.disableBrushing}
- hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
- dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
- xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)}
- yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
+ disableBrushing={this.treeView._props.disableBrushing}
+ hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
+ dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
+ xPadding={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
+ yPadding={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -1006,16 +1013,16 @@ export class TreeView extends React.Component<TreeViewProps> {
return (
<>
<div
- className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? '-system' : ''}`}
+ className={`docContainer${Doc.IsSystem(this.Document) || this.Document.isFolder ? '-system' : ''}`}
ref={this._tref}
title="click to edit title. Double Click or Drag to Open"
style={{
- backgroundColor: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? SettingsManager.userVariantColor : undefined,
- color: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? lightOrDark(SettingsManager.userVariantColor) : undefined,
- fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? 'bold' : undefined,
- textDecoration: Doc.GetT(this.doc, 'title', 'string', true) ? 'underline' : undefined,
- outline: this.doc === Doc.ActiveDashboard ? 'dashed 1px #06123232' : undefined,
- pointerEvents: !this.props.isContentActive() ? 'none' : undefined,
+ backgroundColor: Doc.IsSystem(this.Document) || this.Document.isFolder ? SettingsManager.userVariantColor : undefined,
+ color: Doc.IsSystem(this.Document) || this.Document.isFolder ? lightOrDark(SettingsManager.userVariantColor) : undefined,
+ fontWeight: Doc.IsSearchMatch(this.Document) !== undefined ? 'bold' : undefined,
+ textDecoration: Doc.GetT(this.Document, 'title', 'string', true) ? 'underline' : undefined,
+ outline: this.Document === Doc.ActiveDashboard ? 'dashed 1px #06123232' : undefined,
+ pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
}}>
{view}
</div>
@@ -1055,42 +1062,42 @@ export class TreeView extends React.Component<TreeViewProps> {
return (
<div style={{ height: this.embeddedPanelHeight(), width: this.embeddedPanelWidth() }}>
<DocumentView
- key={this.doc[Id]}
+ key={this.Document[Id]}
ref={action((r: DocumentView | null) => (this._dref = r))}
- Document={this.doc}
+ Document={this.Document}
layout_fitWidth={this.fitWidthFilter}
PanelWidth={this.embeddedPanelWidth}
PanelHeight={this.embeddedPanelHeight}
LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined}
- LayoutTemplate={this.props.treeView.props.childLayoutTemplate}
+ LayoutTemplate={this.treeView._props.childLayoutTemplate}
isContentActive={isActive}
isDocumentActive={isActive}
styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
hideTitle={asText}
fitContentsToBox={returnTrue}
- hideDecorationTitle={this.props.treeView.outlineMode}
- hideResizeHandles={this.props.treeView.outlineMode}
+ hideDecorationTitle={this.treeView.outlineMode}
+ hideResizeHandles={this.treeView.outlineMode}
onClick={this.onChildClick}
focus={this.refocus}
onKey={this.onKeyDown}
- hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
- dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
+ hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
+ dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
ScreenToLocalTransform={this.docTransform}
- renderDepth={this.props.renderDepth + 1}
- treeViewDoc={this.props.treeView?.props.Document}
- docViewPath={this.props.treeView.props.docViewPath}
+ renderDepth={this._props.renderDepth + 1}
+ treeViewDoc={this.treeView?.Document}
+ docViewPath={this.treeView._props.docViewPath}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
- addDocument={this.props.addDocument}
+ addDocument={this._props.addDocument}
moveDocument={this.move}
- removeDocument={this.props.removeDoc}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)}
- yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.treeView.props.pinToPres}
- disableBrushing={this.props.treeView.props.disableBrushing}
+ removeDocument={this._props.removeDoc}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ xPadding={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
+ yPadding={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
+ addDocTab={this._props.addDocTab}
+ pinToPres={this.treeView._props.pinToPres}
+ disableBrushing={this.treeView._props.disableBrushing}
bringToFront={returnFalse}
scriptContext={this}
/>
@@ -1100,7 +1107,7 @@ export class TreeView extends React.Component<TreeViewProps> {
// renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views.
@computed get renderTitleAsHeader() {
- return this.props.treeView.Document.treeView_HideUnrendered && this.doc.layout_unrendered && !this.doc.treeView_FieldKey ? (
+ return this.treeView.Document.treeView_HideUnrendered && this.Document.layout_unrendered && !this.Document.treeView_FieldKey ? (
<div></div>
) : (
<>
@@ -1115,16 +1122,16 @@ export class TreeView extends React.Component<TreeViewProps> {
return (
<>
{this.renderBullet}
- {this.renderEmbeddedDocument(asText, this.props.isContentActive)}
+ {this.renderEmbeddedDocument(asText, this._props.isContentActive)}
</>
);
};
@computed get renderBorder() {
- const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.WhenAdded);
- const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } };
+ const sorting = StrCast(this.Document.treeView_SortCriterion, TreeSort.WhenAdded);
+ const sortings = (this._props.styleProvider?.(this.Document, this.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 }}>
+ <div className={`treeView-border${this.treeView.outlineMode ? TreeViewType.outline : ''}`} style={{ borderColor: sortings[sorting]?.color }}>
{!this.treeViewOpen ? null : this.renderContent}
</div>
);
@@ -1134,28 +1141,28 @@ export class TreeView extends React.Component<TreeViewProps> {
const pt = [de.clientX, de.clientY];
const rect = this._header.current!.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
- const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
+ const inside = this.treeView.fileSysMode && !this.Document.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
- const docs = this.props.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
+ const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
};
render() {
TraceMobx();
- const hideTitle = this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode;
- 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
+ const hideTitle = this.Document.treeView_HideHeader || (this.Document.treeView_HideHeaderIfTemplate && this.treeView._props.childLayoutTemplate?.()) || this.treeView.outlineMode;
+ return this._props.renderedIds?.indexOf(this.Document[Id]) !== -1 ? (
+ '<' + this.Document.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
) : (
<div
- className={`treeView-container${this.props.isContentActive() ? '-active' : ''}`}
+ className={`treeView-container${this._props.isContentActive() ? '-active' : ''}`}
ref={this.createTreeDropTarget}
onDrop={this.onTreeDrop}
- //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
+ //onPointerDown={e => this._props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
// onKeyDown={this.onKeyDown}
>
<li className="collection-child">
- {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeView_RenderAsBulletHeader // should test for prop 'treeView_RenderDocWithBulletAsHeader"
+ {hideTitle && this.Document.type !== DocumentType.RTF && !this.Document.treeView_RenderAsBulletHeader // should test for prop 'treeView_RenderDocWithBulletAsHeader"
? this.renderEmbeddedDocument(false, returnFalse)
- : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeView_RenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
+ : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.Document.treeView_RenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
</li>
</div>
);
@@ -1231,7 +1238,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
const docs = TreeView.sortDocs(childDocs, StrCast(treeView_Parent.treeView_SortCriterion, TreeSort.WhenAdded));
- const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1);
+ const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView._props.NativeDimScaling?.() || 1);
const treeView_Refs = new Map<Doc, TreeView | undefined>();
return docs
.filter(child => child instanceof Doc)
@@ -1243,7 +1250,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => {
- if (parent instanceof TreeView && parent.props.treeView.fileSysMode && !newParent.isFolder) return;
+ if (parent instanceof TreeView && parent._props.treeView.fileSysMode && !newParent.isFolder) return;
const fieldKey = Doc.LayoutFieldKey(newParent);
if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) {
remove(child);
@@ -1255,7 +1262,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
};
const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeView_Refs.get(docs[i - 1]));
- const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
+ const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView._props.parentTreeView : undefined);
const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
const childLayout = Doc.Layout(pair.layout);
const rowHeight = () => {
@@ -1266,7 +1273,7 @@ export class TreeView extends React.Component<TreeViewProps> {
<TreeView
key={child[Id]}
ref={r => treeView_Refs.set(child, r ? r : undefined)}
- document={pair.layout}
+ Document={pair.layout}
dataDoc={pair.data}
treeViewParent={treeView_Parent}
prevSibling={docs[i]}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
index 3ba7aedef..dd7e12e41 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
@@ -1,6 +1,7 @@
-import { IReactionDisposer, reaction } from 'mobx';
+import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
+import { copyProps } from '../../../../Utils';
import './CollectionFreeFormView.scss';
/**
@@ -49,8 +50,16 @@ export interface CollectionFreeFormInfoStateProps {
export class CollectionFreeFormInfoState extends React.Component<CollectionFreeFormInfoStateProps> {
_disposers: IReactionDisposer[] = [];
+ _prevProps: React.PropsWithChildren<CollectionFreeFormInfoStateProps>;
+ @observable _props: React.PropsWithChildren<CollectionFreeFormInfoStateProps>;
+ constructor(props: React.PropsWithChildren<CollectionFreeFormInfoStateProps>) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ }
+
get State() {
- return this.props.infoState;
+ return this._props.infoState;
}
get Arcs() {
return Object.keys(this.State).map(key => this.State[key]);
@@ -65,7 +74,7 @@ export class CollectionFreeFormInfoState extends React.Component<CollectionFreeF
res => {
if (res) {
const next = arc.act(res);
- this.props.next(next);
+ this._props.next(next);
}
},
{ fireImmediately: true }
@@ -76,6 +85,7 @@ export class CollectionFreeFormInfoState extends React.Component<CollectionFreeF
this.initState();
}
componentDidUpdate() {
+ copyProps(this);
this.clearState();
this.initState();
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
index 1265dc2de..f0a052c1d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, computed, observable, reaction, action, runInAction } from 'mobx';
+import { IReactionDisposer, computed, observable, reaction, action, runInAction, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc } from '../../../../fields/Doc';
import { ScriptField } from '../../../../fields/ScriptField';
@@ -10,11 +10,12 @@ import { NumCast } from '../../../../fields/Types';
import { LinkManager } from '../../../util/LinkManager';
import { InkTool } from '../../../../fields/InkField';
import { LinkDocPreview } from '../../nodes/LinkDocPreview';
-import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
+import { DocumentLinksButton, DocButtonState } from '../../nodes/DocumentLinksButton';
import { DocumentManager } from '../../../util/DocumentManager';
import { CollectionFreeFormInfoState, infoState, StateMessage, infoArc, StateEntryFunc, InfoState } from './CollectionFreeFormInfoState';
import { string32 } from 'pdfjs-dist/types/src/shared/util';
import { any } from 'bluebird';
+import { copyProps } from '../../../../Utils';
export interface CollectionFreeFormInfoUIProps {
Document: Doc;
@@ -25,10 +26,23 @@ export interface CollectionFreeFormInfoUIProps {
export class CollectionFreeFormInfoUI extends React.Component<CollectionFreeFormInfoUIProps> {
private _disposers: { [name: string]: IReactionDisposer } = {};
- @observable currState!: infoState;
- constructor(props: any) {
+ @observable _currState: infoState | undefined = undefined;
+ get currState() {
+ return this._currState!;
+ }
+ set currState(val) {
+ this._currState = val;
+ }
+ _prevProps: React.PropsWithChildren<CollectionFreeFormInfoUIProps>;
+ @observable _props: React.PropsWithChildren<CollectionFreeFormInfoUIProps>;
+ constructor(props: React.PropsWithChildren<CollectionFreeFormInfoUIProps>) {
super(props);
- this.setCurrState(this.setupStates());
+ this._props = this._prevProps = this.props;
+ makeObservable(this);
+ this.currState = this.setupStates();
+ }
+ componentDidUpdate() {
+ copyProps(this);
}
setCurrState = (state: infoState) => {
@@ -40,12 +54,12 @@ export class CollectionFreeFormInfoUI extends React.Component<CollectionFreeForm
setupStates = () => {
// state entry functions
- const setBackground = (col: string) => () => (this.props.Freeform.layoutDoc.backgroundColor = col);
+ const setBackground = (col: string) => () => (this._props.Freeform.layoutDoc.backgroundColor = col);
// arc transition trigger conditions
- const firstDoc = () => this.props.Freeform.childDocs.lastElement();
- const numDocs = () => this.props.Freeform.childDocs.length;
+ const firstDoc = () => this._props.Freeform.childDocs.lastElement();
+ const numDocs = () => this._props.Freeform.childDocs.length;
const numDocLinks = () => LinkManager.Instance.getAllDirectLinks(firstDoc())?.length;
- const linkMenuOpen = () => DocumentLinksButton.LinkEditorDocView;
+ const linkMenuOpen = () => DocButtonState.Instance.LinkEditorDocView;
// set of states.
const start = InfoState('Click to create Object', {
@@ -78,7 +92,7 @@ export class CollectionFreeFormInfoUI extends React.Component<CollectionFreeForm
/*
componentDidMount(): void {
this._disposers.reaction1 = reaction(
- () => this.props.Freeform.childDocs.slice(),
+ () => this._props.Freeform.childDocs.slice(),
docs => {
if (docs.length === 1) {
this.firstDoc = docs[0];
@@ -162,8 +176,8 @@ export class CollectionFreeFormInfoUI extends React.Component<CollectionFreeForm
// this._disposers.reaction1();
@observable message = 'Click anywhere and begin typing to create your first document!';
- @observable firstDoc: Doc | undefined;
- @observable secondDoc: Doc | undefined;
+ @observable firstDoc: Doc | undefined = undefined;
+ @observable secondDoc: Doc | undefined = undefined;
*/
firstDocPos = { x: 0, y: 0 };
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 4995925c8..5cbea4783 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -171,8 +171,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
@action
toggleProperties = () => {
- if ((SettingsManager.propertiesWidth ?? 0) < 100) {
- SettingsManager.propertiesWidth = 250;
+ if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
+ SettingsManager.Instance.propertiesWidth = 250;
}
};
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 03d302f39..154c914ad 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, toJS } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
@@ -16,7 +16,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../
import { ImageField } from '../../../../fields/URLField';
import { TraceMobx } from '../../../../fields/util';
import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
-import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { aggregateBounds, copyProps, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
import { Docs, DocUtils } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -43,7 +43,7 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../../nodes/trails/PresBox';
import { CreateImage } from '../../nodes/WebBoxRenderer';
import { StyleProp } from '../../StyleProvider';
-import { CollectionSubView } from '../CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import { TreeViewType } from '../CollectionTreeView';
import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid';
import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI';
@@ -69,9 +69,20 @@ export type collectionFreeformViewProps = {
@observer
export class CollectionFreeFormView extends CollectionSubView<Partial<collectionFreeformViewProps>>() {
public get displayName() {
- return 'CollectionFreeFormView(' + this.props.Document.title?.toString() + ')';
+ return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')';
} // this makes mobx trace() statements more descriptive
+ _prevProps: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionFreeformViewProps>>;
+ @override _props: React.PropsWithChildren<SubCollectionViewProps & Partial<collectionFreeformViewProps>>;
+ constructor(props: any) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ }
+ componentDidUpdate() {
+ copyProps(this);
+ }
+
@observable
public static ShowPresPaths = false;
@@ -90,19 +101,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
private _brushtimer1: any;
public get isAnnotationOverlay() {
- return this.props.isAnnotationOverlay;
+ return this._props.isAnnotationOverlay;
}
public get scaleFieldKey() {
- return (this.props.viewField ?? '') + '_freeform_scale';
+ return (this._props.viewField ?? '') + '_freeform_scale';
}
private get panXFieldKey() {
- return (this.props.viewField ?? '') + '_freeform_panX';
+ return (this._props.viewField ?? '') + '_freeform_panX';
}
private get panYFieldKey() {
- return (this.props.viewField ?? '') + '_freeform_panY';
+ return (this._props.viewField ?? '') + '_freeform_panY';
}
private get autoResetFieldKey() {
- return (this.props.viewField ?? '') + '_freeform_autoReset';
+ return (this._props.viewField ?? '') + '_freeform_autoReset';
}
@observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables
@@ -113,7 +124,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _deleteList: DocumentView[] = [];
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeViewRef = React.createRef<MarqueeView>();
- @observable _brushedView: { width: number; height: number; panX: number; panY: number } | undefined; // highlighted region of freeform canvas used by presentations to indicate a region
+ @observable _brushedView: { width: number; height: number; panX: number; panY: number } | undefined = undefined; // highlighted region of freeform canvas used by presentations to indicate a region
@observable GroupChildDrag: boolean = false; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
@computed get contentViews() {
@@ -130,11 +141,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
scale:
(!this.childDocs.length || !Number.isFinite(hgt) || !Number.isFinite(wid)
? 1 //
- : Math.min(this.props.PanelHeight() / hgt, this.props.PanelWidth() / wid)) / (this.props.NativeDimScaling?.() || 1),
+ : Math.min(this._props.PanelHeight() / hgt, this._props.PanelWidth() / wid)) / (this._props.NativeDimScaling?.() || 1),
};
}
@computed get fitContentsToBox() {
- return (this.props.fitContentsToBox?.() || this.Document._freeform_fitContentsToBox) && !this.isAnnotationOverlay;
+ return (this._props.fitContentsToBox?.() || this.Document._freeform_fitContentsToBox) && !this.isAnnotationOverlay;
}
@computed get contentBounds() {
const cb = Cast(this.dataDoc.contentBounds, listSpec('number'));
@@ -147,30 +158,30 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
}
@computed get nativeWidth() {
- return this.props.NativeWidth?.() || Doc.NativeWidth(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
+ return this._props.NativeWidth?.() || Doc.NativeWidth(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
}
@computed get nativeHeight() {
- return this.props.NativeHeight?.() || Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
+ return this._props.NativeHeight?.() || Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
}
@computed get cachedCenteringShiftX(): number {
const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling;
- return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+ return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : this._props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
- const dv = this.props.DocumentView?.();
- const fitWidth = this.props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth;
+ const dv = this._props.DocumentView?.();
+ const fitWidth = this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth;
const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling;
// if freeform has a native aspect, then the panel height needs to be adjusted to match it
- const aspect = dv?.nativeWidth && dv?.nativeHeight && !fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
- return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : (aspect * this.props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+ const aspect = dv?.nativeWidth && dv?.nativeHeight && !fitWidth ? dv.nativeHeight / dv.nativeWidth : this._props.PanelHeight() / this._props.PanelWidth();
+ return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : (aspect * this._props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get panZoomXf() {
return new Transform(this.panX(), this.panY(), 1 / this.zoomScaling());
}
@computed get screenToLocalXf() {
- return this.props
+ return this._props
.ScreenToLocalTransform()
- .scale(this.props.isAnnotationOverlay ? 1 : 1)
+ .scale(this._props.isAnnotationOverlay ? 1 : 1)
.translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY)
.transform(this.panZoomXf);
}
@@ -219,9 +230,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _keyframeEditing = false;
@action setKeyFrameEditing = (set: boolean) => (this._keyframeEditing = set);
getKeyFrameEditing = () => this._keyframeEditing;
- onBrowseClickHandler = () => this.props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick);
- onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
- onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
+ onBrowseClickHandler = () => this._props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick);
+ onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick);
+ onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
elementFunc = () => this._layoutElements;
fitContentOnce = () => {
const vals = this.fitToContentVals;
@@ -236,27 +247,27 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1));
zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1));
PanZoomCenterXf = () =>
- this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
+ this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
ScreenToLocalXf = () => this.screenToLocalXf.copy();
getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
- isAnyChildContentActive = () => this.props.isAnyChildContentActive();
+ isAnyChildContentActive = () => this._props.isAnyChildContentActive();
addLiveTextBox = (newDoc: Doc) => {
FormattedTextBox.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
this.addDocument(newDoc);
};
selectDocuments = (docs: Doc[]) => {
SelectionManager.DeselectAll();
- docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true));
+ docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true));
};
addDocument = (newBox: Doc | Doc[]) => {
let retVal = false;
if (newBox instanceof Doc) {
- if ((retVal = this.props.addDocument?.(newBox) || false)) {
+ if ((retVal = this._props.addDocument?.(newBox) || false)) {
this.bringToFront(newBox);
this.updateCluster(newBox);
}
} else {
- retVal = this.props.addDocument?.(newBox) || false;
+ retVal = this._props.addDocument?.(newBox) || false;
// bcz: deal with clusters
}
if (retVal) {
@@ -270,7 +281,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
CollectionFreeFormDocumentView.animFields.forEach((field, i) => field.key !== 'opacity' && (newBox[field.key] = vals[i]));
}
}
- if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) {
+ if (this.Document._currentFrame !== undefined && !this._props.isAnnotationOverlay) {
CollectionFreeFormDocumentView.setupKeyframes(newBoxes, NumCast(this.Document._currentFrame), true);
}
}
@@ -286,7 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
groupFocus = (anchor: Doc, options: DocFocusOptions) => {
options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1);
- const res = this.props.focus(this.Document, options);
+ const res = this._props.focus(this.Document, options);
options.docTransform = undefined;
return res;
};
@@ -324,11 +335,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
findDoc(dv => res(dv));
});
- @action
internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
if (!super.onInternalDrop(e, de)) return false;
const refDoc = docDragData.droppedDocuments[0];
- const [xpo, ypo] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+ const [xpo, ypo] = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y);
const z = NumCast(refDoc.z);
const x = (z ? xpo : xp) - docDragData.offset[0];
const y = (z ? ypo : yp) - docDragData.offset[1];
@@ -343,7 +353,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
const d = docDragData.droppedDocuments[i];
const layoutDoc = Doc.Layout(d);
- const delta = Utils.rotPt(x - dropPos[0], y - dropPos[1], this.props.ScreenToLocalTransform().Rotate);
+ const delta = Utils.rotPt(x - dropPos[0], y - dropPos[1], this._props.ScreenToLocalTransform().Rotate);
if (this.Document._currentFrame !== undefined) {
CollectionFreeFormDocumentView.setupKeyframes([d], NumCast(this.Document._currentFrame), false);
const pvals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000)); // get filled in values (uses defaults when not value is specified) for position
@@ -405,7 +415,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
- if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) {
+ if (linkDragData.linkDragView.props.docViewPath().includes(this._props.docViewPath().lastElement())) {
let added = false;
// do nothing if link is dropped into any freeform view parent of dragged document
const source =
@@ -426,7 +436,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_xPadding: 0,
onClick: FollowLinkScript(),
});
- added = this.props.addDocument?.(source) ? true : false;
+ added = this._props.addDocument?.(source) ? true : false;
de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
e.stopPropagation();
@@ -463,7 +473,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return this.childLayoutPairs
.map(pair => pair.layout)
.reduce((cluster, cd) => {
- const grouping = this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
+ const grouping = this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
if (grouping !== -1) {
const layoutDoc = Doc.Layout(cd);
const cx = NumCast(cd.x) - this._clusterDistance / 2;
@@ -480,11 +490,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (cluster !== -1) {
const ptsParent = e;
if (ptsParent) {
- const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
- const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!);
+ const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
+ const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this._props.DocumentView?.())!);
const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined);
- de.moveDocument = this.props.moveDocument;
+ de.moveDocument = this._props.moveDocument;
de.offset = this.screenToLocalXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top);
DragManager.StartDocumentDrag(
clusterDocs.map(v => v.ContentDiv!),
@@ -502,7 +512,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateClusters(_freeform_useClusters: boolean) {
- this.props.Document._freeform_useClusters = _freeform_useClusters;
+ this._props.Document._freeform_useClusters = _freeform_useClusters;
this._clusterSets.length = 0;
this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c));
}
@@ -510,7 +520,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateClusterDocs(docs: Doc[]) {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this.props.Document._freeform_useClusters) {
+ if (this._props.Document._freeform_useClusters) {
const docFirst = docs[0];
docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)));
const preferredInd = NumCast(docFirst.layout_cluster);
@@ -553,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateCluster = (doc: Doc) => {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this.props.Document._freeform_useClusters) {
+ if (this._props.Document._freeform_useClusters) {
this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
const preferredInd = NumCast(doc.layout_cluster);
doc.layout_cluster = -1;
@@ -583,7 +593,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
clusterStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
- let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
+ let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
if (doc && this.childDocList?.includes(doc))
switch (property) {
case StyleProp.BackgroundColor:
@@ -612,7 +622,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
trySelectCluster = (addToSel: boolean) => {
if (this._hitCluster !== -1) {
!addToSel && SelectionManager.DeselectAll();
- const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
+ const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
this.selectDocuments(eles);
return true;
}
@@ -625,7 +635,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this._downY = this._lastY = e.pageY;
this._downTime = Date.now();
const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode;
- if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this.props.isContentActive(true)) {
+ if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this._props.isContentActive(true)) {
if (!this.Document.isGroup) {
// group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag
// prettier-ignore
@@ -638,7 +648,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
break;
case InkTool.None:
- if (!(this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
+ if (!(this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
this._hitCluster = this.pickCluster(this.screenToLocalXf.transformPoint(e.clientX, e.clientY));
setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, this._hitCluster !== -1 ? true : false, false);
}
@@ -661,7 +671,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
case GestureUtils.Gestures.Stroke:
const points = ge.points;
const B = this.screenToLocalXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
- const inkWidth = ActiveInkWidth() * this.props.ScreenToLocalTransform().Scale;
+ const inkWidth = ActiveInkWidth() * this._props.ScreenToLocalTransform().Scale;
const inkDoc = Docs.Create.InkDocument(
points,
{ title: ge.gesture.toString(),
@@ -710,7 +720,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (this._lightboxDoc) this._lightboxDoc = undefined;
if (Utils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) {
if (this.onBrowseClickHandler()) {
- this.onBrowseClickHandler().script.run({ documentView: this.props.DocumentView?.(), clientX: e.clientX, clientY: e.clientY });
+ this.onBrowseClickHandler().script.run({ documentView: this._props.DocumentView?.(), clientX: e.clientX, clientY: e.clientY });
e.stopPropagation();
e.preventDefault();
} else if (this.isContentActive() && e.shiftKey) {
@@ -733,9 +743,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const ctrlKey = e.ctrlKey && !e.shiftKey;
const shiftKey = e.shiftKey && !e.ctrlKey;
PresBox.Instance?.pauseAutoPres();
- this.props.DocumentView?.().clearViewTransition();
+ this._props.DocumentView?.().clearViewTransition();
const [dxi, dyi] = this.screenToLocalXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.props.ScreenToLocalTransform().Rotate);
+ const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this._props.ScreenToLocalTransform().Rotate);
this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0, true);
this._lastX = e.clientX;
this._lastY = e.clientY;
@@ -788,7 +798,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return true;
}
// pan the view if this is a regular collection, or it's an overlay and the overlay is zoomed (otherwise, there's nothing to pan)
- if (!this.props.isAnnotationOverlay || 1 - NumCast(this.layoutDoc._freeform_scale_min, 1) / this.zoomScaling()) {
+ if (!this._props.isAnnotationOverlay || 1 - NumCast(this.layoutDoc._freeform_scale_min, 1) / this.zoomScaling()) {
this.pan(e);
e.stopPropagation(); // if we are actually panning, stop propagation -- this will preven things like the overlayView from dragging the document while we're panning
}
@@ -804,7 +814,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
return this.childDocs
- .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.()))
+ .map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.()))
.filter(inkView => inkView?.ComponentView instanceof InkingStroke)
.map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
.filter(
@@ -901,7 +911,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.childDocs
.filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
.forEach(doc => {
- const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())?.ComponentView as InkingStroke;
+ const otherInk = DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())?.ComponentView as InkingStroke;
const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
@@ -933,7 +943,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
zoom = (pointX: number, pointY: number, deltaY: number): void => {
- if (this.Document.isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return;
+ if (this.Document.isGroup || this.Document[(this._props.viewField ?? '_') + 'freeform_noZoom']) return;
let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
if (deltaScale < 0) deltaScale = -deltaScale;
const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY);
@@ -955,8 +965,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const localTransform = invTransform.scaleAbout(deltaScale, x, y);
if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
- this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
- this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
+ this._props.Document[this.scaleFieldKey] = Math.abs(safeScale);
+ this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this._props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
}
};
@@ -964,10 +974,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onPointerWheel = (e: React.WheelEvent): void => {
if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
PresBox.Instance?.pauseAutoPres();
- if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return;
+ if (this.layoutDoc._Transform || this._props.Document.treeView_OutlineMode === TreeViewType.outline) return;
e.stopPropagation();
const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight);
- const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4;
+ const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling + 1e-4;
switch (
!e.ctrlKey && !e.shiftKey && !e.metaKey && !e.altKey ?//
Doc.UserDoc().freeformScrollMode : // no modifiers, do assigned mode
@@ -975,7 +985,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
freeformScrollMode.Zoom : freeformScrollMode.Pan // prettier-ignore
) {
case freeformScrollMode.Pan:
- if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this.props.isContentActive(true)) {
+ if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this._props.isContentActive(true)) {
const deltaX = e.shiftKey ? e.deltaX : e.ctrlKey ? 0 : e.deltaX;
const deltaY = e.shiftKey ? 0 : e.ctrlKey ? e.deltaY : e.deltaY;
this.scrollPan({ deltaX: -deltaX * this.screenToLocalXf.Scale, deltaY: e.shiftKey ? 0 : -deltaY * this.screenToLocalXf.Scale });
@@ -983,8 +993,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
default:
case freeformScrollMode.Zoom:
- if ((e.ctrlKey || !scrollable) && this.props.isContentActive(true)) {
- this.zoom(e.clientX, e.clientY, Math.max(-1, Math.min(1, e.deltaY))); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
+ if ((e.ctrlKey || !scrollable) && this._props.isContentActive(true)) {
+ this.zoom(e.clientX, e.clientY, Math.max(-1, Math.min(1, e.deltaY))); // if (!this._props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
e.preventDefault();
}
break;
@@ -1013,19 +1023,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) },
}),
{
- xrange: { min: this.props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
- yrange: { min: this.props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
+ xrange: { min: this._props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
+ yrange: { min: this._props.originTopLeft ? 0 : Number.MAX_VALUE, max: -Number.MAX_VALUE },
}
);
- const scaling = this.zoomScaling() * (this.props.NativeDimScaling?.() || 1);
- const panelWidMax = (this.props.PanelWidth() / scaling) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1);
- const panelWidMin = (this.props.PanelWidth() / scaling) * (this.props.originTopLeft ? 0 : 1);
- const panelHgtMax = (this.props.PanelHeight() / scaling) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1);
- const panelHgtMin = (this.props.PanelHeight() / scaling) * (this.props.originTopLeft ? 0 : 1);
- if (ranges.xrange.min >= panX + panelWidMax / 2) panX = ranges.xrange.max + (this.props.originTopLeft ? 0 : panelWidMax / 2);
- else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this.props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2);
- if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this.props.originTopLeft ? 0 : panelHgtMax / 2);
- else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2);
+ const scaling = this.zoomScaling() * (this._props.NativeDimScaling?.() || 1);
+ const panelWidMax = (this._props.PanelWidth() / scaling) * (this._props.originTopLeft ? 2 / this.nativeDimScaling : 1);
+ const panelWidMin = (this._props.PanelWidth() / scaling) * (this._props.originTopLeft ? 0 : 1);
+ const panelHgtMax = (this._props.PanelHeight() / scaling) * (this._props.originTopLeft ? 2 / this.nativeDimScaling : 1);
+ const panelHgtMin = (this._props.PanelHeight() / scaling) * (this._props.originTopLeft ? 0 : 1);
+ if (ranges.xrange.min >= panX + panelWidMax / 2) panX = ranges.xrange.max + (this._props.originTopLeft ? 0 : panelWidMax / 2);
+ else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this._props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2);
+ if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this._props.originTopLeft ? 0 : panelHgtMax / 2);
+ else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this._props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2);
}
}
if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc) {
@@ -1036,13 +1046,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const minPanY = NumCast(this.dataDoc._freeform_panY_min, 0);
const maxPanX = NumCast(this.dataDoc._freeform_panX_max, this.nativeWidth);
const newPanX = Math.min(minPanX + scale * maxPanX, Math.max(minPanX, panX));
- const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this.props.PanelWidth() - this.props.PanelHeight()) * this.props.ScreenToLocalTransform().Scale) / minScale;
- const nativeHeight = (this.props.PanelHeight() / this.props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
- const maxScrollTop = this.nativeHeight / this.props.ScreenToLocalTransform().Scale - this.props.PanelHeight();
+ const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this._props.PanelWidth() - this._props.PanelHeight()) * this._props.ScreenToLocalTransform().Scale) / minScale;
+ const nativeHeight = (this._props.PanelHeight() / this._props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
+ const maxScrollTop = this.nativeHeight / this._props.ScreenToLocalTransform().Scale - this._props.PanelHeight();
const maxPanY =
minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by layout_fitWidth
scale * NumCast(this.dataDoc._panY_max, nativeHeight) +
- (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
+ (!this._props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
if (false && NumCast(this.layoutDoc.layout_scrollTop) && NumCast(this.layoutDoc._freeform_scale, minScale) !== minScale) {
const relTop = NumCast(this.layoutDoc.layout_scrollTop) / maxScrollTop;
@@ -1061,11 +1071,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
nudge = (x: number, y: number, nudgeTime: number = 500) => {
- const collectionDoc = this.props.docViewPath().lastElement().Document;
+ const collectionDoc = this._props.docViewPath().lastElement().Document;
if (collectionDoc?._type_collection !== CollectionViewType.Freeform) {
this.setPan(
- NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
- NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
+ NumCast(this.layoutDoc[this.panXFieldKey]) + ((this._props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
+ NumCast(this.layoutDoc[this.panYFieldKey]) + ((this._props.PanelHeight() / 2) * -y) / this.zoomScaling(),
nudgeTime,
true
);
@@ -1132,20 +1142,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const newScale =
scale === 0
? NumCast(this.layoutDoc[this.scaleFieldKey])
- : Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this.props.PanelWidth() / Math.abs(bounds.width), this.props.PanelHeight() / Math.abs(bounds.height)));
+ : Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this._props.PanelWidth() / Math.abs(bounds.width), this._props.PanelHeight() / Math.abs(bounds.height)));
return {
- panX: this.props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2,
- panY: this.props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2,
+ panX: this._props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2,
+ panY: this._props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2,
scale: newScale,
};
}
- const panelWidth = this.props.isAnnotationOverlay ? this.nativeWidth : this.props.PanelWidth();
- const panelHeight = this.props.isAnnotationOverlay ? this.nativeHeight : this.props.PanelHeight();
+ const panelWidth = this._props.isAnnotationOverlay ? this.nativeWidth : this._props.PanelWidth();
+ const panelHeight = this._props.isAnnotationOverlay ? this.nativeHeight : this._props.PanelHeight();
const pw = panelWidth / NumCast(this.layoutDoc._freeform_scale, 1);
const ph = panelHeight / NumCast(this.layoutDoc._freeform_scale, 1);
- const cx = NumCast(this.layoutDoc[this.panXFieldKey]) + (this.props.isAnnotationOverlay ? pw / 2 : 0);
- const cy = NumCast(this.layoutDoc[this.panYFieldKey]) + (this.props.isAnnotationOverlay ? ph / 2 : 0);
+ const cx = NumCast(this.layoutDoc[this.panXFieldKey]) + (this._props.isAnnotationOverlay ? pw / 2 : 0);
+ const cy = NumCast(this.layoutDoc[this.panYFieldKey]) + (this._props.isAnnotationOverlay ? ph / 2 : 0);
const screen = { left: cx - pw / 2, right: cx + pw / 2, top: cy - ph / 2, bot: cy + ph / 2 };
const maxYShift = Math.max(0, screen.bot - screen.top - (bounds.bot - bounds.top));
const phborder = bounds.top < screen.top || bounds.bot > screen.bot ? Math.min(ph / 10, maxYShift / 2) : 0;
@@ -1153,19 +1163,18 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return {
panX: (bounds.left + bounds.right) / 2,
panY: (bounds.top + bounds.bot) / 2,
- scale: Math.min(this.props.PanelHeight() / (bounds.bot - bounds.top), this.props.PanelWidth() / (bounds.right - bounds.left)) / 1.1,
+ scale: Math.min(this._props.PanelHeight() / (bounds.bot - bounds.top), this._props.PanelWidth() / (bounds.right - bounds.left)) / 1.1,
};
}
return {
- panX: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panXFieldKey]) : cx) + Math.min(0, bounds.left - pw / 10 - screen.left) + Math.max(0, bounds.right + pw / 10 - screen.right),
- panY: (this.props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panYFieldKey]) : cy) + Math.min(0, bounds.top - phborder - screen.top) + Math.max(0, bounds.bot + phborder - screen.bot),
+ panX: (this._props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panXFieldKey]) : cx) + Math.min(0, bounds.left - pw / 10 - screen.left) + Math.max(0, bounds.right + pw / 10 - screen.right),
+ panY: (this._props.isAnnotationOverlay ? NumCast(this.layoutDoc[this.panYFieldKey]) : cy) + Math.min(0, bounds.top - phborder - screen.top) + Math.max(0, bounds.bot + phborder - screen.bot),
};
};
- isContentActive = () => this.props.isContentActive();
+ isContentActive = () => this._props.isContentActive();
@undoBatch
- @action
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
const docView = fieldProps.DocumentView?.();
if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
@@ -1186,21 +1195,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
@computed get childPointerEvents() {
- const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
+ const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
const pointerevents = DocumentView.Interacting
? 'none'
- : this.props.childPointerEvents?.() ??
- (this.props.viewDefDivClick || //
- (engine === computePassLayout.name && !this.props.isSelected()) ||
+ : this._props.childPointerEvents?.() ??
+ (this._props.viewDefDivClick || //
+ (engine === computePassLayout.name && !this._props.isSelected()) ||
this.isContentActive() === false
? 'none'
- : this.props.pointerEvents?.());
+ : this._props.pointerEvents?.());
return pointerevents;
}
- @observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined;
+ @observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined;
childPointerEventsFunc = () => this._childPointerEvents;
- childContentsActive = () => (this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)();
+ childContentsActive = () => (this._props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)();
getChildDocView(entry: PoolData) {
const childLayout = entry.pair.layout;
const childData = entry.pair.data;
@@ -1212,50 +1221,50 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
TemplateDataDocument={childData}
dragStarting={this.dragStarting}
dragEnding={this.dragEnding}
- isGroupActive={this.props.isGroupActive}
- renderDepth={this.props.renderDepth + 1}
+ isGroupActive={this._props.isGroupActive}
+ renderDepth={this._props.renderDepth + 1}
hideDecorations={BoolCast(childLayout._layout_isSvg && childLayout.type === DocumentType.LINK)}
suppressSetHeight={this.layoutEngine ? true : false}
RenderCutoffProvider={this.renderCutoffProvider}
CollectionFreeFormView={this}
- LayoutTemplate={childLayout.z ? undefined : this.props.childLayoutTemplate}
- LayoutTemplateString={childLayout.z ? undefined : this.props.childLayoutString}
+ LayoutTemplate={childLayout.z ? undefined : this._props.childLayoutTemplate}
+ LayoutTemplateString={childLayout.z ? undefined : this._props.childLayoutString}
rootSelected={childData ? this.rootSelected : returnFalse}
- waitForDoubleClickToClick={this.props.waitForDoubleClickToClick}
+ waitForDoubleClickToClick={this._props.waitForDoubleClickToClick}
onClick={this.onChildClickHandler}
onKey={this.onKeyDown}
onDoubleClick={this.onChildDoubleClickHandler}
onBrowseClick={this.onBrowseClickHandler}
- ScreenToLocalTransform={childLayout.z ? this.props.ScreenToLocalTransform : this.ScreenToLocalXf}
+ ScreenToLocalTransform={childLayout.z ? this._props.ScreenToLocalTransform : this.ScreenToLocalXf}
PanelWidth={childLayout[Width]}
PanelHeight={childLayout[Height]}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- isDocumentActive={childLayout.pointerEvents === 'none' ? returnFalse : this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
+ isDocumentActive={childLayout.pointerEvents === 'none' ? returnFalse : this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this.isContentActive}
isContentActive={this.childContentsActive}
- focus={this.Document.isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
+ focus={this.Document.isGroup ? this.groupFocus : this.isAnnotationOverlay ? this._props.focus : this.focus}
addDocTab={this.addDocTab}
- addDocument={this.props.addDocument}
- removeDocument={this.props.removeDocument}
- moveDocument={this.props.moveDocument}
- pinToPres={this.props.pinToPres}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- docViewPath={this.props.docViewPath}
+ addDocument={this._props.addDocument}
+ removeDocument={this._props.removeDocument}
+ moveDocument={this._props.moveDocument}
+ pinToPres={this._props.pinToPres}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ docViewPath={this._props.docViewPath}
styleProvider={this.clusterStyleProvider}
- dragAction={(this.Document.childDragAction ?? this.props.childDragAction) as dropActionType}
+ dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
bringToFront={this.bringToFront}
- layout_showTitle={this.props.childlayout_showTitle}
- dontRegisterView={this.props.dontRegisterView}
+ layout_showTitle={this._props.childlayout_showTitle}
+ dontRegisterView={this._props.dontRegisterView}
pointerEvents={this.childPointerEventsFunc}
/>
);
}
addDocTab = action((doc: Doc, where: OpenWhere) => {
- if (this.props.isAnnotationOverlay) return this.props.addDocTab(doc, where);
+ if (this._props.isAnnotationOverlay) return this._props.addDocTab(doc, where);
switch (where) {
case OpenWhere.inParent:
- return this.props.addDocument?.(doc) || false;
+ return this._props.addDocument?.(doc) || false;
case OpenWhere.inParentFromScreen:
const docContext = DocCast((doc instanceof Doc ? doc : doc?.[0])?.embedContainer);
return (
@@ -1267,7 +1276,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return doc;
})
) &&
- (!docContext || this.props.removeDocument?.(docContext))) ||
+ (!docContext || this._props.removeDocument?.(docContext))) ||
false
);
case undefined:
@@ -1281,9 +1290,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return true;
}
}
- return this.props.addDocTab(doc, where);
+ return this._props.addDocTab(doc, where);
});
- @observable _lightboxDoc: Opt<Doc>;
+ @observable _lightboxDoc: Opt<Doc> = undefined;
getCalculatedPositions(pair: { layout: Doc; data?: Doc }): PoolData {
const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + (((Math.abs(x * y) * 9301 + 49297) % 233280) / 233280) * (max - min);
@@ -1295,7 +1304,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const { backgroundColor, color } = contentFrameNumber === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, contentFrameNumber);
const { x, y, autoDim, _width, _height, opacity, _rotation } =
layoutFrameNumber === undefined // -1 for width/height means width/height should be PanelWidth/PanelHeight (prevents collectionfreeformdocumentview width/height from getting out of synch with panelWIdth/Height which causes detailView to re-render and lose focus because HTMLtag scaling gets set to a bad intermediate value)
- ? { autoDim: 1, _width: Cast(childDoc._width, 'number'), _height: Cast(childDoc._height, 'number'), _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() }
+ ? { autoDim: 1, _width: Cast(childDoc._width, 'number'), _height: Cast(childDoc._height, 'number'), _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this._props.childOpacity?.() }
: CollectionFreeFormDocumentView.getValues(childDoc, layoutFrameNumber);
// prettier-ignore
const rotation = Cast(_rotation,'number',
@@ -1307,9 +1316,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
z: Cast(z, 'number'),
autoDim,
rotation,
- color: Cast(color, 'string') ? StrCast(color) : this.props.styleProvider?.(childDoc, this.props, StyleProp.Color),
- backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, this.props, StyleProp.BackgroundColor),
- opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this.props.styleProvider?.(childDoc, this.props, StyleProp.Opacity),
+ color: Cast(color, 'string') ? StrCast(color) : this._props.styleProvider?.(childDoc, this._props, StyleProp.Color),
+ backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, this._props, StyleProp.BackgroundColor),
+ opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this._props.styleProvider?.(childDoc, this._props, StyleProp.Opacity),
zIndex: Cast(zIndex, 'number'),
width: _width,
height: _height,
@@ -1321,7 +1330,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
onViewDefDivClick = (e: React.MouseEvent, payload: any) => {
- (this.props.viewDefDivClick || ScriptCast(this.props.Document.onViewDefDivClick))?.script.run({ this: this.props.Document, payload });
+ (this._props.viewDefDivClick || ScriptCast(this._props.Document.onViewDefDivClick))?.script.run({ this: this._props.Document, payload });
e.stopPropagation();
};
@@ -1376,7 +1385,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
poolData: Map<string, PoolData>,
engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[]
) {
- return engine(poolData, this.props.Document, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX, this.props.engineProps);
+ return engine(poolData, this._props.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps);
}
doFreeformLayout(poolData: Map<string, PoolData>) {
@@ -1385,7 +1394,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
@computed get layoutEngine() {
- return this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine);
+ return this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine);
}
@computed get doInternalLayoutComputation() {
TraceMobx();
@@ -1423,10 +1432,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document);
if (addAsAnnotation) {
- if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
- Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor);
+ if (Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
+ Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor);
} else {
- this.dataDoc[this.props.fieldKey + '_annotations'] = new List<Doc>([anchor]);
+ this.dataDoc[this._props.fieldKey + '_annotations'] = new List<Doc>([anchor]);
}
}
return anchor;
@@ -1435,7 +1444,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
infoUI = () => <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} />;
componentDidMount() {
- this.props.setContentView?.(this);
+ this._props.setContentView?.(this);
super.componentDidMount?.();
setTimeout(
action(() => {
@@ -1473,15 +1482,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this._disposers.pointerevents = reaction(
() => {
- const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
+ const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
return DocumentView.Interacting
? 'none'
- : this.props.childPointerEvents?.() ??
- (this.props.viewDefDivClick || //
- (engine === computePassLayout.name && !this.props.isSelected()) ||
+ : this._props.childPointerEvents?.() ??
+ (this._props.viewDefDivClick || //
+ (engine === computePassLayout.name && !this._props.isSelected()) ||
this.isContentActive() === false
? 'none'
- : this.props.pointerEvents?.());
+ : this._props.pointerEvents?.());
},
pointerevents => (this._childPointerEvents = pointerevents as any),
{ fireImmediately: true }
@@ -1536,11 +1545,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
updateIcon = () =>
CollectionFreeFormView.UpdateIcon(
this.layoutDoc[Id] + '-icon' + new Date().getTime(),
- this.props.docViewPath().lastElement().ContentDiv!,
+ this._props.docViewPath().lastElement().ContentDiv!,
NumCast(this.layoutDoc._width),
NumCast(this.layoutDoc._height),
- this.props.PanelWidth(),
- this.props.PanelHeight(),
+ this._props.PanelWidth(),
+ this._props.PanelHeight(),
0,
1,
false,
@@ -1600,7 +1609,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
doc.x = scr?.[0];
doc.y = scr?.[1];
});
- this.props.addDocTab(childDocs as any as Doc, OpenWhere.inParentFromScreen);
+ this._props.addDocTab(childDocs as any as Doc, OpenWhere.inParentFromScreen);
};
@undoBatch
@@ -1643,28 +1652,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
onContextMenu = (e: React.MouseEvent) => {
- if (this.props.isAnnotationOverlay || !ContextMenu.Instance) return;
+ if (this._props.isAnnotationOverlay || !ContextMenu.Instance) return;
const appearance = ContextMenu.Instance.findByDescription('Appearance...');
const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
- !this.props.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
- !this.props.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
+ !this._props.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
+ !this._props.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
!Doc.noviceMode &&
appearanceItems.push({
description: 'Toggle auto arrange',
event: () => (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange),
icon: 'compress-arrows-alt',
});
- if (this.props.setContentView === emptyFunction) {
+ if (this._props.setContentView === emptyFunction) {
!appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' });
return;
}
!Doc.noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: 'Reset default note style', event: () => (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' });
- appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.Document, { pinViewport: MarqueeView.CurViewBounds(this.dataDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' });
+ appearanceItems.push({ description: `Pin View`, event: () => this._props.pinToPres(this.Document, { pinViewport: MarqueeView.CurViewBounds(this.dataDoc, this._props.PanelWidth(), this._props.PanelHeight()) }), icon: 'map-pin' });
!Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' });
- this.props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' });
+ this._props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' });
- this.props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' });
+ this._props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' });
!Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null;
!Doc.noviceMode ? appearanceItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null;
@@ -1672,11 +1681,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const options = ContextMenu.Instance.findByDescription('Options...');
const optionItems = options && 'subitems' in options ? options.subitems : [];
- !this.props.isAnnotationOverlay &&
+ !this._props.isAnnotationOverlay &&
!Doc.noviceMode &&
optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
- this.props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
- this.props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
+ this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
+ this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
if (!Doc.noviceMode) {
optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });
}
@@ -1687,10 +1696,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@undoBatch
- @action
transcribeStrokes = () => {
- if (this.props.Document.isGroup && this.props.Document.transcription) {
- const text = StrCast(this.props.Document.transcription);
+ if (this._props.Document.isGroup && this._props.Document.transcription) {
+ const text = StrCast(this._props.Document.transcription);
const lines = text.split('\n');
const height = 30 + 15 * lines.length;
@@ -1709,7 +1717,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
visited.add(this.Document);
showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document.isGroup));
const activeDocs = this.getActiveDocuments();
- const size = this.screenToLocalXf.transformDirection(this.props.PanelWidth(), this.props.PanelHeight());
+ const size = this.screenToLocalXf.transformDirection(this._props.PanelWidth(), this._props.PanelHeight());
const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] };
const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) });
const isDocInView = (doc: Doc, rect: { left: number; top: number; width: number; height: number }) => intersectRect(docDims(doc), rect);
@@ -1738,7 +1746,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0;
incrementalRender = action(() => {
- if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) {
+ if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath())) {
const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id]));
const loadIncrement = 5;
for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) {
@@ -1752,28 +1760,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// which will be a DocumentView. In this sitation, this freeform views acts as an annotation overlay for
// the underlying DocumentView and will pan and scoll with the underlying Documen tView.
@computed get underlayViews() {
- return this.props.children ? [this.props.children] : [];
+ return this._props.children ? [toJS(this._props.children)] : [];
}
@computed get placeholder() {
return (
- <div className="collectionfreeformview-placeholder" style={{ background: this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor) }}>
- <span className="collectionfreeformview-placeholderSpan">{this.props.Document.annotationOn ? '' : this.props.Document.title?.toString()}</span>
+ <div className="collectionfreeformview-placeholder" style={{ background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) }}>
+ <span className="collectionfreeformview-placeholderSpan">{this._props.Document.annotationOn ? '' : this._props.Document.title?.toString()}</span>
</div>
);
}
brushedView = () => this._brushedView;
gridColor = () =>
- DashColor(lightOrDark(this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor)))
+ DashColor(lightOrDark(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor)))
.fade(0.5)
.toString();
@computed get backgroundGrid() {
return (
<div>
<CollectionFreeFormBackgroundGrid // bcz : UGHH don't know why, but if we don't wrap in a div, then PDF's don't render when taking snapshot of a dashboard and the background grid is on!!?
- PanelWidth={this.props.PanelWidth}
- PanelHeight={this.props.PanelHeight}
+ PanelWidth={this._props.PanelWidth}
+ PanelHeight={this._props.PanelHeight}
panX={this.panX}
panY={this.panY}
color={this.gridColor}
@@ -1795,11 +1803,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
brushedView={this.brushedView}
isAnnotationOverlay={this.isAnnotationOverlay}
transform={this.PanZoomCenterXf}
- transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.props.DocumentView?.()?.Document._viewTransition, 'string', null))}
- viewDefDivClick={this.props.viewDefDivClick}>
+ transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this._props.DocumentView?.()?.Document._viewTransition, 'string', null))}
+ viewDefDivClick={this._props.viewDefDivClick}>
{this.underlayViews}
{this.contentViews}
- <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
+ <CollectionFreeFormRemoteCursors {...this._props} key="remoteCursors" />
</CollectionFreeFormPannableContents>
);
}
@@ -1807,10 +1815,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
TraceMobx();
return (
<MarqueeView
- {...this.props}
+ {...this._props}
ref={this._marqueeViewRef}
ungroup={this.Document.isGroup ? this.promoteCollection : undefined}
- nudge={this.isAnnotationOverlay || this.props.renderDepth > 0 ? undefined : this.nudge}
+ nudge={this.isAnnotationOverlay || this._props.renderDepth > 0 ? undefined : this.nudge}
addDocTab={this.addDocTab}
slowLoadDocuments={this.slowLoadDocuments}
trySelectCluster={this.trySelectCluster}
@@ -1818,25 +1826,25 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
selectDocuments={this.selectDocuments}
addDocument={this.addDocument}
addLiveTextDocument={this.addLiveTextBox}
- getContainerTransform={this.props.ScreenToLocalTransform}
+ getContainerTransform={this._props.ScreenToLocalTransform}
getTransform={this.ScreenToLocalXf}
panXFieldKey={this.panXFieldKey}
panYFieldKey={this.panYFieldKey}
isAnnotationOverlay={this.isAnnotationOverlay}>
{this.layoutDoc._freeform_backgroundGrid ? this.backgroundGrid : null}
{this.pannableContents}
- {this._showAnimTimeline ? <Timeline ref={this._timelineRef} {...this.props} /> : null}
+ {this._showAnimTimeline ? <Timeline ref={this._timelineRef} {...this._props} /> : null}
</MarqueeView>
);
}
@computed get nativeDimScaling() {
- if (this._firstRender || (this.props.isAnnotationOverlay && !this.props.annotationLayerHostsContent)) return 0;
+ if (this._firstRender || (this._props.isAnnotationOverlay && !this._props.annotationLayerHostsContent)) return 0;
const nw = this.nativeWidth;
const nh = this.nativeHeight;
- const hscale = nh ? this.props.PanelHeight() / nh : 1;
- const wscale = nw ? this.props.PanelWidth() / nw : 1;
- return wscale < hscale || (this.props.layout_fitWidth?.(this.Document) ?? this.layoutDoc.layout_fitWidth) ? wscale : hscale;
+ const hscale = nh ? this._props.PanelHeight() / nh : 1;
+ const wscale = nw ? this._props.PanelWidth() / nw : 1;
+ return wscale < hscale || (this._props.layout_fitWidth?.(this.Document) ?? this.layoutDoc.layout_fitWidth) ? wscale : hscale;
}
nativeDim = () => this.nativeDimScaling;
@@ -1853,13 +1861,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
transTime + 1
);
};
- lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30);
- lightboxPanelHeight = () => Math.max(0, this.props.PanelHeight() - 30);
- lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15);
+ lightboxPanelWidth = () => Math.max(0, this._props.PanelWidth() - 30);
+ lightboxPanelHeight = () => Math.max(0, this._props.PanelHeight() - 30);
+ lightboxScreenToLocal = () => this._props.ScreenToLocalTransform().translate(-15, -15);
onPassiveWheel = (e: WheelEvent) => {
const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight);
- const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling;
- this.props.isSelected() && !scrollable && e.preventDefault();
+ const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling;
+ this._props.isSelected() && !scrollable && e.preventDefault();
};
_oldWheel: any;
render() {
@@ -1882,16 +1890,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onDragOver={e => e.preventDefault()}
onContextMenu={this.onContextMenu}
style={{
- pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : (this.props.pointerEvents?.() as any),
+ pointerEvents: this._props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : (this._props.pointerEvents?.() as any),
textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
transform: `scale(${this.nativeDimScaling || 1})`,
width: `${100 / (this.nativeDimScaling || 1)}%`,
- height: this.props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
+ height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
}}>
{this._lightboxDoc ? (
<div style={{ padding: 15, width: '100%', height: '100%' }}>
<DocumentView
- {...this.props}
+ {...this._props}
Document={this._lightboxDoc}
TemplateDataDocument={undefined}
PanelWidth={this.lightboxPanelWidth}
@@ -1905,8 +1913,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
- isContentActive={this.props.childContentsActive ?? emptyFunction}
+ isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this.isContentActive}
+ isContentActive={this._props.childContentsActive ?? emptyFunction}
addDocTab={this.addDocTab}
ScreenToLocalTransform={this.lightboxScreenToLocal}
fitContentsToBox={undefined}
@@ -1916,7 +1924,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
) : (
<>
{this._firstRender ? this.placeholder : this.marqueeView}
- {this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
+ {this._props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
{!this.GroupChildDrag ? null : <div className="collectionFreeForm-groupDropper" />}
</>
)}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 330c13e97..9f316bef3 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, Opt } from '../../../../fields/Doc';
import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols';
@@ -57,6 +57,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return { left: NumCast(pinDoc._freeform_panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._freeform_panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps };
}
+ @observable _props: React.PropsWithChildren<SubCollectionViewProps & MarqueeViewProps>;
+ constructor(props: React.PropsWithChildren<SubCollectionViewProps & MarqueeViewProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+
private _commandExecuted = false;
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@@ -67,7 +74,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@observable _lassoFreehand: boolean = false;
@computed get Transform() {
- return this.props.getTransform();
+ return this._props.getTransform();
}
@computed get Bounds() {
// nda - ternary argument to transformPoint is returning the lower of the downX/Y and lastX/Y and passing in as args x,y
@@ -79,7 +86,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
componentDidMount() {
- this.props.setPreviewCursor?.(this.setPreviewCursor);
+ this._props.setPreviewCursor?.(this.setPreviewCursor);
}
@action
@@ -101,20 +108,20 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const cm = ContextMenu.Instance;
const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
if (e.key === '?') {
- cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', data_useCors: true }), OpenWhere.addRight));
+ cm.setDefaultItem('?', (str: string) => this._props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', data_useCors: true }), OpenWhere.addRight));
cm.displayMenu(this._downX, this._downY, undefined, true);
e.stopPropagation();
- } else if (e.key === 'u' && this.props.ungroup) {
+ } else if (e.key === 'u' && this._props.ungroup) {
e.stopPropagation();
- this.props.ungroup();
+ this._props.ungroup();
} else if (e.key === ':') {
- DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument || returnFalse, x, y);
+ DocUtils.addDocumentCreatorMenuItems(this._props.addLiveTextDocument, this._props.addDocument || returnFalse, x, y);
cm.displayMenu(this._downX, this._downY, undefined, true);
e.stopPropagation();
} else if (e.key === 'a' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
- this.props.selectDocuments(this.props.activeDocuments());
+ this._props.selectDocuments(this._props.activeDocuments());
e.stopPropagation();
} else if (e.key === 'q' && e.ctrlKey) {
e.preventDefault();
@@ -136,7 +143,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
ns.map(line => {
const indent = line.search(/\S|$/);
const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + (indent / 3) * 10, y: ypos, title: line });
- this.props.addDocument?.(newBox);
+ this._props.addDocument?.(newBox);
ypos += 40 * this.Transform.Scale;
});
})();
@@ -147,8 +154,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
pasteImageBitmap((data: any, error: any) => {
error && console.log(error);
data &&
- Utils.convertDataUri(data, this.props.Document[Id] + '-thumb-frozen').then(returnedfilename => {
- this.props.Document['thumb-frozen'] = new ImageField(returnedfilename);
+ Utils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => {
+ this._props.Document['thumb-frozen'] = new ImageField(returnedfilename);
});
})
);
@@ -159,7 +166,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
slide.y = y;
FormattedTextBox.SelectOnLoad = slide[Id];
TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
- this.props.addDocument?.(slide);
+ this._props.addDocument?.(slide);
e.stopPropagation();
}*/ else if (e.key === 'p' && e.ctrlKey) {
e.preventDefault();
@@ -170,9 +177,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
})();
e.stopPropagation();
} else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
- FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
+ FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this._props.childLayoutString ? e.key : '';
FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note');
- this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0));
+ this._props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this._props.xPadding === 0));
e.stopPropagation();
}
};
@@ -203,7 +210,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const file = new File([blob], 'droppedTable', options);
const loading = Docs.Create.LoadingDocument(file, options);
DocUtils.uploadFileToDoc(file, {}, loading);
- this.props.addDocument?.(loading);
+ this._props.addDocument?.(loading);
}
@action
@@ -214,9 +221,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode;
// allow marquee if right drag/meta drag, or pan mode
if (e.button === 2 || e.metaKey || scrollMode === freeformScrollMode.Pan) {
- this.setPreviewCursor(e.clientX, e.clientY, true, false, this.props.Document);
+ this.setPreviewCursor(e.clientX, e.clientY, true, false, this._props.Document);
e.preventDefault();
- } else PreviewCursor.Visible = false;
+ } else PreviewCursor.Instance.Visible = false;
};
@action
@@ -243,10 +250,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (this._visible) {
const mselect = this.marqueeSelect();
if (!e.shiftKey) {
- SelectionManager.DeselectAll(mselect.length ? undefined : this.props.Document);
+ SelectionManager.DeselectAll(mselect.length ? undefined : this._props.Document);
}
- const docs = mselect.length ? mselect : [this.props.Document];
- this.props.selectDocuments(docs);
+ const docs = mselect.length ? mselect : [this._props.Document];
+ this._props.selectDocuments(docs);
}
const hideMarquee = () => {
this.hideMarquee();
@@ -285,14 +292,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._downX = this._lastX = x;
this._downY = this._lastY = y;
this._commandExecuted = false;
- PreviewCursor.Visible = false;
- PreviewCursor.Doc = undefined;
+ PreviewCursor.Instance.Visible = false;
+ PreviewCursor.Instance.Doc = undefined;
} else if (drag) {
this._downX = this._lastX = x;
this._downY = this._lastY = y;
this._commandExecuted = false;
- PreviewCursor.Visible = false;
- PreviewCursor.Doc = undefined;
+ PreviewCursor.Instance.Visible = false;
+ PreviewCursor.Instance.Doc = undefined;
this.cleanupInteractions(true);
document.addEventListener('pointermove', this.onPointerMove, true);
document.addEventListener('pointerup', this.onPointerUp, true);
@@ -300,10 +307,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- const effectiveAcl = GetEffectiveAcl(this.props.Document[DocData]);
+ const effectiveAcl = GetEffectiveAcl(this._props.Document[DocData]);
if ([AclAdmin, AclEdit, AclAugment].includes(effectiveAcl)) {
- PreviewCursor.Doc = doc;
- PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge, this.props.slowLoadDocuments);
+ PreviewCursor.Instance.Doc = doc;
+ PreviewCursor.Show(x, y, this.onKeyPress, this._props.addLiveTextDocument, this._props.getTransform, this._props.addDocument, this._props.nudge, this._props.slowLoadDocuments);
}
this.clearSelection();
}
@@ -311,11 +318,11 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
onClick = (e: React.MouseEvent): void => {
- if (this.props.pointerEvents?.() === 'none') return;
+ if (this._props.pointerEvents?.() === 'none') return;
if (Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
if (Doc.ActiveTool === InkTool.None) {
- if (!this.props.trySelectCluster(e.shiftKey)) {
- !DocumentView.ExploreMode && this.setPreviewCursor(e.clientX, e.clientY, false, false, this.props.Document);
+ if (!this._props.trySelectCluster(e.shiftKey)) {
+ !DocumentView.ExploreMode && this.setPreviewCursor(e.clientX, e.clientY, false, false, this._props.Document);
} else e.stopPropagation();
}
// let the DocumentView stopPropagation of this event when it selects this document
@@ -332,16 +339,15 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
hideMarquee = () => (this._visible = false);
@undoBatch
- @action
- delete = (e?: React.PointerEvent<Element> | KeyboardEvent | undefined, hide?: boolean) => {
+ delete = action((e?: React.PointerEvent<Element> | KeyboardEvent | undefined, hide?: boolean) => {
const selected = this.marqueeSelect(false);
SelectionManager.DeselectAll();
- selected.forEach(doc => (hide ? (doc.hidden = true) : this.props.removeDocument?.(doc)));
+ selected.forEach(doc => (hide ? (doc.hidden = true) : this._props.removeDocument?.(doc)));
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- };
+ });
getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, makeGroup: Opt<boolean>) => {
const newCollection = creator
@@ -366,17 +372,16 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
});
@undoBatch
- @action
- pileup = (e: KeyboardEvent | React.PointerEvent | undefined) => {
+ pileup = action((e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false);
SelectionManager.DeselectAll();
- selected.forEach(d => this.props.removeDocument?.(d));
+ selected.forEach(d => this._props.removeDocument?.(d));
const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2)!;
- this.props.addDocument?.(newCollection);
- this.props.selectDocuments([newCollection]);
+ this._props.addDocument?.(newCollection);
+ this._props.selectDocuments([newCollection]);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- };
+ });
/**
* This triggers the TabDocView.PinDoc method which is the universal method
@@ -385,35 +390,32 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
* This one is unique in that it includes the bounds associated with marquee view.
*/
@undoBatch
- @action
- pinWithView = () => {
- this.props.pinToPres(this.props.Document, { pinViewport: this.Bounds });
+ pinWithView = action(() => {
+ this._props.pinToPres(this._props.Document, { pinViewport: this.Bounds });
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- };
+ });
@undoBatch
- @action
- collection = (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean, selection?: Doc[]) => {
+ collection = action((e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean, selection?: Doc[]) => {
const selected = selection ?? this.marqueeSelect(false);
const activeFrame = selected.reduce((v, d) => v ?? Cast(d._activeFrame, 'number', null), undefined as number | undefined);
if (e instanceof KeyboardEvent ? 'cg'.includes(e.key) : true) {
- this.props.removeDocument?.(selected);
+ this._props.removeDocument?.(selected);
}
const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === 't' ? Docs.Create.StackingDocument : undefined, group);
newCollection._freeform_panX = this.Bounds.left + this.Bounds.width / 2;
newCollection._freeform_panY = this.Bounds.top + this.Bounds.height / 2;
newCollection._currentFrame = activeFrame;
- this.props.addDocument?.(newCollection);
- this.props.selectDocuments([newCollection]);
+ this._props.addDocument?.(newCollection);
+ this._props.selectDocuments([newCollection]);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- };
+ });
@undoBatch
- @action
- syntaxHighlight = (e: KeyboardEvent | React.PointerEvent | undefined) => {
+ syntaxHighlight = action((e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === 'i' : true) {
const inks = selected.filter(s => s.type === DocumentType.INK);
@@ -472,15 +474,15 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// }
const lines = results.filter((r: any) => r.category === 'line');
const text = lines.map((l: any) => l.recognizedText).join('\r\n');
- this.props.addDocument?.(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text }));
+ this._props.addDocument?.(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text }));
});
}
- };
+ });
@undoBatch
summary = action((e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false).map(d => {
- this.props.removeDocument?.(d);
+ this._props.removeDocument?.(d);
d.x = NumCast(d.x) - this.Bounds.left;
d.y = NumCast(d.y) - this.Bounds.top;
return d;
@@ -500,8 +502,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
DocUtils.MakeLink(summary, portal, { link_relationship: 'summary of:summarized by' });
portal.hidden = true;
- this.props.addDocument?.(portal);
- this.props.addLiveTextDocument(summary);
+ this._props.addDocument?.(portal);
+ this._props.addLiveTextDocument(summary);
MarqueeOptionsMenu.Instance.fadeOut(true);
});
@@ -582,17 +584,17 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
(this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc);
}
};
- this.props
+ this._props
.activeDocuments()
.filter(doc => !doc.z && !doc._lockedPosition)
.map(selectFunc);
if (!selection.length && selectBackgrounds)
- this.props
+ this._props
.activeDocuments()
.filter(doc => doc.z === undefined)
.map(selectFunc);
if (!selection.length)
- this.props
+ this._props
.activeDocuments()
.filter(doc => doc.z !== undefined)
.map(selectFunc);
@@ -601,8 +603,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@computed get marqueeDiv() {
const cpt = this._lassoFreehand || !this._visible ? [0, 0] : [this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY];
- const p = this.props.getContainerTransform().transformPoint(cpt[0], cpt[1]);
- const v = this._lassoFreehand ? [0, 0] : this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+ const p = this._props.getContainerTransform().transformPoint(cpt[0], cpt[1]);
+ const v = this._lassoFreehand ? [0, 0] : this._props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
return (
<div
className="marquee"
@@ -610,8 +612,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
transform: `translate(${p[0]}px, ${p[1]}px)`,
width: Math.abs(v[0]),
height: Math.abs(v[1]),
- color: lightOrDark(this.props.Document?.backgroundColor ?? 'white'),
- borderColor: lightOrDark(this.props.Document?.backgroundColor ?? 'white'),
+ color: lightOrDark(this._props.Document?.backgroundColor ?? 'white'),
+ borderColor: lightOrDark(this._props.Document?.backgroundColor ?? 'white'),
zIndex: 2000,
}}>
{' '}
@@ -620,7 +622,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
<polyline //
points={this._lassoPts.reduce((s, pt) => s + pt[0] + ',' + pt[1] + ' ', '')}
fill="none"
- stroke={lightOrDark(this.props.Document?.backgroundColor ?? 'white')}
+ stroke={lightOrDark(this._props.Document?.backgroundColor ?? 'white')}
strokeWidth="1"
strokeDasharray="3"
/>
@@ -635,19 +637,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
onDragAutoScroll = (e: CustomEvent<React.DragEvent>) => {
- if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
+ if ((e as any).handlePan || this._props.isAnnotationOverlay) return;
(e as any).handlePan = true;
const bounds = this.MarqueeRef?.getBoundingClientRect();
- if (!this.props.Document._freeform_noAutoPan && !this.props.renderDepth && bounds) {
+ if (!this._props.Document._freeform_noAutoPan && !this._props.renderDepth && bounds) {
const dragX = e.detail.clientX;
const dragY = e.detail.clientY;
const deltaX = dragX - bounds.left < 25 ? -(25 + (bounds.left - dragX)) : bounds.right - dragX < 25 ? 25 - (bounds.right - dragX) : 0;
const deltaY = dragY - bounds.top < 25 ? -(25 + (bounds.top - dragY)) : bounds.bottom - dragY < 25 ? 25 - (bounds.bottom - dragY) : 0;
if (deltaX !== 0 || deltaY !== 0) {
- this.props.Document[this.props.panYFieldKey] = NumCast(this.props.Document[this.props.panYFieldKey]) + deltaY / 2;
- this.props.Document[this.props.panXFieldKey] = NumCast(this.props.Document[this.props.panXFieldKey]) + deltaX / 2;
+ this._props.Document[this._props.panYFieldKey] = NumCast(this._props.Document[this._props.panYFieldKey]) + deltaY / 2;
+ this._props.Document[this._props.panXFieldKey] = NumCast(this._props.Document[this._props.panXFieldKey]) + deltaX / 2;
}
}
e.stopPropagation();
@@ -661,7 +663,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.MarqueeRef = r;
}}
style={{
- overflow: StrCast(this.props.Document._overflow),
+ overflow: StrCast(this._props.Document._overflow),
cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible ? 'crosshair' : 'pointer',
}}
onDragOver={e => e.preventDefault()}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 8daed9746..697a11ccc 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -277,7 +277,6 @@ export class CollectionGridView extends CollectionSubView() {
/**
* Handles internal drop of Dash documents.
*/
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
const savedLayouts = this.savedLayoutList;
const dropped = de.complete.docDragData?.droppedDocuments;
@@ -292,7 +291,6 @@ export class CollectionGridView extends CollectionSubView() {
/**
* Handles external drop of images/PDFs etc from outside Dash.
*/
- @action
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
this.dropLocation = this.screenToCell(e.clientX, e.clientY);
super.onExternalDrop(e, {});
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 0ee5f3b40..a9782f699 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -1,14 +1,14 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { Toggle, ToggleType, Type } from 'browndash-components';
-import { action, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, Opt } from '../../../../fields/Doc';
import { Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
+import { copyProps, emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
import { CollectionViewType } from '../../../documents/DocumentTypes';
import { BranchingTrailManager } from '../../../util/BranchingTrailManager';
import { DocumentManager } from '../../../util/DocumentManager';
@@ -20,7 +20,7 @@ import { DocumentView } from '../../nodes/DocumentView';
import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
import { UndoStack } from '../../UndoStack';
import { CollectionStackedTimeline } from '../CollectionStackedTimeline';
-import { CollectionSubView } from '../CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import './CollectionLinearView.scss';
/**
@@ -39,6 +39,18 @@ export class CollectionLinearView extends CollectionSubView() {
private _widthDisposer?: IReactionDisposer;
private _selectedDisposer?: IReactionDisposer;
+ _prevProps: SubCollectionViewProps;
+ @override _props: SubCollectionViewProps;
+ constructor(props: SubCollectionViewProps) {
+ super(props);
+ this._props = this._prevProps = props;
+ makeObservable(this);
+ }
+
+ componentDidUpdate() {
+ copyProps(this);
+ }
+
componentWillUnmount() {
this._dropDisposer?.();
this._widthDisposer?.();
@@ -170,28 +182,28 @@ export class CollectionLinearView extends CollectionSubView() {
}}>
<DocumentView
Document={doc}
- isContentActive={this.props.isContentActive}
+ isContentActive={this._props.isContentActive}
isDocumentActive={returnTrue}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ addDocTab={this._props.addDocTab}
pinToPres={emptyFunction}
- dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
+ dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
rootSelected={this.rootSelected}
- removeDocument={this.props.removeDocument}
+ removeDocument={this._props.removeDocument}
ScreenToLocalTransform={docXf}
PanelWidth={doc[Width]}
PanelHeight={nested || doc._height ? doc[Height] : this.dimension}
- renderDepth={this.props.renderDepth + 1}
+ renderDepth={this._props.renderDepth + 1}
dontRegisterView={BoolCast(this.Document.childDontRegisterViews)}
focus={emptyFunction}
- styleProvider={this.props.styleProvider}
+ styleProvider={this._props.styleProvider}
docViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
bringToFront={emptyFunction}
- childFilters={this.props.childFilters}
- childFiltersByRanges={this.props.childFiltersByRanges}
- searchFilterDocs={this.props.searchFilterDocs}
+ childFilters={this._props.childFilters}
+ childFiltersByRanges={this._props.childFiltersByRanges}
+ searchFilterDocs={this._props.searchFilterDocs}
hideResizeHandles={true}
/>
</div>
@@ -205,8 +217,8 @@ export class CollectionLinearView extends CollectionSubView() {
const menuOpener = (
<Toggle
- text={Cast(this.props.Document.icon, 'string', null)}
- icon={Cast(this.props.Document.icon, 'string', null) ? undefined : <FontAwesomeIcon color={SettingsManager.userColor} icon={isExpanded ? 'minus' : 'plus'} />}
+ text={Cast(this.Document.icon, 'string', null)}
+ icon={Cast(this.Document.icon, 'string', null) ? undefined : <FontAwesomeIcon color={SettingsManager.userColor} icon={isExpanded ? 'minus' : 'plus'} />}
color={SettingsManager.userColor}
background={SettingsManager.userVariantColor}
type={Type.TERT}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index e7af91390..037786abf 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -192,7 +192,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
};
@undoBatch
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
let dropInd = -1;
if (de.complete.docDragData && this._mainCont) {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index ef66e8ce5..bbf3481dd 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -188,7 +188,6 @@ export class CollectionMultirowView extends CollectionSubView() {
};
@undoBatch
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
let dropInd = -1;
if (de.complete.docDragData && this._mainCont) {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 029d39f88..9a00595f9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -68,16 +68,16 @@ export class CollectionSchemaView extends CollectionSubView() {
@observable _menuKeys: string[] = [];
@observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
@observable _colEles: HTMLDivElement[] = [];
- @observable _displayColumnWidths: number[] | undefined;
- @observable _columnMenuIndex: number | undefined;
+ @observable _displayColumnWidths: number[] | undefined = undefined;
+ @observable _columnMenuIndex: number | undefined = undefined;
@observable _newFieldWarning: string = '';
@observable _makeNewField: boolean = false;
@observable _newFieldDefault: any = 0;
@observable _newFieldType: ColumnType = ColumnType.Number;
@observable _menuValue: string = '';
- @observable _filterColumnIndex: number | undefined;
+ @observable _filterColumnIndex: number | undefined = undefined;
@observable _filterSearchValue: string = '';
- @observable _selectedCell: [Doc, number] | undefined;
+ @observable _selectedCell: [Doc, number] | undefined = undefined;
// target HTMLelement portal for showing a popup menu to edit cell values.
public get MenuTarget() {
@@ -437,7 +437,6 @@ export class CollectionSchemaView extends CollectionSubView() {
setDropIndex = (index: number) => (this._closestDropIndex = index);
- @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.columnDragData) {
const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
@@ -473,7 +472,6 @@ export class CollectionSchemaView extends CollectionSubView() {
return false;
};
- @action
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc)))));
};
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 0e37198bb..04443b4a7 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -26,7 +26,7 @@ export interface SchemaColumnHeaderProps {
export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
@observable _ref: HTMLDivElement | null = null;
- @computed get fieldKey() {
+ get fieldKey() {
return this.props.columnKeys[this.props.columnIndex];
}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 53f4a4d51..8d2671a6e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -34,11 +34,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
bounds = () => this._ref?.getBoundingClientRect();
@computed get schemaView() {
- return this.props.DocumentView?.().props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
+ return this.props.DocumentView?.()._props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
}
@computed get schemaDoc() {
- return this.props.DocumentView?.().props.docViewPath().lastElement()?.Document;
+ return this.props.DocumentView?.()._props.docViewPath().lastElement()?.Document;
}
@computed get rowIndex() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index bd6d3bad6..af0fe73c3 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import Select, { MenuPlacement } from 'react-select';
-import { action, computed, observable } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import { extname } from 'path';
import DatePicker from 'react-datepicker';
@@ -95,13 +95,19 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
return { color, textDecoration, fieldProps, cursor, pointerEvents };
}
+ @observable _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ }
+
@computed get selected() {
- const selected: [Doc, number] | undefined = this.props.selectedCell();
- return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+ const selected: [Doc, number] | undefined = this._props.selectedCell();
+ return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
}
@computed get defaultCellContent() {
- const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this.props);
+ const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this._props);
return (
<div
@@ -113,17 +119,17 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
pointerEvents,
}}>
<EditableView
- oneLine={this.props.oneLine}
- allowCRs={this.props.allowCRs}
+ oneLine={this._props.oneLine}
+ allowCRs={this._props.allowCRs}
contents={<FieldView {...fieldProps} />}
editing={this.selected ? undefined : false}
- GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+ GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey)}
SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => {
if (shiftDown && enterKey) {
- this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
+ this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
}
- const ret = KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
- this.props.finishEdit?.();
+ const ret = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value);
+ this._props.finishEdit?.();
return ret;
}, 'edit schema cell')}
/>
@@ -132,8 +138,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
}
get getCellType() {
- const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
- const cellValue = this.props.Document[this.props.fieldKey];
+ const columnTypeStr = this._props.getFinfo(this._props.fieldKey)?.fieldType;
+ const cellValue = this._props.Document[this._props.fieldKey];
if (cellValue instanceof ImageField) return ColumnType.Image;
if (cellValue instanceof DateField) return ColumnType.Date;
if (cellValue instanceof RichTextField) return ColumnType.RTF;
@@ -152,11 +158,11 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
const cellType: ColumnType = this.getCellType;
// prettier-ignore
switch (cellType) {
- case ColumnType.Image: return <SchemaImageCell {...this.props} />;
- case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
- case ColumnType.RTF: return <SchemaRTFCell {...this.props} />;
- case ColumnType.Enumeration: return <SchemaEnumerationCell {...this.props} options={this.props.getFinfo(this.props.fieldKey)?.values?.map(val => val.toString())} />;
- case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
+ case ColumnType.Image: return <SchemaImageCell {...this._props} />;
+ case ColumnType.Boolean: return <SchemaBoolCell {...this._props} />;
+ case ColumnType.RTF: return <SchemaRTFCell {...this._props} />;
+ case ColumnType.Enumeration: return <SchemaEnumerationCell {...this._props} options={this._props.getFinfo(this._props.fieldKey)?.values?.map(val => val.toString())} />;
+ case ColumnType.Date: // return <SchemaDateCell {...this._props} />;
default: return this.defaultCellContent;
}
}
@@ -165,8 +171,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
return (
<div
className="schema-table-cell"
- onPointerDown={action(e => !this.selected && this.props.selectCell(this.props.Document, this.props.col))}
- style={{ padding: this.props.padding, maxWidth: this.props.maxWidth?.(), width: this.props.columnWidth() || undefined, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+ onPointerDown={action(e => !this.selected && this._props.selectCell(this._props.Document, this._props.col))}
+ style={{ padding: this._props.padding, maxWidth: this._props.maxWidth?.(), width: this._props.columnWidth() || undefined, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
{this.content}
</div>
);
@@ -176,7 +182,14 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
// mj: most of this is adapted from old schema code so I'm not sure what it does tbh
@observer
export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
- @observable _previewRef: HTMLImageElement | undefined;
+ @observable _previewRef: HTMLImageElement | undefined = undefined;
+
+ _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
choosePath(url: URL) {
if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
@@ -188,8 +201,8 @@ export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
}
get url() {
- const field = Cast(this.props.Document[this.props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
- const alts = DocListCast(this.props.Document[this.props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
+ const field = Cast(this._props.Document[this._props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+ const alts = DocListCast(this._props.Document[this._props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
const altpaths = alts
.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url)
.filter(url => url)
@@ -226,10 +239,10 @@ export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
};
render() {
- const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
- // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
+ const aspect = Doc.NativeAspect(this._props.Document); // aspect ratio
+ // let width = Math.max(75, this._props.columnWidth); // get a with that is no smaller than 75px
// const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
- const height = this.props.rowHeight() ? this.props.rowHeight() - (this.props.padding || 6) * 2 : undefined;
+ const height = this._props.rowHeight() ? this._props.rowHeight() - (this._props.padding || 6) * 2 : undefined;
const width = height ? height * aspect : undefined; // increase the width of the image if necessary to maintain proportionality
return <img src={this.url} width={width ? width : undefined} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
@@ -240,19 +253,26 @@ export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
@observable _pickingDate: boolean = false;
+ @observable _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+
@computed get date(): DateField {
// if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined.
- return DateCast(this.props.Document[this.props.fieldKey]);
+ return DateCast(this._props.Document[this._props.fieldKey]);
}
@action
handleChange = (date: any) => {
// const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
// if (script.compiled) {
- // this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
+ // this.applyToDoc(this._document, this._props.row, this._props.col, script.run);
// } else {
// ^ DateCast is always undefined for some reason, but that is what the field should be set to
- this.props.Document[this.props.fieldKey] = new DateField(date as Date);
+ this._props.Document[this._props.fieldKey] = new DateField(date as Date);
//}
};
@@ -262,13 +282,20 @@ export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
}
@observer
export class SchemaRTFCell extends React.Component<SchemaTableCellProps> {
+ @observable _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+
@computed get selected() {
- const selected: [Doc, number] | undefined = this.props.selectedCell();
- return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+ const selected: [Doc, number] | undefined = this._props.selectedCell();
+ return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
}
selectedFunc = () => this.selected;
render() {
- const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+ const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
fieldProps.isContentActive = this.selectedFunc;
return (
<div className="schemaRTFCell" style={{ display: 'flex', fontStyle: this.selected ? undefined : 'italic', width: '100%', height: '100%', position: 'relative', color, textDecoration, cursor, pointerEvents }}>
@@ -279,35 +306,42 @@ export class SchemaRTFCell extends React.Component<SchemaTableCellProps> {
}
@observer
export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
+ @observable _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+
@computed get selected() {
- const selected: [Doc, number] | undefined = this.props.selectedCell();
- return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+ const selected: [Doc, number] | undefined = this._props.selectedCell();
+ return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
}
render() {
- const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+ const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
return (
<div className="schemaBoolCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
<input
style={{ marginRight: 4 }}
type="checkbox"
- checked={BoolCast(this.props.Document[this.props.fieldKey])}
+ checked={BoolCast(this._props.Document[this._props.fieldKey])}
onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
if ((value?.nativeEvent as any).shiftKey) {
- this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+ this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
}
- KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+ KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
})}
/>
<EditableView
contents={<FieldView {...fieldProps} />}
editing={this.selected ? undefined : false}
- GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+ GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey)}
SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
if (shiftDown && enterKey) {
- this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
+ this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
}
- const set = KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
- this.props.finishEdit?.();
+ const set = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value);
+ this._props.finishEdit?.();
return set;
})}
/>
@@ -317,13 +351,20 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
}
@observer
export class SchemaEnumerationCell extends React.Component<SchemaTableCellProps> {
+ @observable _props: React.PropsWithChildren<SchemaTableCellProps>;
+ constructor(props: React.PropsWithChildren<SchemaTableCellProps>) {
+ super(props);
+ this._props = props;
+ makeObservable(this);
+ }
+
@computed get selected() {
- const selected: [Doc, number] | undefined = this.props.selectedCell();
- return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+ const selected: [Doc, number] | undefined = this._props.selectedCell();
+ return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
}
render() {
- const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
- const options = this.props.options?.map(facet => ({ value: facet, label: facet }));
+ const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
+ const options = this._props.options?.map(facet => ({ value: facet, label: facet }));
return (
<div className="schemaSelectionCell" style={{ color, textDecoration, cursor, pointerEvents }}>
<div style={{ width: '100%' }}>
@@ -357,17 +398,17 @@ export class SchemaEnumerationCell extends React.Component<SchemaTableCellProps>
...base,
left: 0,
top: 0,
- transform: `translate(${this.props.transform().TranslateX}px, ${this.props.transform().TranslateY}px)`,
- width: Number(base.width) * this.props.transform().Scale,
+ transform: `translate(${this._props.transform().TranslateX}px, ${this._props.transform().TranslateY}px)`,
+ width: Number(base.width) * this._props.transform().Scale,
zIndex: 9999,
}),
}}
- menuPortalTarget={this.props.menuTarget}
+ menuPortalTarget={this._props.menuTarget}
menuPosition={'absolute'}
- placeholder={StrCast(this.props.Document[this.props.fieldKey], 'select...')}
+ placeholder={StrCast(this._props.Document[this._props.fieldKey], 'select...')}
options={options}
isMulti={false}
- onChange={val => KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)}
+ onChange={val => KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)}
/>
</div>
</div>