aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx4
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx10
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx13
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx25
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx32
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx54
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewColumn.tsx6
-rw-r--r--src/client/views/collections/CollectionPileView.tsx5
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx30
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx65
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx33
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx61
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx100
-rw-r--r--src/client/views/collections/CollectionView.tsx19
-rw-r--r--src/client/views/collections/TabDocView.tsx28
-rw-r--r--src/client/views/collections/TreeView.scss10
-rw-r--r--src/client/views/collections/TreeView.tsx137
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss12
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx318
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss13
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx25
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss48
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx316
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/index.ts12
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx6
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx23
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx69
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx13
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx6
-rw-r--r--src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.scss16
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx24
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx30
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx53
38 files changed, 660 insertions, 990 deletions
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
index 4c0a917f5..cbcc980a9 100644
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ b/src/client/views/collections/CollectionCalendarView.tsx
@@ -62,7 +62,7 @@ export class CollectionCalendarView extends CollectionSubView() {
screenToLocalTransform = () =>
this._props
.ScreenToLocalTransform()
- .translate(Doc.NativeWidth(this._props.Document), 0)
+ .translate(Doc.NativeWidth(this.Document), 0)
.scale(this._props.NativeDimScaling?.() || 1);
get calendarsKey() {
@@ -74,7 +74,7 @@ export class CollectionCalendarView extends CollectionSubView() {
<div className="collectionCalendarView">
<CollectionStackingView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
ref={this._stackRef}
PanelHeight={this.panelHeight}
PanelWidth={this._props.PanelWidth}
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 8e072e235..7e484f3df 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Utils, returnFalse, returnZero } from '../../../Utils';
+import { Utils, emptyFunction, returnFalse, returnZero } from '../../../Utils';
import { Doc, DocListCast } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -10,7 +10,8 @@ import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions } from '../nodes/FieldView';
import './CollectionCarousel3DView.scss';
import { CollectionSubView } from './CollectionSubView';
const { default: { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore
@@ -49,7 +50,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
.translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2)
.scale(1 / this.centerScale);
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return;
options.didMove = true;
@@ -70,7 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
layout_fitWidth={undefined}
- onDoubleClick={this.onChildDoubleClick}
+ onDoubleClickScript={this.onChildDoubleClick}
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
@@ -80,7 +81,6 @@ export class CollectionCarousel3DView extends CollectionSubView() {
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
- bringToFront={returnFalse}
/>
);
};
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index a125f1356..dae16bafb 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -7,11 +7,11 @@ import { Doc, Opt } from '../../../fields/Doc';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DragManager } from '../../util/DragManager';
import { StyleProp } from '../StyleProvider';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import './CollectionCarouselView.scss';
import { CollectionSubView } from './CollectionSubView';
-import { FieldViewProps } from '../nodes/FieldView';
@observer
export class CollectionCarouselView extends CollectionSubView() {
@@ -41,7 +41,7 @@ export class CollectionCarouselView extends CollectionSubView() {
e.stopPropagation();
this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
};
- captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string): any => {
// first look for properties on the document in the carousel, then fallback to properties on the container
const childValue = doc?.['caption-' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined;
return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property);
@@ -66,9 +66,9 @@ export class CollectionCarouselView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
layout_fitWidth={undefined}
- setContentView={undefined}
- onDoubleClick={this.onContentDoubleClick}
- onClick={this.onContentClick}
+ setContentViewBox={undefined}
+ onDoubleClickScript={this.onContentDoubleClick}
+ onClickScript={this.onContentClick}
isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction}
hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions
@@ -78,7 +78,6 @@ export class CollectionCarouselView extends CollectionSubView() {
Document={curDoc.layout}
TemplateDataDocument={DocCast(curDoc.layout.resolvedDataDoc)}
PanelHeight={this.panelHeight}
- bringToFront={returnFalse}
/>
</div>
{!carouselShowsCaptions ? null : (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 874cdffd9..d9d6a5eb5 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import * as GoldenLayout from '../../../client/goldenLayout';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
+import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
@@ -277,8 +277,8 @@ export class CollectionDockingView extends CollectionSubView() {
}
setupGoldenLayout = async () => {
if (this._unmounting) return;
- //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.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.Document)));
+ const config = StrCast(this.Document.dockingConfig);
if (config) {
const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
@@ -322,7 +322,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.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.
@@ -381,7 +381,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.Document.dockingConfig !== json;
if (changesMade) {
if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) {
this.layoutDoc.dockingConfig = json;
@@ -421,7 +421,6 @@ export class CollectionDockingView extends CollectionSubView() {
if (map?.DashDoc && DocumentManager.Instance.getFirstDocumentView(map.DashDoc)) {
SelectionManager.SelectView(DocumentManager.Instance.getFirstDocumentView(map.DashDoc), false);
}
- if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
}
}
}
@@ -431,7 +430,7 @@ export class CollectionDockingView extends CollectionSubView() {
};
public CaptureThumbnail() {
- const content = this._props.DocumentView?.()?.ContentDiv;
+ const content = this.DocumentView?.()?.ContentDiv;
if (content) {
const _width = Number(getComputedStyle(content).width.replace('px', ''));
const _height = Number(getComputedStyle(content).height.replace('px', ''));
@@ -449,7 +448,7 @@ export class CollectionDockingView extends CollectionSubView() {
if (clone) {
const cloned = await Doc.MakeClone(doc);
Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id])));
- Doc.GetProto(cloned.clone).dockingConfig = json;
+ cloned.clone[DocData].dockingConfig = json;
return DashboardView.openDashboard(cloned.clone);
}
const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
@@ -463,7 +462,7 @@ export class CollectionDockingView extends CollectionSubView() {
const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab);
const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
if (newtabdocs.length) {
- Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
+ newtab[DocData].data = new List<Doc>(newtabdocs);
newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab));
}
json = json.replace(origtab[Id], newtab[Id]);
@@ -479,7 +478,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.Document.dockingConfig !== json;
return changesMade;
};
@@ -489,8 +488,10 @@ export class CollectionDockingView extends CollectionSubView() {
Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc, undefined, undefined, true);
// if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed
if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined;
- if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
- Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc);
+ if (!tab.DashDoc.embedContainer) {
+ Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+ Doc.RemoveEmbedding(tab.DashDoc, tab.DashDoc);
+ }
}
if (CollectionDockingView.Instance) {
const dview = CollectionDockingView.Instance.Document;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 8627ba650..41c5d5b42 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -71,7 +71,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document);
}
};
@action
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 98ae01591..8729ef549 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -11,7 +11,7 @@ import { RichTextField } from '../../../fields/RichTextField';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
-import { DragManager } from '../../util/DragManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { Transform } from '../../util/Transform';
@@ -19,14 +19,17 @@ import { undoBatch } from '../../util/UndoManager';
import { AntimodeMenu } from '../AntimodeMenu';
import { EditableView } from '../EditableView';
import { MainView } from '../MainView';
-import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
import { DefaultStyleProvider } from '../StyleProvider';
import { CollectionLinearView } from './collectionLinear';
import './CollectionMenu.scss';
+import { DocData } from '../../../fields/DocSymbols';
interface CollectionMenuProps {
panelHeight: () => number;
panelWidth: () => number;
+ toggleTopBar: () => void;
+ topBarHeight: () => number;
}
@observer
@@ -66,15 +69,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
};
@action
- toggleTopBar = () => {
- if (SettingsManager.Instance.headerBarHeight > 0) {
- SettingsManager.Instance.headerBarHeight = 0;
- } else {
- SettingsManager.Instance.headerBarHeight = 60;
- }
- };
-
- @action
toggleProperties = () => {
if (MainView.Instance.propertiesWidth() > 0) {
SettingsManager.Instance.propertiesWidth = 0;
@@ -95,16 +89,14 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
<div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this._props.panelHeight() }}>
<CollectionLinearView
Document={selDoc}
+ docViewPath={returnEmptyDocViewList}
fieldKey="data"
- dropAction="embed"
- setHeight={returnFalse}
+ dropAction={dropActionType.embed}
styleProvider={DefaultStyleProvider}
- bringToFront={emptyFunction}
select={emptyFunction}
isContentActive={returnTrue}
isAnyChildContentActive={returnFalse}
isSelected={returnFalse}
- docViewPath={returnEmptyDoclist}
moveDocument={returnFalse}
addDocument={returnFalse}
addDocTab={DocumentViewInternal.addDocTabFunc}
@@ -125,8 +117,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
}
render() {
- 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 headerIcon = this.props.topBarHeight() > 0 ? 'angle-double-up' : 'angle-double-down';
+ const headerTitle = this.props.topBarHeight() > 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';
@@ -136,8 +128,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
toggleType={ToggleType.BUTTON}
type={Type.PRIM}
color={SettingsManager.userColor}
- onClick={this.toggleTopBar}
- toggleStatus={SettingsManager.Instance.headerBarHeight > 0}
+ onClick={this.props.toggleTopBar}
+ toggleStatus={this.props.topBarHeight() > 0}
icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
tooltip={headerTitle}
/>
@@ -221,7 +213,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
params: ['target', 'source'],
title: 'set content',
script: 'getProto(this.target).data = copyField(this.source);',
- immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List<Doc>(source))),
+ immediate: undoBatch((source: Doc[]) => (this.target[DocData].data = new List<Doc>(source))),
initialize: emptyFunction,
};
_onClickCommand = {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 302ccd2db..b8133806f 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -1,6 +1,6 @@
-import * as React from 'react';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
+import * as React from 'react';
import { Doc, Field, Opt } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Copy, Id } from '../../../fields/FieldSymbols';
@@ -18,14 +18,15 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { LightboxView } from '../LightboxView';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import './CollectionNoteTakingView.scss';
import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn';
import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider';
import { CollectionSubView } from './CollectionSubView';
+import { JsxElement } from 'typescript';
const _global = (window /* browser */ || global) /* node */ as any;
/**
@@ -51,7 +52,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
@computed get chromeHidden() {
- return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClick?.() ? true : false;
+ return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false;
}
// columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
@computed get colHeaderData() {
@@ -189,7 +190,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
};
// let's dive in and get the actual document we want to drag/move around
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
@@ -203,7 +204,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
};
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
switch (property) {
case StyleProp.BoxShadow:
if (doc && DragManager.docsBeingDragged.includes(doc)) {
@@ -238,7 +239,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
PanelWidth={width}
PanelHeight={height}
styleProvider={this.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
layout_fitWidth={this._props.childLayoutFitWidth}
isContentActive={emptyFunction}
onKey={this.onKeyDown}
@@ -254,9 +255,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
rootSelected={this.rootSelected}
layout_showTitle={this._props.childlayout_showTitle}
dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onBrowseClick={this._props.onBrowseClick}
- onDoubleClick={this.onChildDoubleClickHandler}
+ onClickScript={this.onChildClickHandler}
+ onBrowseClickScript={this._props.onBrowseClickScript}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={noteTakingDocTransform}
focus={this.focusDocument}
childFilters={this.childDocFilters}
@@ -267,10 +268,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
removeDocument={this._props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any}
+ contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
- bringToFront={returnFalse}
pinToPres={this._props.pinToPres}
/>
);
@@ -407,11 +407,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
@undoBatch
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- const docView = fieldProps.DocumentView?.();
- if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
+ if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
e.stopPropagation?.();
- const newDoc = Doc.MakeCopy(docView.Document, true);
- Doc.GetProto(newDoc).text = undefined;
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
@@ -443,7 +442,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
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.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();
de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
@@ -503,6 +502,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
const type = 'number';
return (
<CollectionNoteTakingViewColumn
+ key={heading?.heading ?? 'unset'}
unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
observeHeight={ref => {
if (ref) {
@@ -511,7 +511,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
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())) {
+ if (!LightboxView.Contains(this.DocumentView?.())) {
this._props.setHeight?.(height);
}
}
@@ -536,7 +536,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
dividerWidth={this.DividerWidth}
maxColWidth={this.maxColWidth}
availableWidth={this.availableWidth}
- key={heading?.heading ?? 'unset'}
headings={this.headings}
heading={heading?.heading ?? 'unset'}
headingObject={heading}
@@ -598,14 +597,11 @@ export class CollectionNoteTakingView extends CollectionSubView() {
@computed get renderedSections() {
TraceMobx();
const sections = Array.from(this.Sections.entries());
- return sections.map((sec, i) => (
- <>
- {this.sectionNoteTaking(sec[0], sec[1])}
- {i === sections.length - 1 ? null : ( //
- <CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />
- )}
- </>
- ));
+ return sections.reduce((list, sec, i) => {
+ list.push(this.sectionNoteTaking(sec[0], sec[1]));
+ i !== sections.length - 1 && list.push(<CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />);
+ return list;
+ }, [] as JSX.Element[]);
}
@computed get nativeWidth() {
@@ -643,8 +639,8 @@ export class CollectionNoteTakingView extends CollectionSubView() {
onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
- onWheel={e => this._props.isContentActive(true) && e.stopPropagation()}>
- {this.renderedSections}
+ onWheel={e => this._props.isContentActive() && e.stopPropagation()}>
+ <>{this.renderedSections}</>
</div>
);
}
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 3f6d3c82e..38846c79d 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -81,7 +81,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
}
};
@@ -90,11 +90,11 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
}
@undoBatch
- columnDrop = action((e: Event, de: DragManager.DropEvent) => {
+ columnDrop = (e: Event, de: DragManager.DropEvent) => {
const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
drop.docs?.forEach(d => Doc.SetInPlace(d, this._props.pivotField, drop.val, false));
return true;
- });
+ };
getValue = (value: string): any => {
const parsed = parseInt(value);
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index b1d379631..7d7f0bb61 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -13,6 +13,7 @@ import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import './CollectionPileView.scss';
import { CollectionSubView } from './CollectionSubView';
+import { dropActionType } from '../../util/DragManager';
@observer
export class CollectionPileView extends CollectionSubView() {
@@ -48,7 +49,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.DocumentView?.()._props.removeDocument?.(this.Document);
return ret;
};
@@ -72,7 +73,7 @@ export class CollectionPileView extends CollectionSubView() {
// pile children never have their contents active, but will be document active whenever the entire pile is.
childContentsActive={returnFalse}
childDocumentsActive={this._props.isDocumentActive}
- childDragAction="move"
+ childDragAction={dropActionType.move}
childClickScript={this.toggleIcon}
/>
</div>
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 22a67c501..5c47d4b9e 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { Doc, Opt } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
@@ -23,17 +24,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager';
import { CollectionSubView } from '../collections/CollectionSubView';
import { LightboxView } from '../LightboxView';
import { AudioWaveform } from '../nodes/audio/AudioWaveform';
-import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
+import { DocumentView, OpenWhere } from '../nodes/DocumentView';
+import { FocusFuncType, FocusViewOptions, StyleProviderFuncType } from '../nodes/FieldView';
import { LabelBox } from '../nodes/LabelBox';
import { VideoBox } from '../nodes/VideoBox';
import { ObservableReactComponent } from '../ObservableReactComponent';
import './CollectionStackedTimeline.scss';
-import { FieldViewProps } from '../nodes/FieldView';
export type CollectionStackedTimelineProps = {
Play: () => void;
Pause: () => void;
- playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
+ playLink: (linkDoc: Doc, options: FocusViewOptions) => void;
playFrom: (seekTimeInSeconds: number, endTime?: number) => void;
playing: () => boolean;
thumbnails?: () => string[];
@@ -162,7 +163,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc);
- getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
+ getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
@@ -427,8 +428,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
_isTimelineLabel: true,
layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
});
- Doc.GetProto(anchor)[startTag] = anchorStartTime;
- Doc.GetProto(anchor)[endTag] = anchorEndTime;
+ anchor[DocData][startTag] = anchorStartTime;
+ anchor[DocData][endTag] = anchorEndTime;
if (addAsAnnotation) {
if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
@@ -579,7 +580,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
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 : (
+ return this.Document.hideAnchors ? null : (
<div
className={'collectionStackedTimeline-marker-timeline'}
key={d.anchor[Id]}
@@ -691,8 +692,8 @@ interface StackedTimelineAnchorProps {
width: number;
height: number;
toTimeline: (screen_delta: number, width: number) => number;
- styleProvider?: StyleProviderFunc;
- playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
+ styleProvider?: StyleProviderFuncType;
+ playLink: (linkDoc: Doc, options: FocusViewOptions) => void;
setTime: (time: number) => void;
startTag: string;
endTag: string;
@@ -701,7 +702,7 @@ interface StackedTimelineAnchorProps {
isDocumentActive?: () => boolean | undefined;
ScreenToLocalTransform: () => Transform;
_timeline: HTMLDivElement | null;
- focus: DocFocusFunc;
+ focus: FocusFuncType;
currentTimecode: () => number;
isSelected: () => boolean;
stackedTimeline: CollectionStackedTimeline;
@@ -810,7 +811,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
// renders anchor LabelBox
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 => {
+ const focusFunc = (doc: Doc, options: FocusViewOptions): number | undefined => {
this._props.playLink(mark, options);
return undefined;
};
@@ -825,7 +826,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
ref={action((r: DocumentView | null) => (anchor.view = r))}
Document={mark}
TemplateDataDocument={undefined}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
pointerEvents={this.noEvents ? returnNone : undefined}
styleProvider={this._props.styleProvider}
renderDepth={this._props.renderDepth + 1}
@@ -842,11 +843,10 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
searchFilterDocs={returnEmptyDoclist}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
- onClick={script}
- onDoubleClick={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
+ onClickScript={script}
+ onDoubleClickScript={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
ignoreAutoHeight={false}
hideResizeHandles={true}
- bringToFront={emptyFunction}
contextMenuItems={this.contextMenuItems}
/>
),
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 995f071ca..54314f62c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,8 +24,8 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
import { LightboxView } from '../LightboxView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
@@ -135,14 +135,15 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return docs.map((d, i) => {
const height = () => this.getDocHeight(d);
const width = () => this.getDocWidth(d);
+ const trans = () => this.getDocTransition(d);
// assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
// just getting the style
- const style = this.isStackingView ? { margin: this.Document._stacking_alignCenter ? 'auto' : undefined, width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+ const style = this.isStackingView ? { margin: this.Document._stacking_alignCenter ? 'auto' : undefined, transition: trans(), width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
// So we're choosing whether we're going to render a column or a masonry doc
return (
<div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
- {this.getDisplayDoc(d, width, i)}
+ {this.getDisplayDoc(d, width, trans, i)}
</div>
);
});
@@ -203,7 +204,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
componentDidMount() {
super.componentDidMount?.();
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
@@ -249,7 +250,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
// let's dive in and get the actual document we want to drag/move around
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
@@ -265,7 +266,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return undefined;
};
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (property === StyleProp.Opacity && doc) {
if (this._props.childOpacity) {
return this._props.childOpacity();
@@ -278,18 +279,17 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
@undoBatch
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- const docView = fieldProps.DocumentView?.();
- if (docView && ['Enter'].includes(e.key) && e.ctrlKey) {
+ if (['Enter'].includes(e.key) && e.ctrlKey) {
e.stopPropagation?.();
const below = !e.altKey && e.key !== 'Tab';
- const layout_fieldKey = StrCast(docView.LayoutFieldKey);
- const newDoc = Doc.MakeCopy(docView.Document, true);
- const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
+ const layout_fieldKey = StrCast(fieldProps.fieldKey);
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) {
- newDoc[layout_fieldKey] = docView.Document[layout_fieldKey];
+ if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
+ newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
}
- Doc.GetProto(newDoc).text = undefined;
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
@@ -310,7 +310,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
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) {
+ getDisplayDoc(doc: Doc, width: () => number, trans: () => string, count: number) {
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()));
@@ -325,13 +325,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
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.DocumentView?.()._props.onClickScript?.() ? 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}
+ containerViewPath={this.childContainerViewPath}
layout_fitWidth={this.childFitWidth}
isContentActive={doc.onClick ? this.isChildButtonContentActive : this.isChildContentActive}
onKey={this.onKeyDown}
- onBrowseClick={this._props.onBrowseClick}
+ DataTransition={trans}
+ onBrowseClickScript={this._props.onBrowseClickScript}
isDocumentActive={this.isContentActive}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
@@ -342,8 +343,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
rootSelected={this.rootSelected}
layout_showTitle={this._props.childlayout_showTitle}
dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={stackedDocTransform}
focus={this.focusDocument}
childFilters={this.childDocFilters}
@@ -356,10 +357,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
removeDocument={this._props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any}
+ contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
- bringToFront={returnFalse}
pinToPres={this._props.pinToPres}
/>
);
@@ -381,6 +381,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
return maxWidth;
}
+ getDocTransition(d?: Doc) {
+ if (!d) return '';
+ return StrCast(d.dataTransition);
+ }
getDocHeight(d?: Doc) {
if (!d || d.hidden) return 0;
const childLayoutDoc = Doc.Layout(d, this._props.childLayoutTemplate?.());
@@ -469,7 +473,7 @@ 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.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();
de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
@@ -540,7 +544,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
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())) {
+ if (!LightboxView.Contains(this.DocumentView?.())) {
this._props.setHeight?.(height);
}
}
@@ -552,7 +556,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this.addDocument}
chromeHidden={this.chromeHidden}
colHeaderData={this.colHeaderData}
- Document={this._props.Document}
+ Document={this.Document}
TemplateDataDocument={this._props.TemplateDataDocument}
renderChildren={this.children}
columnWidth={this.columnWidth}
@@ -584,7 +588,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return (
<CollectionMasonryViewFieldRow
showHandle={first}
- Document={this._props.Document}
+ Document={this.Document}
chromeHidden={this.chromeHidden}
pivotField={this.pivotField}
unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
@@ -671,7 +675,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
addDocTab={this._props.addDocTab}
- onBrowseClick={this._props.onBrowseClick}
+ onBrowseClickScript={this._props.onBrowseClickScript}
pinToPres={emptyFunction}
rootSelected={this.rootSelected}
removeDocument={this._props.removeDocument}
@@ -681,9 +685,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
renderDepth={this._props.renderDepth}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -739,7 +742,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.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 69f1c332d..c455f20d8 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -74,7 +74,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
}
};
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 570330174..fdbd1cc90 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -62,17 +62,16 @@ export function CollectionSubView<X>(moreProps?: X) {
}
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
+ return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : Doc.GetProto(this.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
}
+ get childContainerViewPath() {
+ return this.DocumentView?.().docViewPath;
+ }
// 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?.());
- // 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.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'
@@ -93,14 +92,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.Document._childFilters);
+ collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.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()];
// 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);
+ searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -123,7 +122,7 @@ export function CollectionSubView<X>(moreProps?: X) {
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.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
}
@@ -132,9 +131,9 @@ export function CollectionSubView<X>(moreProps?: X) {
// dragging facets
const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter));
if (dragged && SnappingManager.CanEmbed && 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.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.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];
@@ -167,7 +166,7 @@ export function CollectionSubView<X>(moreProps?: X) {
@action
protected async setCursorPosition(position: [number, number]) {
let ind;
- const doc = this._props.Document;
+ const doc = this.Document;
const id = Doc.UserDoc()[Id];
const email = Doc.CurrentUserEmail;
const pos = { x: position[0], y: position[1] };
@@ -197,13 +196,11 @@ export function CollectionSubView<X>(moreProps?: X) {
@undoBatch
protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {}
- protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) {
+ protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, dropAction: dropActionType) {
if (de.complete.docDragData) {
- // override the dropEvent's dropAction
- 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.Document && this.childDocs.includes(d))) {
de.complete.docDragData.dropAction = dropAction;
}
e.stopPropagation();
@@ -467,7 +464,7 @@ 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.Document._type_collection === CollectionViewType.Freeform;
const set = !isFreeformView
? generatedDocuments
: generatedDocuments.length > 1
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 7036ec41c..b92edd165 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,12 +1,10 @@
-import { toUpper } from 'lodash';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
import { Doc, Opt, StrListCast } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
-import { RichTextField } from '../../../fields/RichTextField';
import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
@@ -15,8 +13,9 @@ import { DocumentManager } from '../../util/DocumentManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { EditableView } from '../EditableView';
-import { DocFocusOptions, DocumentView } from '../nodes/DocumentView';
+import { FieldsDropdown } from '../FieldsDropdown';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions } from '../nodes/FieldView';
import { PresBox } from '../nodes/trails';
import { CollectionSubView } from './CollectionSubView';
import './CollectionTimeView.scss';
@@ -38,7 +37,7 @@ export class CollectionTimeView extends CollectionSubView() {
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
runInAction(() => {
this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name });
this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
@@ -68,7 +67,7 @@ export class CollectionTimeView extends CollectionSubView() {
};
@action
- scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
+ scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: FocusViewOptions) => {
// if in preview, then override document's fields with view spec
this._focusFilters = StrListCast(anchor.config_docFilters);
this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters);
@@ -191,50 +190,6 @@ export class CollectionTimeView extends CollectionSubView() {
ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
};
- @computed get _allFacets() {
- const facets = new Set<string>();
- this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
- Doc.AreProtosEqual(this.dataDoc, this.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key)));
- return Array.from(facets);
- }
- menuCallback = (x: number, y: number) => {
- ContextMenu.Instance.clearItems();
- const docItems: ContextMenuProps[] = [];
- const keySet: Set<string> = new Set();
-
- this.childLayoutPairs.map(pair =>
- this._allFacets
- .filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof pair.layout[fieldKey] === 'number' || typeof pair.layout[fieldKey] === 'boolean' || typeof pair.layout[fieldKey] === 'string')
- .filter(fieldKey => fieldKey[0] !== '_' && (fieldKey === 'tags' || fieldKey[0] === toUpper(fieldKey)[0]))
- .map(fieldKey => keySet.add(fieldKey))
- );
- Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' }));
- docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' });
- ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' });
- ContextMenu.Instance.displayMenu(x, y, ':');
- };
-
- @computed get pivotKeyUI() {
- return (
- <div className={'pivotKeyEntry'}>
- <EditableView
- GetValue={returnEmptyString}
- SetValue={(value: any) => {
- if (value?.length) {
- this.layoutDoc._pivotField = value;
- return true;
- }
- return false;
- }}
- background={'#f1efeb'} // this._props.headingObject ? this._props.headingObject.color : "#f1efeb";
- contents={':' + StrCast(this.layoutDoc._pivotField)}
- showMenuOnLoad={true}
- display={'inline'}
- menuCallback={this.menuCallback}
- />
- </div>
- );
- }
render() {
let nonNumbers = 0;
@@ -261,7 +216,6 @@ export class CollectionTimeView extends CollectionSubView() {
return (
<div className={'collectionTimeView' + (doTimeline ? '' : '-pivot')} onContextMenu={this.specificMenu} style={{ width: this._props.PanelWidth(), height: '100%' }}>
- {this.pivotKeyUI}
{this.contents}
{!this._props.isSelected() || !doTimeline ? null : (
<>
@@ -270,6 +224,9 @@ export class CollectionTimeView extends CollectionSubView() {
<div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} />
</>
)}
+ <div style={{ right: 0, top: 0, position: 'absolute' }}>
+ <FieldsDropdown Document={this.Document} selectFunc={fieldKey => (this.layoutDoc._pivotField = fieldKey)} placeholder={StrCast(this.layoutDoc._pivotField)} />
+ </div>
</div>
);
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 18e0b98ef..4d60cbefc 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -8,8 +8,8 @@ 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 { DocUtils } from '../../documents/Documents';
+import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils';
+import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
@@ -27,6 +27,7 @@ import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView } from './CollectionSubView';
import './CollectionTreeView.scss';
import { TreeView } from './TreeView';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
const _global = (window /* browser */ || global) /* node */ as any;
export type collectionTreeViewProps = {
@@ -51,6 +52,7 @@ export enum TreeViewType {
@observer
export class CollectionTreeView extends CollectionSubView<Partial<collectionTreeViewProps>>() {
+ public static AddTreeFunc = 'addTreeFolder(this.embedContainer)';
private _treedropDisposer?: DragManager.DragDropDisposer;
private _mainEle?: HTMLDivElement;
private _titleRef?: HTMLDivElement | HTMLInputElement | null;
@@ -140,20 +142,35 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
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) => {
- const dropAction = this.layoutDoc.dropAction as dropActionType;
+ protected onInternalDrop(e: Event, de: DragManager.DropEvent) {
+ const res = super.onInternalDrop(e, de);
+ if (res && de.complete.docDragData) {
+ if (this.Document !== Doc.MyRecentlyClosed)
+ de.complete.docDragData.droppedDocuments.forEach(doc => {
+ if (this.Document !== Doc.MyRecentlyClosed) Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc);
+ });
+ }
+ return res;
+ }
+
+ protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetDropAction: dropActionType) => {
const dragData = de.complete.docDragData;
if (dragData) {
- const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.Document) ? true : false;
+ const sourceDragAction = dragData.dropAction;
+ const sameTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.Document);
const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d));
- if (isAlreadyInTree() !== sameTree) {
- console.log('WHAAAT');
- }
- dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree && dragData.dropAction !== 'inSame' ? 'same' : dragData.dropAction;
+ dragData.dropAction =
+ targetDropAction && !isAlreadyInTree() // if dropped document is not in the tree
+ ? targetDropAction // then use the target's drop action if it's specified
+ : !sameTree() || sourceDragAction === dropActionType.inPlace // if doc from another tree, or a non inPlace source drag action is specified
+ ? sourceDragAction // use the source dragAction
+ : dropActionType.same; // otherwise use same tree semantics to move within tree
e.stopPropagation();
}
};
+ dragConfig = (dragData: DragManager.DocumentDragData) => (dragData.treeViewDoc = this.Document);
+
screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight);
@action
@@ -163,34 +180,41 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
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);
- if (ind > 0 && prev) {
- FormattedTextBox.SetSelectOnLoad(prev);
- DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false);
+ if (result.length !== value.length) {
+ if (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);
+ if (ind > 0 && prev) {
+ FormattedTextBox.SetSelectOnLoad(prev);
+ DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false);
+ }
+ return true;
}
- return true;
+ return this._props.removeDocument?.(doc) ?? false;
}
return false;
};
@action
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.Document[DocData], this._props.fieldKey, doc, relativeTo, before);
- res && Doc.SetContainer(doc, this.Document);
- return res;
- }, true);
+ const doclist = docs instanceof Doc ? [docs] : docs;
+ const addDocRelativeTo = (doc: Doc | Doc[]) => doclist.reduce((flg, doc) => flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before), true);
if (this.Document.resolvedDataDoc instanceof Promise) return false;
- return relativeTo === undefined ? this._props.addDocument?.(docs) || false : doAddDoc(docs);
+ const res = relativeTo === undefined ? this._props.addDocument?.(docs) || false : addDocRelativeTo(docs);
+ res &&
+ doclist.forEach(doc => {
+ Doc.SetContainer(doc, this.Document);
+ if (this.Document !== Doc.MyRecentlyClosed) Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc);
+ });
+ return res;
};
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
+ const layoutItems: ContextMenuProps[] = [];
+ const menuDoc = ScriptCast(Cast(this.layoutDoc.layout_headerButton, Doc, null)?.onClick).script.originalScript === CollectionTreeView.AddTreeFunc;
+ menuDoc && layoutItems.push({ description: 'Create new folder', event: () => CollectionTreeView.addTreeFolder(this.Document), icon: 'paint-brush' });
if (!Doc.noviceMode) {
- const layoutItems: ContextMenuProps[] = [];
layoutItems.push({
description: 'Make tree state ' + (this.Document.treeView_OpenIsTransient ? 'persistent' : 'transient'),
event: () => (this.Document.treeView_OpenIsTransient = !this.Document.treeView_OpenIsTransient),
@@ -198,7 +222,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
});
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' });
+ }
+ ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
+ if (!Doc.noviceMode) {
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.Document, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' });
@@ -254,7 +280,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
moveDocument={returnFalse}
removeDocument={returnFalse}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- bringToFront={returnFalse}
/>
);
}
@@ -268,7 +293,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@observable _renderCount = 1;
@computed get treeViewElements() {
TraceMobx();
- const dragAction = StrCast(this.Document.childDragAction) as dropActionType;
+ const dragAction = StrCast(this.Document.childDragAction) as any 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;
if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
@@ -347,9 +372,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
renderDepth={this._props.renderDepth + 1}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -447,20 +471,19 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
{!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? (
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
pointerEvents={this._props.isContentActive() && SnappingManager.IsDragging ? returnAll : returnNone}
isAnnotationOverlay={true}
isAnnotationOverlayScrollable={true}
- childDocumentsActive={this._props.isDocumentActive}
+ childDocumentsActive={this._props.isContentActive}
fieldKey={this._props.fieldKey + '_annotations'}
- dropAction="move"
+ dropAction={dropActionType.move}
select={emptyFunction}
addDocument={this.addAnnotationDocument}
removeDocument={this.remAnnotationDocument}
moveDocument={this.moveAnnotationDocument}
- bringToFront={emptyFunction}
renderDepth={this._props.renderDepth + 1}>
{this.content}
</CollectionFreeFormView>
@@ -470,4 +493,13 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
</div>
);
}
+ static addTreeFolder(container: Doc) {
+ TreeView._editTitleOnLoad = { id: Utils.GenerateGuid(), parent: undefined };
+ const opts = { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true };
+ return Doc.AddDocToList(container, 'data', Docs.Create.TreeDocument([], opts, TreeView._editTitleOnLoad.id));
+ }
}
+
+ScriptingGlobals.add(function addTreeFolder(doc: Doc) {
+ CollectionTreeView.addTreeFolder(doc);
+});
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4a239e4b1..18eb4dd1f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,7 +13,7 @@ import { dropActionType } from '../../util/DragManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { OpenWhere } from '../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCalendarView } from './CollectionCalendarView';
@@ -33,7 +33,7 @@ import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
-interface CollectionViewProps_ extends FieldViewProps {
+export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently)
layoutEngine?: () => string;
@@ -63,9 +63,8 @@ interface CollectionViewProps_ extends FieldViewProps {
RemFromMap?: (treeViewDoc: Doc, index: number[]) => void;
hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views)
}
-export interface CollectionViewProps extends React.PropsWithChildren<CollectionViewProps_> {}
@observer
-export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() {
+export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(CollectionView, fieldStr);
}
@@ -190,7 +189,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
- if (!Doc.noviceMode && !this.Document.annotationOn) {
+ if (!Doc.noviceMode && !this.Document.annotationOn && !this._props.hideClickBehaviors) {
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
const funcs = [
@@ -232,13 +231,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
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
- );
- };
+ pointerEvents = () =>
+ this.layoutDoc._lockedPosition && //
+ this.Document?._type_collection === CollectionViewType.Freeform;
render() {
TraceMobx();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 80808be92..b52f2e7b6 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -29,7 +29,8 @@ import { LightboxView } from '../LightboxView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
import { Colors } from '../global/globalEnums';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { KeyValueBox } from '../nodes/KeyValueBox';
import { DashFieldView } from '../nodes/formattedText/DashFieldView';
import { PinProps, PresBox, PresMovement } from '../nodes/trails';
@@ -37,7 +38,6 @@ import { CollectionDockingView } from './CollectionDockingView';
import { CollectionView } from './CollectionView';
import './TabDocView.scss';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { FieldViewProps } from '../nodes/FieldView';
const _global = (window /* browser */ || global) /* node */ as any;
interface TabDocViewProps {
@@ -118,7 +118,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
titleEle.onchange = (e: any) => {
undoable(() => {
titleEle.size = e.currentTarget.value.length + 3;
- Doc.GetProto(doc).title = e.currentTarget.value;
+ doc[DocData].title = e.currentTarget.value;
}, 'edit tab title')();
};
@@ -416,7 +416,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
return tab !== undefined;
};
@action
- focusFunc = (doc: Doc, options: DocFocusOptions) => {
+ focusFunc = (doc: Doc, options: FocusViewOptions) => {
if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
}
@@ -452,7 +452,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
hideTitle={this._props.keyValue}
Document={this._document}
TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
- onBrowseClick={DocumentView.exploreMode}
+ onBrowseClickScript={DocumentView.exploreMode}
waitForDoubleClickToClick={this.waitForDoubleClick}
isContentActive={this.isContentActive}
isDocumentActive={returnFalse}
@@ -469,8 +469,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
dontCenter={'y'}
whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
focus={this.focusFunc}
- docViewPath={returnEmptyDoclist}
- bringToFront={emptyFunction}
+ containerViewPath={returnEmptyDoclist}
pinToPres={TabDocView.PinDoc}
/>
{this.disableMinimap() ? null : <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />}
@@ -521,6 +520,7 @@ interface TabMiniThumbProps {
miniLeft: () => number;
}
+@observer
class TabMiniThumb extends React.Component<TabMiniThumbProps> {
render() {
return <div className="miniThumb" style={{ width: `${this.props.miniWidth()}% `, height: `${this.props.miniHeight()}% `, left: `${this.props.miniLeft()}% `, top: `${this.props.miniTop()}% ` }} />;
@@ -528,7 +528,7 @@ class TabMiniThumb extends React.Component<TabMiniThumbProps> {
}
@observer
export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps> {
- static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ static miniStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
if (doc) {
switch (property.split(':')[0]) {
default:
@@ -564,6 +564,12 @@ export class TabMinimapView extends ObservableReactComponent<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 };
}
+ @computed get xPadding() {
+ return !this.renderBounds ? 0 : Math.max(0, this._props.PanelWidth() / NumCast(this._props.document._freeform_scale, 1) - 2 * (this.renderBounds.cx - this.renderBounds.l));
+ }
+ @computed get yPadding() {
+ return !this.renderBounds ? 0 : Math.max(0, this._props.PanelHeight() / NumCast(this._props.document._freeform_scale, 1) - 2 * (this.renderBounds.cy - this.renderBounds.l));
+ }
childLayoutTemplate = () => Cast(this._props.document.childLayoutTemplate, Doc, null);
returnMiniSize = () => NumCast(this._props.document._miniMapSize, 150);
miniDown = (e: React.PointerEvent) => {
@@ -595,17 +601,15 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps
<div className="miniMap" style={{ width: miniSize, height: miniSize, background: this._props.background() }}>
<CollectionFreeFormView
Document={this._props.document}
- docViewPath={returnEmptyDoclist}
+ docViewPath={returnEmptyDocViewList}
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
- setHeight={returnFalse}
isContentActive={emptyFunction}
isAnyChildContentActive={returnFalse}
select={emptyFunction}
isSelected={returnFalse}
dontRegisterView={true}
fieldKey={Doc.LayoutFieldKey(this._props.document)}
- bringToFront={emptyFunction}
addDocument={returnFalse}
moveDocument={returnFalse}
removeDocument={returnFalse}
@@ -622,6 +626,8 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps
childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
fitContentsToBox={returnTrue}
+ xPadding={this.xPadding}
+ yPadding={this.yPadding}
/>
<div className="miniOverlay" onPointerDown={this.miniDown}>
<TabMiniThumb miniLeft={miniLeft} miniTop={miniTop} miniWidth={miniWidth} miniHeight={miniHeight} />
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 0a1946f09..2ab1a5ac1 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -128,6 +128,10 @@
position: relative;
z-index: 1;
+ .treeView-rightButtons > .iconButton-container {
+ min-height: unset;
+ }
+
.treeView-background {
width: 100%;
height: 100%;
@@ -220,13 +224,13 @@
}
.treeView-header-above {
- border-top: black 1px solid;
+ border-top: red 1px solid;
}
.treeView-header-below {
- border-bottom: black 1px solid;
+ border-bottom: red 1px solid;
}
.treeView-header-inside {
- border: black 1px solid;
+ border: red 1px solid;
}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 01b80e209..4f2d8b9c0 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -4,7 +4,7 @@ import { IconButton, Size } from 'browndash-components';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick } from '../../../Utils';
+import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../Utils';
import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
@@ -27,8 +27,8 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager';
import { EditableView } from '../EditableView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
-import { DocumentView, DocumentViewInternal, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView';
+import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView';
import { KeyValueBox } from '../nodes/KeyValueBox';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
@@ -62,7 +62,7 @@ export interface TreeViewProps {
ScreenToLocalTransform: () => Transform;
contextMenuItems?: { script: ScriptField; filter: ScriptField; icon: string; label: string }[];
dontRegisterView?: boolean;
- styleProvider?: StyleProviderFunc | undefined;
+ styleProvider?: StyleProviderFuncType | undefined;
treeViewHideHeaderFields: () => boolean;
renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
onCheckedClick?: () => ScriptField;
@@ -198,7 +198,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
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.treeView._props.DocumentView?.())?.select(false);
+ res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false);
return res;
};
@@ -282,12 +282,13 @@ export class TreeView extends ObservableReactComponent<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.Document);
+ ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), this.Document, this.preTreeDrop.bind(this))), this.Document);
if (this._treeEle) this._props.unobserveHeight(this._treeEle);
this._props.observeHeight((this._treeEle = ele));
};
componentWillUnmount() {
+ this._treedropDisposer?.();
this._renderTimer && clearTimeout(this._renderTimer);
Object.values(this._disposers).forEach(disposer => disposer?.());
this._treeEle && this._props.unobserveHeight(this._treeEle);
@@ -339,11 +340,9 @@ export class TreeView extends ObservableReactComponent<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.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';
- }
+ 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';
e.stopPropagation();
};
@@ -367,8 +366,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
_width: 1000,
_height: 10,
});
- Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text');
- Doc.GetProto(bullet).data = new List<Doc>([]);
+ const bulletData = bullet[DocData];
+ bulletData.title = ComputedField.MakeFunction('this.text?.Text');
+ bulletData.data = new List<Doc>([]);
DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.());
return bullet;
@@ -383,12 +383,11 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
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);
+ return this.localAdd(folder);
};
- preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
- const dragData = de.complete.docDragData;
- dragData && (dragData.dropAction = this.treeView.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
+ preTreeDrop = (e: Event, de: DragManager.DropEvent, docDropAction: dropActionType) => {
+ // fall through and let the CollectionTreeView handle this since treeView items have no special properties of their own
};
@undoBatch
@@ -415,7 +414,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
docDragData.dropAction,
docDragData.removeDocument,
docDragData.moveDocument,
- docDragData.treeViewDoc === this.treeView.Document
+ docDragData.treeViewDoc === this.treeView.Document,
+ de.embedKey
);
e.stopPropagation();
!added && e.preventDefault();
@@ -424,22 +424,33 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return false;
};
+ 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.Document.embedContainer));
+ return added;
+ };
+ return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
+ };
+
dropping: boolean = false;
- dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
+ dropDocuments(
+ droppedDocuments: Doc[],
+ before: boolean,
+ inside: number | boolean,
+ dropAction: dropActionType | undefined,
+ removeDocument: DragManager.RemoveFunction | undefined,
+ moveDocument: DragManager.MoveFunction | undefined,
+ forceAdd: boolean,
+ canEmbed?: boolean
+ ) {
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.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.treeView.outlineMode && !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
+
+ const addDoc = inside ? this.localAdd : parentAddDoc;
+ const canAdd = !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))) {
+ const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
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);
@@ -601,7 +612,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
docs.sort((a, b) => (NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1)).forEach((d, i) => (d.zIndex = i));
}
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);
+ const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false);
!dataIsComputed && added && Doc.SetContainer(doc, this.Document);
return added;
@@ -830,17 +841,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
};
contextMenuItems = () => {
const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'New Folder' };
- const folderOp = this.childDocs?.length ? [makeFolder] : [];
const openEmbedding = { script: ScriptField.MakeFunction(`openDoc(getEmbedding(this), "${OpenWhere.addRight}")`)!, icon: 'copy', label: 'Open New Embedding' };
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.Document })?.result)),
...(this.Document.isFolder
- ? folderOp
+ ? [makeFolder]
: Doc.IsSystem(this.Document)
? []
- : this.treeView.fileSysMode && this.Document === Doc.GetProto(this.Document)
+ : this.treeView.fileSysMode && this.Document === this.Document[DocData]
? [openEmbedding, makeFolder]
: this.Document._type_collection === CollectionViewType.Docking
? []
@@ -867,7 +877,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
e.preventDefault();
}
};
- titleStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ titleStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
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.treeView;
@@ -899,7 +909,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
}
return treeView._props.styleProvider?.(doc, props, property);
};
- embeddedStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ embeddedStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, 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
};
@@ -973,18 +983,18 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
Document={this.Document}
layout_fitWidth={returnTrue}
scriptContext={this}
- hideDecorationTitle={this.treeView.outlineMode}
- hideResizeHandles={this.treeView.outlineMode}
+ hideDecorations={true}
+ hideClickBehaviors={true}
styleProvider={this.titleStyleProvider}
onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
- docViewPath={this.treeView._props.docViewPath}
- treeViewDoc={this.treeView.Document}
+ containerViewPath={this.treeView.childContainerViewPath}
addDocument={undefined}
addDocTab={this._props.addDocTab}
pinToPres={this.treeView._props.pinToPres}
- onClick={this.onChildClick}
- onDoubleClick={this.onChildDoubleClick}
+ onClickScript={this.onChildClick}
+ onDoubleClickScript={this.onChildDoubleClick}
dragAction={this._props.dragAction}
+ dragConfig={this.treeView.dragConfig}
moveDocument={this.move}
removeDocument={this._props.removeDoc}
ScreenToLocalTransform={this.getTransform}
@@ -998,7 +1008,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
isDocumentActive={this._props.isContentActive}
focus={this.refocus}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- bringToFront={emptyFunction}
disableBrushing={this.treeView._props.disableBrushing}
hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
@@ -1040,7 +1049,19 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
key="titleheader"
ref={this._header}
onClick={this.ignoreEvent}
- onPointerDown={this.ignoreEvent}
+ onPointerDown={e => {
+ this.treeView.isContentActive() &&
+ setupMoveUpEvents(
+ this,
+ e,
+ () => {
+ this._dref?.startDragging(e.clientX, e.clientY, '' as any);
+ return true;
+ },
+ returnFalse,
+ emptyFunction
+ );
+ }}
onPointerEnter={this.onPointerEnter}
onPointerLeave={this.onPointerLeave}>
<div
@@ -1072,22 +1093,21 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
isContentActive={isActive}
isDocumentActive={isActive}
styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
- hideTitle={asText}
fitContentsToBox={returnTrue}
- hideDecorationTitle={this.treeView.outlineMode}
- hideResizeHandles={this.treeView.outlineMode}
- onClick={this.onChildClick}
- focus={this.refocus}
- onKey={this.onKeyDown}
+ hideTitle={asText}
+ hideDecorations={true}
+ hideClickBehaviors={true}
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.treeView?.Document}
- docViewPath={this.treeView._props.docViewPath}
+ onClickScript={this.onChildClick}
+ onKey={this.onKeyDown}
+ containerViewPath={this.treeView.childContainerViewPath}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
+ focus={this.refocus}
addDocument={this._props.addDocument}
moveDocument={this.move}
removeDocument={this._props.removeDoc}
@@ -1097,7 +1117,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
addDocTab={this._props.addDocTab}
pinToPres={this.treeView._props.pinToPres}
disableBrushing={this.treeView._props.disableBrushing}
- bringToFront={returnFalse}
scriptContext={this}
/>
</div>
@@ -1142,7 +1161,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
const before = pt[1] < rect.top + rect.height / 2;
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.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
+ this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, dropActionType.copy, undefined, undefined, false, false));
};
render() {
@@ -1209,7 +1228,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
move: DragManager.MoveFunction,
dragAction: dropActionType,
addDocTab: (doc: Doc, where: OpenWhere) => boolean,
- styleProvider: undefined | StyleProviderFunc,
+ styleProvider: undefined | StyleProviderFuncType,
screenToLocalXf: () => Transform,
isContentActive: (outsideReaction?: boolean) => boolean,
panelWidth: () => number,
@@ -1311,9 +1330,3 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
});
}
}
-
-ScriptingGlobals.add(function TreeView_addNewFolder() {
- TreeView._editTitleOnLoad = { id: Utils.GenerateGuid(), parent: undefined };
- const opts = { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true };
- return Doc.AddDocToList(Doc.MyFilesystem, 'data', Docs.Create.TreeDocument([], opts, TreeView._editTitleOnLoad.id));
-});
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
deleted file mode 100644
index b44acfce8..000000000
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.collectionfreeformlinkview-linkLine {
- stroke: black;
- opacity: 0.8;
- stroke-width: 3px;
- transition: opacity 0.5s ease-in;
- fill: transparent;
-}
-.collectionfreeformlinkview-linkText {
- stroke: rgb(0, 0, 0);
- pointer-events: all;
- cursor: move;
-}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
deleted file mode 100644
index 5204633ea..000000000
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ /dev/null
@@ -1,318 +0,0 @@
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, Field } from '../../../../fields/Doc';
-import { Brushed, DocCss } from '../../../../fields/DocSymbols';
-import { Id } from '../../../../fields/FieldSymbols';
-import { List } from '../../../../fields/List';
-import { Cast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
-import { LinkManager } from '../../../util/LinkManager';
-import { SelectionManager } from '../../../util/SelectionManager';
-import { SettingsManager } from '../../../util/SettingsManager';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { Colors } from '../../global/globalEnums';
-import { DocumentView } from '../../nodes/DocumentView';
-import { ObservableReactComponent } from '../../ObservableReactComponent';
-import './CollectionFreeFormLinkView.scss';
-
-export interface CollectionFreeFormLinkViewProps {
- A: DocumentView;
- B: DocumentView;
- LinkDocs: Doc[];
-}
-
-@observer
-export class CollectionFreeFormLinkView extends ObservableReactComponent<CollectionFreeFormLinkViewProps> {
- @observable _opacity: number = 0;
- @observable _start = 0;
- _anchorDisposer: IReactionDisposer | undefined;
- _timeout: NodeJS.Timeout | undefined;
- constructor(props: any) {
- super(props);
- makeObservable(this);
- }
-
- componentWillUnmount() {
- this._anchorDisposer?.();
- }
- @action timeout: any = action(() => Date.now() < this._start++ + 1000 && (this._timeout = setTimeout(this.timeout, 25)));
- componentDidMount() {
- this._anchorDisposer = reaction(
- () => [
- this._props.A.screenToViewTransform(),
- Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
- Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
- this._props.B.screenToViewTransform(),
- Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
- Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
- ],
- action(() => {
- this._start = Date.now();
- this._timeout && clearTimeout(this._timeout);
- this._timeout = setTimeout(this.timeout, 25);
- setTimeout(this.placeAnchors, 10); // when docs are dragged, their transforms will update before a render has been performed. placeanchors needs to come after a render to find things in the dom. a 0 timeout will still come before the render
- }),
- { fireImmediately: true }
- );
- }
- placeAnchors = () => {
- const { A, B, LinkDocs } = this._props;
- const linkDoc = LinkDocs[0];
- if (SnappingManager.IsDragging || !A.ContentDiv || !B.ContentDiv) return;
- setTimeout(
- action(() => (this._opacity = 0.75)),
- 0
- ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
- setTimeout(
- action(() => (!LinkDocs.length || !(linkDoc.link_displayLine || Doc.UserDoc().showLinkLines)) && (this._opacity = 0.05)),
- 750
- ); // this will unhighlight the link line.
- const a = A.ContentDiv.getBoundingClientRect();
- const b = B.ContentDiv.getBoundingClientRect();
- const { left: aleft, top: atop, width: awidth, height: aheight } = A.ContentDiv.parentElement!.getBoundingClientRect();
- const { left: bleft, top: btop, width: bwidth, height: bheight } = B.ContentDiv.parentElement!.getBoundingClientRect();
- const apt = Utils.closestPtBetweenRectangles(aleft, atop, awidth, aheight, bleft, btop, bwidth, bheight, a.left + a.width / 2, a.top + a.height / 2);
- const bpt = Utils.closestPtBetweenRectangles(bleft, btop, bwidth, bheight, aleft, atop, awidth, aheight, apt.point.x, apt.point.y);
-
- // really hacky stuff to make the LinkAnchorBox display where we want it to:
- // if there's an element in the DOM with a classname containing a link anchor's id,
- // then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right
- // otherwise, we just use the computed nearest point on the document boundary to the target Document
- const targetAhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_1 as Doc)[Id])).lastElement();
- const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_2 as Doc)[Id])).lastElement();
- if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
- if (!targetAhyperlink) {
- if (linkDoc.link_autoMoveAnchors) {
- linkDoc.link_anchor_1_x = ((apt.point.x - aleft) / awidth) * 100;
- linkDoc.link_anchor_1_y = ((apt.point.y - atop) / aheight) * 100;
- }
- } else {
- const m = targetAhyperlink.getBoundingClientRect();
- const mp = A.screenToViewTransform().transformPoint(m.right, m.top + 5);
- const mpx = mp[0] / A._props.PanelWidth();
- const mpy = mp[1] / A._props.PanelHeight();
- if (mpx >= 0 && mpx <= 1) linkDoc.link_anchor_1_x = mpx * 100;
- if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_1_y = mpy * 100;
- if (getComputedStyle(targetAhyperlink).fontSize === '0px') linkDoc.opacity = 0;
- else linkDoc.opacity = 1;
- }
- if (!targetBhyperlink) {
- if (linkDoc.link_autoMoveAnchors) {
- linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100;
- linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100;
- }
- } else {
- const m = targetBhyperlink.getBoundingClientRect();
- const mp = B.screenToViewTransform().transformPoint(m.right, m.top + 5);
- const mpx = mp[0] / B._props.PanelWidth();
- const mpy = mp[1] / B._props.PanelHeight();
- if (mpx >= 0 && mpx <= 1) linkDoc.link_anchor_2_x = mpx * 100;
- if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_2_y = mpy * 100;
- if (getComputedStyle(targetBhyperlink).fontSize === '0px') linkDoc.opacity = 0;
- else linkDoc.opacity = 1;
- }
- };
-
- pointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(
- this,
- e,
- (e, down, delta) => {
- this._props.LinkDocs[0].link_relationship_OffsetX = NumCast(this._props.LinkDocs[0].link_relationship_OffsetX) + delta[0];
- this._props.LinkDocs[0].link_relationship_OffsetY = NumCast(this._props.LinkDocs[0].link_relationship_OffsetY) + delta[1];
- return false;
- },
- emptyFunction,
- action(() => {
- SelectionManager.DeselectAll();
- SelectionManager.SelectSchemaViewDoc(this._props.LinkDocs[0], true);
- LinkManager.currentLink = this._props.LinkDocs[0];
- this.toggleProperties();
- // OverlayView.Instance.addElement(
- // <LinkEditor sourceDoc={this._props.A._props.Document} linkDoc={this._props.LinkDocs[0]}
- // showLinks={action(() => { })}
- // />, { x: 300, y: 300 });
- })
- );
- };
-
- visibleY = (el: any) => {
- let rect = el.getBoundingClientRect();
- const top = rect.top,
- height = rect.height;
- var el = el.parentNode;
- while (el && el !== document.body) {
- if (el.className === 'tabDocView-content') break;
- rect = el.getBoundingClientRect?.();
- if (rect?.width) {
- if (top <= rect.bottom === false && getComputedStyle(el).overflow === 'hidden') return rect.bottom;
- // Check if the element is out of view due to a container scrolling
- if (top + height <= rect.top && getComputedStyle(el).overflow === 'hidden') return rect.top;
- }
- el = el.parentNode;
- }
- // Check its within the document viewport
- return top; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
- };
- visibleX = (el: any) => {
- let rect = el.getBoundingClientRect();
- const left = rect.left,
- width = rect.width;
- var el = el.parentNode;
- while (el && el !== document.body) {
- rect = el?.getBoundingClientRect();
- if (rect?.width) {
- if (left <= rect.right === false && getComputedStyle(el).overflow === 'hidden') return rect.right;
- // Check if the element is out of view due to a container scrolling
- if (left + width <= rect.left && getComputedStyle(el).overflow === 'hidden') return rect.left;
- }
- el = el.parentNode;
- }
- // Check its within the document viewport
- return left; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
- };
-
- @action
- toggleProperties = () => {
- if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
- SettingsManager.Instance.propertiesWidth = 250;
- }
- };
-
- @action
- onClickLine = () => {
- SelectionManager.DeselectAll();
- SelectionManager.SelectSchemaViewDoc(this._props.LinkDocs[0], true);
- LinkManager.currentLink = this._props.LinkDocs[0];
- this.toggleProperties();
- };
-
- @computed.struct get renderData() {
- this._start;
- SnappingManager.IsDragging;
- const { A, B, LinkDocs } = this._props;
- if (!A.ContentDiv || !B.ContentDiv || !LinkDocs.length) return undefined;
- const acont = A.ContentDiv.getElementsByClassName('linkAnchorBox-cont');
- const bcont = B.ContentDiv.getElementsByClassName('linkAnchorBox-cont');
- const adiv = acont.length ? acont[0] : A.ContentDiv;
- const bdiv = bcont.length ? bcont[0] : B.ContentDiv;
- for (let apdiv = adiv; apdiv; apdiv = apdiv.parentElement as any) if ((apdiv as any).hidden) return;
- for (let bpdiv = bdiv; bpdiv; bpdiv = bpdiv.parentElement as any) if ((bpdiv as any).hidden) return;
- const a = adiv.getBoundingClientRect();
- const b = bdiv.getBoundingClientRect();
- const atop = this.visibleY(adiv);
- const btop = this.visibleY(bdiv);
- if (!a.width || !b.width) return undefined;
- const aDocBounds = (A._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
- const bDocBounds = (B._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
- const aleft = this.visibleX(adiv);
- const bleft = this.visibleX(bdiv);
- const aclipped = aleft !== a.left || atop !== a.top;
- const bclipped = bleft !== b.left || btop !== b.top;
- if (aclipped && bclipped) return undefined;
- const clipped = aclipped || bclipped;
- const pt1inside = NumCast(LinkDocs[0].link_anchor_1_x) % 100 !== 0 && NumCast(LinkDocs[0].link_anchor_1_y) % 100 !== 0;
- const pt2inside = NumCast(LinkDocs[0].link_anchor_2_x) % 100 !== 0 && NumCast(LinkDocs[0].link_anchor_2_y) % 100 !== 0;
- const pt1 = [aleft + a.width / 2, atop + a.height / 2];
- const pt2 = [bleft + b.width / 2, btop + b.width / 2];
- const pt2vec = pt2inside ? [-0.7071, 0.7071] : [(bDocBounds.left + bDocBounds.right) / 2 - pt2[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt2[1]];
- const pt1vec = pt1inside ? [-0.7071, 0.7071] : [(aDocBounds.left + aDocBounds.right) / 2 - pt1[0], (aDocBounds.top + aDocBounds.bottom) / 2 - pt1[1]];
- const pt1len = Math.sqrt(pt1vec[0] * pt1vec[0] + pt1vec[1] * pt1vec[1]);
- const pt2len = Math.sqrt(pt2vec[0] * pt2vec[0] + pt2vec[1] * pt2vec[1]);
- const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
- const pt1norm = clipped ? [0, 0] : [-(pt1vec[0] / pt1len) * ptlen, -(pt1vec[1] / pt1len) * ptlen];
- const pt2norm = clipped ? [0, 0] : [-(pt2vec[0] / pt2len) * ptlen, -(pt2vec[1] / pt2len) * ptlen];
- const pt1normlen = Math.sqrt(pt1norm[0] * pt1norm[0] + pt1norm[1] * pt1norm[1]) || 1;
- const pt2normlen = Math.sqrt(pt2norm[0] * pt2norm[0] + pt2norm[1] * pt2norm[1]) || 1;
- const pt1normalized = [pt1norm[0] / pt1normlen, pt1norm[1] / pt1normlen];
- const pt2normalized = [pt2norm[0] / pt2normlen, pt2norm[1] / pt2normlen];
- const aActive = A.IsSelected || A.Document[Brushed];
- const bActive = B.IsSelected || B.Document[Brushed];
-
- const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetX);
- const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetY);
- const link = this._props.LinkDocs[0];
- return {
- a,
- b,
- pt1norm,
- pt2norm,
- aActive,
- bActive,
- textX,
- textY,
- // fully connected
- // pt1,
- // pt2,
- // this code adds space between links
- pt1: link.link_displayArrow ? [pt1[0] + pt1normalized[0] * 3 * NumCast(link.link_displayArrow_scale, 4), pt1[1] + pt1normalized[1] * 3 * NumCast(link.link_displayArrow_scale, 3)] : pt1,
- pt2: link.link_displayArrow ? [pt2[0] + pt2normalized[0] * 3 * NumCast(link.link_displayArrow_scale, 4), pt2[1] + pt2normalized[1] * 3 * NumCast(link.link_displayArrow_scale, 3)] : pt2,
- };
- }
-
- render() {
- if (!this.renderData) return null;
-
- const link = this._props.LinkDocs[0];
- const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
- const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship
- const linkRelationshipList = Doc.UserDoc().link_relationshipList as List<string>;
- const linkColorList = Doc.UserDoc().link_ColorList as List<string>;
- const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List<number>;
- const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
- const linkDescription = Field.toString(link.link_description as any as Field).split('\n')[0];
-
- const linkSize = Doc.noviceMode || currRelationshipIndex === -1 || currRelationshipIndex >= linkRelationshipSizes.length ? -1 : linkRelationshipSizes[currRelationshipIndex];
-
- //access stroke color using index of the relationship in the color list (default black)
- const stroke = currRelationshipIndex === -1 || currRelationshipIndex >= linkColorList.length ? StrCast(link._backgroundColor, 'black') : linkColorList[currRelationshipIndex];
- // const hexStroke = this.rgbToHex(stroke)
-
- //calculate stroke width/thickness based on the relative importance of the relationshipship (i.e. how many links the relationship has)
- //thickness varies linearly from 3px to 12px for increasing link count
- const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
-
- const arrowScale = NumCast(link.link_displayArrow_scale, 3);
- return link.opacity === 0 || !a.width || !b.width || (!(Doc.UserDoc().showLinkLines || link.link_displayLine) && !aActive && !bActive) ? null : (
- <>
- <defs>
- <marker id={`${link[Id] + 'arrowhead'}`} markerWidth={`${4 * arrowScale}`} markerHeight={`${3 * arrowScale}`} refX="0" refY={`${1.5 * arrowScale}`} orient="auto">
- <polygon points={`0 0, ${3 * arrowScale} ${1.5 * arrowScale}, 0 ${3 * arrowScale}`} fill={stroke} />
- </marker>
- <filter id="outline">
- <feMorphology in="SourceAlpha" result="expanded" operator="dilate" radius="1" />
- <feFlood floodColor={`${Colors.DARK_GRAY}`} />
- <feComposite in2="expanded" operator="in" />
- <feComposite in="SourceGraphic" />
- </filter>
- <filter x="0" y="0" width="1" height="1" id={`${link[Id] + 'background'}`}>
- <feFlood floodColor={`${StrCast(link._backgroundColor, 'white')}`} result="bg" />
- <feMerge>
- <feMergeNode in="bg" />
- <feMergeNode in="SourceGraphic" />
- </feMerge>
- </filter>
- </defs>
- <path
- filter={LinkManager.currentLink === link ? 'url(#outline)' : ''}
- fill="pink"
- stroke="antiquewhite"
- strokeWidth="4"
- className="collectionfreeformlinkview-linkLine"
- style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
- onClick={this.onClickLine}
- d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
- markerEnd={link.link_displayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
- />
- {textX === undefined || !linkDescription ? null : (
- <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
- <tspan>&nbsp;</tspan>
- <tspan dy="2">{linkDescription.substring(0, 50) + (linkDescription.length > 50 ? '...' : '')}</tspan>
- <tspan dy="2">&nbsp;</tspan>
- </text>
- )}
- </>
- );
- }
-}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
deleted file mode 100644
index 4ada1731f..000000000
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-// TODO: change z-index to -1 when a modal is active?
-
-.collectionfreeformlinksview-svgCanvas {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- pointer-events: none;
-}
-.collectionfreeformlinksview-container {
- pointer-events: none;
-}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
deleted file mode 100644
index 95d521f65..000000000
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { computed } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Id } from '../../../../fields/FieldSymbols';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { LightboxView } from '../../LightboxView';
-import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView';
-import './CollectionFreeFormLinksView.scss';
-
-@observer
-export class CollectionFreeFormLinksView extends React.Component {
- @computed get uniqueConnections() {
- return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews))
- .filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath)))
- .map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />);
- }
-
- render() {
- return (
- <div className="collectionfreeformlinksview-container">
- <svg className="collectionfreeformlinksview-svgCanvas">{this.uniqueConnections}</svg>
- </div>
- );
- }
-}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
index ec8416303..69cbae86f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
@@ -1,4 +1,4 @@
-import { computed } from 'mobx';
+import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
@@ -18,6 +18,10 @@ export interface CollectionFreeFormPannableContentsProps {
@observer
export class CollectionFreeFormPannableContents extends React.Component<CollectionFreeFormPannableContentsProps> {
+ constructor(props: CollectionFreeFormPannableContentsProps) {
+ super(props);
+ makeObservable(this);
+ }
@computed get presPaths() {
return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 7d3acaea7..9e7d364ea 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -176,6 +176,11 @@
// touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions.
touch-action: none;
transform-origin: top left;
+ > svg {
+ height: 100%;
+ width: 100%;
+ margin: auto;
+ }
.collectionfreeformview-placeholder {
background: gray;
@@ -270,34 +275,31 @@
padding: 10px;
.msg {
- position: relative;
- // display: block;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
-
+ position: relative;
+ // display: block;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
}
-
+
.gif-container {
- position: relative;
- margin-top: 5px;
- // display: block;
-
- justify-content: center;
- align-items: center;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
-
-
+ position: relative;
+ margin-top: 5px;
+ // display: block;
+
+ justify-content: center;
+ align-items: center;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+
.gif {
background-color: transparent;
height: 300px;
}
}
-
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8268a47d8..e48656f5e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,15 +1,16 @@
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, toJS } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { DateField } from '../../../../fields/DateField';
-import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
import { DocData, Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkData, InkField, InkTool, PointData, Segment } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
+import { RichTextField } from '../../../../fields/RichTextField';
import { listSpec } from '../../../../fields/Schema';
import { ScriptField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -22,8 +23,8 @@ import { Docs, DocUtils } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager, dropActionType } from '../../../util/DragManager';
-import { FollowLinkScript } from '../../../util/LinkFollower';
import { ReplayMovements } from '../../../util/ReplayMovements';
+import { CompileScript } from '../../../util/Scripting';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { SelectionManager } from '../../../util/SelectionManager';
import { freeformScrollMode } from '../../../util/SettingsManager';
@@ -36,10 +37,10 @@ import { GestureOverlay } from '../../GestureOverlay';
import { CtrlKey } from '../../GlobalKeyHandler';
import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
import { LightboxView } from '../../LightboxView';
-import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView';
+import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { DocumentView, OpenWhere } from '../../nodes/DocumentView';
+import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../../nodes/trails/PresBox';
import { CreateImage } from '../../nodes/WebBoxRenderer';
@@ -54,7 +55,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
-export type collectionFreeformViewProps = {
+export interface collectionFreeformViewProps {
NativeWidth?: () => number;
NativeHeight?: () => number;
originTopLeft?: boolean;
@@ -65,14 +66,25 @@ export type collectionFreeformViewProps = {
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
engineProps?: any;
getScrollHeight?: () => number | undefined;
-};
+}
@observer
export class CollectionFreeFormView extends CollectionSubView<Partial<collectionFreeformViewProps>>() {
public get displayName() {
- return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')';
+ return 'CollectionFreeFormView(' + this.Document.title?.toString() + ')';
} // this makes mobx trace() statements more descriptive
+ @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, '');
+ @computed get paintFunc() {
+ const field = this.layoutDoc[this.fieldKey];
+ const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as Field)).trim();
+ return !paintFunc
+ ? ''
+ : paintFunc.includes('dashDiv')
+ ? `const dashDiv = document.querySelector('#${this._paintedId}');
+ (async () => { ${paintFunc} })()`
+ : paintFunc;
+ }
constructor(props: any) {
super(props);
makeObservable(this);
@@ -147,8 +159,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
? { x: cb[0], y: cb[1], r: cb[2], b: cb[3] }
: aggregateBounds(
this._layoutElements.filter(e => e.bounds?.width && !e.bounds.z).map(e => e.bounds!),
- NumCast(this.layoutDoc._xPadding, 10),
- NumCast(this.layoutDoc._yPadding, 10)
+ NumCast(this.layoutDoc._xPadding, this._props.xPadding ?? 10),
+ NumCast(this.layoutDoc._yPadding, this._props.yPadding ?? 10)
);
}
@computed get nativeWidth() {
@@ -162,7 +174,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
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 dv = this.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
@@ -180,12 +192,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) {
- if (timer) clearTimeout(timer);
- return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true);
+ return DocumentView.SetViewTransition(docs, 'all', duration, timer, undefined, true);
}
public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number) {
- if (timer) clearTimeout(timer);
- const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, undefined, true);
+ const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, timer, undefined, true);
const timecode = Math.round(time);
docs.forEach(doc => {
CollectionFreeFormDocumentView.animFields.forEach(val => {
@@ -223,10 +233,11 @@ 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);
+ onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick);
onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
elementFunc = () => this._layoutElements;
+ viewTransition = () => (this._panZoomTransition ? '' + this._panZoomTransition : undefined);
fitContentOnce = () => {
const vals = this.fitToContentVals;
this.layoutDoc._freeform_panX = vals.bounds.cx;
@@ -250,7 +261,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
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.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true));
};
addDocument = (newBox: Doc | Doc[]) => {
let retVal = false;
@@ -288,20 +299,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime);
}
- groupFocus = (anchor: Doc, options: DocFocusOptions) => {
+ groupFocus = (anchor: Doc, options: FocusViewOptions) => {
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);
options.docTransform = undefined;
return res;
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
if (this._lightboxDoc) return;
if (anchor === this.Document) {
- if (options.willZoomCentered && options.zoomScale) {
- this.fitContentOnce();
- options.didMove = true;
- }
+ // if (options.willZoomCentered && options.zoomScale) {
+ // this.fitContentOnce();
+ // options.didMove = true;
+ // }
}
if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor)) return;
const xfToCollection = options?.docTransform ?? Transform.Identity();
@@ -321,7 +332,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
- getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
+ getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
@@ -365,28 +376,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!d._keepZWhenDragged && (d.zIndex = zsorted.length + 1 + i); // bringToFront
}
- if (this.layoutDoc._autoArrange || de.metaKey) {
- const sorted = this.childLayoutPairs.slice().sort((a, b) => NumCast(a.layout.y) - NumCast(b.layout.y));
- sorted.splice(
- sorted.findIndex(pair => pair.layout === refDoc),
- 1
- );
- if (sorted.length && refDoc && NumCast(sorted[0].layout.y) < NumCast(refDoc.y)) {
- const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height) / 2;
- const deltay = sorted.length > 1 ? NumCast(refDoc.y) - (NumCast(sorted[0].layout.y) + (topIndexed ? 0 : NumCast(sorted[0].layout._height))) : 0;
- const deltax = sorted.length > 1 ? NumCast(refDoc.x) - NumCast(sorted[0].layout.x) : 0;
-
- let lastx = NumCast(refDoc.x);
- let lasty = NumCast(refDoc.y) + (topIndexed ? 0 : NumCast(refDoc._height));
- runInAction(() =>
- sorted.slice(1).forEach((pair, i) => {
- lastx = pair.layout.x = lastx + deltax;
- lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
- })
- );
- }
- }
-
(docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
return true;
}
@@ -409,31 +398,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) {
- if (linkDragData.linkDragView.props.docViewPath().includes(this._props.docViewPath().lastElement())) {
+ if (this.DocumentView?.() && linkDragData.linkDragView.containerViewPath?.().includes(this.DocumentView())) {
const [x, y] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y);
let added = false;
// do nothing if link is dropped into any freeform view parent of dragged document
- const source =
- !linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.Document
- ? Docs.Create.TextDocument('', { _width: 200, _height: 75, x, y, title: 'dropped annotation' })
- : Docs.Create.FontIconDocument({
- title: 'anchor',
- icon_label: '',
- followLinkToggle: true,
- icon: 'map-pin',
- x,
- y,
- backgroundColor: '#ACCEF7',
- layout_hideAllLinks: true,
- layout_hideLinkButton: true,
- _width: 15,
- _height: 15,
- _xPadding: 0,
- onClick: FollowLinkScript(),
- });
+ const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x, y, title: 'dropped annotation' });
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
-
+ if (de.complete.linkDocument) {
+ de.complete.linkDocument.layout_isSvg = true;
+ this.addDocument(de.complete.linkDocument);
+ }
e.stopPropagation();
!added && e.preventDefault();
return added;
@@ -467,7 +442,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.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;
@@ -484,10 +459,10 @@ 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 { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
- const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined);
+ const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
+ const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!);
+ const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 };
+ const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? dropActionType.embed : undefined);
de.moveDocument = this._props.moveDocument;
de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top);
DragManager.StartDocumentDrag(
@@ -506,7 +481,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateClusters(_freeform_useClusters: boolean) {
- this._props.Document._freeform_useClusters = _freeform_useClusters;
+ this.Document._freeform_useClusters = _freeform_useClusters;
this._clusterSets.length = 0;
this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c));
}
@@ -514,7 +489,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.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);
@@ -557,7 +532,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.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;
@@ -586,7 +561,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
- clusterStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ clusterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
if (doc && this.childDocList?.includes(doc))
switch (property) {
@@ -616,7 +591,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.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
this.selectDocuments(eles);
return true;
}
@@ -629,7 +604,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()) {
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
@@ -704,7 +679,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
onEraserUp = (e: PointerEvent): void => {
- this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document));
+ this._deleteList.forEach(ink => ink._props.removeDocument?.(ink.Document));
this._deleteList = [];
this._batch?.end();
};
@@ -714,7 +689,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.DocumentView?.(), clientX: e.clientX, clientY: e.clientY });
e.stopPropagation();
e.preventDefault();
} else if (this.isContentActive() && e.shiftKey) {
@@ -737,7 +712,7 @@ 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.DocumentView?.().clearViewTransition();
const [dxi, dyi] = this.screenToFreeformContentsXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.ScreenToLocalBoxXf().Rotate);
this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0, true);
@@ -808,9 +783,9 @@ 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.DocumentView?.()))
.filter(inkView => inkView?.ComponentView instanceof InkingStroke)
- .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
+ .map(inkView => ({ inkViewBounds: inkView!.getBounds, inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
.filter(
({ inkViewBounds }) =>
inkViewBounds && // bounding box of eraser segment and ink stroke overlap
@@ -905,7 +880,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.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));
@@ -959,8 +934,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.Document[this.scaleFieldKey] = Math.abs(safeScale);
+ this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
}
};
@@ -968,7 +943,7 @@ 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.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;
@@ -979,7 +954,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()) {
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.screenToFreeformContentsXf.Scale, deltaY: e.shiftKey ? 0 : -deltaY * this.screenToFreeformContentsXf.Scale });
@@ -987,9 +962,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
default:
case freeformScrollMode.Zoom:
- if ((e.ctrlKey || !scrollable) && this._props.isContentActive(true)) {
+ if ((e.ctrlKey || !scrollable) && this._props.isContentActive()) {
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();
+ // e.preventDefault();
}
break;
}
@@ -1002,7 +977,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!this.isAnnotationOverlay && clamp) {
// this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds
- const docs = this.childLayoutPairs.map(pair => pair.layout).filter(doc => doc instanceof Doc);
+ const docs = this.childLayoutPairs.map(pair => pair.layout).filter(doc => doc instanceof Doc && doc.type !== DocumentType.LINK);
const measuredDocs = docs
.map(doc => ({ pos: { x: NumCast(doc.x), y: NumCast(doc.y) }, size: { width: NumCast(doc._width), height: NumCast(doc._height) } }))
.filter(({ pos, size }) => pos && size)
@@ -1065,7 +1040,7 @@ 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.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
@@ -1170,35 +1145,33 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
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)) {
+ if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
e.stopPropagation?.();
const below = !e.altKey && e.key !== 'Tab';
- const layout_fieldKey = StrCast(docView.LayoutFieldKey);
- const newDoc = Doc.MakeCopy(docView.Document, true);
- const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
+ const layout_fieldKey = StrCast(fieldProps.fieldKey);
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10;
- else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10;
- if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) {
- newDoc[layout_fieldKey] = docView.Document[layout_fieldKey];
+ if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10;
+ else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10;
+ if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
+ newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
}
- Doc.GetProto(newDoc).text = undefined;
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
};
@computed get childPointerEvents() {
- const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
- const pointerevents = SnappingManager.IsResizing
+ const engine = this._props.layoutEngine?.() || StrCast(this.Document._layoutEngine);
+ return SnappingManager.IsResizing
? 'none'
: this._props.childPointerEvents?.() ??
- (this._props.viewDefDivClick || //
- (engine === computePassLayout.name && !this._props.isSelected()) ||
- this.isContentActive() === false
- ? 'none'
- : this._props.pointerEvents?.());
- return pointerevents;
+ (this._props.viewDefDivClick || //
+ (engine === computePassLayout.name && !this._props.isSelected()) ||
+ this.isContentActive() === false
+ ? 'none'
+ : this._props.pointerEvents?.());
}
@observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined;
@@ -1208,10 +1181,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const childLayout = entry.pair.layout;
const childData = entry.pair.data;
return (
- <CollectionFreeFormDocumentViewWrapper
+ <CollectionFreeFormDocumentView
{...OmitKeys(entry, ['replica', 'pair']).omit}
key={childLayout[Id] + (entry.replica || '')}
Document={childLayout}
+ containerViewPath={this.DocumentView?.().docViewPath}
+ styleProvider={this.clusterStyleProvider}
TemplateDataDocument={childData}
dragStarting={this.dragStarting}
dragEnding={this.dragEnding}
@@ -1225,10 +1200,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
LayoutTemplateString={childLayout.z ? undefined : this._props.childLayoutString}
rootSelected={childData ? this.rootSelected : returnFalse}
waitForDoubleClickToClick={this._props.waitForDoubleClickToClick}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
onKey={this.onKeyDown}
- onDoubleClick={this.onChildDoubleClickHandler}
- onBrowseClick={this.onBrowseClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ onBrowseClickScript={this.onBrowseClickHandler}
+ bringToFront={this.bringToFront}
ScreenToLocalTransform={childLayout.z ? this.ScreenToLocalBoxXf : this.ScreenToContentsXf}
PanelWidth={childLayout[Width]}
PanelHeight={childLayout[Height]}
@@ -1244,10 +1220,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
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}
- bringToFront={this.bringToFront}
layout_showTitle={this._props.childlayout_showTitle}
dontRegisterView={this._props.dontRegisterView}
pointerEvents={this.childPointerEventsFunc}
@@ -1324,7 +1297,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.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload });
e.stopPropagation();
};
@@ -1379,7 +1352,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.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps);
}
doFreeformLayout(poolData: Map<string, PoolData>) {
@@ -1439,7 +1412,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
infoUI = () => (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />);
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
super.componentDidMount?.();
setTimeout(
action(() => {
@@ -1476,17 +1449,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
this._disposers.pointerevents = reaction(
- () => {
- const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
- return SnappingManager.IsResizing
- ? 'none'
- : this._props.childPointerEvents?.() ??
- (this._props.viewDefDivClick || //
- (engine === computePassLayout.name && !this._props.isSelected()) ||
- this.isContentActive() === false
- ? 'none'
- : this._props.pointerEvents?.());
- },
+ () => this.childPointerEvents,
pointerevents => (this._childPointerEvents = pointerevents as any),
{ fireImmediately: true }
);
@@ -1497,6 +1460,18 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
})
);
+
+ this._disposers.paintFunc = reaction(
+ () => ({ code: this.paintFunc, first: this._firstRender, width: this.Document._width, height: this.Document._height }),
+ ({ code, first }) => {
+ if (!code.includes('dashDiv')) {
+ const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true });
+ if (script.compiled) script.run({ this: this.DocumentView?.() });
+ } else code && !first && eval(code);
+ },
+ { fireImmediately: true }
+ );
+
this._disposers.layoutElements = reaction(
// layoutElements can't be a computed value because doLayoutComputation() is an action that has side effect of updating clusters
() => this.doInternalLayoutComputation,
@@ -1540,7 +1515,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
updateIcon = () =>
CollectionFreeFormView.UpdateIcon(
this.layoutDoc[Id] + '-icon' + new Date().getTime(),
- this._props.docViewPath().lastElement().ContentDiv!,
+ this.DocumentView?.().ContentDiv!,
NumCast(this.layoutDoc._width),
NumCast(this.layoutDoc._height),
this._props.PanelWidth(),
@@ -1640,9 +1615,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
toggleResetView = () => {
this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey];
if (this.dataDoc[this.autoResetFieldKey]) {
- this.dataDoc[this.panXFieldKey + '_reset'] = this.dataDoc[this.panXFieldKey];
- this.dataDoc[this.panYFieldKey + '_reset'] = this.dataDoc[this.panYFieldKey];
- this.dataDoc[this.scaleFieldKey + '_reset'] = this.dataDoc[this.scaleFieldKey];
+ this.dataDoc[this.panXFieldKey + '_reset'] = this.layoutDoc[this.panXFieldKey];
+ this.dataDoc[this.panYFieldKey + '_reset'] = this.layoutDoc[this.panYFieldKey];
+ this.dataDoc[this.scaleFieldKey + '_reset'] = this.layoutDoc[this.scaleFieldKey];
}
};
@@ -1651,15 +1626,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
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' });
- !Doc.noviceMode &&
- appearanceItems.push({
- description: 'Toggle auto arrange',
- event: () => (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange),
- icon: 'compress-arrows-alt',
- });
- if (this._props.setContentView === emptyFunction) {
+ !this.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
+ !this.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
+ if (this._props.setContentViewBox === emptyFunction) {
!appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' });
return;
}
@@ -1668,7 +1637,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!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.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' });
+ this.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;
@@ -1692,8 +1661,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
transcribeStrokes = () => {
- if (this._props.Document.isGroup && this._props.Document.transcription) {
- const text = StrCast(this._props.Document.transcription);
+ if (this.Document.isGroup && this.Document.transcription) {
+ const text = StrCast(this.Document.transcription);
const lines = text.split('\n');
const height = 30 + 15 * lines.length;
@@ -1741,7 +1710,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.Contains(this.DocumentView?.())) {
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++) {
@@ -1751,17 +1720,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1);
});
- // if a freeform view has any children, then the children will likely consist of a single child
- // 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 ? [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>
+ <span className="collectionfreeformview-placeholderSpan">{this.Document.annotationOn ? '' : this.Document.title?.toString()}</span>
</div>
);
}
@@ -1790,24 +1752,23 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
</div>
);
}
- @computed get pannableContents() {
- this.incrementalRender();
+ get pannableContents() {
+ this.incrementalRender(); // needs to happen synchronously or freshly typed text documents will flash and miss their first characters
return (
<CollectionFreeFormPannableContents
Document={this.Document}
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))}
+ transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.Document._viewTransition, 'string', null))}
viewDefDivClick={this._props.viewDefDivClick}>
- {this.underlayViews}
+ {this.props.children ?? null} {/* most likely case of children is document content that's being annoated: eg., an image */}
{this.contentViews}
<CollectionFreeFormRemoteCursors {...this._props} key="remoteCursors" />
</CollectionFreeFormPannableContents>
);
}
- @computed get marqueeView() {
- TraceMobx();
+ get marqueeView() {
return (
<MarqueeView
{...this._props}
@@ -1870,6 +1831,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return (
<div
className="collectionfreeformview-container"
+ id={this._paintedId}
ref={r => {
this.createDashEventsTarget(r);
this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
@@ -1891,20 +1853,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
width: `${100 / (this.nativeDimScaling || 1)}%`,
height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
}}>
- {this._lightboxDoc ? (
+ {this.paintFunc ? null : this._lightboxDoc ? (
<div style={{ padding: 15, width: '100%', height: '100%' }}>
<DocumentView
{...this._props}
Document={this._lightboxDoc}
+ containerViewPath={this.DocumentView?.().docViewPath}
TemplateDataDocument={undefined}
PanelWidth={this.lightboxPanelWidth}
PanelHeight={this.lightboxPanelHeight}
NativeWidth={returnZero}
NativeHeight={returnZero}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
onKey={this.onKeyDown}
- onDoubleClick={this.onChildDoubleClickHandler}
- onBrowseClick={this.onBrowseClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ onBrowseClickScript={this.onBrowseClickHandler}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
@@ -1942,15 +1905,15 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
if (!focused) {
const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
- let containers = dv.props.docViewPath();
+ let containers = dv.containerViewPath?.() ?? [];
let parFfview = dv.CollectionFreeFormView;
for (var cont of containers) {
parFfview = parFfview ?? cont.CollectionFreeFormView;
}
- while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView;
+ while (parFfview?.Document.isGroup) parFfview = parFfview.DocumentView?.().CollectionFreeFormView;
const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview
ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime);
- Doc.linkFollowHighlight(dv?.props.Document, false);
+ Doc.linkFollowHighlight(dv?.Document, false);
}
});
}
@@ -1968,13 +1931,13 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) {
});
ScriptingGlobals.add(function pinWithView(pinContent: boolean) {
SelectionManager.Views.forEach(view =>
- view.props.pinToPres(view.Document, {
+ view._props.pinToPres(view.Document, {
currentFrame: Cast(view.Document.currentFrame, 'number', null),
pinData: {
poslayoutview: pinContent,
dataview: pinContent,
},
- pinViewport: MarqueeView.CurViewBounds(view.Document, view.props.PanelWidth(), view.props.PanelHeight()),
+ pinViewport: MarqueeView.CurViewBounds(view.Document, view._props.PanelWidth(), view._props.PanelHeight()),
})
);
});
@@ -1985,6 +1948,7 @@ ScriptingGlobals.add(function sendToBack(doc: Doc) {
SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true));
});
ScriptingGlobals.add(function datavizFromSchema(doc: Doc) {
+ // creating a dataviz doc to represent the schema table
SelectionManager.Views.forEach(view => {
if (!view.layoutDoc.schema_columnKeys) {
view.layoutDoc.schema_columnKeys = new List<string>(['title', 'type', 'author', 'author_date']);
@@ -1998,22 +1962,22 @@ ScriptingGlobals.add(function datavizFromSchema(doc: Doc) {
for (let i = 0; i < children.length; i++) {
let eachRow = [];
for (let j = 0; j < keys.length; j++) {
- var cell = children[i][keys[j]];
- if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
+ var cell = children[i][keys[j]]?.toString();
+ if (cell) cell = cell.toString().replace(/\,/g, '');
eachRow.push(cell);
}
csvRows.push(eachRow);
}
const blob = new Blob([csvRows.join('\n')], { type: 'text/csv' });
- const options = { x: 0, y: -300, title: 'schemaTable', _width: 300, _height: 100, type: 'text/csv' };
+ const options = { x: 0, y: 0, title: 'schemaTable', _width: 300, _height: 100, type: 'text/csv' };
const file = new File([blob], 'schemaTable', options);
const loading = Docs.Create.LoadingDocument(file, options);
loading.presentation_openInLightbox = true;
DocUtils.uploadFileToDoc(file, {}, loading);
+ // holds the doc in a popup until it is dragged onto a canvas
if (view.ComponentView?.addDocument) {
- // loading.dataViz_fromSchema = true;
- loading.dataViz_asSchema = view.layoutDoc;
+ loading._dataViz_asSchema = view.layoutDoc;
SchemaCSVPopUp.Instance.setView(view);
SchemaCSVPopUp.Instance.setTarget(view.layoutDoc);
SchemaCSVPopUp.Instance.setDataVizDoc(loading);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 39d828302..d0e59180d 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -219,7 +219,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
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) {
+ if (e.button === 2 || e.metaKey || (this._props.isContentActive() && scrollMode === freeformScrollMode.Pan && Doc.ActiveTool === InkTool.None)) {
this.setPreviewCursor(e.clientX, e.clientY, true, false, this._props.Document);
e.preventDefault();
} else PreviewCursor.Instance.Visible = false;
@@ -352,9 +352,10 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
const newCollection = creator
? creator(selected, { title: 'nested stack' })
: ((doc: Doc) => {
- Doc.GetProto(doc).data = new List<Doc>(selected);
- Doc.GetProto(doc).isGroup = makeGroup;
- Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
+ const docData = doc[DocData];
+ docData.data = new List<Doc>(selected);
+ docData.isGroup = makeGroup;
+ docData.title = makeGroup ? 'grouping' : 'nested freeform';
doc._freeform_panX = doc._freeform_panY = 0;
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
@@ -634,8 +635,13 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
}
MarqueeRef: HTMLDivElement | null = null;
+ /**
+ * This is called for every drag movement when a document is dragged over this collection.
+ * If the document is dragged within 25 pixels of the edge of the collection and paused, this will
+ * auto scroll the collection so that it can be dragged farther (unless auto panning has been disabled)
+ */
@action
- onDragAutoScroll = (e: CustomEvent<React.DragEvent>) => {
+ onDragMovePause = (e: CustomEvent<React.DragEvent>) => {
if ((e as any).handlePan || this._props.isAnnotationOverlay) return;
(e as any).handlePan = true;
@@ -658,7 +664,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
<div
className="marqueeView"
ref={r => {
- r?.addEventListener('dashDragAutoScroll', this.onDragAutoScroll as any);
+ r?.addEventListener('dashDragMovePause', this.onDragMovePause as any);
this.MarqueeRef = r;
}}
style={{
diff --git a/src/client/views/collections/collectionFreeForm/index.ts b/src/client/views/collections/collectionFreeForm/index.ts
index 702dc8d42..9a54ce63a 100644
--- a/src/client/views/collections/collectionFreeForm/index.ts
+++ b/src/client/views/collections/collectionFreeForm/index.ts
@@ -1,7 +1,5 @@
-export * from "./CollectionFreeFormLayoutEngines";
-export * from "./CollectionFreeFormLinkView";
-export * from "./CollectionFreeFormLinksView";
-export * from "./CollectionFreeFormRemoteCursors";
-export * from "./CollectionFreeFormView";
-export * from "./MarqueeOptionsMenu";
-export * from "./MarqueeView"; \ No newline at end of file
+export * from './CollectionFreeFormLayoutEngines';
+export * from './CollectionFreeFormRemoteCursors';
+export * from './CollectionFreeFormView';
+export * from './MarqueeOptionsMenu';
+export * from './MarqueeView';
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 113ffedb3..f25872c2b 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -192,7 +192,7 @@ export class CollectionGridView extends CollectionSubView() {
{...this._props}
NativeWidth={returnZero}
NativeHeight={returnZero}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
Document={layout}
TemplateDataDocument={layout.resolvedDataDoc as Doc}
isContentActive={this.isChildContentActive}
@@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() {
PanelHeight={height}
ScreenToLocalTransform={dxf}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
renderDepth={this._props.renderDepth + 1}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
@@ -340,7 +340,7 @@ export class CollectionGridView extends CollectionSubView() {
* Handles text document creation on double click.
*/
onPointerDown = (e: React.PointerEvent) => {
- if (this._props.isContentActive(true)) {
+ if (this._props.isContentActive()) {
setupMoveUpEvents(
this,
e,
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index d105b04f7..228af78aa 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -79,16 +79,16 @@ export class CollectionLinearView extends CollectionSubView() {
@action
changeDescriptionSetting = () => {
- if (LinkDescriptionPopup.showDescriptions) {
- if (LinkDescriptionPopup.showDescriptions === 'ON') {
- LinkDescriptionPopup.showDescriptions = 'OFF';
- LinkDescriptionPopup.descriptionPopup = false;
+ if (LinkDescriptionPopup.Instance.showDescriptions) {
+ if (LinkDescriptionPopup.Instance.showDescriptions === 'ON') {
+ LinkDescriptionPopup.Instance.showDescriptions = 'OFF';
+ LinkDescriptionPopup.Instance.display = false;
} else {
- LinkDescriptionPopup.showDescriptions = 'ON';
+ LinkDescriptionPopup.Instance.showDescriptions = 'ON';
}
} else {
- LinkDescriptionPopup.showDescriptions = 'OFF';
- LinkDescriptionPopup.descriptionPopup = false;
+ LinkDescriptionPopup.Instance.showDescriptions = 'OFF';
+ LinkDescriptionPopup.Instance.display = false;
}
};
@@ -110,7 +110,7 @@ export class CollectionLinearView extends CollectionSubView() {
<Tooltip title={<div className="dash-tooltip">{'Toggle description pop-up'} </div>} placement="top">
<span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
- Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'}
+ Labels: {LinkDescriptionPopup.Instance.showDescriptions ? LinkDescriptionPopup.Instance.showDescriptions : 'ON'}
</span>
</Tooltip>
@@ -147,8 +147,8 @@ export class CollectionLinearView extends CollectionSubView() {
switch (doc.layout) {
case '<LinkingUI>': return this.getLinkUI();
case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI();
- case '<UndoStack>': return <UndoStack />;
- case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager /> : null;
+ case '<UndoStack>': return <UndoStack key={doc[Id]}/>;
+ case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager key={doc[Id]} /> : null;
}
const nested = doc._type_collection === CollectionViewType.Linear;
@@ -189,9 +189,8 @@ export class CollectionLinearView extends CollectionSubView() {
dontRegisterView={BoolCast(this.Document.childDontRegisterViews)}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={this.childContainerViewPath}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 563084af8..85fe7c896 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,10 +1,10 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
-import { Button } from 'browndash-components';
-import { action, computed, makeObservable } from 'mobx';
+import { Button, IconButton } from 'browndash-components';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse } from '../../../../Utils';
+import { FaChevronRight } from 'react-icons/fa';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { DragManager, dropActionType } from '../../../util/DragManager';
@@ -37,6 +37,8 @@ const resizerWidth = 8;
@observer
export class CollectionMulticolumnView extends CollectionSubView() {
+ @observable _startIndex = 0;
+
constructor(props: any) {
super(props);
makeObservable(this);
@@ -48,7 +50,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
*/
@computed
private get ratioDefinedDocs() {
- return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio);
+ return this.childLayouts.filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio);
}
@computed
@@ -57,6 +59,15 @@ export class CollectionMulticolumnView extends CollectionSubView() {
return ratioDocs.length ? Math.min(...ratioDocs.map(layout => NumCast(layout._dimMagnitude))) : 1;
}
+ @computed get maxShown() {
+ return NumCast(this.layoutDoc.layout_maxShown);
+ }
+
+ @computed
+ private get childLayouts() {
+ return (this.maxShown ? this.childLayoutPairs.slice(this._startIndex, this._startIndex + this.maxShown) : this.childLayoutPairs).map(pair => pair.layout);
+ }
+
/**
* This loops through all childLayoutPairs and extracts the values for _dimUnit
* and _dimMagnitude, ignoring any that are malformed. Additionally, it then
@@ -69,9 +80,9 @@ export class CollectionMulticolumnView extends CollectionSubView() {
private get resolvedLayoutInformation(): LayoutData {
let starSum = 0;
const widthSpecifiers: WidthSpecifier[] = [];
- this.childLayoutPairs.map(pair => {
- const unit = StrCast(pair.layout._dimUnit, '*');
- const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
+ this.childLayouts.map(layout => {
+ const unit = StrCast(layout._dimUnit, '*');
+ const magnitude = NumCast(layout._dimMagnitude, this.minimumDim);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
unit === DimUnit.Ratio && (starSum += magnitude);
widthSpecifiers.push({ magnitude, unit });
@@ -90,7 +101,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
*/
// setTimeout(() => {
// const { ratioDefinedDocs } = this;
- // if (this.childLayoutPairs.length) {
+ // if (this.childPairs.length) {
// const minimum = this.minimumDim;
// if (minimum !== 0) {
// ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
@@ -127,7 +138,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
private get totalRatioAllocation(): number | undefined {
const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
- return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._xMargin);
+ return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._xMargin);
}
}
@@ -187,13 +198,14 @@ export class CollectionMulticolumnView extends CollectionSubView() {
return Transform.Identity(); // we're still waiting on promises to resolve
}
let offset = 0;
- for (const { layout: candidate } of this.childLayoutPairs) {
+ var xf = Transform.Identity();
+ this.childLayouts.map(candidate => {
if (candidate === layout) {
- return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0);
+ return (xf = this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0));
}
offset += this.lookupPixels(candidate) + resizerWidth;
- }
- return Transform.Identity(); // type coersion, this case should never be hit
+ });
+ return xf;
};
@undoBatch
@@ -259,16 +271,16 @@ export class CollectionMulticolumnView extends CollectionSubView() {
Document={childLayout}
TemplateDataDocument={childLayout.resolvedDataDoc as Doc}
styleProvider={this._props.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
renderDepth={this._props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dragAction={(this._props.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
suppressSetHeight={true}
ScreenToLocalTransform={dxf}
isContentActive={this.isChildContentActive}
@@ -287,7 +299,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
);
@@ -298,10 +309,8 @@ export class CollectionMulticolumnView extends CollectionSubView() {
*/
@computed
private get contents(): JSX.Element[] | null {
- const { childLayoutPairs } = this;
const collector: JSX.Element[] = [];
- for (let i = 0; i < childLayoutPairs.length; i++) {
- const { layout } = childLayoutPairs[i];
+ this.childLayouts.forEach((layout, i) => {
collector.push(
<Tooltip title={'Tab: ' + StrCast(layout.title)} key={'wrapper' + i}>
<div className="document-wrapper" style={{ flexDirection: 'column', width: this.lookupPixels(layout) }}>
@@ -318,10 +327,10 @@ export class CollectionMulticolumnView extends CollectionSubView() {
select={this._props.select}
columnUnitLength={this.getColumnUnitLength}
toLeft={layout}
- toRight={childLayoutPairs[i + 1]?.layout}
+ toRight={this.childLayouts[i + 1]}
/>
);
- }
+ });
collector.pop(); // removes the final extraneous resize bar
return collector;
}
@@ -340,6 +349,20 @@ export class CollectionMulticolumnView extends CollectionSubView() {
marginBottom: NumCast(this.Document._yMargin),
}}>
{this.contents}
+ {!this._startIndex ? null : (
+ <Tooltip title={'scroll back'}>
+ <div style={{ position: 'absolute', bottom: 0, left: 0, background: SettingsManager.userVariantColor }} onClick={action(e => (this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}>
+ <Button tooltip="Scroll back" icon={<FontAwesomeIcon icon="chevron-left" size="lg" />} onClick={action(e => (this._startIndex = Math.max(0, this._startIndex - this.maxShown)))} color={SettingsManager.userColor} />
+ </div>
+ </Tooltip>
+ )}
+ {this._startIndex > this.childLayoutPairs.length - 1 ? null : (
+ <Tooltip title={'scroll forward'}>
+ <div style={{ position: 'absolute', bottom: 0, right: 0, background: SettingsManager.userVariantColor }} onClick={action(e => (this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}>
+ <IconButton icon={<FaChevronRight />} color={SettingsManager.userColor} />
+ </div>
+ </Tooltip>
+ )}
</div>
);
}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bf0d39197..17bf3e50c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,7 +1,6 @@
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse } from '../../../../Utils';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { DragManager, dropActionType } from '../../../util/DragManager';
@@ -122,7 +121,7 @@ export class CollectionMultirowView extends CollectionSubView() {
private get totalRatioAllocation(): number | undefined {
const layoutInfoLen = this.resolvedLayoutInformation.heightSpecifiers.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
- return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._yMargin);
+ return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._yMargin);
}
}
@@ -254,23 +253,22 @@ export class CollectionMultirowView extends CollectionSubView() {
Document={layout}
TemplateDataDocument={layout.resolvedDataDoc as Doc}
styleProvider={this._props.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
renderDepth={this._props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dropAction={StrCast(this.Document.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
isContentActive={this.isChildContentActive}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
hideResizeHandles={layout.layout_fitWidth || this._props.childHideResizeHandles ? true : false}
hideDecorationTitle={this._props.childHideDecorationTitle}
fitContentsToBox={this._props.fitContentsToBox}
- dragAction={this._props.childDragAction}
focus={this._props.focus}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
@@ -282,7 +280,6 @@ export class CollectionMultirowView extends CollectionSubView() {
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
);
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
index c38c6dc4e..d580d9c52 100644
--- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
@@ -1,16 +1,16 @@
-import { action, observable } from 'mobx';
+import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { UndoManager } from '../../../util/UndoManager';
import { StyleProp } from '../../StyleProvider';
-import { StyleProviderFunc } from '../../nodes/DocumentView';
+import { StyleProviderFuncType } from '../../nodes/FieldView';
import { DimUnit } from './CollectionMulticolumnView';
interface ResizerProps {
width: number;
- styleProvider?: StyleProviderFunc;
+ styleProvider?: StyleProviderFuncType;
isContentActive?: () => boolean | undefined;
columnUnitLength(): number | undefined;
toLeft?: Doc;
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
index 6f1b3b425..73d08d5ef 100644
--- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
@@ -1,16 +1,16 @@
-import { action, observable } from 'mobx';
+import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { UndoManager } from '../../../util/UndoManager';
import { StyleProp } from '../../StyleProvider';
-import { StyleProviderFunc } from '../../nodes/DocumentView';
+import { StyleProviderFuncType } from '../../nodes/FieldView';
import { DimUnit } from './CollectionMultirowView';
interface ResizerProps {
height: number;
- styleProvider?: StyleProviderFunc;
+ styleProvider?: StyleProviderFuncType;
isContentActive?: () => boolean | undefined;
columnUnitLength(): number | undefined;
toTop?: Doc;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 02131ae22..fed4e89cf 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -18,17 +18,21 @@
.schema-add {
position: relative;
- height: 30;
+ height: 35;
display: flex;
align-items: center;
+ top: -10px;
width: 100%;
text-align: right;
background: lightgray;
.editableView-container-editing {
width: 100%;
+ height: 35px;
+ margin: 20px;
}
.editableView-input {
width: 100%;
+ margin: 20px;
float: right;
text-align: right;
background: yellow;
@@ -128,7 +132,7 @@
.row-menu {
display: flex;
- justify-content: flex-end;
+ justify-content: center;
}
}
@@ -210,8 +214,9 @@
border: 1px solid $medium-gray;
overflow-x: hidden;
overflow-y: auto;
- padding: 5px;
display: inline-flex;
+ padding: 0;
+ align-items: center;
}
.schema-row {
@@ -223,7 +228,10 @@
display: flex;
flex-direction: row;
min-width: 50px;
- justify-content: flex-end;
+ justify-content: center;
+ .iconButton-container {
+ min-width: unset !important;
+ }
}
.row-cells {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 492aed0ea..eee3836d2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -10,13 +10,14 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty
import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
import { SelectionManager } from '../../../util/SelectionManager';
import { undoable, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView';
import { KeyValueBox } from '../../nodes/KeyValueBox';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
@@ -24,7 +25,7 @@ import { CollectionSubView } from '../CollectionSubView';
import './CollectionSchemaView.scss';
import { SchemaColumnHeader } from './SchemaColumnHeader';
import { SchemaRowBox } from './SchemaRowBox';
-import { FieldViewProps } from '../../nodes/FieldView';
+const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
export enum ColumnType {
Number,
@@ -69,7 +70,7 @@ export class CollectionSchemaView extends CollectionSubView() {
public static _minColWidth: number = 25;
public static _rowMenuWidth: number = 60;
public static _previewDividerWidth: number = 4;
- public static _newNodeInputHeight: number = 20;
+ public static _newNodeInputHeight: number = Number(SCHEMA_NEW_NODE_HEIGHT);
public fieldInfos = new ObservableMap<string, FInfo>();
@observable _menuKeys: string[] = [];
@@ -147,7 +148,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
document.addEventListener('keydown', this.onKeyDown);
Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
@@ -498,13 +499,13 @@ export class CollectionSchemaView extends CollectionSubView() {
ContextMenu.Instance.displayMenu(x, y, undefined, true);
};
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
this.scrollToDoc(doc, options);
return undefined;
};
- scrollToDoc = (doc: Doc, options: DocFocusOptions) => {
+ scrollToDoc = (doc: Doc, options: FocusViewOptions) => {
const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
const rect = found.getBoundingClientRect();
@@ -907,14 +908,13 @@ export class CollectionSchemaView extends CollectionSubView() {
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
styleProvider={DefaultStyleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
moveDocument={this._props.moveDocument}
addDocument={this.addRow}
removeDocument={this._props.removeDocument}
whenChildContentsActiveChanged={returnFalse}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
/>
)}
</div>
@@ -962,7 +962,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
tableWidthFunc = () => this._props.schema.tableWidth;
screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight());
- noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
if (property === StyleProp.Opacity) return 1;
return DefaultStyleProvider(doc, props, property);
};
@@ -971,6 +971,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
<DocumentView
key={this._props.doc[Id]}
{...this._props.schema._props}
+ containerViewPath={this._props.schema.childContainerViewPath}
LayoutTemplate={this._props.schema._props.childLayoutTemplate}
LayoutTemplateString={SchemaRowBox.LayoutString(this._props.schema._props.fieldKey, this._props.index)}
Document={this._props.doc}
@@ -980,7 +981,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
styleProvider={this.noOpacityStyleProvider}
waitForDoubleClickToClick={returnNever}
defaultDoubleClick={returnIgnore}
- dragAction="move"
+ dragAction={dropActionType.move}
onClickScriptDisable="always"
focus={this._props.schema.focusDocument}
childFilters={this._props.schema.childDocFilters}
@@ -988,7 +989,6 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
searchFilterDocs={this._props.schema.searchFilterDocs}
rootSelected={this._props.schema.rootSelected}
ScreenToLocalTransform={this.screenToLocalXf}
- bringToFront={emptyFunction}
dragWhenActive={true}
isDocumentActive={this._props.schema._props.childDocumentsActive?.() ? this._props.schema._props.isDocumentActive : this._props.schema.isContentActive}
isContentActive={emptyFunction}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 5a3be826b..39fea2d2e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -3,7 +3,7 @@ import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
-import { CgClose } from 'react-icons/cg';
+import { CgClose, CgLock, CgLockUnlock } from 'react-icons/cg';
import { FaExternalLinkAlt } from 'react-icons/fa';
import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils';
import { Doc } from '../../../../fields/Doc';
@@ -20,17 +20,17 @@ import { CollectionSchemaView } from './CollectionSchemaView';
import './CollectionSchemaView.scss';
import { SchemaTableCell } from './SchemaTableCell';
-interface SchemaRowBoxProps {
+interface SchemaRowBoxProps extends FieldViewProps {
rowIndex: number;
}
@observer
-export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
public static LayoutString(fieldKey: string, rowIndex: number) {
return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`);
}
private _ref: HTMLDivElement | null = null;
- constructor(props: any) {
+ constructor(props: SchemaRowBoxProps) {
super(props);
makeObservable(this);
}
@@ -38,11 +38,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.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionSchemaView;
}
@computed get schemaDoc() {
- return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.Document;
}
@computed get rowIndex() {
@@ -50,7 +50,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
}
componentDidMount(): void {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
select = (ctrlKey: boolean, shiftKey: boolean) => {
@@ -121,6 +121,22 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
}}>
<IconButton
+ tooltip="whether document interactions are enabled"
+ icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />}
+ size={Size.XSMALL}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoable(e => {
+ e.stopPropagation();
+ Doc.toggleLockedPosition(this.Document);
+ }, 'Delete Row')
+ )
+ }></IconButton>
+ <IconButton
tooltip="close"
icon={<CgClose size={'16px'} />}
size={Size.XSMALL}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 85269028b..46867665d 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -10,7 +10,7 @@ import { Doc, DocListCast, Field } from '../../../../fields/Doc';
import { RichTextField } from '../../../../fields/RichTextField';
import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../../../fields/Types';
import { ImageField } from '../../../../fields/URLField';
-import { FInfo } from '../../../documents/Documents';
+import { FInfo, FInfoFieldType } from '../../../documents/Documents';
import { DocFocusOrOpen } from '../../../util/DocumentManager';
import { Transform } from '../../../util/Transform';
import { undoBatch, undoable } from '../../../util/UndoManager';
@@ -18,12 +18,18 @@ import { EditableView } from '../../EditableView';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DefaultStyleProvider } from '../../StyleProvider';
import { Colors } from '../../global/globalEnums';
-import { OpenWhere } from '../../nodes/DocumentView';
+import { OpenWhere, returnEmptyDocViewList } from '../../nodes/DocumentView';
import { FieldViewProps } from '../../nodes/FieldView';
import { KeyValueBox } from '../../nodes/KeyValueBox';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { ColumnType, FInfotoColType } from './CollectionSchemaView';
import './CollectionSchemaView.scss';
+import 'react-datepicker/dist/react-datepicker.css';
+import { Popup, Size, Type } from 'browndash-components';
+import { IconLookup, faCaretDown } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { SettingsManager } from '../../../util/SettingsManager';
+import { dropActionType } from '../../../util/DragManager';
export interface SchemaTableCellProps {
Document: Doc;
@@ -49,7 +55,7 @@ export interface SchemaTableCellProps {
@observer
export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> {
- constructor(props: any) {
+ constructor(props: SchemaTableCellProps) {
super(props);
makeObservable(this);
}
@@ -75,14 +81,13 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
const fieldProps: FieldViewProps = {
childFilters: returnEmptyFilter,
childFiltersByRanges: returnEmptyFilter,
+ docViewPath: returnEmptyDocViewList,
searchFilterDocs: returnEmptyDoclist,
styleProvider: DefaultStyleProvider,
- docViewPath: returnEmptyDoclist,
isSelected: returnFalse,
setHeight: returnFalse,
select: emptyFunction,
- dragAction: 'move',
- bringToFront: emptyFunction,
+ dragAction: dropActionType.move,
renderDepth: 1,
isContentActive: returnFalse,
whenChildContentsActiveChanged: emptyFunction,
@@ -145,7 +150,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
if (cellValue instanceof DateField) return ColumnType.Date;
if (cellValue instanceof RichTextField) return ColumnType.RTF;
if (typeof cellValue === 'number') return ColumnType.Any;
- if (typeof cellValue === 'string' && columnTypeStr !== 'enumeration') return ColumnType.Any;
+ if (typeof cellValue === 'string' && columnTypeStr !== FInfoFieldType.enumeration) return ColumnType.Any;
if (typeof cellValue === 'boolean') return ColumnType.Boolean;
if (columnTypeStr && columnTypeStr in FInfotoColType) {
@@ -163,7 +168,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
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.Date: return <SchemaDateCell {...this._props} />;
default: return this.defaultCellContent;
}
}
@@ -261,19 +266,39 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp
return DateCast(this._props.Document[this._props.fieldKey]);
}
- @action
- handleChange = (date: any) => {
+ handleChange = undoable((date: Date | null) => {
// 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);
// } 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);
+ date && (this._props.Document[this._props.fieldKey] = new DateField(date));
//}
- };
+ }, 'date change');
render() {
- return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
+ const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
+ return (
+ <>
+ <div style={{ pointerEvents: 'none' }}>
+ <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={e => {}} />
+ </div>
+ {pointerEvents === 'none' ? null : (
+ <Popup
+ icon={<FontAwesomeIcon size="sm" icon="caret-down" />}
+ size={Size.XSMALL}
+ type={Type.TERT}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
+ popup={
+ <div style={{ width: 'fit-content', height: '200px' }}>
+ <DatePicker open={true} dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={this.handleChange} />
+ </div>
+ }
+ />
+ )}
+ </>
+ );
}
}
@observer
@@ -395,7 +420,7 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC
}),
}}
menuPortalTarget={this._props.menuTarget}
- menuPosition={'absolute'}
+ menuPosition="absolute"
placeholder={StrCast(this._props.Document[this._props.fieldKey], 'select...')}
options={options}
isMulti={false}