aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authormehekj <mehek.jethani@gmail.com>2023-03-23 15:16:40 -0400
committermehekj <mehek.jethani@gmail.com>2023-03-23 15:16:40 -0400
commit5c22004907c210951154017609746e86362c4fb5 (patch)
tree108371dccd171c6bd523a01dc3f39a657d85ad96 /src/client/views/collections
parent016e51965ae2d0a83ca2d4e17000d57a40aac264 (diff)
parent923f0fdb0f039a923e4e6f870158bd2f2ba32db0 (diff)
Merge branch 'master' into schema-mehek
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx40
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx49
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx13
-rw-r--r--src/client/views/collections/CollectionSubView.tsx10
-rw-r--r--src/client/views/collections/CollectionView.tsx40
-rw-r--r--src/client/views/collections/TabDocView.tsx14
-rw-r--r--src/client/views/collections/TreeView.tsx10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx31
9 files changed, 115 insertions, 94 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 1ead80bd0..e38905cbc 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -26,12 +26,14 @@ import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import { TabDocView } from './TabDocView';
import React = require('react');
import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { OverlayView } from '../OverlayView';
+import { ScriptingRepl } from '../ScriptingRepl';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
export class CollectionDockingView extends CollectionSubView() {
@observable public static Instance: CollectionDockingView | undefined;
- public static makeDocumentConfig(document: Doc, panelName?: string, width?: number) {
+ public static makeDocumentConfig(document: Doc, panelName?: string, width?: number, keyValue?: boolean) {
return {
type: 'react-component',
component: 'DocumentFrameRenderer',
@@ -39,6 +41,7 @@ export class CollectionDockingView extends CollectionSubView() {
width: width,
props: {
documentId: document[Id],
+ keyValue,
panelName, // name of tab that can be used to close or replace its contents
},
};
@@ -143,10 +146,10 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
@action
- public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean): boolean {
+ public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean, keyValue?: boolean): boolean {
const instance = CollectionDockingView.Instance;
if (!instance) return false;
- const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
+ const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue);
if (!panelName && stack) {
const activeContentItemIndex = stack.contentItems.findIndex((item: any) => item.config === stack._activeContentItem.config);
const newContentItem = stack.layoutManager.createContentItem(newConfig, instance._goldenLayout);
@@ -168,10 +171,10 @@ export class CollectionDockingView extends CollectionSubView() {
}
@undoBatch
- public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string) {
+ public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1
? CollectionDockingView.CloseSplit(doc)
- : CollectionDockingView.AddSplit(doc, location, stack, panelName);
+ : CollectionDockingView.AddSplit(doc, location, stack, panelName, keyValue);
}
//
@@ -179,7 +182,7 @@ export class CollectionDockingView extends CollectionSubView() {
//
@undoBatch
@action
- public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string) {
+ public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
if (!CollectionDockingView.Instance) return false;
const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
@@ -190,7 +193,7 @@ export class CollectionDockingView extends CollectionSubView() {
const instance = CollectionDockingView.Instance;
const glayRoot = instance._goldenLayout.root;
if (!instance) return false;
- const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
+ const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue);
if (!pullSide && stack) {
stack.addChild(docContentConfig, undefined);
@@ -407,11 +410,10 @@ export class CollectionDockingView extends CollectionSubView() {
const _width = Number(getComputedStyle(content).width.replace('px', ''));
const _height = Number(getComputedStyle(content).height.replace('px', ''));
return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => {
- const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: this.rootDoc.title + '-icon', _width, _height, _nativeWidth, _nativeHeight });
const proto = this.dataDoc; // Cast(img.proto, Doc, null)!;
proto['thumb-nativeWidth'] = _width;
proto['thumb-nativeHeight'] = _height;
- this.dataDoc.thumb = new ImageField(iconFile);
+ proto.thumb = new ImageField(iconFile);
});
}
}
@@ -580,19 +582,25 @@ ScriptingGlobals.add(
'(doc: any)'
);
ScriptingGlobals.add(
- function openOnRight(doc: any) {
- return CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
+ function openDoc(doc: any, where: OpenWhere) {
+ switch (where) {
+ case OpenWhere.addRight:
+ return CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
+ case OpenWhere.overlay:
+ if (doc === 'repl') OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
+ else Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ }
},
- 'opens up document in tab on right side of the screen',
+ 'opens up document in location specified',
'(doc: any)'
);
ScriptingGlobals.add(
- function openInOverlay(doc: any) {
- return Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ function openRepl() {
+ return 'openRepl';
},
'opens up document in screen overlay layer',
'(doc: any)'
);
-ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) {
- CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, shiftKey);
+ScriptingGlobals.add(function useRightSplit(doc: any, addToRightSplit?: boolean) {
+ CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, addToRightSplit);
});
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index 5a107d2ca..a55b70e22 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -97,7 +97,7 @@
top: 2.5%;
height: 95%;
border-radius: 4px;
- background: $light-gray;
+ //background: $light-gray;
&:hover {
opacity: 1;
}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 5bdff347c..4941bc722 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { Cast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
-import { emptyFunction, formatTime, OmitKeys, returnFalse, returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
+import { emptyFunction, formatTime, OmitKeys, returnFalse, returnNone, returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
@@ -180,12 +180,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
if (
// need to include range inputs because after dragging video time slider it becomes target element
!(e.target instanceof HTMLInputElement && !(e.target.type === 'range')) &&
- this.props.isSelected(true)
+ this.props.isContentActive()
) {
// if shift pressed scrub 1 second otherwise 1/10th
const jump = e.shiftKey ? 1 : 0.1;
switch (e.key) {
case ' ':
+ this.props.playing() ? this.props.Pause() : this.props.Play();
+ break;
+ case '^':
if (!CollectionStackedTimeline.SelectingRegion) {
this._markerStart = this._markerEnd = this.currentTime;
CollectionStackedTimeline.SelectingRegion = this;
@@ -399,8 +402,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
_minFontSize: 12,
_maxFontSize: 24,
- _singleLine: false,
+ _singleLine: true,
_stayInCollection: true,
+ backgroundColor: 'rgba(128, 128, 128, 0.5)',
useLinkSmallAnchor: true,
hideLinkButton: true,
_isLinkButton: true,
@@ -422,7 +426,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
@action
playOnClick = (anchorDoc: Doc, clientX: number) => {
- const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
+ const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
const endTime = this.anchorEnd(anchorDoc);
if (this.layoutDoc.autoPlayAnchors) {
if (this.props.playing()) this.props.Pause();
@@ -448,9 +452,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
@action
clickAnchor = (anchorDoc: Doc, clientX: number) => {
if (anchorDoc.isLinkButton) {
- LinkFollower.FollowLink(undefined, anchorDoc, this.props, false);
+ LinkFollower.FollowLink(undefined, anchorDoc, false);
}
- const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
+ const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
const endTime = this.anchorEnd(anchorDoc);
if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) {
if (this.props.playing()) this.props.Pause();
@@ -564,7 +568,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
anchor,
}));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
- return (
+ return this.clipDuration === 0 ? null : (
<div ref={this.createDashEventsTarget} style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : undefined }}>
<div
className="collectionStackedTimeline-timelineContainer"
@@ -597,10 +601,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
top,
width: `${width}px`,
height: `${height}px`,
- }}
- onClick={e => {
- this.props.playFrom(start, this.anchorEnd(d.anchor));
- e.stopPropagation();
+ pointerEvents: 'none',
}}>
<StackedTimelineAnchor
{...this.props}
@@ -753,7 +754,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
time < NumCast(this.props.mark[this.props.endTag]) &&
this._lastTimecode < NumCast(this.props.mark[this.props.startTag]) - 1e-5
) {
- LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false);
+ LinkFollower.FollowLink(undefined, this.props.mark, false);
}
this._lastTimecode = time;
}
@@ -764,7 +765,9 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
this._disposer?.();
}
+ @observable noEvents = false;
// starting the drag event for anchor resizing
+ @action
onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => {
//this.props._timeline?.setPointerCapture(e.pointerId);
const newTime = (e: PointerEvent) => {
@@ -782,8 +785,8 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
}
return false;
};
+ this.noEvents = true;
var undo: UndoManager.Batch | undefined;
-
setupMoveUpEvents(
this,
e,
@@ -792,11 +795,11 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
this.props.setTime(newTime(e));
return changeAnchor(anchor, left, newTime(e));
},
- e => {
+ action(e => {
this.props.setTime(newTime(e));
- // this.props._timeline?.releasePointerCapture(e.pointerId);
undo?.end();
- },
+ this.noEvents = false;
+ }),
emptyFunction
);
};
@@ -814,10 +817,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
// 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 any });
- const focusFunc = (doc: Doc, options: DocFocusOptions) => {
- this.props.playLink(mark);
- this.props.focus(doc, options);
- };
+ const focusFunc = (doc: Doc, options: DocFocusOptions) => this.props.playLink(mark);
return {
anchor,
view: (
@@ -827,6 +827,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
ref={action((r: DocumentView | null) => (anchor.view = r))}
Document={mark}
DataDoc={undefined}
+ pointerEvents={this.noEvents ? returnNone : undefined}
styleProvider={this.props.styleProvider}
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={undefined}
@@ -857,15 +858,15 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
render() {
const inner = this.renderInner(this.props.mark, this.props.rangeClickScript, this.props.rangePlayScript, this.anchorScreenToLocalXf, this.width, this.height);
return (
- <>
+ <div style={{ pointerEvents: this.noEvents ? 'none' : undefined }}>
{inner.view}
{!inner.anchor.view || !SelectionManager.IsSelected(inner.anchor.view) ? null : (
<>
- <div key="left" className="collectionStackedTimeline-left-resizer" onPointerDown={e => this.onAnchorDown(e, this.props.mark, true)} />
- <div key="right" className="collectionStackedTimeline-resizer" onPointerDown={e => this.onAnchorDown(e, this.props.mark, false)} />
+ <div key="left" className="collectionStackedTimeline-left-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this.props.mark, true)} />
+ <div key="right" className="collectionStackedTimeline-resizer" style={{ pointerEvents: this.noEvents ? 'none' : undefined }} onPointerDown={e => this.onAnchorDown(e, this.props.mark, false)} />
</>
)}
- </>
+ </div>
);
}
}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4805a748b..33d468950 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -201,6 +201,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
componentDidMount() {
super.componentDidMount?.();
+ this.props.setContentView?.(this);
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
@@ -226,6 +227,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
this._autoHeightDisposer?.();
}
+ isAnyChildContentActive = () => this.props.isAnyChildContentActive();
+
@action
moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => {
return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
@@ -651,8 +654,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
<DocumentView
Document={menuDoc}
DataDoc={menuDoc}
- isContentActive={this.props.isContentActive}
- isDocumentActive={returnTrue}
+ isContentActive={this.isContentActive}
+ isDocumentActive={this.isContentActive}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
@@ -716,14 +719,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
className={this.isStackingView ? 'collectionStackingView' : 'collectionMasonryView'}
ref={this.createRef}
style={{
- overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
+ overflowY: this.isContentActive() ? 'auto' : 'hidden',
background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
- pointerEvents: this.backgroundEvents ? 'all' : undefined,
+ pointerEvents: (this.props.pointerEvents?.() as any) ?? (this.backgroundEvents ? 'all' : undefined),
}}
onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
- onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
+ 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 }}>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index e46220f02..bd74c9399 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -269,10 +269,10 @@ export function CollectionSubView<X>(moreProps?: X) {
if (FormattedTextBox.IsFragment(html)) {
const href = FormattedTextBox.GetHref(html);
if (href) {
- const docid = FormattedTextBox.GetDocFromUrl(href);
- if (docid) {
+ const docId = FormattedTextBox.GetDocFromUrl(href);
+ if (docId) {
// prosemirror text containing link to dash document
- DocServer.GetRefField(docid).then(f => {
+ DocServer.GetRefField(docId).then(f => {
if (f instanceof Doc) {
if (options.x || options.y) {
f.x = options.x as number;
@@ -311,8 +311,8 @@ export function CollectionSubView<X>(moreProps?: X) {
} else {
const path = window.location.origin + '/doc/';
if (text.startsWith(path)) {
- const docid = text.replace(Doc.globalServerPath(), '').split('?')[0];
- DocServer.GetRefField(docid).then(f => {
+ const docId = text.replace(Doc.globalServerPath(), '').split('?')[0];
+ DocServer.GetRefField(docId).then(f => {
if (f instanceof Doc) {
if (options.x || options.y) {
f.x = options.x as number;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 48e5748a0..eafa50d27 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -2,7 +2,6 @@ import { computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
-import { Id } from '../../../fields/FieldSymbols';
import { ObjectField } from '../../../fields/ObjectField';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -10,13 +9,12 @@ import { TraceMobx } from '../../../fields/util';
import { returnEmptyString } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { CollectionViewType } from '../../documents/DocumentTypes';
-import { BranchCreate, BranchTask } from '../../documents/Gitlike';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
-import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { OpenWhere } from '../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
@@ -169,7 +167,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
onContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
- if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== Doc.MainDocId) {
+ if (cm && !e.isPropagationStopped()) {
// need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
this.setupViewTypes(
'UI Controls...',
@@ -193,23 +191,23 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
}
!Doc.noviceMode && optionItems.push({ description: `${this.rootDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' });
- if (!Doc.noviceMode && false) {
- optionItems.push({
- description: 'Create Branch',
- event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight),
- icon: 'project-diagram',
- });
- optionItems.push({
- description: 'Pull Master',
- event: () => BranchTask(this.rootDoc, 'pull'),
- icon: 'project-diagram',
- });
- optionItems.push({
- description: 'Merge Branches',
- event: () => BranchTask(this.rootDoc, 'merge'),
- icon: 'project-diagram',
- });
- }
+ // if (!Doc.noviceMode && false) {
+ // optionItems.push({
+ // description: 'Create Branch',
+ // event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight),
+ // icon: 'project-diagram',
+ // });
+ // optionItems.push({
+ // description: 'Pull Master',
+ // event: () => BranchTask(this.rootDoc, 'pull'),
+ // icon: 'project-diagram',
+ // });
+ // optionItems.push({
+ // description: 'Merge Branches',
+ // event: () => BranchTask(this.rootDoc, 'merge'),
+ // icon: 'project-diagram',
+ // });
+ // }
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 9459aaf1e..631b9add5 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -35,10 +35,12 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
import { CollectionView } from './CollectionView';
import './TabDocView.scss';
import React = require('react');
+import { KeyValueBox } from '../nodes/KeyValueBox';
const _global = (window /* browser */ || global) /* node */ as any;
interface TabDocViewProps {
documentId: FieldId;
+ keyValue?: boolean;
glContainer: any;
}
@observer
@@ -57,7 +59,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
@computed get tabBorderColor() {
const highlight = DefaultStyleProvider(this._document, undefined, StyleProp.Highlighting);
- if (highlight?.highlightIndex >= Doc.DocBrushStatus.highlighted) return highlight.highlightColor;
+ if (highlight?.highlightIndex === Doc.DocBrushStatus.highlighted) return highlight.highlightColor;
return 'transparent';
}
@computed get tabColor() {
@@ -348,7 +350,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
addDocTab = (doc: Doc, location: OpenWhere) => {
SelectionManager.DeselectAll();
const whereFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':');
- const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none;
+ const keyValue = whereFields[1]?.includes('KeyValue');
+ const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none;
if (doc.dockingConfig) return DashboardView.openDashboard(doc);
// prettier-ignore
switch (whereFields[0]) {
@@ -365,9 +368,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
case OpenWhere.dashboard: return DashboardView.openDashboard(doc);
case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc);
case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods);
- case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack);
- case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack);
- case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, this.stack);
+ case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, undefined, keyValue);
+ case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack, undefined, keyValue);
+ case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, this.stack, undefined, keyValue);
}
};
remDocTab = (doc: Doc | Doc[]) => {
@@ -419,6 +422,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
this._lastView = this._view;
})}
renderDepth={0}
+ LayoutTemplateString={this.props.keyValue ? KeyValueBox.LayoutString('data') : undefined}
Document={this._document}
DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
ContainingCollectionView={undefined}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 2bdcf472f..af2d148e0 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { RichTextField } from '../../../fields/RichTextField';
@@ -172,11 +172,7 @@ export class TreeView extends React.Component<TreeViewProps> {
childDocList(field: string) {
const layout = Cast(Doc.LayoutField(this.doc), Doc, null);
- return (
- (this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
- (layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
- DocListCastOrNull(this.doc[field])
- ); // otherwise use the document's data field
+ return DocListCast(this.props.dataDoc?.[field], DocListCast(layout?.[field], DocListCast(this.doc[field])));
}
moving: boolean = false;
@undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
@@ -759,7 +755,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'New Folder' };
const deleteItem = { script: ScriptField.MakeFunction(`scriptContext.deleteItem()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'Delete' };
const folderOp = this.childDocs?.length ? [makeFolder] : [];
- const openAlias = { script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, icon: 'copy', label: 'Open Alias' };
+ const openAlias = { script: ScriptField.MakeFunction(`openDoc(getAlias(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Alias' };
const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: 'eye', label: 'Focus or Open' };
return [
...(this.props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result)),
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 15d8144fc..aea7a3ad9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -120,7 +120,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
constructor(props: any) {
super(props);
- this.props.setContentView?.(this);
}
@computed get views() {
@@ -293,6 +292,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime);
}
+ groupFocus = (anchor: Doc, options: DocFocusOptions) => {
+ options.docTransform = new Transform(-NumCast(this.rootDoc.panX) + NumCast(anchor.x), -NumCast(this.rootDoc.panY) + NumCast(anchor.y), 1);
+ const res = this.props.focus(this.rootDoc, options);
+ options.docTransform = undefined;
+ return res;
+ };
+
focus = (anchor: Doc, options: DocFocusOptions) => {
const xfToCollection = options?.docTransform ?? Transform.Identity();
const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
@@ -301,6 +307,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// focus on the document in the collection
const didMove = !cantTransform && !anchor.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale);
+ if (didMove) options.didMove = true;
// glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
if (didMove) {
const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
@@ -1068,7 +1075,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
onPointerWheel = (e: React.WheelEvent): void => {
- if (this.Document._isGroup) return; // group style collections neither pan nor zoom
+ if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
PresBox.Instance?.pauseAutoPres();
if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
e.stopPropagation();
@@ -1320,7 +1327,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
searchFilterDocs={this.searchFilterDocs}
isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
isContentActive={emptyFunction}
- focus={this.isAnnotationOverlay ? this.props.focus : this.focus}
+ focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
addDocTab={this.addDocTab}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
@@ -1568,6 +1575,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
componentDidMount() {
+ this.props.setContentView?.(this);
super.componentDidMount?.();
this.props.setBrushViewer?.(this.brushView);
setTimeout(
@@ -1796,11 +1804,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
const mores = ContextMenu.Instance.findByDescription('More...');
const moreItems = mores && 'subitems' in mores ? mores.subitems : [];
- if (!Doc.noviceMode) {
- e.persist();
- moreItems.push({ description: 'Export collection', icon: 'download', event: async () => Doc.Zip(this.props.Document) });
- moreItems.push({ description: 'Import exported collection', icon: 'upload', event: ({ x, y }) => this.importDocument(e.clientX, e.clientY) });
- }
+ moreItems.push({ description: 'Import exported collection', icon: 'upload', event: ({ x, y }) => this.importDocument(e.clientX, e.clientY) });
!mores && ContextMenu.Instance.addItem({ description: 'More...', subitems: moreItems, icon: 'eye' });
};
@@ -2250,8 +2254,9 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
zoomTime: browseTransitionTime,
}) === undefined
) {
- const selfFfview = dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
- const parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
+ let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
const ffview = selfFfview && selfFfview.rootDoc[selfFfview.props.scaleField || '_viewScale'] !== 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.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
Doc.linkFollowHighlight(dv?.props.Document, false);
@@ -2275,3 +2280,9 @@ ScriptingGlobals.add(function pinWithView(readOnly: boolean, pinDocContent: bool
TabDocView.PinDoc(view.rootDoc, { currentFrame: Cast(view.rootDoc.currentFrame, 'number', null), pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) })
);
});
+ScriptingGlobals.add(function bringToFront() {
+ SelectionManager.Views().forEach(view => view.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.bringToFront(view.rootDoc));
+});
+ScriptingGlobals.add(function sendToBack(doc: Doc) {
+ SelectionManager.Views().forEach(view => view.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.bringToFront(view.rootDoc, true));
+});