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/CollectionDockingView.tsx25
-rw-r--r--src/client/views/collections/CollectionMenu.tsx1246
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx716
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx6
-rw-r--r--src/client/views/collections/CollectionSubView.tsx286
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx9
-rw-r--r--src/client/views/collections/CollectionView.tsx75
-rw-r--r--src/client/views/collections/TabDocView.tsx16
-rw-r--r--src/client/views/collections/TreeView.tsx1168
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx248
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx201
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx105
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx28
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx517
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx9
15 files changed, 2449 insertions, 2206 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 27478e59b..d47dfbea0 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -12,18 +12,17 @@ import { inheritParentAcls } from '../../../fields/util';
import { emptyFunction, incrementTitleCopy } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { Docs } from '../../documents/Documents';
-import { DocumentType } from '../../documents/DocumentTypes';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { DashboardView } from '../DashboardView';
import { LightboxView } from '../LightboxView';
import './CollectionDockingView.scss';
import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-import { CollectionViewType } from './CollectionView';
import { TabDocView } from './TabDocView';
import React = require('react');
const _global = (window /* browser */ || global) /* node */ as any;
@@ -121,7 +120,7 @@ export class CollectionDockingView extends CollectionSubView() {
SelectionManager.DeselectAll();
const instance = CollectionDockingView.Instance;
if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === 'layout') {
- return CurrentUserUtils.openDashboard(doc);
+ return DashboardView.openDashboard(doc);
}
const newItemStackConfig = {
type: 'stack',
@@ -170,7 +169,7 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
@action
public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
- if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(document);
+ if (document._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
if (tab) {
@@ -378,7 +377,7 @@ export class CollectionDockingView extends CollectionSubView() {
}
}
}
- if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) {
+ if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
e.stopPropagation();
}
};
@@ -404,7 +403,7 @@ export class CollectionDockingView extends CollectionSubView() {
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;
- return CurrentUserUtils.openDashboard(cloned.clone);
+ return DashboardView.openDashboard(cloned.clone);
}
const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
const origtabids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) || [];
@@ -424,7 +423,7 @@ export class CollectionDockingView extends CollectionSubView() {
return newtab;
});
const copy = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) });
- return CurrentUserUtils.openDashboard(await copy);
+ return DashboardView.openDashboard(await copy);
}
@action
@@ -451,8 +450,8 @@ export class CollectionDockingView extends CollectionSubView() {
tabDestroyed = (tab: any) => {
if (tab.DashDoc?.type !== DocumentType.KVP) {
- Doc.AddDocToList(CurrentUserUtils.MyHeaderBar, 'data', tab.DashDoc);
- Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+ Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
+ Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
}
const dview = CollectionDockingView.Instance.props.Document;
const fieldKey = CollectionDockingView.Instance.props.fieldKey;
@@ -469,7 +468,7 @@ export class CollectionDockingView extends CollectionSubView() {
stackCreated = (stack: any) => {
stack.header?.element.on('mousedown', (e: any) => {
- const dashboard = CurrentUserUtils.ActiveDashboard;
+ const dashboard = Doc.ActiveDashboard;
if (dashboard && e.target === stack.header?.element[0] && e.button === 2) {
dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
const docToAdd = Docs.Create.FreeformDocument([], {
@@ -507,7 +506,7 @@ export class CollectionDockingView extends CollectionSubView() {
.click(
action(() => {
// stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size
- const dashboard = CurrentUserUtils.ActiveDashboard;
+ const dashboard = Doc.ActiveDashboard;
if (dashboard) {
dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
const docToAdd = Docs.Create.FreeformDocument([], {
@@ -545,7 +544,7 @@ ScriptingGlobals.add(
);
ScriptingGlobals.add(
function openInOverlay(doc: any) {
- return Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc);
+ return Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
},
'opens up document in screen overlay layer',
'(doc: any)'
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 668d82387..2c0e44bc3 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1,46 +1,46 @@
-import React = require("react");
+import React = require('react');
import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
-import { Tooltip } from "@material-ui/core";
-import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import { ColorState } from "react-color";
-import { Doc, DocListCast, Opt } from "../../../fields/Doc";
-import { Document } from "../../../fields/documentSchemas";
-import { Id } from "../../../fields/FieldSymbols";
-import { InkTool } from "../../../fields/InkField";
-import { List } from "../../../fields/List";
-import { ObjectField } from "../../../fields/ObjectField";
-import { RichTextField } from "../../../fields/RichTextField";
-import { listSpec } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DragManager } from "../../util/DragManager";
-import { ScriptingGlobals } from "../../util/ScriptingGlobals";
-import { SelectionManager } from "../../util/SelectionManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
-import { EditableView } from "../EditableView";
-import { GestureOverlay } from "../GestureOverlay";
-import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
-import { LightboxView } from "../LightboxView";
-import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { DocumentView } from "../nodes/DocumentView";
-import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
-import { RichTextMenu } from "../nodes/formattedText/RichTextMenu";
-import { PresBox } from "../nodes/trails/PresBox";
-import { DefaultStyleProvider } from "../StyleProvider";
-import { CollectionDockingView } from "./CollectionDockingView";
-import { CollectionLinearView } from "./collectionLinear";
-import "./CollectionMenu.scss";
-import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
-import { TabDocView } from "./TabDocView";
-import { Colors } from "../global/globalEnums";
+import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
+import { action, computed, Lambda, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { ColorState } from 'react-color';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Document } from '../../../fields/documentSchemas';
+import { Id } from '../../../fields/FieldSymbols';
+import { InkTool } from '../../../fields/InkField';
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { RichTextField } from '../../../fields/RichTextField';
+import { listSpec } from '../../../fields/Schema';
+import { ScriptField } from '../../../fields/ScriptField';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DragManager } from '../../util/DragManager';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SettingsManager } from '../../util/SettingsManager';
+import { Transform } from '../../util/Transform';
+import { undoBatch } from '../../util/UndoManager';
+import { AntimodeMenu } from '../AntimodeMenu';
+import { EditableView } from '../EditableView';
+import { GestureOverlay } from '../GestureOverlay';
+import { Colors } from '../global/globalEnums';
+import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../InkingStroke';
+import { LightboxView } from '../LightboxView';
+import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
+import { PresBox } from '../nodes/trails/PresBox';
+import { DefaultStyleProvider } from '../StyleProvider';
+import { CollectionDockingView } from './CollectionDockingView';
+import { CollectionLinearView } from './collectionLinear';
+import './CollectionMenu.scss';
+import { COLLECTION_BORDER_WIDTH } from './CollectionView';
+import { TabDocView } from './TabDocView';
interface CollectionMenuProps {
panelHeight: () => number;
@@ -48,7 +48,7 @@ interface CollectionMenuProps {
}
@observer
-export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
+export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
@observable static Instance: CollectionMenu;
@observable SelectedCollection: DocumentView | undefined;
@@ -58,16 +58,18 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
constructor(props: any) {
super(props);
- this.FieldKey = "";
- runInAction(() => CollectionMenu.Instance = this);
+ this.FieldKey = '';
+ runInAction(() => (CollectionMenu.Instance = this));
this._canFade = false; // don't let the inking menu fade away
- runInAction(() => this.Pinned = Cast(Doc.UserDoc()["menuCollections-pinned"], "boolean", true));
+ runInAction(() => (this.Pinned = Cast(Doc.UserDoc()['menuCollections-pinned'], 'boolean', true)));
this.jumpTo(300, 300);
}
componentDidMount() {
- reaction(() => SelectionManager.Views().length && SelectionManager.Views()[0],
- view => view && this.SetSelection(view));
+ reaction(
+ () => SelectionManager.Views().length && SelectionManager.Views()[0],
+ view => view && this.SetSelection(view)
+ );
}
@action
@@ -77,84 +79,87 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
@action
toggleMenuPin = (e: React.MouseEvent) => {
- Doc.UserDoc()["menuCollections-pinned"] = this.Pinned = !this.Pinned;
+ Doc.UserDoc()['menuCollections-pinned'] = this.Pinned = !this.Pinned;
if (!this.Pinned && this._left < 0) {
this.jumpTo(300, 300);
}
- }
+ };
@action
toggleTopBar = () => {
- if (CurrentUserUtils.headerBarHeight > 0) {
- CurrentUserUtils.headerBarHeight = 0;
+ if (SettingsManager.headerBarHeight > 0) {
+ SettingsManager.headerBarHeight = 0;
} else {
- CurrentUserUtils.headerBarHeight = 60;
+ SettingsManager.headerBarHeight = 60;
}
- }
+ };
buttonBarXf = () => {
if (!this._docBtnRef.current) return Transform.Identity();
const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current);
return new Transform(-translateX, -translateY, 1 / scale);
- }
+ };
@computed get contMenuButtons() {
- const selDoc = CurrentUserUtils.MyContextMenuBtns;
- return !(selDoc instanceof Doc) ? (null) : <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this.props.panelHeight() }} >
- <CollectionLinearView
- Document={selDoc}
- DataDoc={undefined}
- fieldKey={"data"}
- dropAction={"alias"}
- setHeight={returnFalse}
- styleProvider={DefaultStyleProvider}
- rootSelected={returnTrue}
- bringToFront={emptyFunction}
- select={emptyFunction}
- isContentActive={returnTrue}
- isAnyChildContentActive={returnFalse}
- isSelected={returnFalse}
- docViewPath={returnEmptyDoclist}
- moveDocument={returnFalse}
- CollectionView={undefined}
- addDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- removeDocument={returnFalse}
- ScreenToLocalTransform={this.buttonBarXf}
- PanelWidth={this.props.panelWidth}
- PanelHeight={this.props.panelHeight}
- renderDepth={0}
- focus={emptyFunction}
- whenChildContentsActiveChanged={emptyFunction}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />
- </div>;
+ const selDoc = Doc.MyContextMenuBtns;
+ return !(selDoc instanceof Doc) ? null : (
+ <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this.props.panelHeight() }}>
+ <CollectionLinearView
+ Document={selDoc}
+ DataDoc={undefined}
+ fieldKey={'data'}
+ dropAction={'alias'}
+ setHeight={returnFalse}
+ styleProvider={DefaultStyleProvider}
+ rootSelected={returnTrue}
+ bringToFront={emptyFunction}
+ select={emptyFunction}
+ isContentActive={returnTrue}
+ isAnyChildContentActive={returnFalse}
+ isSelected={returnFalse}
+ docViewPath={returnEmptyDoclist}
+ moveDocument={returnFalse}
+ CollectionView={undefined}
+ addDocument={returnFalse}
+ addDocTab={returnFalse}
+ pinToPres={emptyFunction}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={this.buttonBarXf}
+ PanelWidth={this.props.panelWidth}
+ PanelHeight={this.props.panelHeight}
+ renderDepth={0}
+ focus={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>
+ );
}
render() {
+ const propIcon = SettingsManager.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
+ const propTitle = SettingsManager.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
- const propIcon = CurrentUserUtils.headerBarHeight > 0 ? "angle-double-up" : "angle-double-down";
- const propTitle = CurrentUserUtils.headerBarHeight > 0 ? "Close Header Bar" : "Open Header Bar";
-
- const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="topar" placement="bottom">
- <div className="collectionMenu-hardCodedButton"
- style={{ backgroundColor: CurrentUserUtils.propertiesWidth > 0 ? Colors.MEDIUM_BLUE : undefined }}
- onPointerDown={this.toggleTopBar}>
- <FontAwesomeIcon icon={propIcon} size="lg" />
- </div>
- </Tooltip>;
+ const prop = (
+ <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="topar" placement="bottom">
+ <div className="collectionMenu-hardCodedButton" style={{ backgroundColor: SettingsManager.propertiesWidth > 0 ? Colors.MEDIUM_BLUE : undefined }} onPointerDown={this.toggleTopBar}>
+ <FontAwesomeIcon icon={propIcon} size="lg" />
+ </div>
+ </Tooltip>
+ );
// NEW BUTTONS
//dash col linear view buttons
- const contMenuButtons =
+ const contMenuButtons = (
<div className="collectionMenu-container">
{this.contMenuButtons}
{prop}
- </div>;
+ </div>
+ );
return contMenuButtons;
@@ -187,49 +192,62 @@ const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
export class CollectionViewBaseChrome extends React.Component<CollectionViewMenuProps> {
//(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\)
- get document() { return this.props.docView?.props.Document; }
- get target() { return this.document; }
+ get document() {
+ return this.props.docView?.props.Document;
+ }
+ get target() {
+ return this.document;
+ }
_templateCommand = {
- params: ["target", "source"], title: "item view",
- script: "self.target.childLayoutTemplate = getDocTemplate(self.source?.[0])",
+ params: ['target', 'source'],
+ title: 'item view',
+ script: 'self.target.childLayoutTemplate = getDocTemplate(self.source?.[0])',
immediate: undoBatch((source: Doc[]) => {
let formatStr = source.length && Cast(source[0].text, RichTextField, null)?.Text;
- try { formatStr && JSON.parse(formatStr); } catch (e) { formatStr = ""; }
+ try {
+ formatStr && JSON.parse(formatStr);
+ } catch (e) {
+ formatStr = '';
+ }
if (source.length === 1 && formatStr) {
- Doc.SetInPlace(this.target, "childLayoutString", formatStr, false);
+ Doc.SetInPlace(this.target, 'childLayoutString', formatStr, false);
} else if (source.length) {
this.target.childLayoutTemplate = Doc.getDocTemplate(source?.[0]);
} else {
- Doc.SetInPlace(this.target, "childLayoutString", undefined, true);
- Doc.SetInPlace(this.target, "childLayoutTemplate", undefined, true);
+ Doc.SetInPlace(this.target, 'childLayoutString', undefined, true);
+ Doc.SetInPlace(this.target, 'childLayoutTemplate', undefined, true);
}
}),
initialize: emptyFunction,
};
_narrativeCommand = {
- params: ["target", "source"], title: "child click view",
- script: "self.target.childClickedOpenTemplateView = getDocTemplate(self.source?.[0])",
+ params: ['target', 'source'],
+ title: 'child click view',
+ script: 'self.target.childClickedOpenTemplateView = getDocTemplate(self.source?.[0])',
immediate: undoBatch((source: Doc[]) => source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))),
initialize: emptyFunction,
};
_contentCommand = {
- params: ["target", "source"], title: "set content",
- script: "getProto(self.target).data = copyField(self.source);",
- immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)),
+ params: ['target', 'source'],
+ title: 'set content',
+ script: 'getProto(self.target).data = copyField(self.source);',
+ immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List<Doc>(source))),
initialize: emptyFunction,
};
_onClickCommand = {
- params: ["target", "proxy"], title: "copy onClick",
+ params: ['target', 'proxy'],
+ title: 'copy onClick',
script: `{ if (self.proxy?.[0]) {
getProto(self.proxy[0]).onClick = copyField(self.target.onClick);
getProto(self.proxy[0]).target = self.target.target;
getProto(self.proxy[0]).source = copyField(self.target.source);
}}`,
- immediate: undoBatch((source: Doc[]) => { }),
+ immediate: undoBatch((source: Doc[]) => {}),
initialize: emptyFunction,
};
_openLinkInCommand = {
- params: ["target", "container"], title: "link follow target",
+ params: ['target', 'container'],
+ title: 'link follow target',
script: `{ if (self.container?.length) {
getProto(self.target).linkContainer = self.container[0];
getProto(self.target).isLinkButton = true;
@@ -239,126 +257,180 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
if (container.length) {
Doc.GetProto(this.target).linkContainer = container[0];
Doc.GetProto(this.target).isLinkButton = true;
- Doc.GetProto(this.target).onClick = ScriptField.MakeScript("getProto(self.linkContainer).data = new List([self.links[0]?.anchor2])");
+ Doc.GetProto(this.target).onClick = ScriptField.MakeScript('getProto(self.linkContainer).data = new List([self.links[0]?.anchor2])');
}
}),
initialize: emptyFunction,
};
_viewCommand = {
- params: ["target"], title: "bookmark view",
+ params: ['target'],
+ title: 'bookmark view',
script: "self.target._panX = self['target-panX']; self.target._panY = self['target-panY']; self.target._viewScale = self['target-viewScale']; gotoFrame(self.target, self['target-currentFrame']);",
- immediate: undoBatch((source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target._viewScale = 1; this.target._currentFrame = (this.target._currentFrame === undefined ? undefined : 0); }),
- initialize: (button: Doc) => { button['target-panX'] = this.target._panX; button['target-panY'] = this.target._panY; button['target-viewScale'] = this.target._viewScale; button['target-currentFrame'] = this.target._currentFrame; },
+ immediate: undoBatch((source: Doc[]) => {
+ this.target._panX = 0;
+ this.target._panY = 0;
+ this.target._viewScale = 1;
+ this.target._currentFrame = this.target._currentFrame === undefined ? undefined : 0;
+ }),
+ initialize: (button: Doc) => {
+ button['target-panX'] = this.target._panX;
+ button['target-panY'] = this.target._panY;
+ button['target-viewScale'] = this.target._viewScale;
+ button['target-currentFrame'] = this.target._currentFrame;
+ },
};
_clusterCommand = {
- params: ["target"], title: "fit content",
- script: "self.target._fitContentsToBox = !self.target._fitContentsToBox;",
- immediate: undoBatch((source: Doc[]) => this.target._fitContentsToBox = !this.target._fitContentsToBox),
- initialize: emptyFunction
+ params: ['target'],
+ title: 'fit content',
+ script: 'self.target._fitContentsToBox = !self.target._fitContentsToBox;',
+ immediate: undoBatch((source: Doc[]) => (this.target._fitContentsToBox = !this.target._fitContentsToBox)),
+ initialize: emptyFunction,
};
_fitContentCommand = {
- params: ["target"], title: "toggle clusters",
- script: "self.target._useClusters = !self.target._useClusters;",
- immediate: undoBatch((source: Doc[]) => this.target._useClusters = !this.target._useClusters),
- initialize: emptyFunction
+ params: ['target'],
+ title: 'toggle clusters',
+ script: 'self.target._useClusters = !self.target._useClusters;',
+ immediate: undoBatch((source: Doc[]) => (this.target._useClusters = !this.target._useClusters)),
+ initialize: emptyFunction,
};
_saveFilterCommand = {
- params: ["target"], title: "save filter",
+ params: ['target'],
+ title: 'save filter',
script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']);
self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
- immediate: undoBatch((source: Doc[]) => { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }),
+ immediate: undoBatch((source: Doc[]) => {
+ this.target._docFilters = undefined;
+ this.target._searchFilterDocs = undefined;
+ }),
initialize: (button: Doc) => {
- const activeDash = CurrentUserUtils.ActiveDashboard;
+ const activeDash = Doc.ActiveDashboard;
if (activeDash) {
- button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ?
- ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined;
+ button['target-docFilters'] = (Doc.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined;
button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
}
},
};
- @computed get _freeform_commands() { return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
- @computed get _stacking_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
- @computed get _masonry_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
- @computed get _schema_commands() { return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
- @computed get _doc_commands() { return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; }
- @computed get _tree_commands() { return undefined; }
+ @computed get _freeform_commands() {
+ return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
+ }
+ @computed get _stacking_commands() {
+ return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
+ }
+ @computed get _masonry_commands() {
+ return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
+ }
+ @computed get _schema_commands() {
+ return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand];
+ }
+ @computed get _doc_commands() {
+ return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand];
+ }
+ @computed get _tree_commands() {
+ return undefined;
+ }
private get _buttonizableCommands() {
switch (this.props.type) {
- default: return this._doc_commands;
- case CollectionViewType.Freeform: return this._freeform_commands;
- case CollectionViewType.Tree: return this._tree_commands;
- case CollectionViewType.Schema: return this._schema_commands;
- case CollectionViewType.Stacking: return this._stacking_commands;
- case CollectionViewType.Masonry: return this._stacking_commands;
- case CollectionViewType.Time: return this._freeform_commands;
- case CollectionViewType.Carousel: return this._freeform_commands;
- case CollectionViewType.Carousel3D: return this._freeform_commands;
+ default:
+ return this._doc_commands;
+ case CollectionViewType.Freeform:
+ return this._freeform_commands;
+ case CollectionViewType.Tree:
+ return this._tree_commands;
+ case CollectionViewType.Schema:
+ return this._schema_commands;
+ case CollectionViewType.Stacking:
+ return this._stacking_commands;
+ case CollectionViewType.Masonry:
+ return this._stacking_commands;
+ case CollectionViewType.Time:
+ return this._freeform_commands;
+ case CollectionViewType.Carousel:
+ return this._freeform_commands;
+ case CollectionViewType.Carousel3D:
+ return this._freeform_commands;
}
}
private _commandRef = React.createRef<HTMLInputElement>();
private _viewRef = React.createRef<HTMLInputElement>();
- @observable private _currentKey: string = "";
+ @observable private _currentKey: string = '';
componentDidMount = action(() => {
- this._currentKey = this._currentKey || (this._buttonizableCommands?.length ? this._buttonizableCommands[0]?.title : "");
+ this._currentKey = this._currentKey || (this._buttonizableCommands?.length ? this._buttonizableCommands[0]?.title : '');
});
@undoBatch
viewChanged = (e: React.ChangeEvent) => {
- const target = this.document !== CurrentUserUtils.MyLeftSidebarPanel ? this.document : this.document.proto as Doc;
+ const target = this.document !== Doc.MyLeftSidebarPanel ? this.document : (this.document.proto as Doc);
//@ts-ignore
target._viewType = e.target.selectedOptions[0].value;
- }
+ };
commandChanged = (e: React.ChangeEvent) => {
//@ts-ignore
- runInAction(() => this._currentKey = e.target.selectedOptions[0].value);
- }
-
+ runInAction(() => (this._currentKey = e.target.selectedOptions[0].value));
+ };
@action closeViewSpecs = () => {
this.document._facetWidth = 0;
- }
+ };
@computed get subChrome() {
- switch (this.props.docView.props.LayoutTemplateString ? CollectionViewType.Freeform : this.props.type) { // bcz: ARgh! hack to get menu for tree view outline items
- default: return this.otherSubChrome;
+ switch (
+ this.props.docView.props.LayoutTemplateString ? CollectionViewType.Freeform : this.props.type // bcz: ARgh! hack to get menu for tree view outline items
+ ) {
+ default:
+ return this.otherSubChrome;
case CollectionViewType.Invalid:
- case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />);
- case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
- case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
- case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" {...this.props} />);
- case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Freeform:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />;
+ case CollectionViewType.Stacking:
+ return <CollectionStackingViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Schema:
+ return <CollectionSchemaViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Tree:
+ return <CollectionTreeViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Masonry:
+ return <CollectionStackingViewChrome key="collchrome" {...this.props} />;
case CollectionViewType.Carousel:
- case CollectionViewType.Carousel3D: return (<Collection3DCarouselViewChrome key="collchrome" {...this.props} />);
- case CollectionViewType.Grid: return (<CollectionGridViewChrome key="collchrome" {...this.props} />);
- case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Carousel3D:
+ return <Collection3DCarouselViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Grid:
+ return <CollectionGridViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Docking:
+ return <CollectionDockingChrome key="collchrome" {...this.props} />;
}
}
@computed get otherSubChrome() {
const docType = this.props.docView.Document.type;
switch (docType) {
- default: return (null);
- case DocumentType.IMG: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
- case DocumentType.PDF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
- case DocumentType.INK: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
- case DocumentType.WEB: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
- case DocumentType.VID: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
- case DocumentType.RTF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} isDoc={true} />);
- case DocumentType.MAP: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ default:
+ return null;
+ case DocumentType.IMG:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
+ case DocumentType.PDF:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
+ case DocumentType.INK:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
+ case DocumentType.WEB:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
+ case DocumentType.VID:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
+ case DocumentType.RTF:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} isDoc={true} />;
+ case DocumentType.MAP:
+ return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />;
}
}
-
private dropDisposer?: DragManager.DragDropDisposer;
protected createDropTarget = (ele: HTMLDivElement) => {
this.dropDisposer?.();
if (ele) {
this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.document);
}
- }
+ };
@undoBatch
@action
@@ -372,120 +444,139 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
}
dragViewDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, (e, down, delta) => {
- const vtype = this.props.type;
- const c = {
- params: ["target"], title: vtype,
- script: `this.target._viewType = '${StrCast(this.props.type)}'`,
- immediate: (source: Doc[]) => this.document._viewType = Doc.getDocTemplate(source?.[0]),
- initialize: emptyFunction,
- };
- DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
- { target: this.document }, c.params, c.initialize, e.clientX, e.clientY);
- return true;
- }, emptyFunction, emptyFunction);
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ (e, down, delta) => {
+ const vtype = this.props.type;
+ const c = {
+ params: ['target'],
+ title: vtype,
+ script: `this.target._viewType = '${StrCast(this.props.type)}'`,
+ immediate: (source: Doc[]) => (this.document._viewType = Doc.getDocTemplate(source?.[0])),
+ initialize: emptyFunction,
+ };
+ DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title), { target: this.document }, c.params, c.initialize, e.clientX, e.clientY);
+ return true;
+ },
+ emptyFunction,
+ emptyFunction
+ );
+ };
dragCommandDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, (e, down, delta) => {
- this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c =>
- DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title,
- { target: this.document }, c.params, c.initialize, e.clientX, e.clientY));
- return true;
- }, emptyFunction, () => {
- this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate([]));
- });
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ (e, down, delta) => {
+ this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title, { target: this.document }, c.params, c.initialize, e.clientX, e.clientY));
+ return true;
+ },
+ emptyFunction,
+ () => {
+ this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate([]));
+ }
+ );
+ };
@computed get templateChrome() {
- return <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} >
- <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
- <div className="commandEntry-outerDiv" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
- <button className={"antimodeMenu-button"} >
- <FontAwesomeIcon icon="bullseye" size="lg" />
- </button>
- <select
- className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""} />
- {this._buttonizableCommands?.map(cmd =>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option>
- )}
- </select>
- </div>
- </Tooltip>
- </div>;
+ return (
+ <div className="collectionViewBaseChrome-template" ref={this.createDropTarget}>
+ <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
+ <div className="commandEntry-outerDiv" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
+ <button className={'antimodeMenu-button'}>
+ <FontAwesomeIcon icon="bullseye" size="lg" />
+ </button>
+ <select className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}>
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={'empty'} value={''} />
+ {this._buttonizableCommands?.map(cmd => (
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>
+ {cmd.title}
+ </option>
+ ))}
+ </select>
+ </div>
+ </Tooltip>
+ </div>
+ );
}
@computed get viewModes() {
const excludedViewTypes = [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear];
- const isPres: boolean = (this.document && this.document.type === DocumentType.PRES);
- return isPres ? (null) : (<div className="collectionViewBaseChrome-viewModes" >
- <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
- <div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}>
- <button className={"antimodeMenu-button"}>
- <FontAwesomeIcon icon="bullseye" size="lg" />
- </button>
- <select
- className="collectionViewBaseChrome-viewPicker"
- onPointerDown={stopPropagation}
- onChange={this.viewChanged}
- value={StrCast(this.props.type)}>
- {Object.values(CollectionViewType).filter(type => !excludedViewTypes.includes(type)).map(type => (
- <option
- key={Utils.GenerateGuid()}
- className="collectionViewBaseChrome-viewOption"
- onPointerDown={stopPropagation}
- value={type}>
- {type[0].toUpperCase() + type.substring(1)}
- </option>
- ))}
- </select>
- </div>
- </Tooltip>
- </div>);
+ const isPres: boolean = this.document && this.document.type === DocumentType.PRES;
+ return isPres ? null : (
+ <div className="collectionViewBaseChrome-viewModes">
+ <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
+ <div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}>
+ <button className={'antimodeMenu-button'}>
+ <FontAwesomeIcon icon="bullseye" size="lg" />
+ </button>
+ <select className="collectionViewBaseChrome-viewPicker" onPointerDown={stopPropagation} onChange={this.viewChanged} value={StrCast(this.props.type)}>
+ {Object.values(CollectionViewType)
+ .filter(type => !excludedViewTypes.includes(type))
+ .map(type => (
+ <option key={Utils.GenerateGuid()} className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value={type}>
+ {type[0].toUpperCase() + type.substring(1)}
+ </option>
+ ))}
+ </select>
+ </div>
+ </Tooltip>
+ </div>
+ );
}
- @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
- @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
+ @computed get selectedDocumentView() {
+ return SelectionManager.Views().lastElement();
+ }
+ @computed get selectedDoc() {
+ return SelectionManager.Docs().lastElement();
+ }
@computed get notACollection() {
if (this.selectedDoc) {
const layoutField = Doc.LayoutField(this.selectedDoc);
- return this.props.type === CollectionViewType.Docking ||
- typeof (layoutField) === "string" && !layoutField?.includes("CollectionView");
- }
- else return false;
+ return this.props.type === CollectionViewType.Docking || (typeof layoutField === 'string' && !layoutField?.includes('CollectionView'));
+ } else return false;
}
@computed
get pinButton() {
const targetDoc = this.selectedDoc;
const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
- return !targetDoc ? (null) : <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div>} placement="top">
- <button className="antimodeMenu-button" style={{ backgroundColor: isPinned ? "121212" : undefined, borderLeft: "1px solid gray" }}
- onClick={e => TabDocView.PinDoc(targetDoc, { /* unpin: isPinned*/ })}>
- <FontAwesomeIcon className="colMenu-icon" size="lg" icon="map-pin" />
- </button>
- </Tooltip>;
+ return !targetDoc ? null : (
+ <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? 'Unpin from presentation' : 'Pin to presentation'}</div>} placement="top">
+ <button
+ className="antimodeMenu-button"
+ style={{ backgroundColor: isPinned ? '121212' : undefined, borderLeft: '1px solid gray' }}
+ onClick={e =>
+ TabDocView.PinDoc(targetDoc, {
+ /* unpin: isPinned*/
+ })
+ }>
+ <FontAwesomeIcon className="colMenu-icon" size="lg" icon="map-pin" />
+ </button>
+ </Tooltip>
+ );
}
@undoBatch
@action
startRecording = () => {
- const doc = Docs.Create.ScreenshotDocument({ title: "screen recording", _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" });
- //Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc);
- CollectionDockingView.AddSplit(doc, "right");
- }
+ const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
+ //Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ CollectionDockingView.AddSplit(doc, 'right');
+ };
@computed
get recordButton() {
const targetDoc = this.selectedDoc;
- return <Tooltip key="record" title={<div className="dash-tooltip">{"Capture screen"}</div>} placement="top">
- <button className="antimodeMenu-button"
- onClick={e => this.startRecording()}>
- <div className="recordButtonOutline" style={{}}>
- <div className="recordButtonInner" style={{}}>
+ return (
+ <Tooltip key="record" title={<div className="dash-tooltip">{'Capture screen'}</div>} placement="top">
+ <button className="antimodeMenu-button" onClick={e => this.startRecording()}>
+ <div className="recordButtonOutline" style={{}}>
+ <div className="recordButtonInner" style={{}}></div>
</div>
- </div>
- </button>
- </Tooltip>;
+ </button>
+ </Tooltip>
+ );
}
@undoBatch
@@ -517,21 +608,20 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
activeDoc.presPinView = true;
}
}
- }
+ };
@computed
get pinWithViewButton() {
- const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
- return !this.selectedDoc ? (null) :
- <Tooltip title={<div className="dash-tooltip">{"Pin with current view"}</div>} placement="top">
- <button className="antimodeMenu-button" style={{ justifyContent: 'center' }}
- onClick={() => this.pinWithView(this.selectedDoc)}>
+ const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: 'auto', width: 19 }} />;
+ return !this.selectedDoc ? null : (
+ <Tooltip title={<div className="dash-tooltip">{'Pin with current view'}</div>} placement="top">
+ <button className="antimodeMenu-button" style={{ justifyContent: 'center' }} onClick={() => this.pinWithView(this.selectedDoc)}>
{presPinWithViewIcon}
</button>
- </Tooltip>;
+ </Tooltip>
+ );
}
-
@undoBatch
onAlias = () => {
if (this.selectedDoc && this.selectedDocumentView) {
@@ -544,10 +634,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
alias.y = NumCast(this.selectedDoc.y) + 30;
this.selectedDocumentView.props.addDocument?.(alias);
}
- }
+ };
onAliasButtonDown = (e: React.PointerEvent): void => {
setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
- }
+ };
@undoBatch
onAliasButtonMoved = (e: PointerEvent) => {
@@ -555,62 +645,72 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
if (contentDiv && this.selectedDoc) {
const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y];
- dragData.defaultDropAction = "alias";
+ dragData.defaultDropAction = 'alias';
dragData.canEmbed = true;
DragManager.StartDocumentDrag([contentDiv], dragData, e.clientX, e.clientY, {
offsetX: offset[0],
offsetY: offset[1],
- hideSource: false
+ hideSource: false,
});
return true;
}
return false;
- }
+ };
@computed
get aliasButton() {
const targetDoc = this.selectedDoc;
- return !targetDoc || targetDoc.type === DocumentType.PRES ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
- <button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
- <FontAwesomeIcon className="colMenu-icon" icon="copy" size="lg" />
- </button>
- </Tooltip>;
+ return !targetDoc || targetDoc.type === DocumentType.PRES ? null : (
+ <Tooltip title={<div className="dash-tooltip">{'Tap or Drag to create an alias'}</div>} placement="top">
+ <button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: 'drag' }}>
+ <FontAwesomeIcon className="colMenu-icon" icon="copy" size="lg" />
+ </button>
+ </Tooltip>
+ );
}
@computed get lightboxButton() {
const targetDoc = this.selectedDoc;
- return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"View in Lightbox"}</div>} placement="top">
- <button className="antimodeMenu-button" onPointerDown={() => {
- const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
- LightboxView.SetLightboxDoc(targetDoc, undefined, docs);
- }}>
- <FontAwesomeIcon className="colMenu-icon" icon="desktop" size="lg" />
- </button>
- </Tooltip>;
+ return !targetDoc ? null : (
+ <Tooltip title={<div className="dash-tooltip">{'View in Lightbox'}</div>} placement="top">
+ <button
+ className="antimodeMenu-button"
+ onPointerDown={() => {
+ const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+ LightboxView.SetLightboxDoc(targetDoc, undefined, docs);
+ }}>
+ <FontAwesomeIcon className="colMenu-icon" icon="desktop" size="lg" />
+ </button>
+ </Tooltip>
+ );
}
@computed get toggleOverlayButton() {
- return <>
- <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom">
- <button className={"antimodeMenu-button"} key="float"
- style={{
- backgroundColor: this.props.docView.layoutDoc.z ? "121212" : undefined,
- pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "none" : undefined,
- color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "dimgrey" : undefined
- }}
- onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
- <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
- </button>
- </Tooltip>
- </>;
+ return (
+ <>
+ <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom">
+ <button
+ className={'antimodeMenu-button'}
+ key="float"
+ style={{
+ backgroundColor: this.props.docView.layoutDoc.z ? '121212' : undefined,
+ pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
+ color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
+ }}
+ onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
+ <FontAwesomeIcon icon={['fab', 'buffer']} size={'lg'} />
+ </button>
+ </Tooltip>
+ </>
+ );
}
render() {
return (
- <div className="collectionMenu-cont" >
+ <div className="collectionMenu-cont">
<div className="collectionMenu">
<div className="collectionViewBaseChrome">
- {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
+ {this.notACollection || this.props.type === CollectionViewType.Invalid ? null : this.viewModes}
<div className="collectionMenu-divider" key="divider1"></div>
{this.aliasButton}
{/* {this.pinButton} */}
@@ -621,7 +721,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
<div className="collectionMenu-divider" key="divider3"></div>
{this.lightboxButton}
{this.recordButton}
- {!this._buttonizableCommands ? (null) : this.templateChrome}
+ {!this._buttonizableCommands ? null : this.templateChrome}
</div>
</div>
</div>
@@ -632,30 +732,40 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
@observer
export class CollectionDockingChrome extends React.Component<CollectionViewMenuProps> {
render() {
- return (null);
+ return null;
}
}
@observer
-export class CollectionFreeFormViewChrome extends React.Component<CollectionViewMenuProps & { isOverlay: boolean, isDoc?: boolean }> {
+export class CollectionFreeFormViewChrome extends React.Component<CollectionViewMenuProps & { isOverlay: boolean; isDoc?: boolean }> {
public static Instance: CollectionFreeFormViewChrome;
constructor(props: any) {
super(props);
CollectionFreeFormViewChrome.Instance = this;
}
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
@computed get dataField() {
- return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
+ return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? '-annotations' : '')];
+ }
+ @computed get childDocs() {
+ return DocListCast(this.dataField);
+ }
+ @computed get selectedDocumentView() {
+ return SelectionManager.Views().lastElement();
+ }
+ @computed get selectedDoc() {
+ return SelectionManager.Docs().lastElement();
+ }
+ @computed get isText() {
+ return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
}
- @computed get childDocs() { return DocListCast(this.dataField); }
- @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
- @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
- @computed get isText() { return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; }
@undoBatch
@action
nextKeyframe = (): void => {
- const currentFrame = Cast(this.document._currentFrame, "number", null);
+ const currentFrame = Cast(this.document._currentFrame, 'number', null);
if (currentFrame === undefined) {
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
@@ -663,72 +773,88 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
this.document._currentFrame = Math.max(0, (currentFrame || 0) + 1);
this.document.lastFrame = Math.max(NumCast(this.document._currentFrame), NumCast(this.document.lastFrame));
- }
+ };
@undoBatch
@action
prevKeyframe = (): void => {
- const currentFrame = Cast(this.document._currentFrame, "number", null);
+ const currentFrame = Cast(this.document._currentFrame, 'number', null);
if (currentFrame === undefined) {
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
- }
+ };
- private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
- private _width = ["1", "5", "10", "100"];
+ private _palette = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', ''];
+ private _width = ['1', '5', '10', '100'];
private _dotsize = [10, 20, 30, 40];
- private _draw = ["∿", "=", "⎯", "→", "↔︎", "ロ", "O"];
- private _head = ["", "", "", "", "arrow", "", ""];
- private _end = ["", "", "", "arrow", "arrow", "", ""];
- private _shapePrims = ["", "", "line", "line", "line", "rectangle", "circle"];
- private _title = ["pen", "highlighter", "line", "line with arrow", "line with double arrows", "square", "circle"];
- private _faName = ["pen-fancy", "highlighter", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
+ private _draw = ['∿', '=', '⎯', '→', '↔︎', 'ロ', 'O'];
+ private _head = ['', '', '', '', 'arrow', '', ''];
+ private _end = ['', '', '', 'arrow', 'arrow', '', ''];
+ private _shapePrims = ['', '', 'line', 'line', 'line', 'rectangle', 'circle'];
+ private _title = ['pen', 'highlighter', 'line', 'line with arrow', 'line with double arrows', 'square', 'circle'];
+ private _faName = ['pen-fancy', 'highlighter', 'minus', 'long-arrow-alt-right', 'arrows-alt-h', 'square', 'circle'];
@observable _selectedPrimitive = this._shapePrims.length;
@observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode
@observable _colorBtn = false;
@observable _widthBtn = false;
@observable _fillBtn = false;
- @action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; }
+ @action clearKeepPrimitiveMode() {
+ this._selectedPrimitive = this._shapePrims.length;
+ }
@action primCreated() {
- if (!this._keepPrimitiveMode) { //get out of ink mode after each stroke=
- if (CurrentUserUtils.ActiveTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor);
- CurrentUserUtils.ActiveTool = InkTool.None;
+ if (!this._keepPrimitiveMode) {
+ //get out of ink mode after each stroke=
+ if (Doc.ActiveTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor);
+ Doc.ActiveTool = InkTool.None;
this._selectedPrimitive = this._shapePrims.length;
- SetActiveArrowStart("none");
- SetActiveArrowEnd("none");
+ SetActiveArrowStart('none');
+ SetActiveArrowEnd('none');
}
}
@action
changeColor = (color: string, type: string) => {
const col: ColorState = {
- hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" },
- rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "",
+ hex: color,
+ hsl: { a: 0, h: 0, s: 0, l: 0, source: '' },
+ hsv: { a: 0, h: 0, s: 0, v: 0, source: '' },
+ rgb: { a: 0, r: 0, b: 0, g: 0, source: '' },
+ oldHue: 0,
+ source: '',
};
- if (type === "color") {
+ if (type === 'color') {
SetActiveInkColor(Utils.colorString(col));
- } else if (type === "fill") {
+ } else if (type === 'fill') {
SetActiveFillColor(Utils.colorString(col));
}
- }
+ };
@action
editProperties = (value: any, field: string) => {
- SelectionManager.Views().forEach(action((element: DocumentView) => {
- const doc = Document(element.rootDoc);
- if (doc.type === DocumentType.INK) {
- switch (field) {
- case "width": doc.strokeWidth = Number(value); break;
- case "color": doc.color = String(value); break;
- case "fill": doc.fillColor = String(value); break;
- case "dash": doc.strokeDash = value;
+ SelectionManager.Views().forEach(
+ action((element: DocumentView) => {
+ const doc = Document(element.rootDoc);
+ if (doc.type === DocumentType.INK) {
+ switch (field) {
+ case 'width':
+ doc.strokeWidth = Number(value);
+ break;
+ case 'color':
+ doc.color = String(value);
+ break;
+ case 'fill':
+ doc.fillColor = String(value);
+ break;
+ case 'dash':
+ doc.strokeDash = value;
+ }
}
- }
- }));
- }
+ })
+ );
+ };
@computed get drawButtons() {
const func = action((e: React.MouseEvent | React.PointerEvent, i: number, keep: boolean) => {
@@ -736,147 +862,184 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
// these are for shapes
if (this._selectedPrimitive !== i) {
this._selectedPrimitive = i;
- if (this._title[i] === "highlighter") {
- CurrentUserUtils.ActiveTool = InkTool.Highlighter;
+ if (this._title[i] === 'highlighter') {
+ Doc.ActiveTool = InkTool.Highlighter;
GestureOverlay.Instance.SavedColor = ActiveInkColor();
- SetActiveInkColor("rgba(245, 230, 95, 0.75)");
+ SetActiveInkColor('rgba(245, 230, 95, 0.75)');
} else {
- CurrentUserUtils.ActiveTool = InkTool.Pen;
+ Doc.ActiveTool = InkTool.Pen;
}
SetActiveArrowStart(this._head[i]);
SetActiveArrowEnd(this._end[i]);
- SetActiveBezierApprox("300");
+ SetActiveBezierApprox('300');
GestureOverlay.Instance.InkShape = this._shapePrims[i];
} else {
this._selectedPrimitive = this._shapePrims.length;
- CurrentUserUtils.ActiveTool = InkTool.None;
- SetActiveArrowStart("");
- SetActiveArrowEnd("");
- GestureOverlay.Instance.InkShape = "";
- SetActiveBezierApprox("0");
+ Doc.ActiveTool = InkTool.None;
+ SetActiveArrowStart('');
+ SetActiveArrowEnd('');
+ GestureOverlay.Instance.InkShape = '';
+ SetActiveBezierApprox('0');
}
e.stopPropagation();
});
- return <div className="btn-draw" key="draw">
- {this._draw.map((icon, i) =>
- <Tooltip key={icon} title={<div className="dash-tooltip">{this._title[i]}</div>} placement="bottom">
- <button className="antimodeMenu-button"
- onPointerDown={e => func(e, i, false)}
- onDoubleClick={e => func(e, i, true)}
- style={{ backgroundColor: i === this._selectedPrimitive ? "525252" : "", fontSize: "20" }}>
- <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
- </button>
- </Tooltip>)}
- </div>;
+ return (
+ <div className="btn-draw" key="draw">
+ {this._draw.map((icon, i) => (
+ <Tooltip key={icon} title={<div className="dash-tooltip">{this._title[i]}</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={e => func(e, i, false)} onDoubleClick={e => func(e, i, true)} style={{ backgroundColor: i === this._selectedPrimitive ? '525252' : '', fontSize: '20' }}>
+ <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
+ </button>
+ </Tooltip>
+ ))}
+ </div>
+ );
}
- toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps["icon"], ele: JSX.Element | null) => {
- return <Tooltip title={<div className="dash-tooltip">{key}</div>} placement="bottom">
- <button className="antimodeMenu-button" key={key}
- onPointerDown={action(e => setter())}
- style={{ backgroundColor: value ? "121212" : "" }}>
- <FontAwesomeIcon icon={icon} size="lg" />
- {ele}
- </button>
- </Tooltip>;
- }
+ toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps['icon'], ele: JSX.Element | null) => {
+ return (
+ <Tooltip title={<div className="dash-tooltip">{key}</div>} placement="bottom">
+ <button className="antimodeMenu-button" key={key} onPointerDown={action(e => setter())} style={{ backgroundColor: value ? '121212' : '' }}>
+ <FontAwesomeIcon icon={icon} size="lg" />
+ {ele}
+ </button>
+ </Tooltip>
+ );
+ };
@computed get widthPicker() {
- const widthPicker = this.toggleButton("stroke width", this._widthBtn, () => this._widthBtn = !this._widthBtn, "bars", null);
- return !this._widthBtn ? widthPicker :
+ const widthPicker = this.toggleButton('stroke width', this._widthBtn, () => (this._widthBtn = !this._widthBtn), 'bars', null);
+ return !this._widthBtn ? (
+ widthPicker
+ ) : (
<div className="btn2-group" key="width">
{widthPicker}
- {this._width.map((wid, i) =>
+ {this._width.map((wid, i) => (
<Tooltip title={<div className="dash-tooltip">change width</div>} placement="bottom">
- <button className="antimodeMenu-button" key={wid}
- onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })}
- style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}>
+ <button
+ className="antimodeMenu-button"
+ key={wid}
+ onPointerDown={action(() => {
+ SetActiveInkWidth(wid);
+ this._widthBtn = false;
+ this.editProperties(wid, 'width');
+ })}
+ style={{ backgroundColor: this._widthBtn ? '121212' : '', zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: 'center' }}>
•
</button>
- </Tooltip>)}
- </div>;
+ </Tooltip>
+ ))}
+ </div>
+ );
}
@computed get colorPicker() {
- const colorPicker = this.toggleButton("stroke color", this._colorBtn, () => this._colorBtn = !this._colorBtn, "pen-nib",
- <div className="color-previewI" style={{ backgroundColor: ActiveInkColor() ?? "121212" }} />);
- return !this._colorBtn ? colorPicker :
+ const colorPicker = this.toggleButton('stroke color', this._colorBtn, () => (this._colorBtn = !this._colorBtn), 'pen-nib', <div className="color-previewI" style={{ backgroundColor: ActiveInkColor() ?? '121212' }} />);
+ return !this._colorBtn ? (
+ colorPicker
+ ) : (
<div className="btn-group" key="color">
{colorPicker}
- {this._palette.map(color =>
- <button className="antimodeMenu-button" key={color}
- onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
- style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}>
+ {this._palette.map(color => (
+ <button
+ className="antimodeMenu-button"
+ key={color}
+ onPointerDown={action(() => {
+ this.changeColor(color, 'color');
+ this._colorBtn = false;
+ this.editProperties(color, 'color');
+ })}
+ style={{ backgroundColor: this._colorBtn ? '121212' : '', zIndex: 1001 }}>
{/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
<div className="color-previewII" style={{ backgroundColor: color }}>
- {color === "" ? <p style={{ fontSize: 40, color: "red", marginTop: -10, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+ {color === '' ? <p style={{ fontSize: 40, color: 'red', marginTop: -10, marginLeft: -5, position: 'fixed' }}>☒</p> : ''}
</div>
- </button >)}
- </div >;
+ </button>
+ ))}
+ </div>
+ );
}
@computed get fillPicker() {
- const fillPicker = this.toggleButton("shape fill color", this._fillBtn, () => this._fillBtn = !this._fillBtn, "fill-drip",
- <div className="color-previewI" style={{ backgroundColor: ActiveFillColor() ?? "121212" }} />);
- return !this._fillBtn ? fillPicker :
- <div className="btn-group" key="fill" >
+ const fillPicker = this.toggleButton('shape fill color', this._fillBtn, () => (this._fillBtn = !this._fillBtn), 'fill-drip', <div className="color-previewI" style={{ backgroundColor: ActiveFillColor() ?? '121212' }} />);
+ return !this._fillBtn ? (
+ fillPicker
+ ) : (
+ <div className="btn-group" key="fill">
{fillPicker}
- {this._palette.map(color =>
- <button className="antimodeMenu-button" key={color}
- onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })}
- style={{ backgroundColor: this._fillBtn ? "121212" : "", zIndex: 1001 }}>
+ {this._palette.map(color => (
+ <button
+ className="antimodeMenu-button"
+ key={color}
+ onPointerDown={action(() => {
+ this.changeColor(color, 'fill');
+ this._fillBtn = false;
+ this.editProperties(color, 'fill');
+ })}
+ style={{ backgroundColor: this._fillBtn ? '121212' : '', zIndex: 1001 }}>
<div className="color-previewII" style={{ backgroundColor: color }}>
- {color === "" ? <p style={{ fontSize: 40, color: "red", marginTop: -10, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+ {color === '' ? <p style={{ fontSize: 40, color: 'red', marginTop: -10, marginLeft: -5, position: 'fixed' }}>☒</p> : ''}
</div>
- </button>)}
-
- </div>;
+ </button>
+ ))}
+ </div>
+ );
}
render() {
- return !this.props.docView.layoutDoc ? (null) :
+ return !this.props.docView.layoutDoc ? null : (
<div className="collectionFreeFormMenu-cont">
<RichTextMenu key="rich" />
- {!this.isText ?
+ {!this.isText ? (
<>
{this.drawButtons}
{this.widthPicker}
{this.colorPicker}
{this.fillPicker}
- {Doc.noviceMode || this.props.isDoc ? (null) :
+ {Doc.noviceMode || this.props.isDoc ? null : (
<>
<Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
<div className="backKeyframe" onClick={this.prevKeyframe}>
- <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
+ <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
</div>
</Tooltip>
<Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
- <div className="numKeyframe" style={{ color: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? "white" : "black", backgroundColor: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? "#5B9FDD" : "#AEDDF8" }}
- onClick={action(() => this.props.docView.ComponentView?.setKeyFrameEditing?.(!this.props.docView.ComponentView?.getKeyFrameEditing?.()))} >
+ <div
+ className="numKeyframe"
+ style={{ color: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? 'white' : 'black', backgroundColor: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? '#5B9FDD' : '#AEDDF8' }}
+ onClick={action(() => this.props.docView.ComponentView?.setKeyFrameEditing?.(!this.props.docView.ComponentView?.getKeyFrameEditing?.()))}>
{NumCast(this.document._currentFrame)}
</div>
</Tooltip>
<Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom">
<div className="fwdKeyframe" onClick={this.nextKeyframe}>
- <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
+ <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
</div>
</Tooltip>
- </>}
- </> : (null)
- }
- {!this.selectedDocumentView?.ComponentView?.menuControls ? (null) : this.selectedDocumentView?.ComponentView?.menuControls?.()}
- </div>;
+ </>
+ )}
+ </>
+ ) : null}
+ {!this.selectedDocumentView?.ComponentView?.menuControls ? null : this.selectedDocumentView?.ComponentView?.menuControls?.()}
+ </div>
+ );
}
}
@observer
export class CollectionStackingViewChrome extends React.Component<CollectionViewMenuProps> {
- @observable private _currentKey: string = "";
+ @observable private _currentKey: string = '';
@observable private suggestions: string[] = [];
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
- @computed private get descending() { return StrCast(this.document._columnsSort) === "descending"; }
- @computed get pivotField() { return StrCast(this.document._pivotField); }
+ @computed private get descending() {
+ return StrCast(this.document._columnsSort) === 'descending';
+ }
+ @computed get pivotField() {
+ return StrCast(this.document._pivotField);
+ }
getKeySuggestions = async (value: string): Promise<string[]> => {
const val = value.toLowerCase();
@@ -884,16 +1047,14 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
if (Doc.noviceMode) {
if (docs instanceof Doc) {
- const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
- key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
- (key[0].toUpperCase() === key[0] && key[0] !== "_"));
+ const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
} else {
const keys = new Set<string>();
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
- const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
- key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
- (key[0]?.toUpperCase() === key[0] && key[0] !== "_"));
+ const noviceKeys = Array.from(keys).filter(
+ key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
+ );
return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
}
}
@@ -905,81 +1066,77 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1);
}
- }
+ };
@action
onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
this._currentKey = newValue;
- }
+ };
getSuggestionValue = (suggestion: string) => suggestion;
renderSuggestion = (suggestion: string) => {
return <p>{suggestion}</p>;
- }
+ };
onSuggestionFetch = async ({ value }: { value: string }) => {
const sugg = await this.getKeySuggestions(value);
runInAction(() => {
this.suggestions = sugg;
});
- }
+ };
@action
onSuggestionClear = () => {
this.suggestions = [];
- }
+ };
@action
setValue = (value: string) => {
this.document._pivotField = value;
return true;
- }
+ };
@action toggleSort = () => {
- this.document._columnsSort =
- this.document._columnsSort === "descending" ? "ascending" :
- this.document._columnsSort === "ascending" ? undefined : "descending";
- }
- @action resetValue = () => { this._currentKey = this.pivotField; };
+ this.document._columnsSort = this.document._columnsSort === 'descending' ? 'ascending' : this.document._columnsSort === 'ascending' ? undefined : 'descending';
+ };
+ @action resetValue = () => {
+ this._currentKey = this.pivotField;
+ };
render() {
const doctype = this.props.docView.Document.type;
- const isPres: boolean = (doctype === DocumentType.PRES);
- return (
- isPres ? (null) : <div className="collectionStackingViewChrome-cont">
+ const isPres: boolean = doctype === DocumentType.PRES;
+ return isPres ? null : (
+ <div className="collectionStackingViewChrome-cont">
<div className="collectionStackingViewChrome-pivotField-cont">
- <div className="collectionStackingViewChrome-pivotField-label">
- GROUP BY:
- </div>
- <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
+ <div className="collectionStackingViewChrome-pivotField-label">GROUP BY:</div>
+ <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? '180' : '0'}deg)` }}>
<FontAwesomeIcon icon="caret-up" size="2x" color="white" />
</div>
<div className="collectionStackingViewChrome-pivotField">
<EditableView
GetValue={() => this.pivotField}
- autosuggestProps={
- {
- resetValue: this.resetValue,
- value: this._currentKey,
- onChange: this.onKeyChange,
- autosuggestProps: {
- inputProps:
- {
- value: this._currentKey,
- onChange: this.onKeyChange
- },
- getSuggestionValue: this.getSuggestionValue,
- suggestions: this.suggestions,
- alwaysRenderSuggestions: true,
- renderSuggestion: this.renderSuggestion,
- onSuggestionsFetchRequested: this.onSuggestionFetch,
- onSuggestionsClearRequested: this.onSuggestionClear
- }
- }}
+ autosuggestProps={{
+ resetValue: this.resetValue,
+ value: this._currentKey,
+ onChange: this.onKeyChange,
+ autosuggestProps: {
+ inputProps: {
+ value: this._currentKey,
+ onChange: this.onKeyChange,
+ },
+ getSuggestionValue: this.getSuggestionValue,
+ suggestions: this.suggestions,
+ alwaysRenderSuggestions: true,
+ renderSuggestion: this.renderSuggestion,
+ onSuggestionsFetchRequested: this.onSuggestionFetch,
+ onSuggestionsClearRequested: this.onSuggestionClear,
+ },
+ }}
oneLine
SetValue={this.setValue}
- contents={this.pivotField ? this.pivotField : "N/A"}
+ contents={this.pivotField ? this.pivotField : 'N/A'}
/>
</div>
</div>
@@ -988,11 +1145,12 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
}
}
-
@observer
export class CollectionSchemaViewChrome extends React.Component<CollectionViewMenuProps> {
// private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
@undoBatch
togglePreview = () => {
@@ -1002,12 +1160,12 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewMe
const previewWidth = NumCast(this.document.schemaPreviewWidth);
const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth;
this.document.schemaPreviewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0;
- }
+ };
@undoBatch
@action
toggleTextwrap = async () => {
- const textwrappedRows = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []);
+ const textwrappedRows = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []);
if (textwrappedRows.length) {
this.document.textwrappedSchemaRows = new List<string>([]);
} else {
@@ -1015,56 +1173,52 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewMe
const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
this.document.textwrappedSchemaRows = new List<string>(allRows);
}
- }
-
+ };
render() {
const previewWidth = NumCast(this.document.schemaPreviewWidth);
- const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
+ const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []).length > 0;
return (
<div className="collectionSchemaViewChrome-cont">
<div className="collectionSchemaViewChrome-toggle">
<div className="collectionSchemaViewChrome-label">Show Preview: </div>
<div className="collectionSchemaViewChrome-toggler" onClick={this.togglePreview}>
- <div className={"collectionSchemaViewChrome-togglerButton" + (previewWidth !== 0 ? " on" : " off")}>
- {previewWidth !== 0 ? "on" : "off"}
- </div>
+ <div className={'collectionSchemaViewChrome-togglerButton' + (previewWidth !== 0 ? ' on' : ' off')}>{previewWidth !== 0 ? 'on' : 'off'}</div>
</div>
</div>
- </div >
+ </div>
);
}
}
@observer
export class CollectionTreeViewChrome extends React.Component<CollectionViewMenuProps> {
-
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
get sortAscending() {
- return this.document[this.props.fieldKey + "-sortAscending"];
+ return this.document[this.props.fieldKey + '-sortAscending'];
}
set sortAscending(value) {
- this.document[this.props.fieldKey + "-sortAscending"] = value;
+ this.document[this.props.fieldKey + '-sortAscending'] = value;
}
@computed private get ascending() {
- return Cast(this.sortAscending, "boolean", null);
+ return Cast(this.sortAscending, 'boolean', null);
}
@action toggleSort = () => {
if (this.sortAscending) this.sortAscending = undefined;
else if (this.sortAscending === undefined) this.sortAscending = false;
else this.sortAscending = true;
- }
+ };
render() {
return (
<div className="collectionTreeViewChrome-cont">
<button className="collectionTreeViewChrome-sort" onClick={this.toggleSort}>
- <div className="collectionTreeViewChrome-sortLabel">
- Sort
- </div>
- <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.ascending === undefined ? "90" : this.ascending ? "180" : "0"}deg)` }}>
+ <div className="collectionTreeViewChrome-sortLabel">Sort</div>
+ <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.ascending === undefined ? '90' : this.ascending ? '180' : '0'}deg)` }}>
<FontAwesomeIcon icon="caret-up" size="2x" color="white" />
</div>
</button>
@@ -1073,10 +1227,12 @@ export class CollectionTreeViewChrome extends React.Component<CollectionViewMenu
}
}
-// Enter scroll speed for 3D Carousel
+// Enter scroll speed for 3D Carousel
@observer
export class Collection3DCarouselViewChrome extends React.Component<CollectionViewMenuProps> {
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
@computed get scrollSpeed() {
return this.document._autoScrollSpeed;
}
@@ -1089,22 +1245,16 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionVi
return true;
}
return false;
- }
+ };
render() {
return (
<div className="collection3DCarouselViewChrome-cont">
<div className="collection3DCarouselViewChrome-scrollSpeed-cont">
- {FormattedTextBox.Focused ? <RichTextMenu /> : (null)}
- <div className="collectionStackingViewChrome-scrollSpeed-label">
- AUTOSCROLL SPEED:
- </div>
+ {FormattedTextBox.Focused ? <RichTextMenu /> : null}
+ <div className="collectionStackingViewChrome-scrollSpeed-label">AUTOSCROLL SPEED:</div>
<div className="collection3DCarouselViewChrome-scrollSpeed">
- <EditableView
- GetValue={() => StrCast(this.scrollSpeed)}
- oneLine
- SetValue={this.setValue}
- contents={this.scrollSpeed ? this.scrollSpeed : 1000} />
+ <EditableView GetValue={() => StrCast(this.scrollSpeed)} oneLine SetValue={this.setValue} contents={this.scrollSpeed ? this.scrollSpeed : 1000} />
</div>
</div>
</div>
@@ -1117,21 +1267,21 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionVi
*/
@observer
export class CollectionGridViewChrome extends React.Component<CollectionViewMenuProps> {
-
private clicked: boolean = false;
private entered: boolean = false;
private decrementLimitReached: boolean = false;
@observable private resize = false;
private resizeListenerDisposer: Opt<Lambda>;
- get document() { return this.props.docView.props.Document; }
+ get document() {
+ return this.props.docView.props.Document;
+ }
componentDidMount() {
-
- runInAction(() => this.resize = this.props.docView.props.PanelWidth() < 700);
+ runInAction(() => (this.resize = this.props.docView.props.PanelWidth() < 700));
// listener to reduce text on chrome resize (panel resize)
this.resizeListenerDisposer = computed(() => this.props.docView.props.PanelWidth()).observe(({ newValue }) => {
- runInAction(() => this.resize = newValue < 700);
+ runInAction(() => (this.resize = newValue < 700));
});
}
@@ -1139,14 +1289,16 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
this.resizeListenerDisposer?.();
}
- get numCols() { return NumCast(this.document.gridNumCols, 10); }
+ get numCols() {
+ return NumCast(this.document.gridNumCols, 10);
+ }
/**
- * Sets the value of `numCols` on the grid's Document to the value entered.
- */
+ * Sets the value of `numCols` on the grid's Document to the value entered.
+ */
onNumColsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- if (e.currentTarget.valueAsNumber > 0) undoBatch(() => this.document.gridNumCols = e.currentTarget.valueAsNumber)();
- }
+ if (e.currentTarget.valueAsNumber > 0) undoBatch(() => (this.document.gridNumCols = e.currentTarget.valueAsNumber))();
+ };
/**
* Sets the value of `rowHeight` on the grid's Document to the value entered.
@@ -1166,7 +1318,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
@undoBatch
toggleFlex = () => {
this.document.gridFlex = !BoolCast(this.document.gridFlex, true);
- }
+ };
/**
* Increments the value of numCols on button click
@@ -1174,9 +1326,9 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
onIncrementButtonClick = () => {
this.clicked = true;
this.entered && (this.document.gridNumCols as number)--;
- undoBatch(() => this.document.gridNumCols = this.numCols + 1)();
+ undoBatch(() => (this.document.gridNumCols = this.numCols + 1))();
this.entered = false;
- }
+ };
/**
* Decrements the value of numCols on button click
@@ -1185,11 +1337,11 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
this.clicked = true;
if (this.numCols > 1 && !this.decrementLimitReached) {
this.entered && (this.document.gridNumCols as number)++;
- undoBatch(() => this.document.gridNumCols = this.numCols - 1)();
+ undoBatch(() => (this.document.gridNumCols = this.numCols - 1))();
if (this.numCols === 1) this.decrementLimitReached = true;
}
this.entered = false;
- }
+ };
/**
* Increments the value of numCols on button hover
@@ -1201,7 +1353,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
}
this.decrementLimitReached = false;
this.clicked = false;
- }
+ };
/**
* Decrements the value of numCols on button hover
@@ -1211,21 +1363,20 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
if (!this.clicked) {
if (this.numCols > 1) {
this.document.gridNumCols = this.numCols - 1;
- }
- else {
+ } else {
this.decrementLimitReached = true;
}
}
this.clicked = false;
- }
+ };
/**
* Toggles the value of preventCollision
*/
toggleCollisions = () => {
this.document.gridPreventCollision = !this.document.gridPreventCollision;
- }
+ };
/**
* Changes the value of the compactType
@@ -1233,16 +1384,26 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
changeCompactType = (e: React.ChangeEvent<HTMLSelectElement>) => {
// need to change startCompaction so that this operation will be undoable.
this.document.gridStartCompaction = e.target.selectedOptions[0].value;
- }
+ };
render() {
return (
- <div className="collectionGridViewChrome-cont" >
- <span className="grid-control" style={{ width: this.resize ? "25%" : "30%" }}>
+ <div className="collectionGridViewChrome-cont">
+ <span className="grid-control" style={{ width: this.resize ? '25%' : '30%' }}>
<span className="grid-icon">
<FontAwesomeIcon icon="columns" size="1x" />
</span>
- <input className="collectionGridViewChrome-entryBox" type="number" value={this.numCols} onChange={this.onNumColsChange} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
+ <input
+ className="collectionGridViewChrome-entryBox"
+ type="number"
+ value={this.numCols}
+ onChange={this.onNumColsChange}
+ onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
+ e.stopPropagation();
+ e.preventDefault();
+ e.currentTarget.focus();
+ }}
+ />
<input className="collectionGridViewChrome-columnButton" onClick={this.onIncrementButtonClick} onMouseEnter={this.incrementValue} onMouseLeave={this.decrementValue} type="button" value="↑" />
<input className="collectionGridViewChrome-columnButton" style={{ marginRight: 5 }} onClick={this.onDecrementButtonClick} onMouseEnter={this.decrementValue} onMouseLeave={this.incrementValue} type="button" value="↓" />
</span>
@@ -1252,36 +1413,30 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
</span>
<input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.document.rowHeight as string} onKeyDown={this.onRowHeightEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
</span> */}
- <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}>
+ <span className="grid-control" style={{ width: this.resize ? '12%' : '20%' }}>
<input type="checkbox" style={{ marginRight: 5 }} onChange={this.toggleCollisions} checked={!this.document.gridPreventCollision} />
- <label className="flexLabel">{this.resize ? "Coll" : "Collisions"}</label>
+ <label className="flexLabel">{this.resize ? 'Coll' : 'Collisions'}</label>
</span>
- <select className="collectionGridViewChrome-viewPicker"
+ <select
+ className="collectionGridViewChrome-viewPicker"
style={{ marginRight: 5 }}
onPointerDown={stopPropagation}
onChange={this.changeCompactType}
value={StrCast(this.document.gridStartCompaction, StrCast(this.document.gridCompaction))}>
- {["vertical", "horizontal", "none"].map(type =>
- <option className="collectionGridViewChrome-viewOption"
- onPointerDown={stopPropagation}
- value={type}>
- {this.resize ? type[0].toUpperCase() + type.substring(1) : "Compact: " + type}
+ {['vertical', 'horizontal', 'none'].map(type => (
+ <option className="collectionGridViewChrome-viewOption" onPointerDown={stopPropagation} value={type}>
+ {this.resize ? type[0].toUpperCase() + type.substring(1) : 'Compact: ' + type}
</option>
- )}
+ ))}
</select>
- <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}>
- <input style={{ marginRight: 5 }} type="checkbox" onChange={this.toggleFlex}
- checked={BoolCast(this.document.gridFlex, true)} />
- <label className="flexLabel">{this.resize ? "Flex" : "Flexible"}</label>
+ <span className="grid-control" style={{ width: this.resize ? '12%' : '20%' }}>
+ <input style={{ marginRight: 5 }} type="checkbox" onChange={this.toggleFlex} checked={BoolCast(this.document.gridFlex, true)} />
+ <label className="flexLabel">{this.resize ? 'Flex' : 'Flexible'}</label>
</span>
- <button onClick={() => this.document.gridResetLayout = true}>
- {!this.resize ? "Reset" :
- <FontAwesomeIcon icon="redo-alt" size="1x" />}
- </button>
-
+ <button onClick={() => (this.document.gridResetLayout = true)}>{!this.resize ? 'Reset' : <FontAwesomeIcon icon="redo-alt" size="1x" />}</button>
</div>
);
}
@@ -1289,7 +1444,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) {
const dataField = doc[Doc.LayoutFieldKey(doc)];
const childDocs = DocListCast(dataField);
- const currentFrame = Cast(doc._currentFrame, "number", null);
+ const currentFrame = Cast(doc._currentFrame, 'number', null);
if (currentFrame === undefined) {
doc._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
@@ -1297,4 +1452,3 @@ ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) {
CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
});
-
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index b00017453..dcf3f7c51 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -1,50 +1,33 @@
-import React = require("react");
-import {
- action,
- computed,
- IReactionDisposer,
- observable,
- reaction
-} from "mobx";
-import { observer } from "mobx-react";
-import { computedFn } from "mobx-utils";
-import { Doc, DocListCast } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
-import { ComputedField, ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast } from "../../../fields/Types";
-import {
- emptyFunction,
- formatTime,
- OmitKeys,
- returnFalse,
- returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent
-} from "../../../Utils";
-import { Docs } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager } from "../../util/DragManager";
-import { LinkManager } from "../../util/LinkManager";
-import { ScriptingGlobals } from "../../util/ScriptingGlobals";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { AudioWaveform } from "../AudioWaveform";
-import { CollectionSubView } from "../collections/CollectionSubView";
-import { Colors } from "../global/globalEnums";
-import { LightboxView } from "../LightboxView";
-import {
- DocAfterFocusFunc,
- DocFocusFunc,
- DocumentView,
- DocumentViewProps
-} from "../nodes/DocumentView";
-import { LabelBox } from "../nodes/LabelBox";
-import "./CollectionStackedTimeline.scss";
-import { VideoBox } from "../nodes/VideoBox";
-import { ImageField } from "../../../fields/URLField";
+import React = require('react');
+import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { listSpec } from '../../../fields/Schema';
+import { ComputedField, ScriptField } from '../../../fields/ScriptField';
+import { Cast, NumCast } from '../../../fields/Types';
+import { emptyFunction, formatTime, OmitKeys, returnFalse, returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
+import { DragManager } from '../../util/DragManager';
+import { LinkFollower } from '../../util/LinkFollower';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { Transform } from '../../util/Transform';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { AudioWaveform } from '../AudioWaveform';
+import { CollectionSubView } from '../collections/CollectionSubView';
+import { Colors } from '../global/globalEnums';
+import { LightboxView } from '../LightboxView';
+import { DocAfterFocusFunc, DocFocusFunc, DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { LabelBox } from '../nodes/LabelBox';
+import './CollectionStackedTimeline.scss';
+import { VideoBox } from '../nodes/VideoBox';
+import { ImageField } from '../../../fields/URLField';
export type CollectionStackedTimelineProps = {
Play: () => void;
@@ -68,7 +51,6 @@ export enum TrimScope {
None = 0,
}
-
@observer
export class CollectionStackedTimeline extends CollectionSubView<CollectionStackedTimelineProps>() {
@observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined;
@@ -94,21 +76,38 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
@observable _thumbnail: string | undefined;
- // ensures that clip doesn't get trimmed so small that controls cannot be adjusted anymore
- get minTrimLength() { return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5); }
-
- @computed get trimStart() { return this.IsTrimming !== TrimScope.None ? this._trimStart : this.clipStart; }
- @computed get trimDuration() { return this.trimEnd - this.trimStart; }
- @computed get trimEnd() { return this.IsTrimming !== TrimScope.None ? this._trimEnd : this.clipEnd; }
+ // ensures that clip doesn't get trimmed so small that controls cannot be adjusted anymore
+ get minTrimLength() {
+ return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5);
+ }
- @computed get clipStart() { return this.IsTrimming === TrimScope.All ? 0 : NumCast(this.layoutDoc.clipStart); }
- @computed get clipDuration() { return this.clipEnd - this.clipStart; }
- @computed get clipEnd() { return this.IsTrimming === TrimScope.All ? this.props.rawDuration : NumCast(this.layoutDoc.clipEnd, this.props.rawDuration); }
+ @computed get trimStart() {
+ return this.IsTrimming !== TrimScope.None ? this._trimStart : this.clipStart;
+ }
+ @computed get trimDuration() {
+ return this.trimEnd - this.trimStart;
+ }
+ @computed get trimEnd() {
+ return this.IsTrimming !== TrimScope.None ? this._trimEnd : this.clipEnd;
+ }
- @computed get currentTime() { return NumCast(this.layoutDoc._currentTimecode); }
+ @computed get clipStart() {
+ return this.IsTrimming === TrimScope.All ? 0 : NumCast(this.layoutDoc.clipStart);
+ }
+ @computed get clipDuration() {
+ return this.clipEnd - this.clipStart;
+ }
+ @computed get clipEnd() {
+ return this.IsTrimming === TrimScope.All ? this.props.rawDuration : NumCast(this.layoutDoc.clipEnd, this.props.rawDuration);
+ }
- @computed get zoomFactor() { return this._zoomFactor; }
+ @computed get currentTime() {
+ return NumCast(this.layoutDoc._currentTimecode);
+ }
+ @computed get zoomFactor() {
+ return this._zoomFactor;
+ }
constructor(props: any) {
super(props);
@@ -117,32 +116,33 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
CollectionStackedTimeline.RangeScript ||
ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, {
self: Doc.name,
- scriptContext: "any",
- clientX: "number",
+ scriptContext: 'any',
+ clientX: 'number',
})!;
CollectionStackedTimeline.RangePlayScript =
CollectionStackedTimeline.RangePlayScript ||
ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, {
self: Doc.name,
- scriptContext: "any",
- clientX: "number",
+ scriptContext: 'any',
+ clientX: 'number',
})!;
}
componentDidMount() {
- document.addEventListener("keydown", this.keyEvents, true);
+ document.addEventListener('keydown', this.keyEvents, true);
}
@action
componentWillUnmount() {
- document.removeEventListener("keydown", this.keyEvents, true);
+ document.removeEventListener('keydown', this.keyEvents, true);
if (CollectionStackedTimeline.SelectingRegion === this) {
CollectionStackedTimeline.SelectingRegion = undefined;
}
}
-
- public get IsTrimming() { return this._trimming; }
+ public get IsTrimming() {
+ return this._trimming;
+ }
@action
public StartTrimming(scope: TrimScope) {
@@ -162,81 +162,63 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._zoomFactor = zoom;
}
-
anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]));
anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this.props.endTag], val) ?? null);
-
// converts screen pixel offset to time
toTimeline = (screen_delta: number, width: number) => {
- return Math.max(
- this.clipStart,
- Math.min(this.clipEnd, (screen_delta / width) * this.clipDuration + this.clipStart));
- }
-
+ return Math.max(this.clipStart, Math.min(this.clipEnd, (screen_delta / width) * this.clipDuration + this.clipStart));
+ };
rangeClickScript = () => CollectionStackedTimeline.RangeScript;
rangePlayScript = () => CollectionStackedTimeline.RangePlayScript;
-
// handles key events for for creating key anchors, scrubbing, exiting trim
@action
keyEvents = (e: KeyboardEvent) => {
if (
// need to include range inputs because after dragging video time slider it becomes target element
- !(e.target instanceof HTMLInputElement && !(e.target.type === "range")) &&
+ !(e.target instanceof HTMLInputElement && !(e.target.type === 'range')) &&
this.props.isSelected(true)
) {
// if shift pressed scrub 1 second otherwise 1/10th
const jump = e.shiftKey ? 1 : 0.1;
switch (e.key) {
- case " ":
+ case ' ':
if (!CollectionStackedTimeline.SelectingRegion) {
this._markerStart = this._markerEnd = this.currentTime;
CollectionStackedTimeline.SelectingRegion = this;
} else {
this._markerEnd = this.currentTime;
- CollectionStackedTimeline.createAnchor(
- this.rootDoc,
- this.dataDoc,
- this.props.fieldKey,
- this.props.startTag,
- this.props.endTag,
- this._markerStart,
- this._markerEnd
- );
+ CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd);
this._markerEnd = undefined;
CollectionStackedTimeline.SelectingRegion = undefined;
}
e.stopPropagation();
break;
- case "Escape":
+ case 'Escape':
// abandons current trim
this._trimStart = this.clipStart;
this._trimStart = this.clipEnd;
this._trimming = TrimScope.None;
e.stopPropagation();
break;
- case "ArrowLeft":
+ case 'ArrowLeft':
this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime - jump), this.clipEnd));
e.stopPropagation();
break;
- case "ArrowRight":
+ case 'ArrowRight':
this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime + jump), this.clipEnd));
e.stopPropagation();
break;
}
}
- }
-
+ };
getLinkData(l: Doc) {
let la1 = l.anchor1 as Doc;
let la2 = l.anchor2 as Doc;
- const linkTime = NumCast(
- la2[this.props.startTag],
- NumCast(la1[this.props.startTag])
- );
+ const linkTime = NumCast(la2[this.props.startTag], NumCast(la1[this.props.startTag]));
if (Doc.AreProtosEqual(la1, this.dataDoc)) {
la1 = l.anchor2 as Doc;
la2 = l.anchor1 as Doc;
@@ -244,7 +226,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
return { la1, la2, linkTime };
}
-
// handles dragging selection to create markers
@action
onPointerDownTimeline = (e: React.PointerEvent): void => {
@@ -259,7 +240,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
setupMoveUpEvents(
this,
e,
- action((e) => {
+ action(e => {
if (!wasSelecting) {
this._markerStart = this._markerEnd = this.toTimeline(clientX - rect.x, rect.width);
wasSelecting = true;
@@ -274,24 +255,11 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._markerStart = this._markerEnd;
this._markerEnd = tmp;
}
- if (
- !isClick &&
- Math.abs(movement[0]) > 15 &&
- !this.IsTrimming
- ) {
- const anchor = CollectionStackedTimeline.createAnchor(
- this.rootDoc,
- this.dataDoc,
- this.props.fieldKey,
- this.props.startTag,
- this.props.endTag,
- this._markerStart,
- this._markerEnd
- );
+ if (!isClick && Math.abs(movement[0]) > 15 && !this.IsTrimming) {
+ const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd);
setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false));
}
- (!isClick || !wasSelecting) &&
- (this._markerEnd = undefined);
+ (!isClick || !wasSelecting) && (this._markerEnd = undefined);
}),
(e, doubleTap) => {
if (e.button !== 2) {
@@ -303,23 +271,14 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
undefined,
() => {
if (shiftKey) {
- CollectionStackedTimeline.createAnchor(
- this.rootDoc,
- this.dataDoc,
- this.props.fieldKey,
- this.props.startTag,
- this.props.endTag,
- this.currentTime
- );
+ CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime);
} else {
!wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
}
);
}
-
- }
-
+ };
@action
onHover = (e: React.MouseEvent): void => {
@@ -329,15 +288,14 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
if (rect) {
this._hoverTime = this.toTimeline(clientX - rect.x, rect.width);
if (this.dataDoc.thumbnails) {
- const nearest = Math.floor(this._hoverTime / this.props.rawDuration * VideoBox.numThumbnails);
- const thumbnails = Cast(this.dataDoc.thumbnails, listSpec("string"), []);
- const imgField = thumbnails && thumbnails.length > 0 ? new ImageField(thumbnails[nearest]) : new ImageField("");
- const src = imgField && imgField.url.href ? imgField.url.href.replace(".png", "_s.png") : "";
+ const nearest = Math.floor((this._hoverTime / this.props.rawDuration) * VideoBox.numThumbnails);
+ const thumbnails = Cast(this.dataDoc.thumbnails, listSpec('string'), []);
+ const imgField = thumbnails && thumbnails.length > 0 ? new ImageField(thumbnails[nearest]) : new ImageField('');
+ const src = imgField && imgField.url.href ? imgField.url.href.replace('.png', '_s.png') : '';
this._thumbnail = src ? src : undefined;
}
}
- }
-
+ };
// for dragging trim start handle
@action
@@ -348,13 +306,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
e,
action((e, [], []) => {
if (rect && this.props.isContentActive()) {
- this._trimStart = Math.min(
- Math.max(
- this.trimStart + (e.movementX / rect.width) * this.clipDuration,
- this.clipStart
- ),
- this.trimEnd - this.minTrimLength
- );
+ this._trimStart = Math.min(Math.max(this.trimStart + (e.movementX / rect.width) * this.clipDuration, this.clipStart), this.trimEnd - this.minTrimLength);
}
return false;
}),
@@ -363,7 +315,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
doubleTap && (this._trimStart = this.clipStart);
})
);
- }
+ };
// for dragging trim end handle
@action
@@ -374,13 +326,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
e,
action((e, [], []) => {
if (rect && this.props.isContentActive()) {
- this._trimEnd = Math.max(
- Math.min(
- this.trimEnd + (e.movementX / rect.width) * this.clipDuration,
- this.clipEnd
- ),
- this.trimStart + this.minTrimLength
- );
+ this._trimEnd = Math.max(Math.min(this.trimEnd + (e.movementX / rect.width) * this.clipDuration, this.clipEnd), this.trimStart + this.minTrimLength);
}
return false;
}),
@@ -389,15 +335,14 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
doubleTap && (this._trimEnd = this.clipEnd);
})
);
- }
-
+ };
// for rendering scrolling when timeline zoomed
@action
setScroll = (e: React.UIEvent) => {
e.stopPropagation();
this._scroll = this._timelineWrapper!.scrollLeft;
- }
+ };
// smooth scrolls to time like when following links overflowed due to zoom
@action
@@ -406,14 +351,12 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
if (time > this.toTimeline(this._scroll + this.props.PanelWidth(), this.timelineContentWidth)) {
this._scroll = Math.min(this._scroll + this.props.PanelWidth(), this.timelineContentWidth - this.props.PanelWidth());
smoothScrollHorizontal(200, this._timelineWrapper, this._scroll);
- }
- else if (time < this.toTimeline(this._scroll, this.timelineContentWidth)) {
- this._scroll = time / this.timelineContentWidth * this.clipDuration;
+ } else if (time < this.toTimeline(this._scroll, this.timelineContentWidth)) {
+ this._scroll = (time / this.timelineContentWidth) * this.clipDuration;
smoothScrollHorizontal(200, this._timelineWrapper, this._scroll);
}
}
- }
-
+ };
// handles dragging and dropping markers in timeline
@action
@@ -428,9 +371,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
docDragData.droppedDocuments.forEach(drop => {
const anchorEnd = this.anchorEnd(drop);
if (anchorEnd !== undefined) {
- Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : "timecodeToHide", timelinePt + anchorEnd - this.anchorStart(drop), false);
+ Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
}
- Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : "timecodeToShow", timelinePt, false);
+ Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
});
return true;
@@ -439,38 +382,28 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, 0);
return false;
- }
-
+ };
// creates marker on timeline
@undoBatch
@action
- static createAnchor(
- rootDoc: Doc,
- dataDoc: Doc,
- fieldKey: string,
- startTag: string,
- endTag: string,
- anchorStartTime?: number,
- anchorEndTime?: number,
- docAnchor?: Doc
- ) {
+ static createAnchor(rootDoc: Doc, dataDoc: Doc, fieldKey: string, startTag: string, endTag: string, anchorStartTime?: number, anchorEndTime?: number, docAnchor?: Doc) {
if (anchorStartTime === undefined) return rootDoc;
- const anchor = docAnchor ?? Docs.Create.LabelDocument({
- title: ComputedField.MakeFunction(
- `self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`
- ) as any,
- _minFontSize: 12,
- _maxFontSize: 24,
- _singleLine: false,
- _stayInCollection: true,
- useLinkSmallAnchor: true,
- hideLinkButton: true,
- _isLinkButton: true,
- annotationOn: rootDoc,
- _timelineLabel: true,
- borderRounding: anchorEndTime === undefined ? "100%" : undefined
- });
+ const anchor =
+ docAnchor ??
+ Docs.Create.LabelDocument({
+ title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
+ _minFontSize: 12,
+ _maxFontSize: 24,
+ _singleLine: false,
+ _stayInCollection: true,
+ useLinkSmallAnchor: true,
+ hideLinkButton: true,
+ _isLinkButton: true,
+ annotationOn: rootDoc,
+ _timelineLabel: true,
+ borderRounding: anchorEndTime === undefined ? '100%' : undefined,
+ });
Doc.GetProto(anchor)[startTag] = anchorStartTime;
Doc.GetProto(anchor)[endTag] = anchorEndTime;
if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
@@ -481,7 +414,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
return anchor;
}
-
@action
playOnClick = (anchorDoc: Doc, clientX: number) => {
const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
@@ -493,10 +425,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this.scrollToTime(seekTimeInSeconds);
}
} else {
- if (
- seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) &&
- endTime > NumCast(this.layoutDoc._currentTimecode)
- ) {
+ if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) {
if (!this.layoutDoc.autoPlayAnchors && this.props.playing()) {
this.props.Pause();
} else {
@@ -508,59 +437,43 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
}
}
return { select: true };
- }
+ };
@action
clickAnchor = (anchorDoc: Doc, clientX: number) => {
if (anchorDoc.isLinkButton) {
- LinkManager.FollowLink(undefined, anchorDoc, this.props, false);
+ LinkFollower.FollowLink(undefined, anchorDoc, this.props, false);
}
const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
const endTime = this.anchorEnd(anchorDoc);
- if (
- seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 &&
- endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4
- ) {
+ if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) {
if (this.props.playing()) this.props.Pause();
else if (this.layoutDoc.autoPlayAnchors) this.props.Play();
else if (!this.layoutDoc.autoPlayAnchors) {
const rect = this._timeline?.getBoundingClientRect();
- rect &&
- this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
+ rect && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
} else {
if (this.layoutDoc.autoPlayAnchors) {
this.props.playFrom(seekTimeInSeconds, endTime);
- }
- else {
+ } else {
this.props.setTime(seekTimeInSeconds);
}
}
return { select: true };
- }
+ };
// makes sure no anchors overlaps each other by setting the correct position and width
- getLevel = (
- m: Doc,
- placed: { anchorStartTime: number; anchorEndTime: number; level: number }[]
- ) => {
+ getLevel = (m: Doc, placed: { anchorStartTime: number; anchorEndTime: number; level: number }[]) => {
const timelineContentWidth = this.timelineContentWidth;
const x1 = this.anchorStart(m);
- const x2 = this.anchorEnd(
- m,
- x1 + (10 / timelineContentWidth) * this.clipDuration
- );
+ const x2 = this.anchorEnd(m, x1 + (10 / timelineContentWidth) * this.clipDuration);
let max = 0;
const overlappedLevels = new Set(
- placed.map((p) => {
+ placed.map(p => {
const y1 = p.anchorStartTime;
const y2 = p.anchorEndTime;
- if (
- (x1 >= y1 && x1 <= y2) ||
- (x2 >= y1 && x2 <= y2) ||
- (y1 >= x1 && y1 <= x2) ||
- (y2 >= x1 && y2 <= x2)
- ) {
+ if ((x1 >= y1 && x1 <= y2) || (x2 >= y1 && x2 <= y2) || (y1 >= x1 && y1 <= x2) || (y2 >= x1 && y2 <= x2)) {
max = Math.max(max, p.level);
return p.level;
}
@@ -571,14 +484,17 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
placed.push({ anchorStartTime: x1, anchorEndTime: x2, level });
return level;
- }
-
+ };
dictationHeightPercent = 50;
dictationHeight = () => (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100;
- @computed get timelineContentHeight() { return this.props.PanelHeight() * this.dictationHeightPercent / 100; }
- @computed get timelineContentWidth() { return this.props.PanelWidth() * this.zoomFactor; } // subtract size of container border
+ @computed get timelineContentHeight() {
+ return (this.props.PanelHeight() * this.dictationHeightPercent) / 100;
+ }
+ @computed get timelineContentWidth() {
+ return this.props.PanelWidth() * this.zoomFactor;
+ } // subtract size of container border
dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight);
@@ -586,24 +502,18 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
currentTimecode = () => this.currentTime;
-
@computed get renderDictation() {
const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
return !dictation ? null : (
<div
style={{
- position: "absolute",
- height: "100%",
+ position: 'absolute',
+ height: '100%',
top: this.timelineContentHeight,
background: Colors.LIGHT_BLUE,
- }}
- >
+ }}>
<DocumentView
- {...OmitKeys(this.props, [
- "NativeWidth",
- "NativeHeight",
- "setContentView",
- ]).omit}
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
Document={dictation}
PanelHeight={this.dictationHeight}
isAnnotationOverlay={true}
@@ -618,8 +528,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
moveDocument={returnFalse}
addDocument={returnFalse}
CollectionView={undefined}
- renderDepth={this.props.renderDepth + 1}
- ></DocumentView>
+ renderDepth={this.props.renderDepth + 1}></DocumentView>
</div>
);
}
@@ -644,145 +553,131 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
anchorEndTime: number;
level: number;
}[] = [];
- const drawAnchors = this.childDocs.map((anchor) => ({
+ const drawAnchors = this.childDocs.map(anchor => ({
level: this.getLevel(anchor, overlaps),
anchor,
}));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
- return (<div ref={this.createDashEventsTarget} style={{ pointerEvents: SnappingManager.GetIsDragging() ? "all" : undefined }}>
- <div className="timeline-container"
- style={{ width: this.props.PanelWidth() }}
- onWheel={e => e.stopPropagation()}
- onScroll={this.setScroll}
- onMouseMove={(e) => this.isContentActive() && this.onHover(e)}
- ref={wrapper => this._timelineWrapper = wrapper}>
+ return (
+ <div ref={this.createDashEventsTarget} style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : undefined }}>
<div
- className="collectionStackedTimeline"
- ref={(timeline: HTMLDivElement | null) => (this._timeline = timeline)}
- onClick={(e) => this.isContentActive() && StopEvent(e)}
- onPointerDown={(e) => this.isContentActive() && this.onPointerDownTimeline(e)}
- style={{ width: this.timelineContentWidth }}>
-
- {drawAnchors.map((d) => {
- const start = this.anchorStart(d.anchor);
- const end = this.anchorEnd(
- d.anchor,
- start + (10 / this.timelineContentWidth) * this.clipDuration
- );
- if (end < this.clipStart || start > this.clipEnd) return (null);
- const left = Math.max((start - this.clipStart) / this.clipDuration * this.timelineContentWidth, 0);
- const top = (d.level / maxLevel) * this.props.PanelHeight();
- const 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 : (
- <div
- className={"collectionStackedTimeline-marker-timeline"}
- key={d.anchor[Id]}
- style={{
- left,
- top,
- width: `${width}px`,
- height: `${height}px`,
- }}
- onClick={(e) => {
- this.props.playFrom(start, this.anchorEnd(d.anchor));
- e.stopPropagation();
- }}
- >
- <StackedTimelineAnchor
- {...this.props}
- mark={d.anchor}
- rangeClickScript={this.rangeClickScript}
- rangePlayScript={this.rangePlayScript}
- left={left - this._scroll}
- top={top}
- width={width}
- height={height}
- toTimeline={this.toTimeline}
- layoutDoc={this.layoutDoc}
- // isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
- currentTimecode={this.currentTimecode}
- _timeline={this._timeline}
- stackedTimeline={this}
- trimStart={this.trimStart}
- trimEnd={this.trimEnd}
- />
- </div>
- );
- })}
- {!this.IsTrimming && this.selectionContainer}
- <AudioWaveform
- rawDuration={this.props.rawDuration}
- duration={this.clipDuration}
- mediaPath={this.props.mediaPath}
- layoutDoc={this.layoutDoc}
- clipStart={this.clipStart}
- clipEnd={this.clipEnd}
- zoomFactor={this.zoomFactor}
- PanelHeight={this.timelineContentHeight}
- PanelWidth={this.timelineContentWidth}
- />
- {/* {this.renderDictation} */}
-
+ className="timeline-container"
+ style={{ width: this.props.PanelWidth() }}
+ onWheel={e => e.stopPropagation()}
+ onScroll={this.setScroll}
+ onMouseMove={e => this.isContentActive() && this.onHover(e)}
+ ref={wrapper => (this._timelineWrapper = wrapper)}>
<div
- className="collectionStackedTimeline-hover"
- style={{
- left: `${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%`,
- }}
- />
+ className="collectionStackedTimeline"
+ ref={(timeline: HTMLDivElement | null) => (this._timeline = timeline)}
+ onClick={e => this.isContentActive() && StopEvent(e)}
+ onPointerDown={e => this.isContentActive() && this.onPointerDownTimeline(e)}
+ style={{ width: this.timelineContentWidth }}>
+ {drawAnchors.map(d => {
+ const start = this.anchorStart(d.anchor);
+ const end = this.anchorEnd(d.anchor, start + (10 / this.timelineContentWidth) * this.clipDuration);
+ if (end < this.clipStart || start > this.clipEnd) return null;
+ const left = Math.max(((start - this.clipStart) / this.clipDuration) * this.timelineContentWidth, 0);
+ const top = (d.level / maxLevel) * this.props.PanelHeight();
+ const 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 : (
+ <div
+ className={'collectionStackedTimeline-marker-timeline'}
+ key={d.anchor[Id]}
+ style={{
+ left,
+ top,
+ width: `${width}px`,
+ height: `${height}px`,
+ }}
+ onClick={e => {
+ this.props.playFrom(start, this.anchorEnd(d.anchor));
+ e.stopPropagation();
+ }}>
+ <StackedTimelineAnchor
+ {...this.props}
+ mark={d.anchor}
+ rangeClickScript={this.rangeClickScript}
+ rangePlayScript={this.rangePlayScript}
+ left={left - this._scroll}
+ top={top}
+ width={width}
+ height={height}
+ toTimeline={this.toTimeline}
+ layoutDoc={this.layoutDoc}
+ // isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+ currentTimecode={this.currentTimecode}
+ _timeline={this._timeline}
+ stackedTimeline={this}
+ trimStart={this.trimStart}
+ trimEnd={this.trimEnd}
+ />
+ </div>
+ );
+ })}
+ {!this.IsTrimming && this.selectionContainer}
+ <AudioWaveform
+ rawDuration={this.props.rawDuration}
+ duration={this.clipDuration}
+ mediaPath={this.props.mediaPath}
+ layoutDoc={this.layoutDoc}
+ clipStart={this.clipStart}
+ clipEnd={this.clipEnd}
+ zoomFactor={this.zoomFactor}
+ PanelHeight={this.timelineContentHeight}
+ PanelWidth={this.timelineContentWidth}
+ />
+ {/* {this.renderDictation} */}
+
+ <div
+ className="collectionStackedTimeline-hover"
+ style={{
+ left: `${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%`,
+ }}
+ />
+
+ <div
+ className="collectionStackedTimeline-current"
+ style={{
+ left: `${((this.currentTime - this.clipStart) / this.clipDuration) * 100}%`,
+ }}
+ />
+
+ {this.IsTrimming !== TrimScope.None && (
+ <>
+ <div className="collectionStackedTimeline-trim-shade" style={{ width: `${((this.trimStart - this.clipStart) / this.clipDuration) * 100}%` }}></div>
- <div
- className="collectionStackedTimeline-current"
- style={{
- left: `${((this.currentTime - this.clipStart) / this.clipDuration) * 100}%`,
- }}
- />
-
- {this.IsTrimming !== TrimScope.None && (
- <>
- <div
- className="collectionStackedTimeline-trim-shade"
- style={{ width: `${((this.trimStart - this.clipStart) / this.clipDuration) * 100}%` }}
- ></div>
-
- <div
- className="collectionStackedTimeline-trim-controls"
- style={{
- left: `${((this.trimStart - this.clipStart) / this.clipDuration) * 100}%`,
- width: `${((this.trimEnd - this.trimStart) / this.clipDuration) * 100}%`,
- }}
- >
<div
- className="collectionStackedTimeline-trim-handle"
- onPointerDown={this.trimLeft}
- ></div>
+ className="collectionStackedTimeline-trim-controls"
+ style={{
+ left: `${((this.trimStart - this.clipStart) / this.clipDuration) * 100}%`,
+ width: `${((this.trimEnd - this.trimStart) / this.clipDuration) * 100}%`,
+ }}>
+ <div className="collectionStackedTimeline-trim-handle" onPointerDown={this.trimLeft}></div>
+ <div className="collectionStackedTimeline-trim-handle" onPointerDown={this.trimRight}></div>
+ </div>
+
<div
- className="collectionStackedTimeline-trim-handle"
- onPointerDown={this.trimRight}
- ></div>
- </div>
-
- <div
- className="collectionStackedTimeline-trim-shade"
- style={{
- left: `${((this.trimEnd - this.clipStart) / this.clipDuration) * 100}%`,
- width: `${((this.clipEnd - this.trimEnd) / this.clipDuration) * 100}%`,
- }}
- ></div>
- </>
- )}
+ className="collectionStackedTimeline-trim-shade"
+ style={{
+ left: `${((this.trimEnd - this.clipStart) / this.clipDuration) * 100}%`,
+ width: `${((this.clipEnd - this.trimEnd) / this.clipDuration) * 100}%`,
+ }}></div>
+ </>
+ )}
+ </div>
+ </div>
+ <div className="timeline-hoverUI" style={{ left: `calc(${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%` }}>
+ <div className="hoverTime">{formatTime(this._hoverTime - this.clipStart)}</div>
+ {this._thumbnail && <img className="videoBox-thumbnail" src={this._thumbnail} />}
</div>
</div>
- <div className="timeline-hoverUI" style={{ left: `calc(${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%` }}>
- <div className="hoverTime">{formatTime(this._hoverTime - this.clipStart)}</div>
- {this._thumbnail && <img className="videoBox-thumbnail" src={this._thumbnail} />}
- </div>
- </div >);
+ );
}
}
-
/**
* StackedTimelineAnchor
* creates the anchors to display markers, links, and embedded documents on timeline
@@ -814,7 +709,6 @@ interface StackedTimelineAnchorProps {
trimEnd: number;
}
-
@observer
class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> {
_lastTimecode: number;
@@ -831,23 +725,14 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart;
const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart;
return `#${formatTime(start)}-${formatTime(end)}`;
- }
+ };
componentDidMount() {
this._disposer = reaction(
() => this.props.currentTimecode(),
- (time) => {
- const dictationDoc = Cast(
- this.props.layoutDoc["data-dictation"],
- Doc,
- null
- );
- const isDictation =
- dictationDoc &&
- DocListCast(this.props.mark.links).some(
- (link) =>
- Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc
- );
+ time => {
+ const dictationDoc = Cast(this.props.layoutDoc['data-dictation'], Doc, null);
+ const isDictation = dictationDoc && DocListCast(this.props.mark.links).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc);
if (
!LightboxView.LightboxDoc &&
// bcz: when should links be followed? we don't want to move away from the video to follow a link but we can open it in a sidebar/etc. But we don't know that upfront.
@@ -859,13 +744,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
) {
- LinkManager.FollowLink(
- undefined,
- this.props.mark,
- this.props as any as DocumentViewProps,
- false,
- true
- );
+ LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false, true);
}
this._lastTimecode = time;
}
@@ -876,7 +755,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
this._disposer?.();
}
-
// starting the drag event for anchor resizing
onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => {
this.props._timeline?.setPointerCapture(e.pointerId);
@@ -885,19 +763,13 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
return this.props.toTimeline(e.clientX - rect.x, rect.width);
};
const changeAnchor = (anchor: Doc, left: boolean, time: number | undefined) => {
- const timelineOnly = Cast(anchor[this.props.startTag], "number", null) !== undefined;
+ const timelineOnly = Cast(anchor[this.props.startTag], 'number', null) !== undefined;
if (timelineOnly) {
if (!left && time !== undefined && time <= NumCast(anchor[this.props.startTag])) time = undefined;
- Doc.SetInPlace(
- anchor,
- left ? this.props.startTag : this.props.endTag,
- time,
- true
- );
- if (!left) Doc.SetInPlace(anchor, "borderRounding", time !== undefined ? undefined : "100%", true);
- }
- else {
- anchor[left ? "_timecodeToShow" : "_timecodeToHide"] = time;
+ Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
+ if (!left) Doc.SetInPlace(anchor, 'borderRounding', time !== undefined ? undefined : '100%', true);
+ } else {
+ anchor[left ? '_timecodeToShow' : '_timecodeToHide'] = time;
}
return false;
};
@@ -906,46 +778,34 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
setupMoveUpEvents(
this,
e,
- (e) => {
- if (!undo) undo = UndoManager.StartBatch("drag anchor");
+ e => {
+ if (!undo) undo = UndoManager.StartBatch('drag anchor');
this.props.setTime(newTime(e));
return changeAnchor(anchor, left, newTime(e));
},
- (e) => {
+ e => {
this.props.setTime(newTime(e));
this.props._timeline?.releasePointerCapture(e.pointerId);
undo?.end();
},
emptyFunction
);
- }
-
+ };
// context menu
contextMenuItems = () => {
- const resetTitle = { script: ScriptField.MakeFunction(`self.title = self["${this.props.endTag}"] ? "#" + formatToTime(self["${this.props.startTag}"]) + "-" + formatToTime(self["${this.props.endTag}"]) : "#" + formatToTime(self["${this.props.startTag}"])`)!, icon: "folder-plus", label: "Reset Title" };
+ const resetTitle = {
+ script: ScriptField.MakeFunction(`self.title = self["${this.props.endTag}"] ? "#" + formatToTime(self["${this.props.startTag}"]) + "-" + formatToTime(self["${this.props.endTag}"]) : "#" + formatToTime(self["${this.props.startTag}"])`)!,
+ icon: 'folder-plus',
+ label: 'Reset Title',
+ };
return [resetTitle];
- }
-
+ };
// renders anchor LabelBox
- renderInner = computedFn(function (
- this: StackedTimelineAnchor,
- mark: Doc,
- script: undefined | (() => ScriptField),
- doublescript: undefined | (() => ScriptField),
- screenXf: () => Transform,
- width: () => number,
- height: () => number
- ) {
+ 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,
- willZoom?: boolean,
- scale?: number,
- afterFocus?: DocAfterFocusFunc,
- docTransform?: Transform
- ) => {
+ const focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, docTransform?: Transform) => {
this.props.playLink(mark);
this.props.focus(doc, { willZoom, scale, afterFocus, docTransform });
};
@@ -954,13 +814,13 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
view: (
<DocumentView
key="view"
- {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
- ref={action((r: DocumentView | null) => anchor.view = r)}
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+ ref={action((r: DocumentView | null) => (anchor.view = r))}
Document={mark}
DataDoc={undefined}
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={undefined}
- LayoutTemplateString={LabelBox.LayoutStringWithTitle("data", this.computeTitle())}
+ LayoutTemplateString={LabelBox.LayoutStringWithTitle('data', this.computeTitle())}
isDocumentActive={this.props.isDocumentActive}
PanelWidth={width}
PanelHeight={height}
@@ -985,32 +845,14 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
height = () => this.props.height;
render() {
- const inner = this.renderInner(
- this.props.mark,
- this.props.rangeClickScript,
- this.props.rangePlayScript,
- this.anchorScreenToLocalXf,
- this.width,
- this.height
- );
+ const inner = this.renderInner(this.props.mark, this.props.rangeClickScript, this.props.rangePlayScript, this.anchorScreenToLocalXf, this.width, this.height);
return (
<>
{inner.view}
- {!inner.anchor.view ||
- !SelectionManager.IsSelected(inner.anchor.view) ? null : (
+ {!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" onPointerDown={e => this.onAnchorDown(e, this.props.mark, true)} />
+ <div key="right" className="collectionStackedTimeline-resizer" onPointerDown={e => this.onAnchorDown(e, this.props.mark, false)} />
</>
)}
</>
@@ -1025,4 +867,4 @@ ScriptingGlobals.add(function min(num1: number, num2: number): number {
});
ScriptingGlobals.add(function max(num1: number, num2: number): number {
return Math.max(num1, num2);
-}); \ No newline at end of file
+});
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7d40cab8c..6850fb23a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -12,6 +12,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Ty
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
+import { CollectionViewType } from '../../documents/DocumentTypes';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
@@ -22,14 +23,13 @@ import { EditableView } from '../EditableView';
import { LightboxView } from '../LightboxView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
+import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
import './CollectionStackingView.scss';
import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
import { CollectionSubView } from './CollectionSubView';
-import { CollectionViewType } from './CollectionView';
-import { FieldViewProps } from '../nodes/FieldView';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
const _global = (window /* browser */ || global) /* node */ as any;
export type collectionStackingViewProps = {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 03450b798..5479929bd 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,24 +1,23 @@
-import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
-import CursorField from "../../../fields/CursorField";
-import { Doc, Opt, Field, DocListCast, AclPrivate, StrListCast } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
-import { WebField } from "../../../fields/URLField";
-import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
-import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
-import { DocServer } from "../../DocServer";
-import { ImageUtils } from "../../util/Import & Export/ImageUtils";
-import { InteractionUtils } from "../../util/InteractionUtils";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { DocComponent } from "../DocComponent";
-import React = require("react");
+import { action, computed, observable } from 'mobx';
import ReactLoading from 'react-loading';
import * as rp from 'request-promise';
-import { Networking } from "../../Network";
-
+import CursorField from '../../../fields/CursorField';
+import { AclPrivate, Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { listSpec } from '../../../fields/Schema';
+import { ScriptField } from '../../../fields/ScriptField';
+import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
+import { WebField } from '../../../fields/URLField';
+import { GestureUtils } from '../../../pen-gestures/GestureUtils';
+import { returnFalse, Utils } from '../../../Utils';
+import { DocServer } from '../../DocServer';
+import { Networking } from '../../Network';
+import { ImageUtils } from '../../util/Import & Export/ImageUtils';
+import { InteractionUtils } from '../../util/InteractionUtils';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { DocComponent } from '../DocComponent';
+import React = require('react');
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: Opt<CollectionView>;
@@ -33,7 +32,8 @@ export function CollectionSubView<X>(moreProps?: X) {
protected _mainCont?: HTMLDivElement;
@observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
@observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
- protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view
+ protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
+ //used for stacking and masonry view
this.dropDisposer?.();
this.gestureDisposer?.();
this._multiTouchDisposer?.();
@@ -43,8 +43,9 @@ export function CollectionSubView<X>(moreProps?: X) {
this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
}
- }
- protected CreateDropTarget(ele: HTMLDivElement) { //used in schema view
+ };
+ protected CreateDropTarget(ele: HTMLDivElement) {
+ //used in schema view
this.createDashEventsTarget(ele);
}
@@ -54,13 +55,12 @@ export function CollectionSubView<X>(moreProps?: X) {
}
@computed get dataDoc() {
- return (this.props.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) :
- 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.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : 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
}
rootSelected = (outsideReaction?: boolean) => {
return this.props.isSelected(outsideReaction) || (this.rootDoc && this.props.rootSelected(outsideReaction));
- }
+ };
// 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.DataDoc.
// When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
@@ -73,10 +73,12 @@ export function CollectionSubView<X>(moreProps?: X) {
return this.dataDoc[this.props.fieldKey];
}
- get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
+ get childLayoutPairs(): { layout: Doc; data: Doc }[] {
const { Document, DataDoc } = this.props;
- const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
- filter(pair => { // filter out any documents that have a proto that we don't have permissions to
+ const validPairs = this.childDocs
+ .map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc))
+ .filter(pair => {
+ // filter out any documents that have a proto that we don't have permissions to
return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
});
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
@@ -85,21 +87,24 @@ export function CollectionSubView<X>(moreProps?: X) {
return Cast(this.dataField, listSpec(Doc));
}
collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
- collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec('string'), []);
childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
- IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
- this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
+ IsFiltered = () =>
+ this.collectionFilters().length || this.collectionRangeDocFilters().length ? 'hasFilter' : this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? 'inheritsFilter' : undefined;
searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
- if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+ if (this.dataField instanceof Doc) {
+ // if collection data is just a document, then promote it to a singleton list;
rawdocs = [this.dataField];
- } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it.
+ } else if (Cast(this.dataField, listSpec(Doc), null)) {
+ // otherwise, if the collection data is a list, then use it.
rawdocs = Cast(this.dataField, listSpec(Doc), null);
- } else { // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc.
+ } else {
+ // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc.
// For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection.
// Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image.
const rootDoc = Cast(this.props.Document.rootDocument, Doc, null);
@@ -117,19 +122,19 @@ export function CollectionSubView<X>(moreProps?: X) {
return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
}
- // console.log(CurrentUserUtils.ActiveDashboard._docFilters);
+ // console.log(Doc.ActiveDashboard._docFilters);
// if (!this.props.Document._docFilters && this.props.Document.currentFilter) {
// (this.props.Document.currentFilter as Doc).filterBoolean = (this.props.ContainingCollectionDoc?.currentFilter as Doc)?.filterBoolean;
// }
const docsforFilter: Doc[] = [];
- childDocs.forEach((d) => {
+ childDocs.forEach(d => {
// if (DocUtils.Excluded(d, docFilters)) return;
- let notFiltered = d.z || Doc.IsSystem(d) || (DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, viewSpecScript, this.props.Document).length > 0);
+ let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, viewSpecScript, this.props.Document).length > 0;
if (notFiltered) {
- notFiltered = ((!searchDocs.length || searchDocs.includes(d)) && (DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0));
+ notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0;
const fieldKey = Doc.LayoutFieldKey(d);
- const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
- const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+ const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
+ const data = d[annos ? fieldKey + '-annotations' : fieldKey];
if (data !== undefined) {
let subDocs = DocListCast(data);
if (subDocs.length > 0) {
@@ -137,11 +142,12 @@ export function CollectionSubView<X>(moreProps?: X) {
notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, viewSpecScript, d).length);
while (subDocs.length > 0 && !notFiltered) {
newarray = [];
- subDocs.forEach((t) => {
+ subDocs.forEach(t => {
const fieldKey = Doc.LayoutFieldKey(t);
- const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
- notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, viewSpecScript, d).length));
- DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
+ const annos = !Field.toString(Doc.LayoutField(t) as Field).includes('CollectionView');
+ notFiltered =
+ notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, viewSpecScript, d).length));
+ DocListCast(t[annos ? fieldKey + '-annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
});
subDocs = newarray;
}
@@ -157,7 +163,7 @@ export function CollectionSubView<X>(moreProps?: X) {
protected async setCursorPosition(position: [number, number]) {
let ind;
const doc = this.props.Document;
- const id = CurrentUserUtils.id;
+ const id = Doc.UserDoc()[Id];
const email = Doc.CurrentUserEmail;
const pos = { x: position[0], y: position[1] };
if (id && email) {
@@ -167,7 +173,7 @@ export function CollectionSubView<X>(moreProps?: X) {
}
// The following conditional detects a recurring bug we've seen on the server
if (proto[Id] === Docs.Prototypes.get(DocumentType.COL)[Id]) {
- alert("COLLECTION PROTO CURSOR ISSUE DETECTED! Check console for more info...");
+ alert('COLLECTION PROTO CURSOR ISSUE DETECTED! Check console for more info...');
console.log(doc);
console.log(proto);
throw new Error(`AHA! You were trying to set a cursor on a collection's proto, which is the original collection proto! Look at the two previously printed lines for document values!`);
@@ -186,8 +192,7 @@ export function CollectionSubView<X>(moreProps?: X) {
}
@undoBatch
- protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
- }
+ protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {}
protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
if (de.complete.docDragData) {
@@ -210,12 +215,16 @@ export function CollectionSubView<X>(moreProps?: X) {
const dropAction = docDragData.dropAction || docDragData.userDropAction;
const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]);
const someMoved = !docDragData.userDropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
- if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop);
- if ((!dropAction || dropAction === "same" || dropAction === "move" || someMoved) && docDragData.moveDocument) {
+ if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop));
+ if ((!dropAction || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) {
const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
if (movedDocs.length) {
- const canAdd = this.props.Document._viewType === CollectionViewType.Pile || de.embedKey || (!this.props.isAnnotationOverlay || this.props.Document.allowOverlayDrop) ||
+ const canAdd =
+ this.props.Document._viewType === CollectionViewType.Pile ||
+ de.embedKey ||
+ !this.props.isAnnotationOverlay ||
+ this.props.Document.allowOverlayDrop ||
Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
} else {
@@ -228,11 +237,10 @@ export function CollectionSubView<X>(moreProps?: X) {
ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
added = this.addDocument(docDragData.droppedDocuments);
}
- !added && alert("You cannot perform this move");
+ !added && alert('You cannot perform this move');
e.stopPropagation();
return added;
- }
- else if (de.complete.annoDragData) {
+ } else if (de.complete.annoDragData) {
const dropCreator = de.complete.annoDragData.dropDocCreator;
de.complete.annoDragData.dropDocCreator = () => {
const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined);
@@ -253,11 +261,11 @@ export function CollectionSubView<X>(moreProps?: X) {
}
const { dataTransfer } = e;
- const html = dataTransfer.getData("text/html");
- const text = dataTransfer.getData("text/plain");
- const uriList = dataTransfer.getData("text/uri-list");
+ const html = dataTransfer.getData('text/html');
+ const text = dataTransfer.getData('text/plain');
+ const uriList = dataTransfer.getData('text/uri-list');
- if (text && text.startsWith("<div")) {
+ if (text && text.startsWith('<div')) {
return;
}
@@ -271,11 +279,15 @@ export function CollectionSubView<X>(moreProps?: X) {
const href = FormattedTextBox.GetHref(html);
if (href) {
const docid = FormattedTextBox.GetDocFromUrl(href);
- if (docid) { // prosemirror text containing link to dash document
+ if (docid) {
+ // prosemirror text containing link to dash document
DocServer.GetRefField(docid).then(f => {
if (f instanceof Doc) {
- if (options.x || options.y) { f.x = options.x as number; f.y = options.y as number; } // should be in CollectionFreeFormView
- (f instanceof Doc) && addDocument(f);
+ if (options.x || options.y) {
+ f.x = options.x as number;
+ f.y = options.y as number;
+ } // should be in CollectionFreeFormView
+ f instanceof Doc && addDocument(f);
}
});
} else {
@@ -286,47 +298,50 @@ export function CollectionSubView<X>(moreProps?: X) {
}
return;
}
- if (!html.startsWith("<a")) {
- const tags = html.split("<");
- if (tags[0] === "") tags.splice(0, 1);
- let img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : "";
- const cors = img.includes("corsProxy") ? img.match(/http.*corsProxy\//)![0] : "";
- img = cors ? img.replace(cors, "") : img;
+ if (!html.startsWith('<a')) {
+ const tags = html.split('<');
+ if (tags[0] === '') tags.splice(0, 1);
+ let img = tags[0].startsWith('img') ? tags[0] : tags.length > 1 && tags[1].startsWith('img') ? tags[1] : '';
+ const cors = img.includes('corsProxy') ? img.match(/http.*corsProxy\//)![0] : '';
+ img = cors ? img.replace(cors, '') : img;
if (img) {
- const split = img.split("src=\"")[1].split("\"")[0];
+ const split = img.split('src="')[1].split('"')[0];
let source = split;
- if (split.startsWith("data:image") && split.includes("base64")) {
- const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
+ if (split.startsWith('data:image') && split.includes('base64')) {
+ const [{ accessPaths }] = await Networking.PostToServer('/uploadRemoteImage', { sources: [split] });
source = Utils.prepend(accessPaths.agnostic.client);
}
- if (source.startsWith("http")) {
+ if (source.startsWith('http')) {
const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 });
ImageUtils.ExtractExif(doc);
addDocument(doc);
}
return;
} else {
- const path = window.location.origin + "/doc/";
+ const path = window.location.origin + '/doc/';
if (text.startsWith(path)) {
- const docid = text.replace(Doc.globalServerPath(), "").split("?")[0];
+ 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; f.y = options.y as number; } // should be in CollectionFreeFormView
- (f instanceof Doc) && addDocument(f);
+ if (options.x || options.y) {
+ f.x = options.x as number;
+ f.y = options.y as number;
+ } // should be in CollectionFreeFormView
+ f instanceof Doc && addDocument(f);
}
});
} else {
const srcWeb = SelectionManager.Views().lastElement();
const srcUrl = (srcWeb?.Document.data as WebField)?.url?.href?.match(/https?:\/\/[^/]*/)?.[0];
- const reg = new RegExp(Utils.prepend(""), "g");
+ const reg = new RegExp(Utils.prepend(''), 'g');
const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
- const backgroundColor = tags.map(tag => tag.match(/.*(background-color: ?[^;]*)/)?.[1]?.replace(/background-color: ?(.*)/, "$1")).filter(t => t)?.[0];
- const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: srcUrl ? "from:" + srcUrl : "-web clip-", _width: 300, _height: 300, backgroundColor });
- Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
+ const backgroundColor = tags.map(tag => tag.match(/.*(background-color: ?[^;]*)/)?.[1]?.replace(/background-color: ?(.*)/, '$1')).filter(t => t)?.[0];
+ const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: srcUrl ? 'from:' + srcUrl : '-web clip-', _width: 300, _height: 300, backgroundColor });
+ Doc.GetProto(htmlDoc)['data-text'] = Doc.GetProto(htmlDoc).text = text;
addDocument(htmlDoc);
if (srcWeb) {
- const iframe = SelectionManager.Views()[0].ContentDiv?.getElementsByTagName("iframe")?.[0];
- const focusNode = (iframe?.contentDocument?.getSelection()?.focusNode as any);
+ const iframe = SelectionManager.Views()[0].ContentDiv?.getElementsByTagName('iframe')?.[0];
+ const focusNode = iframe?.contentDocument?.getSelection()?.focusNode as any;
if (focusNode) {
const anchor = srcWeb?.ComponentView?.getAnchor?.();
anchor && DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor });
@@ -339,11 +354,10 @@ export function CollectionSubView<X>(moreProps?: X) {
}
if (uriList || text) {
- if ((uriList || text).includes("www.youtube.com/watch") || text.includes("www.youtube.com/embed")) {
-
- const batch = UndoManager.StartBatch("youtube upload");
+ if ((uriList || text).includes('www.youtube.com/watch') || text.includes('www.youtube.com/embed')) {
+ const batch = UndoManager.StartBatch('youtube upload');
const generatedDocuments: Doc[] = [];
- this.slowLoadDocuments((uriList || text).split("v=")[1].split("&")[0], options, generatedDocuments, text, completed, e.clientX, e.clientY, addDocument).then(batch.end);
+ this.slowLoadDocuments((uriList || text).split('v=')[1].split('&')[0], options, generatedDocuments, text, completed, e.clientX, e.clientY, addDocument).then(batch.end);
return;
}
@@ -374,15 +388,16 @@ export function CollectionSubView<X>(moreProps?: X) {
// alias._height = 512;
// alias._width = 400;
// addDocument(alias);
- // } else
+ // } else
{
- const newDoc = Docs.Create.WebDocument(uriList.split("#annotations:")[0], {// clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
+ const newDoc = Docs.Create.WebDocument(uriList.split('#annotations:')[0], {
+ // clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
...options,
- title: uriList.split("#annotations:")[0],
+ title: uriList.split('#annotations:')[0],
_width: 400,
_height: 512,
_nativeWidth: 850,
- useCors: true
+ useCors: true,
});
addDocument(newDoc);
}
@@ -394,82 +409,99 @@ export function CollectionSubView<X>(moreProps?: X) {
const files: File[] = [];
const generatedDocuments: Doc[] = [];
if (!length) {
- alert("No uploadable content found.");
+ alert('No uploadable content found.');
return;
}
- const batch = UndoManager.StartBatch("collection view drop");
+ const batch = UndoManager.StartBatch('collection view drop');
for (let i = 0; i < length; i++) {
const item = e.dataTransfer.items[i];
- if (item.kind === "string" && item.type.includes("uri")) {
+ if (item.kind === 'string' && item.type.includes('uri')) {
const stringContents = await new Promise<string>(resolve => item.getAsString(resolve));
- const type = (await rp.head(Utils.CorsProxy(stringContents)))["content-type"];
+ const type = (await rp.head(Utils.CorsProxy(stringContents)))['content-type'];
if (type) {
const doc = await DocUtils.DocumentFromType(type, Utils.CorsProxy(stringContents), options);
doc && generatedDocuments.push(doc);
}
}
- if (item.kind === "file") {
+ if (item.kind === 'file') {
const file = item.getAsFile();
file?.type && files.push(file);
- file?.type === "application/json" && Utils.readUploadedFileAsText(file).then(result => {
- const json = JSON.parse(result as string);
- addDocument(Docs.Create.TreeDocument(
- json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => {
- const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 });
- const proto = Doc.GetProto(label);
- proto._width = 120;
- proto._height = 20;
- return proto;
- }
- ), { _width: 150, _height: 600, title: "across", backgroundColor: "white", _singleLine: true }));
- });
+ file?.type === 'application/json' &&
+ Utils.readUploadedFileAsText(file).then(result => {
+ const json = JSON.parse(result as string);
+ addDocument(
+ Docs.Create.TreeDocument(
+ json['rectangular-puzzle'].crossword.clues[0].clue.map((c: any) => {
+ const label = Docs.Create.LabelDocument({ title: c['#text'], _width: 120, _height: 20 });
+ const proto = Doc.GetProto(label);
+ proto._width = 120;
+ proto._height = 20;
+ return proto;
+ }),
+ { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _singleLine: true }
+ )
+ );
+ });
}
}
this.slowLoadDocuments(files, options, generatedDocuments, text, completed, e.clientX, e.clientY, addDocument).then(batch.end);
}
- slowLoadDocuments = async (files: (File[] | string), options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, clientX: number, clientY: number, addDocument: (doc: Doc | Doc[]) => boolean) => {
- const disposer = OverlayView.Instance.addElement(
- <ReactLoading type={"spinningBubbles"} color={"green"} height={250} width={250} />, { x: clientX - 125, y: clientY - 125 });
- if (typeof files === "string") {
- generatedDocuments.push(...await DocUtils.uploadYoutubeVideo(files, options));
+ slowLoadDocuments = async (
+ files: File[] | string,
+ options: DocumentOptions,
+ generatedDocuments: Doc[],
+ text: string,
+ completed: ((doc: Doc[]) => void) | undefined,
+ clientX: number,
+ clientY: number,
+ addDocument: (doc: Doc | Doc[]) => boolean
+ ) => {
+ const disposer = OverlayView.Instance.addElement(<ReactLoading type={'spinningBubbles'} color={'green'} height={250} width={250} />, { x: clientX - 125, y: clientY - 125 });
+ if (typeof files === 'string') {
+ generatedDocuments.push(...(await DocUtils.uploadYoutubeVideo(files, options)));
} else {
- generatedDocuments.push(...await DocUtils.uploadFilesToDocs(files, options));
+ generatedDocuments.push(...(await DocUtils.uploadFilesToDocs(files, options)));
}
if (generatedDocuments.length) {
// Creating a dash document
const isFreeformView = this.props.Document._viewType === CollectionViewType.Freeform;
- const set = !isFreeformView ? generatedDocuments :
- generatedDocuments.length > 1 ? generatedDocuments.map(d => { DocUtils.iconify(d); return d; }) : [];
+ const set = !isFreeformView
+ ? generatedDocuments
+ : generatedDocuments.length > 1
+ ? generatedDocuments.map(d => {
+ DocUtils.iconify(d);
+ return d;
+ })
+ : [];
if (completed) completed(set);
else {
if (isFreeformView && generatedDocuments.length > 1) {
- addDocument(DocUtils.pileup(generatedDocuments, options.x as number, options.y as number)!,);
+ addDocument(DocUtils.pileup(generatedDocuments, options.x as number, options.y as number)!);
} else {
generatedDocuments.forEach(addDocument);
}
}
} else {
- if (text && !text.includes("https://")) {
+ if (text && !text.includes('https://')) {
addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 }));
} else {
- alert("Document upload failed - possibly an unsupported file type.");
+ alert('Document upload failed - possibly an unsupported file type.');
}
}
disposer();
- }
+ };
}
return CollectionSubView;
}
-import { DragManager, dropActionType } from "../../util/DragManager";
-import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox";
-import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { OverlayView } from "../OverlayView";
-import { GetEffectiveAcl, TraceMobx } from "../../../fields/util"; \ No newline at end of file
+import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
+import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DragManager, dropActionType } from '../../util/DragManager';
+import { SelectionManager } from '../../util/SelectionManager';
+import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+import { OverlayView } from '../OverlayView';
+import { CollectionView, CollectionViewProps } from './CollectionView';
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f5b9162d3..809a73a77 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -9,7 +9,6 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Ty
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
@@ -20,6 +19,7 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
import { DocumentView } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormView } from './collectionFreeForm';
@@ -27,7 +27,6 @@ import { CollectionSubView } from './CollectionSubView';
import './CollectionTreeView.scss';
import { TreeView } from './TreeView';
import React = require('react');
-import { FieldViewProps } from '../nodes/FieldView';
const _global = (window /* browser */ || global) /* node */ as any;
export type collectionTreeViewProps = {
@@ -81,7 +80,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
return this.doc.treeViewType === TreeViewType.fileSystem;
}
@computed get dashboardMode() {
- return this.doc === CurrentUserUtils.MyDashboards;
+ return this.doc === Doc.MyDashboards;
}
@observable _explainerHeight = 0; // height of the description of the tree view
@@ -92,9 +91,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@observable _isAnyChildContentActive = false;
whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
isContentActive = (outsideReaction?: boolean) =>
- CurrentUserUtils.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction)
- ? true
- : false;
+ Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction) ? true : false;
componentWillUnmount() {
this._isDisposing = true;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1576ec40f..f38efe578 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -9,12 +9,13 @@ import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types';
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 { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
+import { DashboardView } from '../DashboardView';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
@@ -35,26 +36,6 @@ import './CollectionView.scss';
export const COLLECTION_BORDER_WIDTH = 2;
const path = require('path');
-export enum CollectionViewType {
- Invalid = 'invalid',
- Freeform = 'freeform',
- Schema = 'schema',
- Docking = 'docking',
- Tree = 'tree',
- Stacking = 'stacking',
- Masonry = 'masonry',
- Multicolumn = 'multicolumn',
- Multirow = 'multirow',
- Time = 'time',
- Carousel = 'carousel',
- Carousel3D = '3D Carousel',
- Linear = 'linear',
- //Staff = "staff",
- Map = 'map',
- Grid = 'grid',
- Pile = 'pileup',
- StackedTimeline = 'stacked timeline',
-}
interface CollectionViewProps_ extends 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)
@@ -127,39 +108,26 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
};
screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()));
+ // prettier-ignore
private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => {
TraceMobx();
if (type === undefined) return null;
switch (type) {
default:
- case CollectionViewType.Freeform:
- return <CollectionFreeFormView key="collview" {...props} />;
- case CollectionViewType.Schema:
- return <CollectionSchemaView key="collview" {...props} />;
- case CollectionViewType.Docking:
- return <CollectionDockingView key="collview" {...props} />;
- case CollectionViewType.Tree:
- return <CollectionTreeView key="collview" {...props} />;
- case CollectionViewType.Multicolumn:
- return <CollectionMulticolumnView key="collview" {...props} />;
- case CollectionViewType.Multirow:
- return <CollectionMultirowView key="collview" {...props} />;
- case CollectionViewType.Linear:
- return <CollectionLinearView key="collview" {...props} />;
- case CollectionViewType.Pile:
- return <CollectionPileView key="collview" {...props} />;
- case CollectionViewType.Carousel:
- return <CollectionCarouselView key="collview" {...props} />;
- case CollectionViewType.Carousel3D:
- return <CollectionCarousel3DView key="collview" {...props} />;
- case CollectionViewType.Stacking:
- return <CollectionStackingView key="collview" {...props} />;
- case CollectionViewType.Masonry:
- return <CollectionStackingView key="collview" {...props} />;
- case CollectionViewType.Time:
- return <CollectionTimeView key="collview" {...props} />;
- case CollectionViewType.Grid:
- return <CollectionGridView key="collview" {...props} />;
+ case CollectionViewType.Freeform: return <CollectionFreeFormView key="collview" {...props} />;
+ case CollectionViewType.Schema: return <CollectionSchemaView key="collview" {...props} />;
+ case CollectionViewType.Docking: return <CollectionDockingView key="collview" {...props} />;
+ case CollectionViewType.Tree: return <CollectionTreeView key="collview" {...props} />;
+ case CollectionViewType.Multicolumn: return <CollectionMulticolumnView key="collview" {...props} />;
+ case CollectionViewType.Multirow: return <CollectionMultirowView key="collview" {...props} />;
+ case CollectionViewType.Linear: return <CollectionLinearView key="collview" {...props} />;
+ case CollectionViewType.Pile: return <CollectionPileView key="collview" {...props} />;
+ case CollectionViewType.Carousel: return <CollectionCarouselView key="collview" {...props} />;
+ case CollectionViewType.Carousel3D: return <CollectionCarousel3DView key="collview" {...props} />;
+ case CollectionViewType.Stacking: return <CollectionStackingView key="collview" {...props} />;
+ case CollectionViewType.Masonry: return <CollectionStackingView key="collview" {...props} />;
+ case CollectionViewType.Time: return <CollectionTimeView key="collview" {...props} />;
+ case CollectionViewType.Grid: return <CollectionGridView key="collview" {...props} />;
//case CollectionViewType.Staff: return <CollectionStaffView key="collview" {...props} />;
}
};
@@ -193,7 +161,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
onContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
if (e.nativeEvent.cancelBubble) return; // nested calls to React to render can cause the same event to trigger in the outer view even if the inner view has handled it. This avoid CollectionDockingView menu options from being added when the event has been handled by a sub-document.
- if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== CurrentUserUtils.MainDocId) {
+ if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== Doc.MainDocId) {
// 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...',
@@ -235,7 +203,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
});
}
if (this.Document._viewType === CollectionViewType.Docking) {
- optionItems.push({ description: 'Create Dashboard', event: () => CurrentUserUtils.createNewDashboard(), icon: 'project-diagram' });
+ optionItems.push({ description: 'Create Dashboard', event: () => DashboardView.createNewDashboard(), icon: 'project-diagram' });
}
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
@@ -286,9 +254,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
return StrCast(this.rootDoc.childLayoutString);
}
- isContentActive = (outsideReaction?: boolean) => {
- return this.props.isContentActive();
- };
+ isContentActive = (outsideReaction?: boolean) => this.props.isContentActive();
+
render() {
TraceMobx();
const props: SubCollectionViewProps = {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index c0a61c90f..b8aaea622 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -9,18 +9,20 @@ import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { FieldId } from '../../../fields/RefField';
+import { listSpec } from '../../../fields/Schema';
+import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { DocUtils } from '../../documents/Documents';
-import { DocumentType } from '../../documents/DocumentTypes';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { DashboardView } from '../DashboardView';
import { Colors, Shadows } from '../global/globalEnums';
import { LightboxView } from '../LightboxView';
import { MainView } from '../MainView';
@@ -30,11 +32,9 @@ import { PinProps, PresBox, PresMovement } from '../nodes/trails';
import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
import { CollectionDockingView } from './CollectionDockingView';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { CollectionView, CollectionViewType } from './CollectionView';
+import { CollectionView } from './CollectionView';
import './TabDocView.scss';
import React = require('react');
-import { listSpec } from '../../../fields/Schema';
-import { ScriptField } from '../../../fields/ScriptField';
const _global = (window /* browser */ || global) /* node */ as any;
interface TabDocViewProps {
@@ -215,7 +215,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
const batch = UndoManager.StartBatch('pinning doc');
// all docs will be added to the ActivePresentation as stored on CurrentUserUtils
- const curPres = CurrentUserUtils.ActivePresentation;
+ const curPres = Doc.ActivePresentation;
curPres &&
docList.forEach(doc => {
// Edge Case 1: Cannot pin document to itself
@@ -306,7 +306,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
.map(d => d.DashDoc)
.includes(curPres)
) {
- const docs = Cast(CurrentUserUtils.MyOverlayDocs.data, listSpec(Doc), []);
+ const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []);
if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
CollectionDockingView.AddSplit(curPres, 'right');
setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
@@ -361,7 +361,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
const locationParams = locationFields.length > 1 ? locationFields[1] : '';
switch (locationFields[0]) {
case 'dashboard':
- return CurrentUserUtils.openDashboard(doc);
+ return DashboardView.openDashboard(doc);
case 'close':
return CollectionDockingView.CloseSplit(doc, locationParams);
case 'fullScreen':
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 704b8989a..eb5faf4e1 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,7 +1,7 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
+import { observer } from 'mobx-react';
import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
@@ -12,26 +12,25 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Ty
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, returnTrue, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
-import { DocumentType } from "../../documents/DocumentTypes";
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
-import { DocumentManager, DocFocusOrOpen } from '../../util/DocumentManager';
-import { DragManager, dropActionType } from "../../util/DragManager";
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
-import { EditableView } from "../EditableView";
+import { EditableView } from '../EditableView';
import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss';
import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
+import { KeyValueBox } from '../nodes/KeyValueBox';
import { StyleProp } from '../StyleProvider';
import { CollectionTreeView, TreeViewType } from './CollectionTreeView';
-import { CollectionView, CollectionViewType } from './CollectionView';
-import "./TreeView.scss";
-import React = require("react");
-import { KeyValueBox } from '../nodes/KeyValueBox';
-import { FieldViewProps } from '../nodes/FieldView';
+import { CollectionView } from './CollectionView';
+import './TreeView.scss';
+import React = require('react');
export interface TreeViewProps {
treeView: CollectionTreeView;
@@ -55,7 +54,7 @@ export interface TreeViewProps {
indentDocument?: (editTitle: boolean) => void;
outdentDocument?: (editTitle: boolean) => void;
ScreenToLocalTransform: () => Transform;
- contextMenuItems: { script: ScriptField, filter: ScriptField, icon: string, label: string }[];
+ contextMenuItems: { script: ScriptField; filter: ScriptField; icon: string; label: string }[];
dontRegisterView?: boolean;
styleProvider?: StyleProviderFunc | undefined;
treeViewHideHeaderFields: () => boolean;
@@ -70,24 +69,26 @@ export interface TreeViewProps {
hierarchyIndex?: number[];
}
-const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
+const treeBulletWidth = function () {
+ return Number(TREE_BULLET_WIDTH.replace('px', ''));
+};
export enum TreeSort {
- Up = "up",
- Down = "down",
- Zindex = "z",
- None = "none"
+ Up = 'up',
+ Down = 'down',
+ Zindex = 'z',
+ None = 'none',
}
/**
* Renders a treeView of a collection of documents
- *
+ *
* special fields:
* treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden
* treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
*/
@observer
export class TreeView extends React.Component<TreeViewProps> {
- static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
+ static _editTitleOnLoad: Opt<{ id: string; parent: TreeView | CollectionTreeView | undefined }>;
static _openTitleScript: Opt<ScriptField | undefined>;
static _openLevelScript: Opt<ScriptField | undefined>;
private _header: React.RefObject<HTMLDivElement> = React.createRef();
@@ -98,7 +99,9 @@ export class TreeView extends React.Component<TreeViewProps> {
private _openScript: (() => ScriptField) | undefined;
private _treedropDisposer?: DragManager.DragDropDisposer;
- get treeViewOpenIsTransient() { return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsPrototype(this.doc); }
+ get treeViewOpenIsTransient() {
+ return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsPrototype(this.doc);
+ }
set treeViewOpen(c: boolean) {
if (this.treeViewOpenIsTransient) this._transientOpenState = c;
else {
@@ -109,26 +112,61 @@ export class TreeView extends React.Component<TreeViewProps> {
@observable _transientOpenState = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
@observable _editTitle: boolean = false;
@observable _dref: DocumentView | undefined | null;
- get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
+ get displayName() {
+ return 'TreeView(' + this.props.document.title + ')';
+ } // this makes mobx trace() statements more descriptive
get defaultExpandedView() {
- return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey :
- this.props.treeView.dashboardMode ? this.fieldKey :
- this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") : // for displaying
- this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
- }
-
- @computed get doc() { return this.props.document; }
- @computed get treeViewOpen() { return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._transientOpenState; }
- @computed get treeViewExpandedView() { return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; }
- @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
- @computed get dataDoc() { return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym]; }
- @computed get layoutDoc() { return Doc.Layout(this.doc); }
- @computed get fieldKey() { return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); }
- @computed get childDocs() { return this.childDocList(this.fieldKey); }
- @computed get childLinks() { return this.childDocList("links"); }
- @computed get childAliases() { return this.childDocList("aliases"); }
- @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
- @computed get selected() { return SelectionManager.IsSelected(this._docRef); }
+ return this.doc.viewType === CollectionViewType.Docking
+ ? this.fieldKey
+ : this.props.treeView.dashboardMode
+ ? this.fieldKey
+ : this.props.treeView.fileSysMode
+ ? this.doc.isFolder
+ ? this.fieldKey
+ : 'aliases' // for displaying
+ : this.props.treeView.outlineMode || this.childDocs
+ ? this.fieldKey
+ : Doc.noviceMode
+ ? 'layout'
+ : StrCast(this.props.treeView.doc.treeViewExpandedView, 'fields');
+ }
+
+ @computed get doc() {
+ return this.props.document;
+ }
+ @computed get treeViewOpen() {
+ return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeViewOpen', 'boolean', true)) || this._transientOpenState;
+ }
+ @computed get treeViewExpandedView() {
+ return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView;
+ }
+ @computed get MAX_EMBED_HEIGHT() {
+ return NumCast(this.props.containerCollection.maxEmbedHeight, 200);
+ }
+ @computed get dataDoc() {
+ return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym];
+ }
+ @computed get layoutDoc() {
+ return Doc.Layout(this.doc);
+ }
+ @computed get fieldKey() {
+ return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc));
+ }
+ @computed get childDocs() {
+ return this.childDocList(this.fieldKey);
+ }
+ @computed get childLinks() {
+ return this.childDocList('links');
+ }
+ @computed get childAliases() {
+ return this.childDocList('aliases');
+ }
+ @computed get childAnnos() {
+ return this.childDocList(this.fieldKey + '-annotations');
+ }
+ @computed get selected() {
+ return SelectionManager.IsSelected(this._docRef);
+ }
// SelectionManager.Views().lastElement()?.props.Document === this.props.document; }
@observable _presTimer!: NodeJS.Timeout;
@@ -136,64 +174,76 @@ export class TreeView extends React.Component<TreeViewProps> {
@observable _selectedArray: ObservableMap = new ObservableMap<Doc, any>();
// the selected item's index
- @computed get itemIndex() { return NumCast(this.doc._itemIndex); }
- // the item that's active
- @computed get activeItem() { return this.childDocs ? Cast(this.childDocs[NumCast(this.doc._itemIndex)], Doc, null) : undefined; }
- @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); }
+ @computed get itemIndex() {
+ return NumCast(this.doc._itemIndex);
+ }
+ // the item that's active
+ @computed get activeItem() {
+ return this.childDocs ? Cast(this.childDocs[NumCast(this.doc._itemIndex)], Doc, null) : undefined;
+ }
+ @computed get targetDoc() {
+ return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
+ }
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
+ 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
+ DocListCastOrNull(this.doc[field])
+ ); // otherwise use the document's data field
}
@undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
- if (this.doc !== target && addDoc !== returnFalse) { // bcz: this should all be running in a Temp undo batch instead of hackily testing for returnFalse
+ if (this.doc !== target && addDoc !== returnFalse) {
+ // bcz: this should all be running in a Temp undo batch instead of hackily testing for returnFalse
if (this.props.removeDoc?.(doc) === true) {
return addDoc(doc);
}
}
return false;
- }
+ };
@undoBatch @action remove = (doc: Doc | Doc[], key: string) => {
this.props.treeView.props.select(false);
const ind = this.dataDoc[key].indexOf(doc);
const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
return res;
- }
+ };
@action setEditTitle = (docView?: DocumentView) => {
this._selDisposer?.();
if (!docView) {
this._editTitle = false;
- }
- else if (docView.isSelected()) {
+ } else if (docView.isSelected()) {
const doc = docView.Document;
SelectionManager.SelectSchemaViewDoc(doc);
this._editTitle = true;
- this._selDisposer = reaction(() => SelectionManager.SelectedSchemaDoc(), seldoc => seldoc !== doc && this.setEditTitle(undefined));
+ this._selDisposer = reaction(
+ () => SelectionManager.SelectedSchemaDoc(),
+ seldoc => seldoc !== doc && this.setEditTitle(undefined)
+ );
} else {
docView.select(false);
}
- }
+ };
@action
openLevel = (docView: DocumentView) => {
if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
this.treeViewOpen = !this.treeViewOpen;
} else {
// choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias
- const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+ const bestAlias =
+ docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
- this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox");
+ this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), 'lightbox');
}
- }
+ };
constructor(props: any) {
super(props);
if (!TreeView._openLevelScript) {
- TreeView._openTitleScript = ScriptField.MakeScript("scriptContext.setEditTitle(documentView)", { scriptContext: "any", documentView: "any" });
- TreeView._openLevelScript = ScriptField.MakeScript(`scriptContext.openLevel(documentView)`, { scriptContext: "any", documentView: "any" });
+ TreeView._openTitleScript = ScriptField.MakeScript('scriptContext.setEditTitle(documentView)', { scriptContext: 'any', documentView: 'any' });
+ TreeView._openLevelScript = ScriptField.MakeScript(`scriptContext.openLevel(documentView)`, { scriptContext: 'any', documentView: 'any' });
}
this._openScript = Doc.IsSystem(this.props.document) ? undefined : () => TreeView._openLevelScript!;
this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
@@ -202,16 +252,16 @@ export class TreeView extends React.Component<TreeViewProps> {
_treeEle: any;
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this)), this.doc);
+ ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.doc);
if (this._treeEle) this.props.unobserveHeight(this._treeEle);
- this.props.observeHeight(this._treeEle = ele);
- }
+ this.props.observeHeight((this._treeEle = ele));
+ };
componentWillUnmount() {
this._selDisposer?.();
this._treeEle && this.props.unobserveHeight(this._treeEle);
- document.removeEventListener("pointermove", this.onDragMove, true);
- document.removeEventListener("pointermove", this.onDragUp, true);
+ document.removeEventListener('pointermove', this.onDragMove, true);
+ document.removeEventListener('pointermove', this.onDragUp, true);
// TODO: [AL] add these
this.props.hierarchyIndex !== undefined && this.props.RemFromMap?.(this.doc, this.props.hierarchyIndex);
}
@@ -225,49 +275,60 @@ export class TreeView extends React.Component<TreeViewProps> {
}
onDragUp = (e: PointerEvent) => {
- document.removeEventListener("pointerup", this.onDragUp, true);
- document.removeEventListener("pointermove", this.onDragMove, true);
- }
+ document.removeEventListener('pointerup', this.onDragUp, true);
+ document.removeEventListener('pointermove', this.onDragMove, true);
+ };
onPointerEnter = (e: React.PointerEvent): void => {
this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
- this._header.current!.className = "treeView-header";
- document.removeEventListener("pointermove", this.onDragMove, true);
- document.removeEventListener("pointerup", this.onDragUp, true);
- document.addEventListener("pointermove", this.onDragMove, true);
- document.addEventListener("pointerup", this.onDragUp, true);
+ this._header.current!.className = 'treeView-header';
+ document.removeEventListener('pointermove', this.onDragMove, true);
+ document.removeEventListener('pointerup', this.onDragUp, true);
+ document.addEventListener('pointermove', this.onDragMove, true);
+ document.addEventListener('pointerup', this.onDragUp, true);
}
- }
+ };
onPointerLeave = (e: React.PointerEvent): void => {
Doc.UnBrushDoc(this.dataDoc);
- if (this._header.current?.className !== "treeView-header-editing") {
- this._header.current!.className = "treeView-header";
+ if (this._header.current?.className !== 'treeView-header-editing') {
+ this._header.current!.className = 'treeView-header';
}
- document.removeEventListener("pointerup", this.onDragUp, true);
- document.removeEventListener("pointermove", this.onDragMove, true);
- }
+ document.removeEventListener('pointerup', this.onDragUp, true);
+ document.removeEventListener('pointermove', this.onDragMove, true);
+ };
onDragMove = (e: PointerEvent): void => {
Doc.UnBrushDoc(this.dataDoc);
const pt = [e.clientX, e.clientY];
const rect = this._header.current!.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
- const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
- this._header.current!.className = "treeView-header";
+ const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocList.length);
+ this._header.current!.className = 'treeView-header';
if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.rootDoc) {
- 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();
- }
+ };
public static makeTextBullet() {
- const bullet = Docs.Create.TextDocument("-text-", {
- layout: CollectionView.LayoutString("data"),
- title: "-title-",
- treeViewExpandedViewLock: true, treeViewExpandedView: "data",
- _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: TreeViewType.outline,
- x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _width: 1000, _height: 10
+ const bullet = Docs.Create.TextDocument('-text-', {
+ layout: CollectionView.LayoutString('data'),
+ title: '-title-',
+ treeViewExpandedViewLock: true,
+ treeViewExpandedView: 'data',
+ _viewType: CollectionViewType.Tree,
+ hideLinkButton: true,
+ _showSidebar: true,
+ treeViewType: TreeViewType.outline,
+ x: 0,
+ y: 0,
+ _xMargin: 0,
+ _yMargin: 0,
+ _autoHeight: true,
+ _singleLine: true,
+ _width: 1000,
+ _height: 10,
});
Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text');
Doc.GetProto(bullet).data = new List<Doc>([]);
@@ -279,19 +340,19 @@ export class TreeView extends React.Component<TreeViewProps> {
const bullet = TreeView.makeTextBullet();
TreeView._editTitleOnLoad = { id: bullet[Id], parent: this };
return this.props.addDocument(bullet);
- }
+ };
makeFolder = () => {
- const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true });
+ const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true });
TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
return this.props.addDocument(folder);
- }
+ };
deleteItem = () => this.props.removeDoc?.(this.doc);
preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
const dragData = de.complete.docDragData;
- dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? "same" : dragData.dropAction);
- }
+ dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
+ };
@undoBatch
treeDrop = (e: Event, de: DragManager.DropEvent) => {
@@ -299,11 +360,11 @@ export class TreeView extends React.Component<TreeViewProps> {
if (!this._header.current) return;
const rect = this._header.current.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
- const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
+ const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocList.length);
if (de.complete.linkDragData) {
const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
const destDoc = this.doc;
- DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link", "");
+ DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, 'tree link', '');
e.stopPropagation();
}
const docDragData = de.complete.docDragData;
@@ -313,22 +374,16 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
}
}
- }
+ };
dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before);
- const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes("add")) || forceAdd;
- const localAdd = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) && ((doc.context = this.doc.context) || true) ? true : false;
- const addDoc = !inside ? parentAddDoc :
- (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean);
- const move = (!dropAction || dropAction === "proto" || dropAction === "move" || dropAction === "same") && moveDocument;
+ const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes('add')) || forceAdd;
+ const localAdd = (doc: Doc) => (Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) && ((doc.context = this.doc.context) || true) ? true : false);
+ const addDoc = !inside ? parentAddDoc : (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean);
+ const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
if (canAdd) {
- return UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) =>
- (move ?
- move(d, undefined, addDoc) || (dropAction === "proto" ? addDoc(d) : false)
- :
- addDoc(d)) || added,
- false));
+ return UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
}
return false;
}
@@ -339,7 +394,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const outerXf = Utils.GetScreenTransform(this.props.treeView.MainEle());
const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
- }
+ };
docTransform = () => this.refTransform(this._dref?.ContentRef?.current);
getTransform = () => this.refTransform(this._tref.current);
docWidth = () => {
@@ -348,22 +403,25 @@ export class TreeView extends React.Component<TreeViewProps> {
if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]());
if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth()));
return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
- }
+ };
docHeight = () => {
const layoutDoc = this.layoutDoc;
- return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
- const aspect = Doc.NativeAspect(layoutDoc);
- if (aspect) return this.docWidth() / (aspect || 1);
- return layoutDoc._fitWidth ?
- (!Doc.NativeHeight(this.doc) ?
- NumCast(this.props.containerCollection._height)
- :
- Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc)) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height))
- ))
- :
- (layoutDoc[HeightSym]() || 50);
- })()));
- }
+ return Math.max(
+ 70,
+ Math.min(
+ this.MAX_EMBED_HEIGHT,
+ (() => {
+ const aspect = Doc.NativeAspect(layoutDoc);
+ if (aspect) return this.docWidth() / (aspect || 1);
+ return layoutDoc._fitWidth
+ ? !Doc.NativeHeight(this.doc)
+ ? NumCast(this.props.containerCollection._height)
+ : Math.min((this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height)))
+ : layoutDoc[HeightSym]() || 50;
+ })()
+ )
+ );
+ };
@computed get expandedField() {
const ids: { [key: string]: string } = {};
@@ -372,11 +430,11 @@ export class TreeView extends React.Component<TreeViewProps> {
doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
for (const key of Object.keys(ids).slice().sort()) {
- if (this.props.skipFields?.includes(key) || key === "title" || key === "treeViewOpen") continue;
+ if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeViewOpen') continue;
const contents = doc[key];
let contentElement: (JSX.Element | null)[] | JSX.Element = [];
- if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && (Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc))) {
+ if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
const added = Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
@@ -384,74 +442,109 @@ export class TreeView extends React.Component<TreeViewProps> {
return added;
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
- contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents),
- this.props.treeView, this, doc, undefined, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
- this.props.dropAction, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.isContentActive,
- this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
- [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems(),
+ contentElement = TreeView.GetChildElements(
+ contents instanceof Doc ? [contents] : DocListCast(contents),
+ this.props.treeView,
+ this,
+ doc,
+ undefined,
+ this.props.containerCollection,
+ this.props.prevSibling,
+ addDoc,
+ remDoc,
+ this.move,
+ this.props.dropAction,
+ this.props.addDocTab,
+ this.titleStyleProvider,
+ this.props.ScreenToLocalTransform,
+ this.props.isContentActive,
+ this.props.panelWidth,
+ this.props.renderDepth,
+ this.props.treeViewHideHeaderFields,
+ [...this.props.renderedIds, doc[Id]],
+ this.props.onCheckedClick,
+ this.props.onChildClick,
+ this.props.skipFields,
+ false,
+ this.props.whenChildContentsActiveChanged,
+ this.props.dontRegisterView,
+ emptyFunction,
+ emptyFunction,
+ this.childContextMenuItems(),
// TODO: [AL] Add these
this.props.AddToMap,
this.props.RemFromMap,
this.props.hierarchyIndex
);
} else {
- contentElement = <EditableView key="editableView"
- contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
- height={13}
- fontSize={12}
- GetValue={() => Field.toKeyValueString(doc, key)}
- SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)} />;
+ contentElement = (
+ <EditableView
+ key="editableView"
+ contents={contents !== undefined ? Field.toString(contents as Field) : 'null'}
+ height={13}
+ fontSize={12}
+ GetValue={() => Field.toKeyValueString(doc, key)}
+ SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+ />
+ );
}
- rows.push(<div style={{ display: "flex" }} key={key}>
- <span style={{ fontWeight: "bold" }}>{key + ":"}</span>
- &nbsp;
- {contentElement}
- </div>);
+ rows.push(
+ <div style={{ display: 'flex' }} key={key}>
+ <span style={{ fontWeight: 'bold' }}>{key + ':'}</span>
+ &nbsp;
+ {contentElement}
+ </div>
+ );
}
- rows.push(<div style={{ display: "flex" }} key={"newKeyValue"}>
- <EditableView
- key="editableView"
- contents={"+key:value"}
- height={13}
- fontSize={12}
- GetValue={returnEmptyString}
- SetValue={value => value.indexOf(":") !== -1 && KeyValueBox.SetField(doc, value.substring(0, value.indexOf(":")), value.substring(value.indexOf(":") + 1, value.length), true)} />
- </div>);
+ rows.push(
+ <div style={{ display: 'flex' }} key={'newKeyValue'}>
+ <EditableView
+ key="editableView"
+ contents={'+key:value'}
+ height={13}
+ fontSize={12}
+ GetValue={returnEmptyString}
+ SetValue={value => value.indexOf(':') !== -1 && KeyValueBox.SetField(doc, value.substring(0, value.indexOf(':')), value.substring(value.indexOf(':') + 1, value.length), true)}
+ />
+ </div>
+ );
return rows;
}
rtfWidth = () => {
- const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ""))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
- return Math.min(layout[WidthSym](), (this.props.panelWidth() - treeBulletWidth())) / (this.props.treeView.props.scaling?.() || 1);
- }
+ const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+ return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1);
+ };
rtfHeight = () => {
- const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ""))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+ const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
return this.rtfWidth() <= layout[WidthSym]() ? Math.min(layout[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
- }
+ };
rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth());
expandPanelHeight = () => {
if (this.layoutDoc._fitWidth) return this.docHeight();
const aspect = this.layoutDoc[WidthSym]() / this.layoutDoc[HeightSym]();
const docAspect = this.docWidth() / this.docHeight();
- return (docAspect < aspect) ? this.docWidth() / aspect : this.docHeight();
- }
+ return docAspect < aspect ? this.docWidth() / aspect : this.docHeight();
+ };
expandPanelWidth = () => {
if (this.layoutDoc._fitWidth) return this.docWidth();
const aspect = this.layoutDoc[WidthSym]() / this.layoutDoc[HeightSym]();
const docAspect = this.docWidth() / this.docHeight();
- return (docAspect > aspect) ? this.docHeight() * aspect : this.docWidth();
- }
+ return docAspect > aspect ? this.docHeight() * aspect : this.docWidth();
+ };
@computed get renderContent() {
TraceMobx();
const expandKey = this.treeViewExpandedView;
- const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } };
- if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) {
+ const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } };
+ if (['links', 'annotations', 'aliases', this.fieldKey].includes(expandKey)) {
const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
const sortKeys = Object.keys(sortings);
- const curSortIndex = Math.max(0, sortKeys.findIndex(val => val === sorting));
- const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey;
+ const curSortIndex = Math.max(
+ 0,
+ sortKeys.findIndex(val => val === sorting)
+ );
+ const key = (expandKey === 'annotations' ? `${this.fieldKey}-` : '') + expandKey;
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
// if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
@@ -461,107 +554,161 @@ export class TreeView extends React.Component<TreeViewProps> {
const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
docs.push(doc);
- docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1).forEach((d, i) => d.zIndex = i);
+ docs.sort((a, b) => (NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1)).forEach((d, i) => (d.zIndex = i));
}
const added = Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
added && (doc.context = this.doc.context);
return added;
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
- const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
- let downX = 0, downY = 0;
- return <>
- {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? (null) : <div className={'treeView-sorting'} style={{ background: sortings[sorting]?.color }} >
- {sortings[sorting]?.label}
- </div>}
- <ul key={expandKey + "more"} title="click to change sort order" className={this.doc.treeViewHideTitle ? "no-indent" : ""}
- onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
- onClick={(e) => {
- if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
- !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
+ const docs = expandKey === 'aliases' ? this.childAliases : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs;
+ let downX = 0,
+ downY = 0;
+ return (
+ <>
+ {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : (
+ <div className={'treeView-sorting'} style={{ background: sortings[sorting]?.color }}>
+ {sortings[sorting]?.label}
+ </div>
+ )}
+ <ul
+ key={expandKey + 'more'}
+ title="click to change sort order"
+ className={this.doc.treeViewHideTitle ? 'no-indent' : ''}
+ onPointerDown={e => {
+ downX = e.clientX;
+ downY = e.clientY;
e.stopPropagation();
- }
- }}>
- {!docs ? (null) :
- TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc,
- this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
- StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
- this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
- [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems(),
- // TODO: [AL] add these
- this.props.AddToMap,
- this.props.RemFromMap,
- this.props.hierarchyIndex)}
- </ul >
- </>;
- } else if (this.treeViewExpandedView === "fields") {
- return <ul key={this.doc[Id] + this.doc.title}>
- <div style={{ display: "inline-block" }} >
- {this.expandedField}
- </div>
- </ul>;
+ }}
+ onClick={e => {
+ if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
+ !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
+ e.stopPropagation();
+ }
+ }}>
+ {!docs
+ ? null
+ : TreeView.GetChildElements(
+ docs,
+ this.props.treeView,
+ this,
+ this.layoutDoc,
+ this.dataDoc,
+ this.props.containerCollection,
+ this.props.prevSibling,
+ addDoc,
+ remDoc,
+ this.move,
+ StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType,
+ this.props.addDocTab,
+ this.titleStyleProvider,
+ this.props.ScreenToLocalTransform,
+ this.props.isContentActive,
+ this.props.panelWidth,
+ this.props.renderDepth,
+ this.props.treeViewHideHeaderFields,
+ [...this.props.renderedIds, this.doc[Id]],
+ this.props.onCheckedClick,
+ this.props.onChildClick,
+ this.props.skipFields,
+ false,
+ this.props.whenChildContentsActiveChanged,
+ this.props.dontRegisterView,
+ emptyFunction,
+ emptyFunction,
+ this.childContextMenuItems(),
+ // TODO: [AL] add these
+ this.props.AddToMap,
+ this.props.RemFromMap,
+ this.props.hierarchyIndex
+ )}
+ </ul>
+ </>
+ );
+ } else if (this.treeViewExpandedView === 'fields') {
+ return (
+ <ul key={this.doc[Id] + this.doc.title}>
+ <div style={{ display: 'inline-block' }}>{this.expandedField}</div>
+ </ul>
+ );
}
- return <ul onPointerDown={e => { e.preventDefault(); e.stopPropagation(); }}>{this.renderEmbeddedDocument(false, this.props.treeView.props.childDocumentsActive ?? returnFalse)}</ul>; // "layout"
+ return (
+ <ul
+ onPointerDown={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ }}>
+ {this.renderEmbeddedDocument(false, this.props.treeView.props.childDocumentsActive ?? returnFalse)}
+ </ul>
+ ); // "layout"
}
- get onCheckedClick() { return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick); }
+ get onCheckedClick() {
+ return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick);
+ }
@action
bulletClick = (e: React.MouseEvent) => {
if (this.onCheckedClick) {
- this.onCheckedClick?.script.run({
- this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
- heading: this.props.containerCollection.title,
- checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? "remove" : "check",
- containingTreeView: this.props.treeView.props.Document,
- }, console.log);
+ this.onCheckedClick?.script.run(
+ {
+ this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
+ heading: this.props.containerCollection.title,
+ checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check',
+ containingTreeView: this.props.treeView.props.Document,
+ },
+ console.log
+ );
} else {
this.treeViewOpen = !this.treeViewOpen;
}
e.stopPropagation();
- }
+ };
@computed get renderBullet() {
TraceMobx();
- const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ":open" : "")) || "question";
- const checked = this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
- return <div className={`bullet${this.props.treeView.outlineMode ? "-outline" : ""}`} key={"bullet"}
- title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
- onClick={this.bulletClick}
- style={this.props.treeView.outlineMode ?
- {
- opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity)
- } :
- {
- pointerEvents: this.props.isContentActive() ? "all" : undefined,
- opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4,
- color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
- }}>
- {this.props.treeView.outlineMode ?
- !(this.doc.text as RichTextField)?.Text ? (null) :
- <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"]} /> :
- <div className="treeView-bulletIcons" >
- <div className={`treeView-${this.onCheckedClick ? "checkIcon" : "expandIcon"}`}>
- <FontAwesomeIcon size="sm" icon={
- checked === "check" ? "check" :
- checked === "x" ? "times" :
- checked === "unchecked" ? "square" :
- !this.treeViewOpen ? "caret-right" : "caret-down"} />
+ const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : '')) || 'question';
+ const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined;
+ return (
+ <div
+ className={`bullet${this.props.treeView.outlineMode ? '-outline' : ''}`}
+ key={'bullet'}
+ title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : 'view fields'}
+ onClick={this.bulletClick}
+ style={
+ this.props.treeView.outlineMode
+ ? {
+ opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity),
+ }
+ : {
+ pointerEvents: this.props.isContentActive() ? 'all' : undefined,
+ opacity: checked === 'unchecked' || typeof iconType !== 'string' ? undefined : 0.4,
+ color: StrCast(this.doc.color, checked === 'unchecked' ? 'white' : 'inherit'),
+ }
+ }>
+ {this.props.treeView.outlineMode ? (
+ !(this.doc.text as RichTextField)?.Text ? null : (
+ <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />
+ )
+ ) : (
+ <div className="treeView-bulletIcons">
+ <div className={`treeView-${this.onCheckedClick ? 'checkIcon' : 'expandIcon'}`}>
+ <FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />
+ </div>
+ {this.onCheckedClick ? null : typeof iconType === 'string' ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
</div>
- {this.onCheckedClick ? (null) : typeof iconType === "string" ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
- </div>
- }
- </div>;
+ )}
+ </div>
+ );
}
@computed get validExpandViewTypes() {
- const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length && !this.props.treeView.dashboardMode ? "annotations" : "";
- const links = () => DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? "links" : "";
- const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : "";
- const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases";
- const fields = () => Doc.noviceMode ? "" : "fields";
- const layout = (Doc.noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"];
+ const annos = () => (DocListCast(this.doc[this.fieldKey + '-annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : '');
+ const links = () => (DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? 'links' : '');
+ const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
+ const aliases = () => (this.props.treeView.dashboardMode ? '' : 'aliases');
+ const fields = () => (Doc.noviceMode ? '' : 'fields');
+ const layout = Doc.noviceMode || this.doc.viewType === CollectionViewType.Docking ? [] : ['layout'];
return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m);
}
@action
@@ -571,49 +718,68 @@ export class TreeView extends React.Component<TreeViewProps> {
this.doc.treeViewExpandedView = next(this.validExpandViewTypes);
}
this.treeViewOpen = true;
- }
+ };
@computed get headerElements() {
- return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? (null)
- : <>
- {this.doc.hideContextMenu ? (null) : <FontAwesomeIcon title="context menu" key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />}
- {this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? (null) :
+ return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
+ <>
+ {this.doc.hideContextMenu ? null : (
+ <FontAwesomeIcon
+ title="context menu"
+ key="bars"
+ icon="bars"
+ size="sm"
+ onClick={e => {
+ this.showContextMenu(e);
+ e.stopPropagation();
+ }}
+ />
+ )}
+ {this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : (
<span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}>
{this.treeViewExpandedView}
- </span>}
- </>;
+ </span>
+ )}
+ </>
+ );
}
showContextMenu = (e: React.MouseEvent) => {
DocumentViewInternal.SelectAfterContextMenu = false;
simulateMouseClick(this._docRef?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
DocumentViewInternal.SelectAfterContextMenu = true;
- }
+ };
contextMenuItems = () => {
- 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 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 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), ... (this.doc.isFolder ? folderOp :
- Doc.IsSystem(this.doc) ? [] :
- this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
- [openAlias, makeFolder] :
- this.doc.viewType === CollectionViewType.Docking ? [] :
- [deleteItem, openAlias, focusDoc])];
- }
+ const openAlias = { script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, 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)),
+ ...(this.doc.isFolder
+ ? folderOp
+ : Doc.IsSystem(this.doc)
+ ? []
+ : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
+ ? [openAlias, makeFolder]
+ : this.doc.viewType === CollectionViewType.Docking
+ ? []
+ : [deleteItem, openAlias, focusDoc]),
+ ];
+ };
childContextMenuItems = () => {
const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
const icons = StrListCast(this.doc.childContextMenuIcons);
return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
- }
+ };
onChildClick = () => {
return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
- }
+ };
- onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick,(!this.props.treeView.outlineMode ? this._openScript?.():null));
+ onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null);
refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document);
ignoreEvent = (e: any) => {
@@ -621,51 +787,59 @@ export class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
e.preventDefault();
}
- }
- titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+ };
+ titleStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
- switch (property.split(":")[0]) {
- case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1;
- case StyleProp.BackgroundColor: return this.selected ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
- case StyleProp.DocContents: return this.props.treeView.outlineMode ? (null) :
- <div className="treeView-label" style={{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props')
- maxWidth: props?.PanelWidth() || undefined,
- background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor),
- }}>
- {StrCast(doc?.title)}
- </div>;
- default: return this.props?.treeView?.props.styleProvider?.(doc, props, property);
+ switch (property.split(':')[0]) {
+ case StyleProp.Opacity:
+ return this.props.treeView.outlineMode ? undefined : 1;
+ case StyleProp.BackgroundColor:
+ return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
+ case StyleProp.DocContents:
+ return this.props.treeView.outlineMode ? null : (
+ <div
+ className="treeView-label"
+ style={{
+ // just render a title for a tree view label (identified by treeViewDoc being set in 'props')
+ maxWidth: props?.PanelWidth() || undefined,
+ background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor),
+ }}>
+ {StrCast(doc?.title)}
+ </div>
+ );
+ default:
+ return this.props?.treeView?.props.styleProvider?.(doc, props, property);
}
- }
- embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
- if (property.startsWith(StyleProp.Decorations)) return (null);
+ };
+ embeddedStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
+ if (property.startsWith(StyleProp.Decorations)) return null;
return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
- }
+ };
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) {
switch (e.key) {
- case "Tab":
+ case 'Tab':
e.stopPropagation?.();
e.preventDefault?.();
setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
- UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab");
+ UndoManager.RunInBatch(() => (e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true)), 'tab');
return true;
- case "Backspace":
+ case 'Backspace':
if (!(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc)) {
e.stopPropagation?.();
e.preventDefault?.();
return true;
}
break;
- case "Enter":
+ case 'Enter':
e.stopPropagation?.();
e.preventDefault?.();
- return UndoManager.RunInBatch(this.makeTextCollection, "bullet");
+ return UndoManager.RunInBatch(this.makeTextCollection, 'bullet');
}
}
return false;
- }
+ };
titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - 2 * treeBulletWidth()));
return18 = () => 18;
@@ -675,28 +849,32 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed
get renderTitle() {
TraceMobx();
- const view = this._editTitle ? <EditableView key="_editTitle"
- oneLine={true}
- display={"inline-block"}
- editing={this._editTitle}
- background={"#7089bb"}
- contents={StrCast(this.doc.title)}
- height={12}
- sizeToContent={true}
- fontSize={12}
- GetValue={() => StrCast(this.doc.title)}
- OnTab={undoBatch((shift?: boolean) => {
- if (!shift) this.props.indentDocument?.(true);
- else this.props.outdentDocument?.(true);
- })}
- OnEmpty={undoBatch(() => this.props.treeView.outlineMode && this.props.removeDoc?.(this.doc))}
- OnFillDown={val => this.props.treeView.fileSysMode && this.makeFolder()}
- SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
- Doc.SetInPlace(this.doc, "title", value, false);
- this.props.treeView.outlineMode && enterKey && this.makeTextCollection();
- })}
- />
- : <DocumentView key="title"
+ const view = this._editTitle ? (
+ <EditableView
+ key="_editTitle"
+ oneLine={true}
+ display={'inline-block'}
+ editing={this._editTitle}
+ background={'#7089bb'}
+ contents={StrCast(this.doc.title)}
+ height={12}
+ sizeToContent={true}
+ fontSize={12}
+ GetValue={() => StrCast(this.doc.title)}
+ OnTab={undoBatch((shift?: boolean) => {
+ if (!shift) this.props.indentDocument?.(true);
+ else this.props.outdentDocument?.(true);
+ })}
+ OnEmpty={undoBatch(() => this.props.treeView.outlineMode && this.props.removeDoc?.(this.doc))}
+ OnFillDown={val => this.props.treeView.fileSysMode && this.makeFolder()}
+ SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
+ Doc.SetInPlace(this.doc, 'title', value, false);
+ this.props.treeView.outlineMode && enterKey && this.makeTextCollection();
+ })}
+ />
+ ) : (
+ <DocumentView
+ key="title"
ref={action((r: any) => {
this._docRef = r ? r : undefined;
if (this._docRef && TreeView._editTitleOnLoad?.id === this.props.document[Id] && TreeView._editTitleOnLoad.parent === this.props.parentTreeView) {
@@ -743,139 +921,161 @@ export class TreeView extends React.Component<TreeViewProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={this.props.treeView.props.Document}
ContentScaling={returnOne}
- />;
-
- const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""));
- return <>
- <div className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? "-system" : ""}`} ref={this._tref} title="click to edit title. Double Click or Drag to Open"
- style={{
- fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? "bold" : undefined,
- textDecoration: Doc.GetT(this.doc, "title", "string", true) ? "underline" : undefined,
- outline: this.doc === CurrentUserUtils.ActiveDashboard ? "dashed 1px #06123232" : undefined,
- pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined
- }} >
- {view}
- </div >
- <div className="treeView-rightButtons">
- {buttons} {/* hide and lock buttons */}
- {this.headerElements}
- </div>
- </>;
- }
+ />
+ );
- renderBulletHeader = (contents: JSX.Element, editing: boolean) => {
- return <>
- <div className={`treeView-header` + (editing ? "-editing" : "")} key="titleheader"
- style={{ width: StrCast(this.doc.treeViewHeaderWidth, "max-content") }}
- ref={this._header}
- onClick={this.ignoreEvent}
- onPointerDown={this.ignoreEvent}
- onPointerEnter={this.onPointerEnter}
- onPointerLeave={this.onPointerLeave}>
- {contents}
- </div>
- {this.renderBorder}
- </>;
+ const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ':afterHeader' : ''));
+ return (
+ <>
+ <div
+ className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? '-system' : ''}`}
+ ref={this._tref}
+ title="click to edit title. Double Click or Drag to Open"
+ style={{
+ fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? 'bold' : undefined,
+ textDecoration: Doc.GetT(this.doc, 'title', 'string', true) ? 'underline' : undefined,
+ outline: this.doc === Doc.ActiveDashboard ? 'dashed 1px #06123232' : undefined,
+ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined,
+ }}>
+ {view}
+ </div>
+ <div className="treeView-rightButtons">
+ {buttons} {/* hide and lock buttons */}
+ {this.headerElements}
+ </div>
+ </>
+ );
}
+ renderBulletHeader = (contents: JSX.Element, editing: boolean) => {
+ return (
+ <>
+ <div
+ className={`treeView-header` + (editing ? '-editing' : '')}
+ key="titleheader"
+ style={{ width: StrCast(this.doc.treeViewHeaderWidth, 'max-content') }}
+ ref={this._header}
+ onClick={this.ignoreEvent}
+ onPointerDown={this.ignoreEvent}
+ onPointerEnter={this.onPointerEnter}
+ onPointerLeave={this.onPointerLeave}>
+ {contents}
+ </div>
+ {this.renderBorder}
+ </>
+ );
+ };
renderEmbeddedDocument = (asText: boolean, isActive: () => boolean | undefined) => {
const isExpandable = this.doc._treeViewGrowsHorizontally;
const panelWidth = asText || isExpandable ? this.rtfWidth : this.expandPanelWidth;
const panelHeight = asText ? this.rtfOutlineHeight : isExpandable ? this.rtfHeight : this.expandPanelHeight;
- return <DocumentView key={this.doc[Id]} ref={action((r: DocumentView | null) => this._dref = r)}
- Document={this.doc}
- DataDoc={undefined}
- PanelWidth={panelWidth}
- PanelHeight={panelHeight}
- NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined}
- NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined}
- LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined}
- LayoutTemplate={this.props.treeView.props.childLayoutTemplate}
- isContentActive={isActive}
- isDocumentActive={isActive}
- styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
- hideTitle={asText}
- fitContentsToBox={returnTrue}
- hideDecorationTitle={this.props.treeView.outlineMode}
- hideResizeHandles={this.props.treeView.outlineMode}
- onClick={this.onChildClick}
- focus={this.refocus}
- ContentScaling={returnOne}
- onKey={this.onKeyDown}
- hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
- dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
- ScreenToLocalTransform={this.docTransform}
- renderDepth={this.props.renderDepth + 1}
- treeViewDoc={this.props.treeView?.props.Document}
- rootSelected={returnTrue}
- docViewPath={this.props.treeView.props.docViewPath}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionDoc={this.props.containerCollection}
- ContainingCollectionView={undefined}
- addDocument={this.props.addDocument}
- moveDocument={this.move}
- removeDocument={this.props.removeDoc}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.treeView.props.pinToPres}
- disableDocBrushing={this.props.treeView.props.disableDocBrushing}
- bringToFront={returnFalse}
- />;
- }
+ return (
+ <DocumentView
+ key={this.doc[Id]}
+ ref={action((r: DocumentView | null) => (this._dref = r))}
+ Document={this.doc}
+ DataDoc={undefined}
+ PanelWidth={panelWidth}
+ PanelHeight={panelHeight}
+ NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined}
+ NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined}
+ LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined}
+ LayoutTemplate={this.props.treeView.props.childLayoutTemplate}
+ isContentActive={isActive}
+ isDocumentActive={isActive}
+ styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
+ hideTitle={asText}
+ fitContentsToBox={returnTrue}
+ hideDecorationTitle={this.props.treeView.outlineMode}
+ hideResizeHandles={this.props.treeView.outlineMode}
+ onClick={this.onChildClick}
+ focus={this.refocus}
+ ContentScaling={returnOne}
+ onKey={this.onKeyDown}
+ hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
+ dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
+ ScreenToLocalTransform={this.docTransform}
+ renderDepth={this.props.renderDepth + 1}
+ treeViewDoc={this.props.treeView?.props.Document}
+ rootSelected={returnTrue}
+ docViewPath={this.props.treeView.props.docViewPath}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionDoc={this.props.containerCollection}
+ ContainingCollectionView={undefined}
+ addDocument={this.props.addDocument}
+ moveDocument={this.move}
+ removeDocument={this.props.removeDoc}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+ addDocTab={this.props.addDocTab}
+ pinToPres={this.props.treeView.props.pinToPres}
+ disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+ bringToFront={returnFalse}
+ />
+ );
+ };
// renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views.
@computed get renderTitleAsHeader() {
- return <>
- {this.renderBullet}
- {this.renderTitle}
- </>;
+ return (
+ <>
+ {this.renderBullet}
+ {this.renderTitle}
+ </>
+ );
}
// renders the document in the header field instead of a text proxy.
renderDocumentAsHeader = (asText: boolean) => {
- return <>
- {this.renderBullet}
- {this.renderEmbeddedDocument(asText, this.props.isContentActive)}
- </>;
- }
+ return (
+ <>
+ {this.renderBullet}
+ {this.renderEmbeddedDocument(asText, this.props.isContentActive)}
+ </>
+ );
+ };
@computed get renderBorder() {
const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
- const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } };
- return <div className={`treeView-border${this.props.treeView.outlineMode ? TreeViewType.outline : ""}`} style={{ borderColor: sortings[sorting]?.color }}>
- {!this.treeViewOpen ? (null) : this.renderContent}
- </div>;
+ const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } };
+ return (
+ <div className={`treeView-border${this.props.treeView.outlineMode ? TreeViewType.outline : ''}`} style={{ borderColor: sortings[sorting]?.color }}>
+ {!this.treeViewOpen ? null : this.renderContent}
+ </div>
+ );
}
onTreeDrop = (de: React.DragEvent) => {
const pt = [de.clientX, de.clientY];
const rect = this._header.current!.getBoundingClientRect();
const before = pt[1] < rect.top + rect.height / 2;
- const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
-
- const docs = this.props.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, "copy", undefined, false));
- }
+ const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocList.length);
+ const docs = this.props.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, false));
+ };
render() {
TraceMobx();
const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode;
- return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
- <div className={`treeView-container${this.props.isContentActive() ? "-active" : ""}`}
+ return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? (
+ '<' + this.doc.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
+ ) : (
+ <div
+ className={`treeView-container${this.props.isContentActive() ? '-active' : ''}`}
ref={this.createTreeDropTarget}
onDrop={this.onTreeDrop}
- //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
- // onKeyDown={this.onKeyDown}
+ //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
+ // onKeyDown={this.onKeyDown}
>
<li className="collection-child">
- {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader"
- this.renderEmbeddedDocument(false, returnFalse) :
- this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
+ {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader // should test for prop 'treeViewRenderDocWithBulletAsHeader"
+ ? this.renderEmbeddedDocument(false, returnFalse)
+ : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
</li>
- </div>;
+ </div>
+ );
}
public static sortDocs(childDocs: Doc[], criterion: string | undefined) {
@@ -883,9 +1083,10 @@ export class TreeView extends React.Component<TreeViewProps> {
if (criterion !== TreeSort.None) {
const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
const reN = /[0-9]*$/;
- const aA = a.replace(reN, "") ? a.replace(reN, "") : +a; // get rid of trailing numbers
- const bA = b.replace(reN, "") ? b.replace(reN, "") : +b;
- if (aA === bA) { // if header string matches, then compare numbers numerically
+ const aA = a.replace(reN, '') ? a.replace(reN, '') : +a; // get rid of trailing numbers
+ const bA = b.replace(reN, '') ? b.replace(reN, '') : +b;
+ if (aA === bA) {
+ // if header string matches, then compare numbers numerically
const aN = parseInt(a.match(reN)![0], 10);
const bN = parseInt(b.match(reN)![0], 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
@@ -894,11 +1095,11 @@ export class TreeView extends React.Component<TreeViewProps> {
}
};
docs.sort(function (d1, d2): 0 | 1 | -1 {
- const a = (criterion === TreeSort.Up ? d2 : d1);
- const b = (criterion === TreeSort.Up ? d1 : d2);
- const first = a[criterion === TreeSort.Zindex ? "zIndex" : "title"];
- const second = b[criterion === TreeSort.Zindex ? "zIndex" : "title"];
- if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
+ const a = criterion === TreeSort.Up ? d2 : d1;
+ const b = criterion === TreeSort.Up ? d1 : d2;
+ const first = a[criterion === TreeSort.Zindex ? 'zIndex' : 'title'];
+ const second = b[criterion === TreeSort.Zindex ? 'zIndex' : 'title'];
+ if (typeof first === 'number' && typeof second === 'number') return first - second > 0 ? 1 : -1;
if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
return criterion ? 1 : -1;
});
@@ -934,11 +1135,11 @@ export class TreeView extends React.Component<TreeViewProps> {
dontRegisterView: boolean | undefined,
observerHeight: (ref: any) => void,
unobserveHeight: (ref: any) => void,
- contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[]),
+ contextMenuItems: { script: ScriptField; filter: ScriptField; label: string; icon: string }[],
// TODO: [AL] add these
AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[],
RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[],
- hierarchyIndex?: number[],
+ hierarchyIndex?: number[]
) {
const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField);
if (viewSpecScript) {
@@ -948,68 +1149,77 @@ export class TreeView extends React.Component<TreeViewProps> {
const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
const rowWidth = () => panelWidth() - treeBulletWidth();
const treeViewRefs = new Map<Doc, TreeView | undefined>();
- return docs.filter(child => child instanceof Doc).map((child, i) => {
- const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child);
- if (!pair.layout || pair.data instanceof Promise) {
- return (null);
- }
-
- const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => {
- if (parent instanceof TreeView && parent.props.treeView.fileSysMode && !newParent.isFolder) return;
- const fieldKey = Doc.LayoutFieldKey(newParent);
- if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) {
- remove(child);
- FormattedTextBox.SelectOnLoad = child[Id];
- TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
- Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
- newParent.treeViewOpen = true;
- child.context = treeView.Document;
+ return docs
+ .filter(child => child instanceof Doc)
+ .map((child, i) => {
+ const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child);
+ if (!pair.layout || pair.data instanceof Promise) {
+ return null;
}
- };
- const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
- const outdent = parentCollectionDoc?._viewType !== CollectionViewType.Tree ? undefined : ((editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined));
- const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
- const childLayout = Doc.Layout(pair.layout);
- const rowHeight = () => {
- const aspect = Doc.NativeAspect(childLayout);
- return (aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]());
- };
- return <TreeView key={child[Id]} ref={r => treeViewRefs.set(child, r ? r : undefined)}
- document={pair.layout}
- dataDoc={pair.data}
- containerCollection={containerCollection}
- prevSibling={docs[i]}
- // TODO: [AL] add these
- hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
- AddToMap={AddToMap}
- RemFromMap={RemFromMap}
- treeView={treeView}
- indentDocument={indent}
- outdentDocument={outdent}
- onCheckedClick={onCheckedClick}
- onChildClick={onChildClick}
- renderDepth={renderDepth}
- removeDoc={StrCast(containerCollection.freezeChildren).includes("remove") ? undefined : remove}
- addDocument={addDocument}
- styleProvider={styleProvider}
- panelWidth={rowWidth}
- panelHeight={rowHeight}
- dontRegisterView={dontRegisterView}
- moveDocument={move}
- dropAction={dropAction}
- addDocTab={addDocTab}
- ScreenToLocalTransform={screenToLocalXf}
- isContentActive={isContentActive}
- treeViewHideHeaderFields={treeViewHideHeaderFields}
- renderedIds={renderedIds}
- skipFields={skipFields}
- firstLevel={firstLevel}
- whenChildContentsActiveChanged={whenChildContentsActiveChanged}
- parentTreeView={parentTreeView}
- observeHeight={observerHeight}
- unobserveHeight={unobserveHeight}
- contextMenuItems={contextMenuItems}
- />;
- });
+
+ const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => {
+ if (parent instanceof TreeView && parent.props.treeView.fileSysMode && !newParent.isFolder) return;
+ const fieldKey = Doc.LayoutFieldKey(newParent);
+ if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) {
+ remove(child);
+ FormattedTextBox.SelectOnLoad = child[Id];
+ TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
+ Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
+ newParent.treeViewOpen = true;
+ child.context = treeView.Document;
+ }
+ };
+ const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
+ const outdent =
+ parentCollectionDoc?._viewType !== CollectionViewType.Tree
+ ? undefined
+ : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
+ const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
+ const childLayout = Doc.Layout(pair.layout);
+ const rowHeight = () => {
+ const aspect = Doc.NativeAspect(childLayout);
+ return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]();
+ };
+ return (
+ <TreeView
+ key={child[Id]}
+ ref={r => treeViewRefs.set(child, r ? r : undefined)}
+ document={pair.layout}
+ dataDoc={pair.data}
+ containerCollection={containerCollection}
+ prevSibling={docs[i]}
+ // TODO: [AL] add these
+ hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
+ AddToMap={AddToMap}
+ RemFromMap={RemFromMap}
+ treeView={treeView}
+ indentDocument={indent}
+ outdentDocument={outdent}
+ onCheckedClick={onCheckedClick}
+ onChildClick={onChildClick}
+ renderDepth={renderDepth}
+ removeDoc={StrCast(containerCollection.freezeChildren).includes('remove') ? undefined : remove}
+ addDocument={addDocument}
+ styleProvider={styleProvider}
+ panelWidth={rowWidth}
+ panelHeight={rowHeight}
+ dontRegisterView={dontRegisterView}
+ moveDocument={move}
+ dropAction={dropAction}
+ addDocTab={addDocTab}
+ ScreenToLocalTransform={screenToLocalXf}
+ isContentActive={isContentActive}
+ treeViewHideHeaderFields={treeViewHideHeaderFields}
+ renderedIds={renderedIds}
+ skipFields={skipFields}
+ firstLevel={firstLevel}
+ whenChildContentsActiveChanged={whenChildContentsActiveChanged}
+ parentTreeView={parentTreeView}
+ observeHeight={observerHeight}
+ unobserveHeight={unobserveHeight}
+ contextMenuItems={contextMenuItems}
+ />
+ );
+ });
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 9de2cfcf9..a0ebe4cdc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -1,13 +1,12 @@
-import { Doc, Field, FieldResult, HeightSym, WidthSym } from "../../../../fields/Doc";
-import { Id, ToString } from "../../../../fields/FieldSymbols";
-import { ObjectField } from "../../../../fields/ObjectField";
-import { RefField } from "../../../../fields/RefField";
-import { listSpec } from "../../../../fields/Schema";
-import { Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { aggregateBounds } from "../../../../Utils";
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import React = require("react");
-import { ColorScheme } from "../../../util/SettingsManager";
+import { Doc, Field, FieldResult, HeightSym, WidthSym } from '../../../../fields/Doc';
+import { Id, ToString } from '../../../../fields/FieldSymbols';
+import { ObjectField } from '../../../../fields/ObjectField';
+import { RefField } from '../../../../fields/RefField';
+import { listSpec } from '../../../../fields/Schema';
+import { Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { aggregateBounds } from '../../../../Utils';
+import { ColorScheme } from '../../../util/SettingsManager';
+import React = require('react');
export interface ViewDefBounds {
type: string;
@@ -25,7 +24,7 @@ export interface ViewDefBounds {
color?: string;
opacity?: number;
replica?: string;
- pair?: { layout: Doc, data?: Doc };
+ pair?: { layout: Doc; data?: Doc };
}
export interface PoolData {
@@ -40,7 +39,7 @@ export interface PoolData {
transition?: string;
highlight?: boolean;
replica: string;
- pair: { layout: Doc, data?: Doc };
+ pair: { layout: Doc; data?: Doc };
}
export interface ViewDefResult {
@@ -48,7 +47,7 @@ export interface ViewDefResult {
bounds?: ViewDefBounds;
}
function toLabel(target: FieldResult<Field>) {
- if (typeof target === "number" || Number(target)) {
+ if (typeof target === 'number' || Number(target)) {
const truncated = Number(Number(target).toFixed(0));
const precise = Number(Number(target).toFixed(2));
return truncated === precise ? Number(target).toFixed(0) : Number(target).toFixed(2);
@@ -60,16 +59,16 @@ function toLabel(target: FieldResult<Field>) {
}
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
- *
+ *
* @param {String} text The text to be rendered.
* @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
- *
+ *
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
function getTextWidth(text: string, font: string): number {
// re-use canvas object for better performance
- const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas"));
- const context = canvas.getContext("2d");
+ const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement('canvas'));
+ const context = canvas.getContext('2d');
context.font = font;
const metrics = context.measureText(text);
return metrics.width;
@@ -81,14 +80,7 @@ interface PivotColumn {
filters: string[];
}
-export function computerPassLayout(
- poolData: Map<string, PoolData>,
- pivotDoc: Doc,
- childPairs: { layout: Doc, data?: Doc }[],
- panelDim: number[],
- viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
- engineProps: any
-) {
+export function computerPassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const docMap = new Map<string, PoolData>();
childPairs.forEach(({ layout, data }, i) => {
docMap.set(layout[Id], {
@@ -97,60 +89,49 @@ export function computerPassLayout(
width: layout[WidthSym](),
height: layout[HeightSym](),
pair: { layout, data },
- replica: ""
+ replica: '',
});
});
return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
}
-export function computerStarburstLayout(
- poolData: Map<string, PoolData>,
- pivotDoc: Doc,
- childPairs: { layout: Doc, data?: Doc }[],
- panelDim: number[],
- viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
- engineProps: any
-) {
+export function computerStarburstLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel
const docMap = new Map<string, PoolData>();
- const docSize = mustFit ? panelDim[0] * .33 : 75; // assume an icon sized at 75
+ const docSize = mustFit ? panelDim[0] * 0.33 : 75; // assume an icon sized at 75
const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]) - docSize, NumCast(pivotDoc._starburstRadius, panelDim[1]) - docSize];
const scaleDim = [burstRadius[0] * 2 + docSize, burstRadius[1] * 2 + docSize];
childPairs.forEach(({ layout, data }, i) => {
- const docSize = layout.layoutKey === "layout_icon" ? (mustFit ? panelDim[0] * .33 : 75) : 400; // assume a icon sized at 75
- const deg = i / childPairs.length * Math.PI * 2;
+ const docSize = layout.layoutKey === 'layout_icon' ? (mustFit ? panelDim[0] * 0.33 : 75) : 400; // assume a icon sized at 75
+ const deg = (i / childPairs.length) * Math.PI * 2;
docMap.set(layout[Id], {
x: Math.cos(deg) * burstRadius[0] - docSize / 2,
- y: Math.sin(deg) * burstRadius[1] - docSize * layout[HeightSym]() / layout[WidthSym]() / 2,
- width: docSize,//layout[WidthSym](),
- height: docSize * layout[HeightSym]() / layout[WidthSym](),
+ y: Math.sin(deg) * burstRadius[1] - (docSize * layout[HeightSym]()) / layout[WidthSym]() / 2,
+ width: docSize, //layout[WidthSym](),
+ height: (docSize * layout[HeightSym]()) / layout[WidthSym](),
zIndex: NumCast(layout.zIndex),
pair: { layout, data },
- replica: ""
+ replica: '',
});
});
- const divider = { type: "div", color: "transparent", x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined };
+ const divider = { type: 'div', color: 'transparent', x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined };
return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]);
}
-
-export function computePivotLayout(
- poolData: Map<string, PoolData>,
- pivotDoc: Doc,
- childPairs: { layout: Doc, data?: Doc }[],
- panelDim: number[],
- viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
- engineProps: any
-) {
+export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const docMap = new Map<string, PoolData>();
- const fieldKey = "data";
+ const fieldKey = 'data';
const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>();
let nonNumbers = 0;
- const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField) || "author";
+ const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField) || 'author';
childPairs.map(pair => {
- const lval = pivotFieldKey === "#" || pivotFieldKey === "tags" ? Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(k => k.startsWith("#")).map(k => k.substring(1)) :
- Cast(pair.layout[pivotFieldKey], listSpec("string"), null);
+ const lval =
+ pivotFieldKey === '#' || pivotFieldKey === 'tags'
+ ? Array.from(Object.keys(Doc.GetProto(pair.layout)))
+ .filter(k => k.startsWith('#'))
+ .map(k => k.substring(1))
+ : Cast(pair.layout[pivotFieldKey], listSpec('string'), null);
const num = toNumber(pair.layout[pivotFieldKey]);
if (num === undefined || Number.isNaN(num)) {
@@ -166,7 +147,7 @@ export function computePivotLayout(
} else if (val) {
!pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] });
pivotColumnGroups.get(val)!.docs.push(pair.layout);
- pivotColumnGroups.get(val)!.replicas.push("");
+ pivotColumnGroups.get(val)!.replicas.push('');
} else {
docMap.set(pair.layout[Id], {
x: 0,
@@ -175,11 +156,11 @@ export function computePivotLayout(
width: 0,
height: 0,
pair,
- replica: ""
+ replica: '',
});
}
});
- const pivotNumbers = nonNumbers / childPairs.length < .1;
+ const pivotNumbers = nonNumbers / childPairs.length < 0.1;
if (pivotColumnGroups.size > 10) {
const arrayofKeys = Array.from(pivotColumnGroups.keys());
const sortedKeys = pivotNumbers ? arrayofKeys.sort((n1: FieldResult, n2: FieldResult) => toNumber(n1)! - toNumber(n2)!) : arrayofKeys.sort();
@@ -196,9 +177,11 @@ export function computePivotLayout(
}
}
}
- const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
+ const fontSize = NumCast(pivotDoc[fieldKey + '-timelineFontSize'], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`;
- const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number);
+ const textlen = Array.from(pivotColumnGroups.keys())
+ .map(c => getTextWidth(toLabel(c), desc))
+ .reduce((p, c) => Math.max(p, c), 0 as number);
const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1] / 2);
const maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1);
@@ -222,7 +205,7 @@ export function computePivotLayout(
const groupNames: ViewDefBounds[] = [];
const expander = 1.05;
- const gap = .15;
+ const gap = 0.15;
const maxColHeight = pivotAxisWidth * expander * Math.ceil(maxInColumn / numCols);
let x = 0;
const sortedPivotKeys = pivotNumbers ? Array.from(pivotColumnGroups.keys()).sort((n1: FieldResult, n2: FieldResult) => toNumber(n1)! - toNumber(n2)!) : Array.from(pivotColumnGroups.keys()).sort();
@@ -232,14 +215,14 @@ export function computePivotLayout(
let xCount = 0;
const text = toLabel(key);
groupNames.push({
- type: "text",
+ type: 'text',
text,
x,
y: pivotAxisWidth,
width: pivotAxisWidth * expander * numCols,
height: max_text,
fontSize,
- payload: val
+ payload: val,
});
val.docs.forEach((doc, i) => {
const layoutDoc = Doc.Layout(doc);
@@ -249,13 +232,13 @@ export function computePivotLayout(
hgt = pivotAxisWidth;
wid = (Doc.NativeAspect(layoutDoc) || 1) * pivotAxisWidth;
}
- docMap.set(doc[Id] + (val.replicas || ""), {
- x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0),
+ docMap.set(doc[Id] + (val.replicas || ''), {
+ x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? ((numCols - val.docs.length) * pivotAxisWidth) / 2 : 0),
y: -y + (pivotAxisWidth - hgt) / 2,
width: wid,
height: hgt,
pair: { layout: doc },
- replica: val.replicas[i]
+ replica: val.replicas[i],
});
xCount++;
if (xCount >= numCols) {
@@ -266,13 +249,14 @@ export function computePivotLayout(
x += pivotAxisWidth * (numCols * expander + gap);
});
- const dividers = sortedPivotKeys.map((key, i) =>
- ({
- type: "div", color: "lightGray",
- x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2,
- y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander,
+ const dividers = sortedPivotKeys.map((key, i) => ({
+ type: 'div',
+ color: 'lightGray',
+ x: i * pivotAxisWidth * (numCols * expander + gap) - (pivotAxisWidth * (expander - 1)) / 2,
+ y: -maxColHeight + pivotAxisWidth,
+ width: pivotAxisWidth * numCols * expander,
height: maxColHeight,
- payload: pivotColumnGroups.get(key)!.filters
+ payload: pivotColumnGroups.get(key)!.filters,
}));
groupNames.push(...dividers);
return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []);
@@ -282,24 +266,17 @@ function toNumber(val: FieldResult<Field>) {
return val === undefined ? undefined : NumCast(val, Number(StrCast(val)));
}
-export function computeTimelineLayout(
- poolData: Map<string, PoolData>,
- pivotDoc: Doc,
- childPairs: { layout: Doc, data?: Doc }[],
- panelDim: number[],
- viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
- engineProps?: any
-) {
- const fieldKey = "data";
+export function computeTimelineLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps?: any) {
+ const fieldKey = 'data';
const pivotDateGroups = new Map<number, Doc[]>();
const docMap = new Map<string, PoolData>();
const groupNames: ViewDefBounds[] = [];
const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field);
- const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]);
- const curTimeSpan = Cast(pivotDoc[fieldKey + "-timelineSpan"], "number", null);
- const minTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + "-timelineMinReq"], "number", null) : curTime && (curTime - curTimeSpan);
- const maxTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + "-timelineMaxReq"], "number", null) : curTime && (curTime + curTimeSpan);
- const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
+ const curTime = toNumber(pivotDoc[fieldKey + '-timelineCur']);
+ const curTimeSpan = Cast(pivotDoc[fieldKey + '-timelineSpan'], 'number', null);
+ const minTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + '-timelineMinReq'], 'number', null) : curTime && curTime - curTimeSpan;
+ const maxTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + '-timelineMaxReq'], 'number', null) : curTime && curTime + curTimeSpan;
+ const fontSize = NumCast(pivotDoc[fieldKey + '-timelineFontSize'], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
const fontHeight = panelDim[1] > 58 ? 30 : panelDim[1] / 2;
const findStack = (time: number, stack: number[]) => {
const index = stack.findIndex(val => val === undefined || val < x);
@@ -325,8 +302,8 @@ export function computeTimelineLayout(
}
}
setTimeout(() => {
- pivotDoc[fieldKey + "-timelineMin"] = minTime = minTimeReq ? Math.min(minTimeReq, minTime) : minTime;
- pivotDoc[fieldKey + "-timelineMax"] = maxTime = maxTimeReq ? Math.max(maxTimeReq, maxTime) : maxTime;
+ pivotDoc[fieldKey + '-timelineMin'] = minTime = minTimeReq ? Math.min(minTimeReq, minTime) : minTime;
+ pivotDoc[fieldKey + '-timelineMax'] = maxTime = maxTimeReq ? Math.max(maxTimeReq, maxTime) : maxTime;
}, 0);
if (maxTime === minTime) {
@@ -340,10 +317,10 @@ export function computeTimelineLayout(
let prevKey = Math.floor(minTime);
if (sortedKeys.length && scaling * (sortedKeys[0] - prevKey) > 25) {
- groupNames.push({ type: "text", text: toLabel(prevKey), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: 'text', text: toLabel(prevKey), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
}
if (!sortedKeys.length && curTime !== undefined) {
- groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: 'text', text: toLabel(curTime), x: (curTime - minTime) * scaling, zIndex: 1000, color: 'orange', y: 0, height: fontHeight, fontSize, payload: undefined });
}
const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5);
@@ -351,26 +328,26 @@ export function computeTimelineLayout(
let zind = 0;
sortedKeys.forEach(key => {
if (curTime !== undefined && curTime > prevKey && curTime <= key) {
- groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key });
+ groupNames.push({ type: 'text', text: toLabel(curTime), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: 'orange', height: fontHeight, fontSize, payload: key });
}
const keyDocs = pivotDateGroups.get(key)!;
x += scaling * (key - prevKey);
const stack = findStack(x, stacking);
prevKey = key;
if (!stack && (curTime === undefined || Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth)) {
- groupNames.push({ type: "text", text: toLabel(key), x: x, y: stack * 25, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: 'text', text: toLabel(key), x: x, y: stack * 25, height: fontHeight, fontSize, payload: undefined });
}
layoutDocsAtTime(keyDocs, key);
});
if (sortedKeys.length && curTime !== undefined && curTime > sortedKeys[sortedKeys.length - 1]) {
x = (curTime - minTime) * scaling;
- groupNames.push({ type: "text", text: toLabel(curTime), x: x, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: 'text', text: toLabel(curTime), x: x, y: 0, zIndex: 1000, color: 'orange', height: fontHeight, fontSize, payload: undefined });
}
if (Math.ceil(maxTime - minTime) * scaling > x + 25) {
- groupNames.push({ type: "text", text: toLabel(Math.ceil(maxTime)), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: 'text', text: toLabel(Math.ceil(maxTime)), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize, payload: undefined });
}
- const divider = { type: "div", color: CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "dimgray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
+ const divider = { type: 'div', color: Doc.ActiveDashboard?.colorScheme === ColorScheme.Dark ? 'dimgray' : 'black', x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
return normalizeResults(panelDim, fontHeight, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
function layoutDocsAtTime(keyDocs: Doc[], key: number) {
@@ -384,13 +361,14 @@ export function computeTimelineLayout(
wid = (Doc.NativeAspect(layoutDoc) || 1) * pivotAxisWidth;
}
docMap.set(doc[Id], {
- x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
- zIndex: (curTime === key ? 1000 : zind++),
+ x: x,
+ y: (-Math.sqrt(stack) * pivotAxisWidth) / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
+ zIndex: curTime === key ? 1000 : zind++,
highlight: curTime === key,
- width: wid / (Math.max(stack, 1)),
- height: hgt / (Math.max(stack, 1)),
+ width: wid / Math.max(stack, 1),
+ height: hgt / Math.max(stack, 1),
pair: { layout: doc },
- replica: ""
+ replica: '',
});
stacking[stack] = x + pivotAxisWidth;
});
@@ -407,41 +385,49 @@ function normalizeResults(
minWidth: number,
extras: ViewDefBounds[]
): ViewDefResult[] {
- const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds);
+ const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height } as ViewDefBounds));
const docEles = Array.from(docMap.entries()).map(ele => ele[1]);
- const aggBounds = aggregateBounds(extras.concat(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" })))).filter(e => e.zIndex !== -99), 0, 0);
+ const aggBounds = aggregateBounds(
+ extras.concat(grpEles.concat(docEles.map(de => ({ ...de, type: 'doc', payload: '' })))).filter(e => e.zIndex !== -99),
+ 0,
+ 0
+ );
aggBounds.r = aggBounds.x + Math.max(minWidth, aggBounds.r - aggBounds.x);
const wscale = panelDim[0] / (aggBounds.r - aggBounds.x);
- let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale;
+ let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? panelDim[1] / (aggBounds.b - aggBounds.y) : wscale;
if (Number.isNaN(scale)) scale = 1;
- Array.from(docMap.entries()).filter(ele => ele[1].pair).map(ele => {
- const newPosRaw = ele[1];
- if (newPosRaw) {
- const newPos = {
- x: newPosRaw.x * scale,
- y: newPosRaw.y * scale,
- z: newPosRaw.z,
- replica: newPosRaw.replica,
- highlight: newPosRaw.highlight,
- zIndex: newPosRaw.zIndex,
- width: (newPosRaw.width || 0) * scale,
- height: newPosRaw.height! * scale,
- pair: ele[1].pair
- };
- poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "all 1s", ...newPos });
- }
- });
+ Array.from(docMap.entries())
+ .filter(ele => ele[1].pair)
+ .map(ele => {
+ const newPosRaw = ele[1];
+ if (newPosRaw) {
+ const newPos = {
+ x: newPosRaw.x * scale,
+ y: newPosRaw.y * scale,
+ z: newPosRaw.z,
+ replica: newPosRaw.replica,
+ highlight: newPosRaw.highlight,
+ zIndex: newPosRaw.zIndex,
+ width: (newPosRaw.width || 0) * scale,
+ height: newPosRaw.height! * scale,
+ pair: ele[1].pair,
+ };
+ poolData.set(newPos.pair.layout[Id] + (newPos.replica || ''), { transition: 'all 1s', ...newPos });
+ }
+ });
- return viewDefsToJSX(extras.concat(groupNames).map(gname => ({
- type: gname.type,
- text: gname.text,
- x: gname.x * scale,
- y: gname.y * scale,
- color: gname.color,
- width: gname.width === undefined ? undefined : gname.width * scale,
- height: gname.height === -1 ? 1 : gname.type === "text" ? Math.max(fontHeight * scale, (gname.height || 0) * scale) : (gname.height || 0) * scale,
- fontSize: gname.fontSize,
- payload: gname.payload
- })));
+ return viewDefsToJSX(
+ extras.concat(groupNames).map(gname => ({
+ type: gname.type,
+ text: gname.text,
+ x: gname.x * scale,
+ y: gname.y * scale,
+ color: gname.color,
+ width: gname.width === undefined ? undefined : gname.width * scale,
+ height: gname.height === -1 ? 1 : gname.type === 'text' ? Math.max(fontHeight * scale, (gname.height || 0) * scale) : (gname.height || 0) * scale,
+ fontSize: gname.fontSize,
+ payload: gname.payload,
+ }))
+ );
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 5f890c810..d979ef961 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -1,19 +1,18 @@
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, Field } from "../../../../fields/Doc";
-import { Id } from "../../../../fields/FieldSymbols";
-import { List } from "../../../../fields/List";
-import { Cast, NumCast } from "../../../../fields/Types";
+import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, Field } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
+import { List } from '../../../../fields/List';
+import { Cast, NumCast } from '../../../../fields/Types';
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
-import { LinkManager } from "../../../util/LinkManager";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { SnappingManager } from "../../../util/SnappingManager";
-import { DocumentView } from "../../nodes/DocumentView";
-import "./CollectionFreeFormLinkView.scss";
-import React = require("react");
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { Colors } from "../../global/globalEnums";
-
+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 './CollectionFreeFormLinkView.scss';
+import React = require('react');
export interface CollectionFreeFormLinkViewProps {
A: DocumentView;
@@ -27,31 +26,41 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
@observable _start = 0;
_anchorDisposer: IReactionDisposer | undefined;
_timeout: NodeJS.Timeout | undefined;
- componentWillUnmount() { this._anchorDisposer?.(); }
- @action timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25)));
+ componentWillUnmount() {
+ this._anchorDisposer?.();
+ }
+ @action timeout = action(() => Date.now() < this._start++ + 1000 && (this._timeout = setTimeout(this.timeout, 25)));
componentDidMount() {
- this._anchorDisposer = reaction(() => [
- this.props.A.props.ScreenToLocalTransform(),
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?._highlights,
- this.props.B.props.ScreenToLocalTransform(),
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?._highlights,
- ],
+ this._anchorDisposer = reaction(
+ () => [
+ this.props.A.props.ScreenToLocalTransform(),
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ this.props.B.props.ScreenToLocalTransform(),
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ ],
action(() => {
this._start = Date.now();
this._timeout && clearTimeout(this._timeout);
this._timeout = setTimeout(this.timeout, 25);
setTimeout(this.placeAnchors);
- })
- , { fireImmediately: true });
+ }),
+ { fireImmediately: true }
+ );
}
placeAnchors = () => {
const { A, B, LinkDocs } = this.props;
const linkDoc = LinkDocs[0];
if (SnappingManager.GetIsDragging() || !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.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
+ 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.linkDisplay) && (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();
@@ -60,7 +69,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
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,
+ // 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.anchor1 as Doc)[Id])).lastElement();
@@ -68,8 +77,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
if (!targetAhyperlink) {
if (linkDoc.linkAutoMove) {
- linkDoc.anchor1_x = (apt.point.x - aleft) / awidth * 100;
- linkDoc.anchor1_y = (apt.point.y - atop) / aheight * 100;
+ linkDoc.anchor1_x = ((apt.point.x - aleft) / awidth) * 100;
+ linkDoc.anchor1_y = ((apt.point.y - atop) / aheight) * 100;
}
} else {
const m = targetAhyperlink.getBoundingClientRect();
@@ -78,13 +87,13 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const mpy = mp[1] / A.props.PanelHeight();
if (mpx >= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100;
if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100;
- if (getComputedStyle(targetAhyperlink).fontSize === "0px") linkDoc.opacity = 0;
+ if (getComputedStyle(targetAhyperlink).fontSize === '0px') linkDoc.opacity = 0;
else linkDoc.opacity = 1;
}
if (!targetBhyperlink) {
if (linkDoc.linkAutoMove) {
- linkDoc.anchor2_x = (bpt.point.x - bleft) / bwidth * 100;
- linkDoc.anchor2_y = (bpt.point.y - btop) / bheight * 100;
+ linkDoc.anchor2_x = ((bpt.point.x - bleft) / bwidth) * 100;
+ linkDoc.anchor2_y = ((bpt.point.y - btop) / bheight) * 100;
}
} else {
const m = targetBhyperlink.getBoundingClientRect();
@@ -93,80 +102,86 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const mpy = mp[1] / B.props.PanelHeight();
if (mpx >= 0 && mpx <= 1) linkDoc.anchor2_x = mpx * 100;
if (mpy >= 0 && mpy <= 1) linkDoc.anchor2_y = mpy * 100;
- if (getComputedStyle(targetBhyperlink).fontSize === "0px") linkDoc.opacity = 0;
+ 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].linkOffsetX = NumCast(this.props.LinkDocs[0].linkOffsetX) + delta[0];
- this.props.LinkDocs[0].linkOffsetY = NumCast(this.props.LinkDocs[0].linkOffsetY) + delta[1];
- return false;
- }, emptyFunction, () => {
- // OverlayView.Instance.addElement(
- // <LinkEditor sourceDoc={this.props.A.props.Document} linkDoc={this.props.LinkDocs[0]}
- // showLinks={action(() => { })}
- // />, { x: 300, y: 300 });
- });
-
-
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ (e, down, delta) => {
+ this.props.LinkDocs[0].linkOffsetX = NumCast(this.props.LinkDocs[0].linkOffsetX) + delta[0];
+ this.props.LinkDocs[0].linkOffsetY = NumCast(this.props.LinkDocs[0].linkOffsetY) + delta[1];
+ return false;
+ },
+ emptyFunction,
+ () => {
+ // 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;
+ const top = rect.top,
+ height = rect.height;
var el = el.parentNode;
while (el && el !== document.body) {
rect = el.getBoundingClientRect?.();
if (rect?.width) {
- if (top <= rect.bottom === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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 (CurrentUserUtils.propertiesWidth > 0) {
- CurrentUserUtils.propertiesWidth = 0;
+ if (SettingsManager.propertiesWidth > 0) {
+ SettingsManager.propertiesWidth = 0;
} else {
- CurrentUserUtils.propertiesWidth = 250;
+ SettingsManager.propertiesWidth = 250;
}
- }
+ };
onClickLine = () => {
SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true);
this.toggleProperties();
- }
+ };
@computed.struct get renderData() {
- this._start; SnappingManager.GetIsDragging();
+ this._start;
+ SnappingManager.GetIsDragging();
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 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;
@@ -185,11 +200,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const pt2 = [bleft + b.width / 2, btop + b.width / 2];
const pt1vec = [(bDocBounds.left + bDocBounds.right) / 2 - pt1[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt1[1]];
const pt2vec = [(aDocBounds.left + aDocBounds.right) / 2 - pt2[0], (aDocBounds.top + aDocBounds.bottom) / 2 - pt2[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 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 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];
@@ -203,7 +218,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
}
render() {
- if (!this.renderData) return (null);
+ if (!this.renderData) return null;
const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
LinkManager.currentLink = this.props.LinkDocs[0];
@@ -216,31 +231,37 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const linkSize = 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 ? "black" : linkColorList[currRelationshipIndex];
+ const stroke = currRelationshipIndex === -1 || currRelationshipIndex >= linkColorList.length ? '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 strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
if (this.props.LinkDocs[0].displayArrow === undefined) {
this.props.LinkDocs[0].displayArrow = false;
}
- return this.props.LinkDocs[0].opacity === 0 || !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
- <defs>
- <marker id="arrowhead" markerWidth="4" markerHeight="3"
- refX="0" refY="1.5" orient="auto">
- <polygon points="0 0, 3 1.5, 0 3" fill={Colors.DARK_GRAY} />
- </marker>
- </defs>
- <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? Colors.MEDIUM_BLUE : 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={this.props.LinkDocs[0].displayArrow ? "url(#arrowhead)" : ""} />
- {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
- {Field.toString(this.props.LinkDocs[0].description as any as Field)}
- </text>}
- </>);
+ return this.props.LinkDocs[0].opacity === 0 || !a.width || !b.width || (!this.props.LinkDocs[0].linkDisplay && !aActive && !bActive) ? null : (
+ <>
+ <defs>
+ <marker id="arrowhead" markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
+ <polygon points="0 0, 3 1.5, 0 3" fill={Colors.DARK_GRAY} />
+ </marker>
+ </defs>
+ <path
+ className="collectionfreeformlinkview-linkLine"
+ style={{ pointerEvents: 'all', opacity: this._opacity, stroke: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? Colors.MEDIUM_BLUE : 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={this.props.LinkDocs[0].displayArrow ? 'url(#arrowhead)' : ''}
+ />
+ {textX === undefined ? null : (
+ <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
+ {Field.toString(this.props.LinkDocs[0].description as any as Field)}
+ </text>
+ )}
+ </>
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
index 9f6938e67..9e8d92d7d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
@@ -1,79 +1,82 @@
-import { computed } from "mobx";
-import { observer } from "mobx-react";
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
import * as mobxUtils from 'mobx-utils';
-import CursorField from "../../../../fields/CursorField";
-import { FieldResult } from "../../../../fields/Doc";
-import { List } from "../../../../fields/List";
-import { listSpec } from "../../../../fields/Schema";
-import { Cast } from "../../../../fields/Types";
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { CollectionViewProps } from "../CollectionView";
-import "./CollectionFreeFormView.scss";
-import React = require("react");
-import v5 = require("uuid/v5");
+import CursorField from '../../../../fields/CursorField';
+import { Doc, FieldResult } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
+import { List } from '../../../../fields/List';
+import { listSpec } from '../../../../fields/Schema';
+import { Cast } from '../../../../fields/Types';
+import { CollectionViewProps } from '../CollectionView';
+import './CollectionFreeFormView.scss';
+import React = require('react');
+import v5 = require('uuid/v5');
@observer
export class CollectionFreeFormRemoteCursors extends React.Component<CollectionViewProps> {
-
@computed protected get cursors(): CursorField[] {
const doc = this.props.Document;
let cursors: FieldResult<List<CursorField>>;
- const { id } = CurrentUserUtils;
+ const id = Doc.UserDoc()[Id];
if (!id || !(cursors = Cast(doc.cursors, listSpec(CursorField)))) {
return [];
}
const now = mobxUtils.now();
- return (cursors || []).filter(({ data: { metadata } }) => metadata.id !== id && (now - metadata.timestamp) < 1000);
+ return (cursors || []).filter(({ data: { metadata } }) => metadata.id !== id && now - metadata.timestamp < 1000);
}
@computed get renderedCursors() {
- return this.cursors.map(({ data: { metadata, position: { x, y } } }) => {
- return (
- <div key={metadata.id} className="collectionFreeFormRemoteCursors-cont"
- style={{ transform: `translate(${x - 10}px, ${y - 10}px)` }}
- >
- <canvas className="collectionFreeFormRemoteCursors-canvas"
- ref={(el) => {
- if (el) {
- const ctx = el.getContext('2d');
- if (ctx) {
- ctx.fillStyle = "#" + v5(metadata.id, v5.URL).substring(0, 6).toUpperCase() + "22";
- ctx.fillRect(0, 0, 20, 20);
+ return this.cursors.map(
+ ({
+ data: {
+ metadata,
+ position: { x, y },
+ },
+ }) => {
+ return (
+ <div key={metadata.id} className="collectionFreeFormRemoteCursors-cont" style={{ transform: `translate(${x - 10}px, ${y - 10}px)` }}>
+ <canvas
+ className="collectionFreeFormRemoteCursors-canvas"
+ ref={el => {
+ if (el) {
+ const ctx = el.getContext('2d');
+ if (ctx) {
+ ctx.fillStyle = '#' + v5(metadata.id, v5.URL).substring(0, 6).toUpperCase() + '22';
+ ctx.fillRect(0, 0, 20, 20);
- ctx.fillStyle = "black";
- ctx.lineWidth = 0.5;
+ ctx.fillStyle = 'black';
+ ctx.lineWidth = 0.5;
- ctx.beginPath();
+ ctx.beginPath();
- ctx.moveTo(10, 0);
- ctx.lineTo(10, 8);
+ ctx.moveTo(10, 0);
+ ctx.lineTo(10, 8);
- ctx.moveTo(10, 20);
- ctx.lineTo(10, 12);
+ ctx.moveTo(10, 20);
+ ctx.lineTo(10, 12);
- ctx.moveTo(0, 10);
- ctx.lineTo(8, 10);
+ ctx.moveTo(0, 10);
+ ctx.lineTo(8, 10);
- ctx.moveTo(20, 10);
- ctx.lineTo(12, 10);
+ ctx.moveTo(20, 10);
+ ctx.lineTo(12, 10);
- ctx.stroke();
+ ctx.stroke();
+ }
}
- }
- }}
- width={20}
- height={20}
- />
- <p className="collectionFreeFormRemoteCursors-symbol">
- {metadata.identifier[0].toUpperCase()}
- </p>
- </div>
- );
- });
+ }}
+ width={20}
+ height={20}
+ />
+ <p className="collectionFreeFormRemoteCursors-symbol">{metadata.identifier[0].toUpperCase()}</p>
+ </div>
+ );
+ }
+ );
}
render() {
return this.renderedCursors;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8444c9119..07ea26346 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -18,13 +18,13 @@ import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from '../../../../Utils';
import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
import { Docs, DocUtils } from '../../../documents/Documents';
-import { DocumentType } from '../../../documents/DocumentTypes';
-import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
+import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager, dropActionType } from '../../../util/DragManager';
import { HistoryUtil } from '../../../util/History';
import { InteractionUtils } from '../../../util/InteractionUtils';
import { RecordingApi } from '../../../util/RecordingApi';
+import { ReplayMovements } from '../../../util/ReplayMovements';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { SelectionManager } from '../../../util/SelectionManager';
import { ColorScheme } from '../../../util/SettingsManager';
@@ -48,7 +48,6 @@ import { StyleProp } from '../../StyleProvider';
import { CollectionDockingView } from '../CollectionDockingView';
import { CollectionSubView } from '../CollectionSubView';
import { TreeViewType } from '../CollectionTreeView';
-import { CollectionViewType } from '../CollectionView';
import { TabDocView } from '../TabDocView';
import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines';
import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors';
@@ -56,8 +55,6 @@ import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
import React = require('react');
import e = require('connect-flash');
-import { ReplayMovements } from '../../../util/ReplayMovements';
-
export type collectionFreeformViewProps = {
annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
@@ -517,7 +514,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) &&
!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)
) {
- switch (CurrentUserUtils.ActiveTool) {
+ switch (Doc.ActiveTool) {
case InkTool.Highlighter:
break;
// TODO: nda - this where we want to create the new "writingDoc" collection that we add strokes to
@@ -556,7 +553,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.addMoveListeners();
this.removeEndListeners();
this.addEndListeners();
- if (CurrentUserUtils.ActiveTool === InkTool.None) {
+ if (Doc.ActiveTool === InkTool.None) {
this._lastX = pt.pageX;
this._lastY = pt.pageY;
e.preventDefault();
@@ -577,14 +574,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
case GestureUtils.Gestures.Stroke:
const points = ge.points;
const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
- const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points, {
+ const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points, {
title: 'ink stroke',
x: B.x - ActiveInkWidth() / 2,
y: B.y - ActiveInkWidth() / 2,
_width: B.width + ActiveInkWidth(),
_height: B.height + ActiveInkWidth(),
});
- if (CurrentUserUtils.ActiveTool === InkTool.Write) {
+ if (Doc.ActiveTool === InkTool.Write) {
this.unprocessedDocs.push(inkDoc);
CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
}
@@ -775,7 +772,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onPointerMove = (e: PointerEvent): void => {
if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return;
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
- CurrentUserUtils.ActiveTool = InkTool.None;
+ Doc.ActiveTool = InkTool.None;
if (this.props.isContentActive(true)) e.stopPropagation();
} else if (!e.cancelBubble) {
if (this.tryDragCluster(e, this._hitCluster)) {
@@ -907,7 +904,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!e.cancelBubble) {
const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
if (myTouches[0]) {
- if (CurrentUserUtils.ActiveTool === InkTool.None) {
+ if (Doc.ActiveTool === InkTool.None) {
if (this.tryDragCluster(e, this._hitCluster)) {
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
e.preventDefault();
@@ -1061,8 +1058,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
onPointerWheel = (e: React.WheelEvent): void => {
- if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline)
- return;
+ if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) {
// things that can scroll vertically should do that instead of zooming
e.stopPropagation();
@@ -1079,7 +1075,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
Doc.UserDoc()?.presentationMode === 'recording' && RecordingApi.Instance.setRecordingFFView(this);
// TODO: make this based off the specific recording FFView
Doc.UserDoc()?.presentationMode === 'none' && RecordingApi.Instance.setPlayFFView(this);
-
+
// TODO: zzz + michael to figure out this merge in case of strange behaviour
// if (Doc.UserDoc()?.presentationMode === 'watching') {
// RecordingApi.Instance.pauseVideoAndMovements();
@@ -1118,7 +1114,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
else if (ranges.yrange.max <= panY - panelDim[1] / 2) panY = ranges.yrange.min - panelDim[1] / 2;
}
}
- if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.Document)) {
+ if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) {
this._viewTransition = panTime;
const scale = this.getLocalTransform().inverse().Scale;
const minScale = NumCast(this.rootDoc._viewScaleMin, 1);
@@ -2218,7 +2214,7 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
const renderGridSpace = gridSpace * this.props.zoomScaling();
const w = this.props.PanelWidth() + 2 * renderGridSpace;
const h = this.props.PanelHeight() + 2 * renderGridSpace;
- const strokeStyle = CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? 'rgba(255,255,255,0.5)' : 'rgba(0, 0,0,0.5)';
+ const strokeStyle = Doc.ActiveDashboard?.colorScheme === ColorScheme.Dark ? 'rgba(255,255,255,0.5)' : 'rgba(0, 0,0,0.5)';
return (
<canvas
className="collectionFreeFormView-grid"
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ab8a34d5a..4513ffb39 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,36 +1,33 @@
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, DocListCastAsync, Opt } from "../../../../fields/Doc";
-import { Id } from "../../../../fields/FieldSymbols";
-import { InkData, InkField, InkTool } from "../../../../fields/InkField";
-import { List } from "../../../../fields/List";
-import { RichTextField } from "../../../../fields/RichTextField";
-import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
-import { Cast, DocCast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
-import { ImageField } from "../../../../fields/URLField";
-import { GetEffectiveAcl } from "../../../../fields/util";
-import { intersectRect, returnFalse, Utils } from "../../../../Utils";
-import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
-import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { Transform } from "../../../util/Transform";
-import { undoBatch, UndoManager } from "../../../util/UndoManager";
-import { ContextMenu } from "../../ContextMenu";
-import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
-import { PinViewProps, PresBox } from "../../nodes/trails/PresBox";
-import { PresMovement } from "../../nodes/trails/PresEnums";
-import { VideoBox } from "../../nodes/VideoBox";
-import { pasteImageBitmap } from "../../nodes/WebBoxRenderer";
-import { PreviewCursor } from "../../PreviewCursor";
-import { CollectionDockingView } from "../CollectionDockingView";
-import { SubCollectionViewProps } from "../CollectionSubView";
-import { TreeView } from "../TreeView";
-import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
-import "./MarqueeView.scss";
-import React = require("react");
-import { TabDocView } from "../TabDocView";
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, Opt } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
+import { InkData, InkField, InkTool } from '../../../../fields/InkField';
+import { List } from '../../../../fields/List';
+import { RichTextField } from '../../../../fields/RichTextField';
+import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
+import { Cast, DocCast, FieldValue, NumCast, StrCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { GetEffectiveAcl } from '../../../../fields/util';
+import { intersectRect, returnFalse, Utils } from '../../../../Utils';
+import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
+import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents';
+import { DocumentType } from '../../../documents/DocumentTypes';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { Transform } from '../../../util/Transform';
+import { undoBatch, UndoManager } from '../../../util/UndoManager';
+import { ContextMenu } from '../../ContextMenu';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import { PinViewProps, PresBox } from '../../nodes/trails/PresBox';
+import { VideoBox } from '../../nodes/VideoBox';
+import { pasteImageBitmap } from '../../nodes/WebBoxRenderer';
+import { PreviewCursor } from '../../PreviewCursor';
+import { SubCollectionViewProps } from '../CollectionSubView';
+import { TabDocView } from '../TabDocView';
+import { TreeView } from '../TreeView';
+import { MarqueeOptionsMenu } from './MarqueeOptionsMenu';
+import './MarqueeView.scss';
+import React = require('react');
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -46,15 +43,14 @@ interface MarqueeViewProps {
}
export interface MarqueeViewBounds {
- left: number;
- top: number;
- width: number;
- height: number;
+ left: number;
+ top: number;
+ width: number;
+ height: number;
}
@observer
-export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
-{
+export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps> {
private _commandExecuted = false;
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@@ -64,18 +60,26 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@observable _lassoPts: [number, number][] = [];
@observable _lassoFreehand: boolean = false;
- @computed get Transform() { return this.props.getTransform(); }
+ @computed get Transform() {
+ return this.props.getTransform();
+ }
@computed get Bounds() {
// nda - ternary argument to transformPoint is returning the lower of the downX/Y and lastX/Y and passing in as args x,y
const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
// nda - args to transformDirection is just x and y diff btw downX/Y and lastX/Y
const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- const bounds:MarqueeViewBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }
+ const bounds: MarqueeViewBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
return bounds;
}
- get inkDoc() { return this.props.Document; }
- get ink() { return Cast(this.props.Document.ink, InkField); }
- set ink(value: Opt<InkField>) { this.props.Document.ink = value; }
+ get inkDoc() {
+ return this.props.Document;
+ }
+ get ink() {
+ return Cast(this.props.Document.ink, InkField);
+ }
+ set ink(value: Opt<InkField>) {
+ this.props.Document.ink = value;
+ }
componentDidMount() {
this.props.setPreviewCursor?.(this.setPreviewCursor);
@@ -84,14 +88,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
cleanupInteractions = (all: boolean = false, hideMarquee: boolean = true) => {
if (all) {
- document.removeEventListener("pointerup", this.onPointerUp, true);
- document.removeEventListener("pointermove", this.onPointerMove, true);
+ document.removeEventListener('pointerup', this.onPointerUp, true);
+ document.removeEventListener('pointermove', this.onPointerMove, true);
}
- document.removeEventListener("keydown", this.marqueeCommand, true);
+ document.removeEventListener('keydown', this.marqueeCommand, true);
hideMarquee && this.hideMarquee();
this._lassoPts = [];
- }
+ };
@undoBatch
@action
@@ -100,76 +104,75 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// tslint:disable-next-line:prefer-const
const cm = ContextMenu.Instance;
const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
- if (e.key === "?") {
- cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
- Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: "bing", useCors: true }), "add:right"));
+ if (e.key === '?') {
+ cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', useCors: true }), 'add:right'));
cm.displayMenu(this._downX, this._downY, undefined, true);
e.stopPropagation();
- } else
- if (e.key === "u" && this.props.ungroup) {
- e.stopPropagation();
- this.props.ungroup();
- }
- else if (e.key === ":") {
- DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument || returnFalse, x, y);
+ } else if (e.key === 'u' && this.props.ungroup) {
+ e.stopPropagation();
+ this.props.ungroup();
+ } else if (e.key === ':') {
+ DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument || returnFalse, x, y);
- cm.displayMenu(this._downX, this._downY, undefined, true);
- e.stopPropagation();
- } else if (e.key === "a" && (e.ctrlKey || e.metaKey)) {
- e.preventDefault();
- this.props.selectDocuments(this.props.activeDocuments());
- e.stopPropagation();
- } else if (e.key === "q" && e.ctrlKey) {
- e.preventDefault();
- (async () => {
- const text: string = await navigator.clipboard.readText();
- const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== "");
- for (let i = 0; i < ns.length - 1; i++) {
- while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") ||
- ns[i].endsWith(";\r") || ns[i].endsWith(";") ||
- ns[i].endsWith(".\r") || ns[i].endsWith(".") ||
- ns[i].endsWith(":\r") || ns[i].endsWith(":")) && i < ns.length - 1) {
- const sub = ns[i].endsWith("\r") ? 1 : 0;
- const br = ns[i + 1].trim() === "";
- ns.splice(i, 2, ns[i].substr(0, ns[i].length - sub) + ns[i + 1].trimLeft());
- if (br) break;
- }
+ cm.displayMenu(this._downX, this._downY, undefined, true);
+ e.stopPropagation();
+ } else if (e.key === 'a' && (e.ctrlKey || e.metaKey)) {
+ e.preventDefault();
+ this.props.selectDocuments(this.props.activeDocuments());
+ e.stopPropagation();
+ } else if (e.key === 'q' && e.ctrlKey) {
+ e.preventDefault();
+ (async () => {
+ const text: string = await navigator.clipboard.readText();
+ const ns = text.split('\n').filter(t => t.trim() !== '\r' && t.trim() !== '');
+ for (let i = 0; i < ns.length - 1; i++) {
+ while (
+ !(ns[i].trim() === '' || ns[i].endsWith('-\r') || ns[i].endsWith('-') || ns[i].endsWith(';\r') || ns[i].endsWith(';') || ns[i].endsWith('.\r') || ns[i].endsWith('.') || ns[i].endsWith(':\r') || ns[i].endsWith(':')) &&
+ i < ns.length - 1
+ ) {
+ const sub = ns[i].endsWith('\r') ? 1 : 0;
+ const br = ns[i + 1].trim() === '';
+ ns.splice(i, 2, ns[i].substr(0, ns[i].length - sub) + ns[i + 1].trimLeft());
+ if (br) break;
}
- let ypos = y;
- ns.map(line => {
- const indent = line.search(/\S|$/);
- const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line });
- this.props.addDocument?.(newBox);
- ypos += 40 * this.Transform.Scale;
- });
- })();
- e.stopPropagation();
- } else if (e.key === "b" && e.ctrlKey) {
- document.body.focus(); // so that we can access the clipboard without an error
- setTimeout(() =>
- pasteImageBitmap((data: any, error: any) => {
- error && console.log(error);
- data && VideoBox.convertDataUri(data, this.props.Document[Id] + "-thumb-frozen").then(returnedfilename => {
- this.props.Document["thumb-frozen"] = new ImageField(returnedfilename);
+ }
+ let ypos = y;
+ ns.map(line => {
+ const indent = line.search(/\S|$/);
+ const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + (indent / 3) * 10, y: ypos, title: line });
+ this.props.addDocument?.(newBox);
+ ypos += 40 * this.Transform.Scale;
+ });
+ })();
+ e.stopPropagation();
+ } else if (e.key === 'b' && e.ctrlKey) {
+ document.body.focus(); // so that we can access the clipboard without an error
+ setTimeout(() =>
+ pasteImageBitmap((data: any, error: any) => {
+ error && console.log(error);
+ data &&
+ VideoBox.convertDataUri(data, this.props.Document[Id] + '-thumb-frozen').then(returnedfilename => {
+ this.props.Document['thumb-frozen'] = new ImageField(returnedfilename);
});
- }));
- } else if (e.key === "s" && e.ctrlKey) {
- e.preventDefault();
- const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!;
- slide.x = x;
- slide.y = y;
- FormattedTextBox.SelectOnLoad = slide[Id];
- TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
- this.props.addDocument?.(slide);
- e.stopPropagation();
- } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
- FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : "";
- FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
- this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xPadding === 0));
- e.stopPropagation();
- }
- }
+ })
+ );
+ } else if (e.key === 's' && e.ctrlKey) {
+ e.preventDefault();
+ const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!;
+ slide.x = x;
+ slide.y = y;
+ FormattedTextBox.SelectOnLoad = slide[Id];
+ TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
+ this.props.addDocument?.(slide);
+ e.stopPropagation();
+ } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
+ FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
+ FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('live text batch');
+ this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0));
+ e.stopPropagation();
+ }
+ };
//heuristically converts pasted text into a table.
// assumes each entry is separated by a tab
// skips all rows until it gets to a row with more than one entry
@@ -178,26 +181,26 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header
// assumes each cell is a string or a number
pasteTable(ns: string[], x: number, y: number) {
- while (ns.length > 0 && ns[0].split("\t").length < 2) {
+ while (ns.length > 0 && ns[0].split('\t').length < 2) {
ns.splice(0, 1);
}
if (ns.length > 0) {
- const columns = ns[0].split("\t");
+ const columns = ns[0].split('\t');
const docList: Doc[] = [];
- let groupAttr: string | number = "";
+ let groupAttr: string | number = '';
const rowProto = new Doc();
rowProto.title = rowProto.Id;
rowProto._width = 200;
rowProto.isPrototype = true;
for (let i = 1; i < ns.length - 1; i++) {
- const values = ns[i].split("\t");
+ const values = ns[i].split('\t');
if (values.length === 1 && columns.length > 1) {
groupAttr = values[0];
continue;
}
const docDataProto = Doc.MakeDelegate(rowProto);
docDataProto.isPrototype = true;
- columns.forEach((col, i) => docDataProto[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined));
+ columns.forEach((col, i) => (docDataProto[columns[i]] = values.length > i ? (values[i].indexOf(Number(values[i]).toString()) !== -1 ? Number(values[i]) : values[i]) : undefined));
if (groupAttr) {
docDataProto._group = groupAttr;
}
@@ -206,7 +209,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
doc._width = 200;
docList.push(doc);
}
- const newCol = Docs.Create.SchemaDocument([...(groupAttr ? [new SchemaHeaderField("_group", "#f1efeb")] : []), ...columns.filter(c => c).map(c => new SchemaHeaderField(c, "#f1efeb"))], docList, { x: x, y: y, title: "droppedTable", _width: 300, _height: 100 });
+ const newCol = Docs.Create.SchemaDocument([...(groupAttr ? [new SchemaHeaderField('_group', '#f1efeb')] : []), ...columns.filter(c => c).map(c => new SchemaHeaderField(c, '#f1efeb'))], docList, {
+ x: x,
+ y: y,
+ title: 'droppedTable',
+ _width: 300,
+ _height: 100,
+ });
this.props.addDocument?.(newCol);
}
@@ -227,10 +236,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// }
// bcz: do we need this? it kills the context menu on the main collection if !altKey
// e.stopPropagation();
- }
- else PreviewCursor.Visible = false;
+ } else PreviewCursor.Visible = false;
}
- }
+ };
@action
onPointerMove = (e: PointerEvent): void => {
@@ -238,8 +246,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._lastY = e.pageY;
this._lassoPts.push([e.clientX, e.clientY]);
if (!e.cancelBubble) {
- if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD ||
- Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) {
+ if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) {
if (!this._commandExecuted) {
this.showMarquee();
}
@@ -253,7 +260,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (PresBox.startMarquee) {
e.stopPropagation();
}
- }
+ };
@action
onPointerUp = (e: PointerEvent): void => {
@@ -270,14 +277,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const hideMarquee = () => {
this.hideMarquee();
MarqueeOptionsMenu.Instance.fadeOut(true);
- document.removeEventListener("pointerdown", hideMarquee);
- document.removeEventListener("wheel", hideMarquee);
+ document.removeEventListener('pointerdown', hideMarquee);
+ document.removeEventListener('wheel', hideMarquee);
};
if (PresBox.startMarquee) {
this.pinWithView();
PresBox.startMarquee = false;
}
- if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100) && !PresBox.startMarquee) {
+ if (!this._commandExecuted && Math.abs(this.Bounds.height * this.Bounds.width) > 100 && !PresBox.startMarquee) {
MarqueeOptionsMenu.Instance.createCollection = this.collection;
MarqueeOptionsMenu.Instance.delete = this.delete;
MarqueeOptionsMenu.Instance.summarize = this.summary;
@@ -285,19 +292,22 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
MarqueeOptionsMenu.Instance.hideMarquee = this.hideMarquee;
MarqueeOptionsMenu.Instance.jumpTo(e.clientX, e.clientY);
MarqueeOptionsMenu.Instance.pinWithView = this.pinWithView;
- document.addEventListener("pointerdown", hideMarquee);
- document.addEventListener("wheel", hideMarquee);
+ document.addEventListener('pointerdown', hideMarquee);
+ document.addEventListener('wheel', hideMarquee);
} else {
this.hideMarquee();
}
this.cleanupInteractions(true, this._commandExecuted);
e.altKey && e.preventDefault();
- }
+ };
clearSelection() {
- if (window.getSelection) { window.getSelection()?.removeAllRanges(); }
- else if (document.getSelection()) { document.getSelection()?.empty(); }
+ if (window.getSelection) {
+ window.getSelection()?.removeAllRanges();
+ } else if (document.getSelection()) {
+ document.getSelection()?.empty();
+ }
}
setPreviewCursor = action((x: number, y: number, drag: boolean, hide: boolean) => {
@@ -312,9 +322,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._commandExecuted = false;
PreviewCursor.Visible = false;
this.cleanupInteractions(true);
- document.addEventListener("pointermove", this.onPointerMove, true);
- document.addEventListener("pointerup", this.onPointerUp, true);
- document.addEventListener("keydown", this.marqueeCommand, true);
+ document.addEventListener('pointermove', this.onPointerMove, true);
+ document.addEventListener('pointerup', this.onPointerUp, true);
+ document.addEventListener('keydown', this.marqueeCommand, true);
} else {
this._downX = x;
this._downY = y;
@@ -328,9 +338,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
onClick = (e: React.MouseEvent): void => {
- if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
- Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
- if (CurrentUserUtils.ActiveTool === InkTool.None) {
+ if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+ if (Doc.ActiveTool === InkTool.None) {
if (!(e.nativeEvent as any).marqueeHit) {
(e.nativeEvent as any).marqueeHit = true;
if (!this.props.trySelectCluster(e.shiftKey)) {
@@ -339,17 +348,22 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
}
// let the DocumentView stopPropagation of this event when it selects this document
- } else { // why do we get a click event when the cursor have moved a big distance?
+ } else {
+ // why do we get a click event when the cursor have moved a big distance?
// let's cut it off here so no one else has to deal with it.
e.stopPropagation();
}
- }
+ };
@action
- showMarquee = () => { this._visible = true; }
+ showMarquee = () => {
+ this._visible = true;
+ };
@action
- hideMarquee = () => { this._visible = false; }
+ hideMarquee = () => {
+ this._visible = false;
+ };
@undoBatch
@action
@@ -361,16 +375,18 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- }
+ };
getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, makeGroup: Opt<boolean>) => {
- const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
- Doc.GetProto(doc).data = new List<Doc>(selected);
- Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform";
- !this.props.isAnnotationOverlay && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, undefined, Doc.GetProto(doc));
- doc._panX = doc._panY = 0;
- return doc;
- })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
+ const newCollection = creator
+ ? creator(selected, { title: 'nested stack' })
+ : ((doc: Doc) => {
+ Doc.GetProto(doc).data = new List<Doc>(selected);
+ Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
+ !this.props.isAnnotationOverlay && Doc.AddDocToList(Doc.MyFileOrphans, undefined, Doc.GetProto(doc));
+ doc._panX = doc._panY = 0;
+ return doc;
+ })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
newCollection.system = undefined;
newCollection._width = this.Bounds.width;
newCollection._height = this.Bounds.height;
@@ -378,7 +394,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
newCollection.forceActive = makeGroup;
newCollection.x = this.Bounds.left;
newCollection.y = this.Bounds.top;
- selected.forEach(d => d.context = newCollection);
+ selected.forEach(d => (d.context = newCollection));
this.hideMarquee();
return newCollection;
});
@@ -393,74 +409,76 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.props.selectDocuments([newCollection]);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- }
-
- /**
- * This triggers the TabDocView.PinDoc method which is the universal method
- * used to pin documents to the currently active presentation trail.
- *
- * This one is unique in that it includes the bounds associated with marquee view.
- */
+ };
+
+ /**
+ * This triggers the TabDocView.PinDoc method which is the universal method
+ * used to pin documents to the currently active presentation trail.
+ *
+ * This one is unique in that it includes the bounds associated with marquee view.
+ */
@undoBatch
@action
pinWithView = async () => {
const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
- const doc = this.props.Document;
- const viewOptions:PinViewProps = {
- bounds: this.Bounds,
- scale: scale
- };
- TabDocView.PinDoc(doc, {pinWithView: viewOptions});
- MarqueeOptionsMenu.Instance.fadeOut(true);
+ const doc = this.props.Document;
+ const viewOptions: PinViewProps = {
+ bounds: this.Bounds,
+ scale: scale,
+ };
+ TabDocView.PinDoc(doc, { pinWithView: viewOptions });
+ MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- }
+ };
@undoBatch
@action
collection = (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => {
const selected = this.marqueeSelect(false);
- if (e instanceof KeyboardEvent ? "cg".includes(e.key) : true) {
- selected.map(action(d => {
- const dx = NumCast(d.x);
- const dy = NumCast(d.y);
- delete d.x;
- delete d.y;
- delete d.activeFrame;
- delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
- delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
- d.x = dx - this.Bounds.left - this.Bounds.width / 2;
- d.y = dy - this.Bounds.top - this.Bounds.height / 2;
- return d;
- }));
+ if (e instanceof KeyboardEvent ? 'cg'.includes(e.key) : true) {
+ selected.map(
+ action(d => {
+ const dx = NumCast(d.x);
+ const dy = NumCast(d.y);
+ delete d.x;
+ delete d.y;
+ delete d.activeFrame;
+ delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+ delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+ d.x = dx - this.Bounds.left - this.Bounds.width / 2;
+ d.y = dy - this.Bounds.top - this.Bounds.height / 2;
+ return d;
+ })
+ );
this.props.removeDocument?.(selected);
}
// TODO: nda - this is the code to actually get a new grouped collection
- const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, group);
+ const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === 't' ? Docs.Create.StackingDocument : undefined, group);
this.props.addDocument?.(newCollection);
this.props.selectDocuments([newCollection]);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- }
+ };
@undoBatch
@action
syntaxHighlight = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false);
- if (e instanceof KeyboardEvent ? e.key === "i" : true) {
+ if (e instanceof KeyboardEvent ? e.key === 'i' : true) {
const inks = selected.filter(s => s.type === DocumentType.INK);
const setDocs = selected.filter(s => s.type === DocumentType.RTF && s.color);
- const sets = setDocs.map((sd) => Cast(sd.data, RichTextField)?.Text as string);
+ const sets = setDocs.map(sd => Cast(sd.data, RichTextField)?.Text as string);
const colors = setDocs.map(sd => FieldValue(sd.color) as string);
const wordToColor = new Map<string, string>();
- sets.forEach((st: string, i: number) => st.split(",").forEach(word => wordToColor.set(word, colors[i])));
+ sets.forEach((st: string, i: number) => st.split(',').forEach(word => wordToColor.set(word, colors[i])));
const strokes: InkData[] = [];
inks.filter(i => Cast(i.data, InkField)).forEach(i => {
const d = Cast(i.data, InkField, null);
- const left = Math.min(...d?.inkData.map(pd => pd.X) ?? [0]);
- const top = Math.min(...d?.inkData.map(pd => pd.Y) ?? [0]);
+ const left = Math.min(...(d?.inkData.map(pd => pd.X) ?? [0]));
+ const top = Math.min(...(d?.inkData.map(pd => pd.Y) ?? [0]));
strokes.push(d.inkData.map(pd => ({ X: pd.X + NumCast(i.x) - left, Y: pd.Y + NumCast(i.y) - top })));
});
- CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then((results) => {
+ CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then(results => {
// const wordResults = results.filter((r: any) => r.category === "inkWord");
// for (const word of wordResults) {
// const indices: number[] = word.strokeIds;
@@ -501,12 +519,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// }
// });
// }
- const lines = results.filter((r: any) => r.category === "line");
- const text = lines.map((l: any) => l.recognizedText).join("\r\n");
+ const lines = results.filter((r: any) => r.category === 'line');
+ const text = lines.map((l: any) => l.recognizedText).join('\r\n');
this.props.addDocument?.(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text }));
});
}
- }
+ };
@undoBatch
@action
@@ -517,15 +535,15 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.y = NumCast(d.y) - this.Bounds.top;
return d;
});
- const summary = Docs.Create.TextDocument("", { backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: "overview" });
- const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: "transparent" });
- DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summary of:summarized by", "");
+ const summary = Docs.Create.TextDocument('', { backgroundColor: '#e2ad32', x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: 'overview' });
+ const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: 'transparent' });
+ DocUtils.MakeLink({ doc: summary }, { doc: portal }, 'summary of:summarized by', '');
portal.hidden = true;
this.props.addDocument?.(portal);
this.props.addLiveTextDocument(summary);
MarqueeOptionsMenu.Instance.fadeOut(true);
- }
+ };
@action
background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
@@ -534,33 +552,33 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
setTimeout(() => this.props.selectDocuments([newCollection]));
- }
+ };
@undoBatch
marqueeCommand = action((e: KeyboardEvent) => {
if (this._commandExecuted || (e as any).propagationIsStopped) {
return;
}
- if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") {
+ if (e.key === 'Backspace' || e.key === 'Delete' || e.key === 'd') {
this._commandExecuted = true;
e.stopPropagation();
(e as any).propagationIsStopped = true;
this.delete();
e.stopPropagation();
}
- if ("cbtsSpg".indexOf(e.key) !== -1) {
+ if ('cbtsSpg'.indexOf(e.key) !== -1) {
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
(e as any).propagationIsStopped = true;
- if (e.key === "g") this.collection(e, true);
- if (e.key === "c" || e.key === "t") this.collection(e);
- if (e.key === "s" || e.key === "S") this.summary(e);
- if (e.key === "b") this.background(e);
- if (e.key === "p") this.pileup(e);
+ if (e.key === 'g') this.collection(e, true);
+ if (e.key === 'c' || e.key === 't') this.collection(e);
+ if (e.key === 's' || e.key === 'S') this.summary(e);
+ if (e.key === 'b') this.background(e);
+ if (e.key === 'p') this.pileup(e);
this.cleanupInteractions(false);
}
- if (e.key === "r" || e.key === " ") {
+ if (e.key === 'r' || e.key === ' ') {
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
@@ -568,18 +586,17 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
});
- touchesLine(r1: { left: number, top: number, width: number, height: number }) {
+ touchesLine(r1: { left: number; top: number; width: number; height: number }) {
for (const lassoPt of this._lassoPts) {
const topLeft = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
- if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width &&
- r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) {
+ if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width && r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) {
return true;
}
}
return false;
}
- boundingShape(r1: { left: number, top: number, width: number, height: number }) {
+ boundingShape(r1: { left: number; top: number; width: number; height: number }) {
const xs = this._lassoPts.map(pair => pair[0]);
const ys = this._lassoPts.map(pair => pair[1]);
const tl = this.Transform.transformPoint(Math.min(...xs), Math.min(...ys));
@@ -592,10 +609,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
let hasRight = false;
for (const lassoPt of this._lassoPts) {
const truePoint = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
- hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
- hasTop = hasTop || (truePoint[1] > tl[1] && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
- hasRight = hasRight || (truePoint[0] < br[0] && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
- hasBottom = hasBottom || (truePoint[1] < br[1] && truePoint[1] > r1.top + r1.height) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
+ hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left && truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
+ hasTop = hasTop || (truePoint[1] > tl[1] && truePoint[1] < r1.top && truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
+ hasRight = hasRight || (truePoint[0] < br[0] && truePoint[0] > r1.left + r1.width && truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
+ hasBottom = hasBottom || (truePoint[1] < br[1] && truePoint[1] > r1.top + r1.height && truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
if (hasTop && hasLeft && hasBottom && hasRight) {
return true;
}
@@ -615,9 +632,20 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
(this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc);
}
};
- this.props.activeDocuments().filter(doc => !doc.z && !doc._lockedPosition).map(selectFunc);
- if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc);
- if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc);
+ this.props
+ .activeDocuments()
+ .filter(doc => !doc.z && !doc._lockedPosition)
+ .map(selectFunc);
+ if (!selection.length && selectBackgrounds)
+ this.props
+ .activeDocuments()
+ .filter(doc => doc.z === undefined)
+ .map(selectFunc);
+ if (!selection.length)
+ this.props
+ .activeDocuments()
+ .filter(doc => doc.z !== undefined)
+ .map(selectFunc);
return selection;
}
@@ -625,31 +653,42 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const cpt = this._lassoFreehand || !this._visible ? [0, 0] : [this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY];
const p = this.props.getContainerTransform().transformPoint(cpt[0], cpt[1]);
const v = this._lassoFreehand ? [0, 0] : this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- return <div className="marquee" style={{
- transform: `translate(${p[0]}px, ${p[1]}px)`,
- width: Math.abs(v[0]),
- height: Math.abs(v[1]),
- zIndex: 2000
- }}> {this._lassoFreehand ?
- <svg height={2000} width={2000}>
- <polyline points={this._lassoPts.reduce((s, pt) => s + pt[0] + "," + pt[1] + " ", "")} fill="none" stroke="black" strokeWidth="1" strokeDasharray="3" />
- </svg>
- :
- <span className="marquee-legend" />}
- </div>;
+ return (
+ <div
+ className="marquee"
+ style={{
+ transform: `translate(${p[0]}px, ${p[1]}px)`,
+ width: Math.abs(v[0]),
+ height: Math.abs(v[1]),
+ zIndex: 2000,
+ }}>
+ {' '}
+ {this._lassoFreehand ? (
+ <svg height={2000} width={2000}>
+ <polyline points={this._lassoPts.reduce((s, pt) => s + pt[0] + ',' + pt[1] + ' ', '')} fill="none" stroke="black" strokeWidth="1" strokeDasharray="3" />
+ </svg>
+ ) : (
+ <span className="marquee-legend" />
+ )}
+ </div>
+ );
}
render() {
- return <div className="marqueeView"
- style={{
- overflow: StrCast(this.props.Document._overflow),
- cursor: [InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool) || this._visible || PresBox.startMarquee ? "crosshair" : "pointer"
- }}
-
- onDragOver={e => e.preventDefault()}
- onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
- {this._visible ? this.marqueeDiv : null}
- {this.props.children}
- </div>;
+ return (
+ <div
+ className="marqueeView"
+ style={{
+ overflow: StrCast(this.props.Document._overflow),
+ cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible || PresBox.startMarquee ? 'crosshair' : 'pointer',
+ }}
+ onDragOver={e => e.preventDefault()}
+ onScroll={e => (e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0)}
+ onClick={this.onClick}
+ onPointerDown={this.onPointerDown}>
+ {this._visible ? this.marqueeDiv : null}
+ {this.props.children}
+ </div>
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 8adfdc70b..0d7d67dd8 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -7,20 +7,17 @@ import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
-import { DocUtils } from '../../../documents/Documents';
-import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
+import { CollectionViewType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
import { Colors, Shadows } from '../../global/globalEnums';
-import { AudioBox } from '../../nodes/AudioBox';
import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
import { DocumentView } from '../../nodes/DocumentView';
import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
import { StyleProp } from '../../StyleProvider';
import { CollectionStackedTimeline } from '../CollectionStackedTimeline';
import { CollectionSubView } from '../CollectionSubView';
-import { CollectionViewType } from '../CollectionView';
import './CollectionLinearView.scss';
/**
@@ -228,7 +225,7 @@ export class CollectionLinearView extends CollectionSubView() {
}}>
{this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
</div>
- {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : (
+ {!DocumentLinksButton.StartLink || this.layoutDoc !== Doc.MyDockedBtns ? null : (
<span className="bottomPopup-background" style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()}>
<span className="bottomPopup-text">
Creating link from:{' '}
@@ -263,7 +260,7 @@ export class CollectionLinearView extends CollectionSubView() {
</Tooltip>
</span>
)}
- {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : (
+ {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== Doc.MyDockedBtns ? null : (
<span className="bottomPopup-background">
<span className="bottomPopup-text">
Currently playing: