aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authoranika-ahluwalia <anika.ahluwalia@gmail.com>2020-05-15 13:26:37 -0500
committeranika-ahluwalia <anika.ahluwalia@gmail.com>2020-05-15 13:26:37 -0500
commit4bca98333ada6536a1bf2ecf1681c5c17a3a1ae1 (patch)
tree7fc20099971de42756af3d238e2ea4f9a608cbd3 /src/client/views/collections
parent0f54ef61653213bd1b26300cb7d14e3da71d1eea (diff)
parent98c7540fff67c232c1b04f2130ee624f9a70afbd (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into script_documents
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx33
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx110
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx10
-rw-r--r--src/client/views/collections/CollectionMapView.tsx25
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx12
-rw-r--r--src/client/views/collections/CollectionPileView.tsx15
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx18
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx2
-rw-r--r--src/client/views/collections/CollectionSchemaMovableTableHOC.tsx20
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx34
-rw-r--r--src/client/views/collections/CollectionStackingView.scss7
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx96
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx28
-rw-r--r--src/client/views/collections/CollectionStaffView.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx145
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx16
-rw-r--r--src/client/views/collections/CollectionTreeView.scss1
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx251
-rw-r--r--src/client/views/collections/CollectionView.scss2
-rw-r--r--src/client/views/collections/CollectionView.tsx120
-rw-r--r--src/client/views/collections/CollectionViewChromes.tsx16
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx14
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx22
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx12
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx12
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx318
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx80
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx53
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx54
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx18
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx4
-rw-r--r--src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx4
-rw-r--r--src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx18
35 files changed, 939 insertions, 644 deletions
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index eda8e5684..39bb9bc23 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -2,21 +2,22 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { observable, computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { documentSchema } from '../../../new_fields/documentSchemas';
-import { makeInterface } from '../../../new_fields/Schema';
-import { NumCast, StrCast } from '../../../new_fields/Types';
+import { documentSchema, collectionSchema } from '../../../fields/documentSchemas';
+import { makeInterface } from '../../../fields/Schema';
+import { NumCast, StrCast, ScriptCast, Cast } from '../../../fields/Types';
import { DragManager } from '../../util/DragManager';
import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
import "./CollectionCarouselView.scss";
import { CollectionSubView } from './CollectionSubView';
import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons';
-import { Doc } from '../../../new_fields/Doc';
+import { Doc } from '../../../fields/Doc';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { ContextMenu } from '../ContextMenu';
-import { ObjectField } from '../../../new_fields/ObjectField';
+import { ObjectField } from '../../../fields/ObjectField';
+import { returnFalse } from '../../../Utils';
-type CarouselDocument = makeInterface<[typeof documentSchema,]>;
-const CarouselDocument = makeInterface(documentSchema);
+type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
+const CarouselDocument = makeInterface(documentSchema, collectionSchema);
@observer
export class CollectionCarouselView extends CollectionSubView(CarouselDocument) {
@@ -39,7 +40,6 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
e.stopPropagation();
this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
}
-
panelHeight = () => this.props.PanelHeight() - 50;
@computed get content() {
const index = NumCast(this.layoutDoc._itemIndex);
@@ -47,11 +47,18 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
<>
<div className="collectionCarouselView-image" key="image">
<ContentFittingDocumentView {...this.props}
+ onDoubleClick={ScriptCast(this.layoutDoc.onChildDoubleClick)}
+ onClick={ScriptCast(this.layoutDoc.onChildClick)}
renderDepth={this.props.renderDepth + 1}
+ LayoutTemplate={this.props.ChildLayoutTemplate}
+ LayoutTemplateString={this.props.ChildLayoutString}
Document={this.childLayoutPairs[index].layout}
- DataDocument={this.childLayoutPairs[index].data}
+ DataDoc={this.childLayoutPairs[index].data}
PanelHeight={this.panelHeight}
- getTransform={this.props.ScreenToLocalTransform} />
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ bringToFront={returnFalse}
+ parentActive={this.props.active}
+ />
</div>
<div className="collectionCarouselView-caption" key="caption"
style={{
@@ -60,9 +67,9 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
}}>
<FormattedTextBox key={index} {...this.props}
- xMargin={NumCast(this.layoutDoc["caption-xMargin"])}
- yMargin={NumCast(this.layoutDoc["caption-yMargin"])}
- Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox>
+ xMargin={NumCast(this.layoutDoc["_carousel-caption-xMargin"])}
+ yMargin={NumCast(this.layoutDoc["_carousel-caption-yMargin"])}
+ Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"} />
</div>
</>;
}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 0d859c3f1..745476ef7 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -7,13 +7,13 @@ import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
import Measure from "react-measure";
import * as GoldenLayout from "../../../client/goldenLayout";
-import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast, Field, Opt, DataSym } from "../../../new_fields/Doc";
-import { Id } from '../../../new_fields/FieldSymbols';
-import { List } from '../../../new_fields/List';
-import { FieldId } from "../../../new_fields/RefField";
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { TraceMobx } from '../../../new_fields/util';
+import { DateField } from '../../../fields/DateField';
+import { Doc, DocListCast, Field, Opt, DataSym } from "../../../fields/Doc";
+import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { FieldId } from "../../../fields/RefField";
+import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from '../../../fields/util';
import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { Docs } from '../../documents/Documents';
@@ -30,6 +30,7 @@ import { SubCollectionViewProps } from "./CollectionSubView";
import { DockingViewButtonSelector } from './ParentDocumentSelector';
import React = require("react");
import { CollectionViewType } from './CollectionView';
+import { SnappingManager } from '../../util/SnappingManager';
library.add(faFile);
const _global = (window /* browser */ || global /* node */) as any;
@@ -68,10 +69,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
//Why is this here?
(window as any).React = React;
(window as any).ReactDOM = ReactDOM;
+ DragManager.StartWindowDrag = this.StartOtherDrag;
}
- hack: boolean = false;
- undohack: any = null;
- public StartOtherDrag(e: any, dragDocs: Doc[]) {
+ public StartOtherDrag = (e: any, dragDocs: Doc[]) => {
let config: any;
if (dragDocs.length === 1) {
config = CollectionDockingView.makeDocumentConfig(dragDocs[0]);
@@ -190,6 +190,30 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
return retVal;
}
+ @undoBatch
+ @action
+ public static ReplaceTab(document: Doc, stack: any): Opt<Doc> {
+ if (!CollectionDockingView.Instance) return undefined;
+ const instance = CollectionDockingView.Instance;
+ const replaceTab = (doc: Doc, child: any): Opt<Doc> => {
+ for (const contentItem of child.contentItems) {
+ const { config, isStack, isRow, isColumn } = contentItem;
+ if (isRow || isColumn || isStack) {
+ const val = replaceTab(doc, contentItem);
+ if (val) return val;
+ } else if (config.component === "DocumentFrameRenderer" &&
+ config.props.documentId === doc[Id]) {
+ const alias = Doc.MakeAlias(doc);
+ config.props.documentId = alias[Id];
+ config.title = alias.title;
+ instance.stateChanged();
+ return alias;
+ }
+ }
+ return undefined;
+ };
+ return replaceTab(document, instance._goldenLayout.root);
+ }
//
// Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split
@@ -453,12 +477,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
const json = JSON.stringify(this._goldenLayout.toConfig());
this.props.Document.dockingConfig = json;
this.updateDataField(json);
-
- if (this.undohack && !this.hack) {
- this.undohack.end();
- this.undohack = undefined;
- }
- this.hack = false;
}
itemDropped = () => {
@@ -499,7 +517,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
const stack = tab.contentItem.parent;
// shifts the focus to this tab when another tab is dragged over it
tab.element[0].onmouseenter = (e: any) => {
- if (!this._isPointerDown || !SelectionManager.GetIsDragging()) return;
+ if (!this._isPointerDown || !SnappingManager.GetIsDragging()) return;
const activeContentItem = tab.header.parent.getActiveContentItem();
if (tab.contentItem !== activeContentItem) {
tab.header.parent.setActiveContentItem(tab.contentItem);
@@ -515,15 +533,17 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
}
};
- let rendered = false;
+
tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
(views) => {
- !rendered && ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
- <DockingViewButtonSelector views={views} Stack={stack} />
- </span>,
- gearSpan);
- rendered = true;
- });
+ if (views.length) {
+ ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
+ <DockingViewButtonSelector views={() => views} Stack={stack} />
+ </span>,
+ gearSpan);
+ tab.buttonDisposer?.();
+ }
+ }, { fireImmediately: true });
tab.reactComponents = [gearSpan];
tab.element.append(gearSpan);
@@ -679,15 +699,20 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
**/
@undoBatch
@action
- public static PinDoc(doc: Doc) {
- //add this new doc to props.Document
- const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
- if (curPres) {
- const pinDoc = Doc.MakeAlias(doc);
- pinDoc.presentationTargetDoc = doc;
- Doc.AddDocToList(curPres, "data", pinDoc);
- if (!DocumentManager.Instance.getDocumentView(curPres)) {
- CollectionDockingView.AddRightSplit(curPres);
+ public static PinDoc(doc: Doc, unpin = false) {
+ if (unpin) DockedFrameRenderer.UnpinDoc(doc);
+ else {
+ //add this new doc to props.Document
+ const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
+ if (curPres) {
+ const pinDoc = Doc.MakeAlias(doc);
+ pinDoc.presentationTargetDoc = doc;
+ pinDoc.presZoomButton = true;
+ pinDoc.context = curPres;
+ Doc.AddDocToList(curPres, "data", pinDoc);
+ if (!DocumentManager.Instance.getDocumentView(curPres)) {
+ CollectionDockingView.AddRightSplit(curPres);
+ }
}
}
}
@@ -732,8 +757,10 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
}
get layoutDoc() { return this._document && Doc.Layout(this._document); }
- panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth;
- panelHeight = () => this._panelHeight;
+ nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
+ panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) :
+ (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth)
+ panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight;
nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0;
nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0;
@@ -771,7 +798,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
return Transform.Identity();
}
get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
- get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
+ get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}%` : undefined; }
addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
SelectionManager.DeselectAll();
@@ -781,6 +808,13 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
return CollectionDockingView.AddRightSplit(doc, libraryPath);
} else if (location === "close") {
return CollectionDockingView.CloseRightSplit(doc);
+ } else if (location === "replace") {
+ const alias = CollectionDockingView.ReplaceTab(doc, this._stack);
+ if (alias) {
+ runInAction(() => this._document = alias);
+ return true;
+ }
+ return false;
} else {// if (location === "inPlace") {
return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
}
@@ -802,8 +836,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ContentScaling={this.contentScaling}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
+ NativeHeight={this.nativeHeight}
+ NativeWidth={this.nativeWidth}
ScreenToLocalTransform={this.ScreenToLocalTransform}
renderDepth={0}
parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 344dca23a..f1002044a 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -1,9 +1,9 @@
import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
-import { makeInterface } from '../../../new_fields/Schema';
-import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types';
+import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { makeInterface } from '../../../fields/Schema';
+import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../fields/Types';
import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse, returnZero } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
import { Transform } from '../../util/Transform';
@@ -11,8 +11,8 @@ import "./CollectionLinearView.scss";
import { CollectionViewType } from './CollectionView';
import { CollectionSubView } from './CollectionSubView';
import { DocumentView } from '../nodes/DocumentView';
-import { documentSchema } from '../../../new_fields/documentSchemas';
-import { Id } from '../../../new_fields/FieldSymbols';
+import { documentSchema } from '../../../fields/documentSchemas';
+import { Id } from '../../../fields/FieldSymbols';
type LinearDocument = makeInterface<[typeof documentSchema,]>;
diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 971224482..d91337ce9 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -1,10 +1,10 @@
import { GoogleApiWrapper, Map as GeoMap, IMapProps, Marker } from "google-maps-react";
import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc";
-import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
+import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../fields/Doc";
+import { documentSchema } from "../../../fields/documentSchemas";
+import { Id } from "../../../fields/FieldSymbols";
+import { makeInterface } from "../../../fields/Schema";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
import "./CollectionMapView.scss";
import { CollectionSubView } from "./CollectionSubView";
import React = require("react");
@@ -47,7 +47,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMapProps>
private _cancelAddrReq = new Map<string, boolean>();
private _cancelLocReq = new Map<string, boolean>();
private _initialLookupPending = new Map<string, boolean>();
- private responders: { location: Lambda, address: Lambda }[] = [];
+ private responders: { locationDisposer: Lambda, addressDisposer: Lambda }[] = [];
/**
* Note that all the uses of runInAction below are not included
@@ -176,13 +176,16 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMapProps>
}
@computed get reactiveContents() {
- this.responders.forEach(({ location, address }) => { location(); address(); });
+ this.responders.forEach(({ locationDisposer, addressDisposer }) => {
+ locationDisposer();
+ addressDisposer();
+ });
this.responders = [];
return this.childLayoutPairs.map(({ layout }) => {
const fieldKey = Doc.LayoutFieldKey(layout);
const id = layout[Id];
this.responders.push({
- location: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] }))
+ locationDisposer: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] }))
.observe(({ oldValue, newValue }) => {
if (this._cancelLocReq.get(id)) {
this._cancelLocReq.set(id, false);
@@ -190,7 +193,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMapProps>
this.respondToLocationChange(layout, fieldKey, newValue, oldValue);
}
}),
- address: computed(() => Cast(layout[`${fieldKey}-address`], "string", null))
+ addressDisposer: computed(() => Cast(layout[`${fieldKey}-address`], "string", null))
.observe(({ oldValue, newValue }) => {
if (this._cancelAddrReq.get(id)) {
this._cancelAddrReq.set(id, false);
@@ -206,7 +209,8 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMapProps>
render() {
const { childLayoutPairs } = this;
const { Document, fieldKey, active, google } = this.props;
- let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false);
+ const mapLoc = this.getLocation(this.rootDoc, `${fieldKey}-mapCenter`, false);
+ let center = mapLoc;
if (center === undefined) {
const childLocations = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false));
center = childLocations.find(location => location) || defaultLocation;
@@ -246,6 +250,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMapProps>
}}
>
{this.reactiveContents}
+ {mapLoc ? this.renderMarker(this.rootDoc) : undefined}
</GeoMap>
</div>
</div>;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 7ad15ef41..d6cb174cc 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -4,20 +4,20 @@ import { faPalette } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
-import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { StrCast, NumCast } from "../../../new_fields/Types";
+import { Doc } from "../../../fields/Doc";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../fields/ScriptField";
+import { StrCast, NumCast } from "../../../fields/Types";
import { numberRange, setupMoveUpEvents, emptyFunction } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
import { CompileScript } from "../../util/Scripting";
-import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { EditableView } from "../EditableView";
import { CollectionStackingView } from "./CollectionStackingView";
import "./CollectionStackingView.scss";
+import { SnappingManager } from "../../util/SnappingManager";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -132,7 +132,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
this._color = color;
}
- pointerEnteredRow = action(() => SelectionManager.GetIsDragging() && (this._background = "#b4b4b4"));
+ pointerEnteredRow = action(() => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4"));
@action
pointerLeaveRow = () => {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 3bbfcc4d7..e3bcf2a21 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -1,8 +1,8 @@
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types";
+import { HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { ScriptField } from "../../../fields/ScriptField";
+import { BoolCast, NumCast, StrCast } from "../../../fields/Types";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
@@ -12,6 +12,7 @@ import React = require("react");
import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils";
import { SelectionManager } from "../../util/SelectionManager";
import { UndoManager } from "../../util/UndoManager";
+import { SnappingManager } from "../../util/SnappingManager";
@observer
export class CollectionPileView extends CollectionSubView(doc => doc) {
@@ -53,7 +54,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
toggleStarburst = action(() => {
if (this._layoutEngine === 'starburst') {
const defaultSize = 110;
- this.layoutDoc.overflow = undefined;
+ this.layoutDoc._overflow = undefined;
this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
@@ -61,7 +62,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
this._layoutEngine = 'pass';
} else {
const defaultSize = 25;
- this.layoutDoc.overflow = 'visible';
+ this.layoutDoc._overflow = 'visible';
!this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500);
!this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5);
if (this._layoutEngine === 'pass') {
@@ -78,7 +79,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
_undoBatch: UndoManager.Batch | undefined;
pointerDown = (e: React.PointerEvent) => {
let dist = 0;
- SelectionManager.SetIsDragging(true);
+ SnappingManager.SetIsDragging(true);
// this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header
setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
if (this.layoutEngine() === "pass" && this.childDocs.length && this.props.isSelected(true)) {
@@ -98,7 +99,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
}, () => {
this._undoBatch?.end();
this._undoBatch = undefined;
- SelectionManager.SetIsDragging(false);
+ SnappingManager.SetIsDragging(false);
if (!this.childDocs.length) {
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 82204ca7b..62aed67ed 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -4,8 +4,8 @@ import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
-import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
+import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
import { KeyCodes } from "../../util/KeyCodes";
import { SetupDrag, DragManager } from "../../util/DragManager";
import { CompileScript } from "../../util/Scripting";
@@ -16,13 +16,13 @@ import { EditableView } from "../EditableView";
import { FieldView, FieldViewProps } from "../nodes/FieldView";
import "./CollectionSchemaView.scss";
import { CollectionView } from "./CollectionView";
-import { NumCast, StrCast, BoolCast, FieldValue, Cast } from "../../../new_fields/Types";
+import { NumCast, StrCast, BoolCast, FieldValue, Cast } from "../../../fields/Types";
import { Docs } from "../../documents/Documents";
-import { SelectionManager } from "../../util/SelectionManager";
import { library } from '@fortawesome/fontawesome-svg-core';
import { faExpand } from '@fortawesome/free-solid-svg-icons';
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
import { undoBatch } from "../../util/UndoManager";
+import { SnappingManager } from "../../util/SnappingManager";
library.add(faExpand);
@@ -37,8 +37,8 @@ export interface CellProps {
renderDepth: number;
addDocTab: (document: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
- moveDocument: (document: Doc, targetCollection: Doc | undefined,
- addDocument: (document: Doc) => boolean) => boolean;
+ moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined,
+ addDocument: (document: Doc | Doc[]) => boolean) => boolean;
isFocused: boolean;
changeFocusedCellByIndex: (row: number, col: number) => void;
setIsEditing: (isEditing: boolean) => void;
@@ -185,11 +185,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const onItemDown = (e: React.PointerEvent) => {
fieldIsDoc && SetupDrag(this._focusRef,
() => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
- this._document[props.fieldKey] instanceof Doc ? (doc: Doc, target: Doc | undefined, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument,
+ this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
};
const onPointerEnter = (e: React.PointerEvent): void => {
- if (e.buttons === 1 && SelectionManager.GetIsDragging() && (type === "document" || type === undefined)) {
+ if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over";
}
};
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 507ee89e4..dae0600b1 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -7,7 +7,7 @@ import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ColumnType } from "./CollectionSchemaView";
import { faFile } from "@fortawesome/free-regular-svg-icons";
-import { SchemaHeaderField, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField";
+import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField";
import { undoBatch } from "../../util/UndoManager";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index 972714e34..6f1e8ac1f 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -2,18 +2,18 @@ import React = require("react");
import { ReactTableDefaults, TableCellRenderer, RowInfo } from "react-table";
import "./CollectionSchemaView.scss";
import { Transform } from "../../util/Transform";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc } from "../../../fields/Doc";
import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager";
-import { SelectionManager } from "../../util/SelectionManager";
-import { Cast, FieldValue, StrCast } from "../../../new_fields/Types";
+import { Cast, FieldValue, StrCast } from "../../../fields/Types";
import { ContextMenu } from "../ContextMenu";
import { action } from "mobx";
import { library } from '@fortawesome/fontawesome-svg-core';
import { faGripVertical, faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { DocumentManager } from "../../util/DocumentManager";
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
import { undoBatch } from "../../util/UndoManager";
+import { SnappingManager } from "../../util/SnappingManager";
library.add(faGripVertical, faTrash);
@@ -32,7 +32,7 @@ export class MovableColumn extends React.Component<MovableColumnProps> {
private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
onPointerEnter = (e: React.PointerEvent): void => {
- if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
+ if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
this._header!.current!.className = "collectionSchema-col-wrapper";
document.addEventListener("pointermove", this.onDragMove, true);
}
@@ -130,8 +130,8 @@ export class MovableColumn extends React.Component<MovableColumnProps> {
export interface MovableRowProps {
rowInfo: RowInfo;
ScreenToLocalTransform: () => Transform;
- addDoc: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean;
- removeDoc: (doc: Doc) => boolean;
+ addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
+ removeDoc: (doc: Doc | Doc[]) => boolean;
rowFocused: boolean;
textWrapRow: (doc: Doc) => void;
rowWrapped: boolean;
@@ -143,7 +143,7 @@ export class MovableRow extends React.Component<MovableRowProps> {
private _rowDropDisposer?: DragManager.DragDropDisposer;
onPointerEnter = (e: React.PointerEvent): void => {
- if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
+ if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
this._header!.current!.className = "collectionSchema-row-wrapper";
document.addEventListener("pointermove", this.onDragMove, true);
}
@@ -183,7 +183,7 @@ export class MovableRow extends React.Component<MovableRowProps> {
if (docDragData) {
e.stopPropagation();
if (docDragData.draggedDocuments[0] === rowDoc) return true;
- const addDocument = (doc: Doc) => this.props.addDoc(doc, rowDoc, before);
+ const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before);
const movedDocs = docDragData.draggedDocuments;
return (docDragData.dropAction || docDragData.userDropAction) ?
docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false)
@@ -201,7 +201,7 @@ export class MovableRow extends React.Component<MovableRowProps> {
@undoBatch
@action
- move: DragManager.MoveFunction = (doc: Doc, targetCollection: Doc | undefined, addDoc) => {
+ move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => {
const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection);
if (targetView && targetView.props.ContainingCollectionDoc) {
return doc !== targetCollection && doc !== targetView.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 380d91d2f..35f892d65 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -6,13 +6,13 @@ import { action, computed, observable, untracked } from "mobx";
import { observer } from "mobx-react";
import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
import "react-table/react-table.css";
-import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { ComputedField } from "../../../new_fields/ScriptField";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
+import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { listSpec } from "../../../fields/Schema";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ComputedField } from "../../../fields/ScriptField";
+import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../fields/Types";
import { Docs, DocumentOptions } from "../../documents/Documents";
import { CompileScript, Transformer, ts } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
@@ -27,7 +27,7 @@ import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
import { CollectionView } from "./CollectionView";
import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
+import { setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils";
import { DocumentView } from "../nodes/DocumentView";
library.add(faCog, faPlus, faSortUp, faSortDown);
@@ -121,7 +121,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{!this.previewDocument ? (null) :
<ContentFittingDocumentView
Document={this.previewDocument}
- DataDocument={undefined}
+ DataDoc={undefined}
NativeHeight={returnZero}
NativeWidth={returnZero}
fitToBox={true}
@@ -132,16 +132,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
rootSelected={this.rootSelected}
PanelWidth={this.previewWidth}
PanelHeight={this.previewHeight}
- getTransform={this.getPreviewTransform}
- CollectionDoc={this.props.CollectionView?.props.Document}
- CollectionView={this.props.CollectionView}
+ ScreenToLocalTransform={this.getPreviewTransform}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
moveDocument={this.props.moveDocument}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
- active={this.props.active}
+ parentActive={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
/>}
</div>;
}
@@ -205,9 +207,9 @@ export interface SchemaTableProps {
ContainingCollectionDoc: Opt<Doc>;
fieldKey: string;
renderDepth: number;
- deleteDocument: (document: Doc) => boolean;
- addDocument: (document: Doc) => boolean;
- moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+ deleteDocument: (document: Doc | Doc[]) => boolean;
+ addDocument: (document: Doc | Doc[]) => boolean;
+ moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
ScreenToLocalTransform: () => Transform;
active: (outsideReaction: boolean) => boolean;
onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 47faa9239..5eaf29316 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -180,13 +180,16 @@
.collectionStackingView-sectionHeader-subCont {
outline: none;
border: 0px;
- color: $light-color;
width: 100%;
- color: grey;
letter-spacing: 2px;
font-size: 75%;
transition: transform 0.2s;
position: relative;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: lightGray;
.editableView-container-editing-oneLine,
.editableView-container-editing {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e3720bf01..cc6077d98 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,14 +4,15 @@ import { CursorProperty } from "csstype";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Switch from 'rc-switch';
-import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
-import { TraceMobx } from "../../../new_fields/util";
-import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
+import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc";
+import { collectionSchema, documentSchema } from "../../../fields/documentSchemas";
+import { Id } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { listSpec, makeInterface } from "../../../fields/Schema";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll } from "../../../Utils";
import { DragManager, dropActionType } from "../../util/DragManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
@@ -24,11 +25,14 @@ import "./CollectionStackingView.scss";
import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
import { CollectionSubView } from "./CollectionSubView";
import { CollectionViewType } from "./CollectionView";
-import { SelectionManager } from "../../util/SelectionManager";
+import { SnappingManager } from "../../util/SnappingManager";
const _global = (window /* browser */ || global /* node */) as any;
+type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
+const StackingDocument = makeInterface(collectionSchema, documentSchema);
+
@observer
-export class CollectionStackingView extends CollectionSubView(doc => doc) {
+export class CollectionStackingView extends CollectionSubView(StackingDocument) {
_masonryGridRef: HTMLDivElement | null = null;
_draggerRef = React.createRef<HTMLDivElement>();
_pivotFieldDisposer?: IReactionDisposer;
@@ -53,6 +57,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
@computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
+ constructor(props: any) {
+ super(props);
+
+ if (this.sectionHeaders === undefined) {
+ this.props.Document.sectionHeaders = new List<SchemaHeaderField>();
+ }
+ }
+
children(docs: Doc[], columns?: number) {
TraceMobx();
this._docXfs.length = 0;
@@ -61,7 +73,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
const width = () => this.getDocWidth(d);
const dref = React.createRef<HTMLDivElement>();
const dxf = () => this.getDocTransform(d, dref.current!);
- this._docXfs.push({ dxf: dxf, width: width, height: height });
+ this._docXfs.push({ dxf, width, height });
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
@@ -81,7 +93,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
return new Map<SchemaHeaderField, Doc[]>();
}
- const sectionHeaders: SchemaHeaderField[] = Array.from(this.sectionHeaders);
+ const sectionHeaders = Array.from(this.sectionHeaders);
const fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
let changed = false;
this.filteredChildren.map(d => {
@@ -116,7 +128,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
getSimpleDocHeight(d?: Doc) {
if (!d) return 0;
- const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
const nw = NumCast(layoutDoc._nativeWidth);
const nh = NumCast(layoutDoc._nativeHeight);
let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
@@ -128,7 +140,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
return layoutDoc._fitWidth ? wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1) : layoutDoc[HeightSym]();
}
componentDidMount() {
- super.componentDidMount();
+ super.componentDidMount?.();
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
@@ -150,8 +162,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
}
- @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
- @computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
+ @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
+ @computed get onChildDoubleClickHandler() { return this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
addDocTab = (doc: Doc, where: string) => {
if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
@@ -160,14 +172,33 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
return this.props.addDocTab(doc, where);
}
+
+
+ focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
+ Doc.BrushDoc(doc);
+ this.props.focus(doc);
+ Doc.linkFollowHighlight(doc);
+
+ const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]);
+ if (found) {
+ const top = found.getBoundingClientRect().top;
+ const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
+ smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ }
+ afterFocus && setTimeout(() => {
+ if (afterFocus?.()) { }
+ }, 500);
+ }
+
getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
- const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
+ const layoutDoc = Doc.Layout(doc, this.props.ChildLayoutTemplate?.());
const height = () => this.getDocHeight(doc);
return <ContentFittingDocumentView
Document={doc}
- DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
+ DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
backgroundColor={this.props.backgroundColor}
- LayoutDoc={this.props.childLayoutTemplate}
+ LayoutTemplate={this.props.ChildLayoutTemplate}
+ LayoutTemplateString={this.props.ChildLayoutString}
LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
@@ -175,33 +206,37 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
PanelHeight={height}
NativeHeight={returnZero}
NativeWidth={returnZero}
- fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+ fitToBox={false}
+ dontRegisterView={this.props.dontRegisterView}
rootSelected={this.rootSelected}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
- onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
- getTransform={dxf}
- focus={this.props.focus}
- CollectionDoc={this.props.CollectionView?.props.Document}
- CollectionView={this.props.CollectionView}
+ onClick={this.onChildClickHandler}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={dxf}
+ focus={this.focusDocument}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
- active={this.props.active}
+ parentActive={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
addDocTab={this.addDocTab}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
pinToPres={this.props.pinToPres}
/>;
}
getDocWidth(d?: Doc) {
if (!d) return 0;
- const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
const nw = NumCast(layoutDoc._nativeWidth);
return Math.min(nw && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
}
getDocHeight(d?: Doc) {
if (!d) return 0;
- const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
const nw = NumCast(layoutDoc._nativeWidth);
const nh = NumCast(layoutDoc._nativeHeight);
let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
@@ -302,7 +337,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this.refList.push(ref);
const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
this.observer = new _global.ResizeObserver(action((entries: any) => {
- if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
+ if (this.props.Document._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
Doc.Layout(doc)._height = Math.min(1200, Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
}
}));
@@ -349,7 +384,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this.refList.push(ref);
const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
this.observer = new _global.ResizeObserver(action((entries: any) => {
- if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
+ if (this.props.Document._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
}
}));
@@ -397,6 +432,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
if (!e.isPropagationStopped()) {
const subItems: ContextMenuProps[] = [];
subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
+ subItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
}
}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 323d7be25..53435ccc9 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -4,16 +4,15 @@ import { faPalette } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { RichTextField } from "../../../new_fields/RichTextField";
-import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast, Cast } from "../../../new_fields/Types";
-import { ImageField } from "../../../new_fields/URLField";
-import { TraceMobx } from "../../../new_fields/util";
+import { Doc, DocListCast } from "../../../fields/Doc";
+import { RichTextField } from "../../../fields/RichTextField";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../fields/ScriptField";
+import { NumCast, StrCast, Cast } from "../../../fields/Types";
+import { ImageField } from "../../../fields/URLField";
+import { TraceMobx } from "../../../fields/util";
import { Docs, DocUtils } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
-import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { ContextMenu } from "../ContextMenu";
@@ -22,7 +21,8 @@ import { EditableView } from "../EditableView";
import { CollectionStackingView } from "./CollectionStackingView";
import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
import "./CollectionStackingView.scss";
-import { listSpec } from "../../../new_fields/Schema";
+import { listSpec } from "../../../fields/Schema";
+import { SnappingManager } from "../../util/SnappingManager";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -120,7 +120,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action
pointerEntered = () => {
- if (SelectionManager.GetIsDragging()) {
+ if (SnappingManager.GetIsDragging()) {
this._background = "#b4b4b4";
}
}
@@ -322,11 +322,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
<div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
title={evContents === `NO ${key.toUpperCase()} VALUE` ?
`Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
- style={{
- width: "100%",
- background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "inherit",
- color: "grey"
- }}>
+ style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "inherit" }}>
<EditableView {...headerEditableViewProps} />
{evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionColor">
@@ -359,7 +355,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
<div className="collectionStackingViewFieldColumn" key={heading}
style={{
width: `${100 / ((uniqueHeadings.length + ((chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`,
- height: undefined, // SelectionManager.GetIsDragging() ? "100%" : undefined,
+ height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined,
background: this._background
}}
ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx
index 5b9a69bf7..c5c3f96e8 100644
--- a/src/client/views/collections/CollectionStaffView.tsx
+++ b/src/client/views/collections/CollectionStaffView.tsx
@@ -1,7 +1,7 @@
import { CollectionSubView } from "./CollectionSubView";
import React = require("react");
import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx";
-import { NumCast } from "../../../new_fields/Types";
+import { NumCast } from "../../../fields/Types";
import "./CollectionStaffView.scss";
import { observer } from "mobx-react";
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 1bfd408f8..c9eb08b45 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,14 +1,14 @@
import { action, computed, IReactionDisposer, reaction } from "mobx";
import { basename } from 'path';
-import CursorField from "../../../new_fields/CursorField";
-import { Doc, Opt } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast } from "../../../new_fields/Types";
+import CursorField from "../../../fields/CursorField";
+import { Doc, Opt } 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 } from "../../../fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { Upload } from "../../../server/SharedMediaTypes";
import { Utils } from "../../../Utils";
import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils";
@@ -16,7 +16,7 @@ import { DocServer } from "../../DocServer";
import { Docs, DocumentOptions } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { Networking } from "../../Network";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
import { InteractionUtils } from "../../util/InteractionUtils";
import { undoBatch, UndoManager } from "../../util/UndoManager";
@@ -27,9 +27,9 @@ import { CollectionView } from "./CollectionView";
import React = require("react");
export interface CollectionViewProps extends FieldViewProps {
- addDocument: (document: Doc) => boolean;
- removeDocument: (document: Doc) => boolean;
- moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+ addDocument: (document: Doc | Doc[]) => boolean;
+ removeDocument: (document: Doc | Doc[]) => boolean;
+ moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
PanelWidth: () => number;
PanelHeight: () => number;
VisibleHeight?: () => number;
@@ -43,6 +43,10 @@ export interface CollectionViewProps extends FieldViewProps {
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: Opt<CollectionView>;
children?: never | (() => JSX.Element[]) | React.ReactNode;
+ ChildLayoutTemplate?: () => Doc;
+ ChildLayoutString?: string;
+ childClickScript?: ScriptField;
+ childDoubleClickScript?: ScriptField;
freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
@@ -56,7 +60,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
private dropDisposer?: DragManager.DragDropDisposer;
private gestureDisposer?: GestureUtils.GestureEventDisposer;
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- private _childLayoutDisposer?: IReactionDisposer;
protected _mainCont?: HTMLDivElement;
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this.dropDisposer?.();
@@ -64,7 +67,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.multiTouchDisposer?.();
if (ele) {
this._mainCont = ele;
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this));
this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
}
@@ -73,25 +76,9 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.createDashEventsTarget(ele);
}
- componentDidMount() {
- this._childLayoutDisposer = reaction(() => ({ childDocs: this.childDocs, childLayout: Cast(this.props.Document.childLayout, Doc) }),
- ({ childDocs, childLayout }) => {
- if (childLayout instanceof Doc) {
- childDocs.map(doc => {
- doc.layout_fromParent = childLayout;
- doc.layoutKey = "layout_fromParent";
- });
- }
- else if (!(childLayout instanceof Promise)) {
- childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout"));
- }
- }, { fireImmediately: true });
-
- }
componentWillUnmount() {
this.gestureDisposer?.();
this.multiTouchDisposer?.();
- this._childLayoutDisposer?.();
}
@computed get dataDoc() {
@@ -108,7 +95,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@computed get dataField() {
- return this.dataDoc[this.props.fieldKey + (this.props.annotationsKey ? "-" + this.props.annotationsKey : "")];
+ return this.dataDoc[this.props.annotationsKey || this.props.fieldKey];
}
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
@@ -208,34 +195,60 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
}
+ protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
+ if (de.complete.docDragData) {
+ // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction.
+ // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
+ if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) {
+ de.complete.docDragData.dropAction = targetAction;
+ }
+ e.stopPropagation();
+ }
+ }
+
+ addDocument = (doc: Doc | Doc[]) => this.props.addDocument(doc);
+
@undoBatch
@action
protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const docDragData = de.complete.docDragData;
- (this.props.Document.dropConverter instanceof ScriptField) &&
- this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this
+ ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
if (docDragData) {
let added = false;
if (docDragData.dropAction || docDragData.userDropAction) {
- added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
+ added = this.addDocument(docDragData.droppedDocuments);
} else if (docDragData.moveDocument) {
- const movedDocs = docDragData.draggedDocuments;
- added = movedDocs.reduce((added: boolean, d, i) =>
- docDragData.droppedDocuments[i] !== d ? this.props.addDocument(docDragData.droppedDocuments[i]) :
- docDragData.moveDocument?.(d, this.props.Document, this.props.addDocument) || added, false);
+ const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
+ const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
+ const res = addedDocs.length ? this.addDocument(addedDocs) : true;
+ added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.addDocument) : res;
} else {
- added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
+ added = this.addDocument(docDragData.droppedDocuments);
}
e.stopPropagation();
return added;
}
else if (de.complete.annoDragData) {
e.stopPropagation();
- return this.props.addDocument(de.complete.annoDragData.dropDocument);
+ return this.addDocument(de.complete.annoDragData.dropDocument);
}
return false;
}
+ readUploadedFileAsText = (inputFile: File) => {
+ const temporaryFileReader = new FileReader();
+
+ return new Promise((resolve, reject) => {
+ temporaryFileReader.onerror = () => {
+ temporaryFileReader.abort();
+ reject(new DOMException("Problem parsing input file."));
+ };
+ temporaryFileReader.onload = () => {
+ resolve(temporaryFileReader.result);
+ };
+ temporaryFileReader.readAsText(inputFile);
+ });
+ }
@undoBatch
@action
protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
@@ -254,7 +267,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
e.stopPropagation();
e.preventDefault();
- const { addDocument } = this.props;
+ const { addDocument } = this;
if (!addDocument) {
alert("this.props.addDocument does not exist. Aborting drop operation.");
return;
@@ -332,23 +345,23 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}));
return;
}
- let matches: RegExpExecArray | null;
- if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
- const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
- const proto = newBox.proto!;
- const documentId = matches[2];
- proto[GoogleRef] = documentId;
- proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
- proto.backgroundColor = "#eeeeff";
- addDocument(newBox);
- return;
- }
- if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
- const albumId = matches[3];
- const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
- console.log(mediaItems);
- return;
- }
+ // let matches: RegExpExecArray | null;
+ // if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
+ // const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
+ // const proto = newBox.proto!;
+ // const documentId = matches[2];
+ // proto[GoogleRef] = documentId;
+ // proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
+ // proto.backgroundColor = "#eeeeff";
+ // addDocument(newBox);
+ // return;
+ // }
+ // if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
+ // const albumId = matches[3];
+ // const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
+ // console.log(mediaItems);
+ // return;
+ // }
}
const { items } = e.dataTransfer;
@@ -373,7 +386,21 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}
if (item.kind === "file") {
const file = item.getAsFile();
- file && file.type && files.push(file);
+ file?.type && files.push(file);
+
+ file?.type === "application/json" && this.readUploadedFileAsText(file).then(result => {
+ console.log(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 }));
+ });
}
}
for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) {
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 045134225..15bc0bfd5 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,11 +1,11 @@
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt, DocCastAsync } from "../../../new_fields/Doc";
-import { List } from "../../../new_fields/List";
-import { ObjectField } from "../../../new_fields/ObjectField";
-import { RichTextField } from "../../../new_fields/RichTextField";
-import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast, BoolCast, Cast } from "../../../new_fields/Types";
+import { Doc, Opt, DocCastAsync } from "../../../fields/Doc";
+import { List } from "../../../fields/List";
+import { ObjectField } from "../../../fields/ObjectField";
+import { RichTextField } from "../../../fields/RichTextField";
+import { ComputedField, ScriptField } from "../../../fields/ScriptField";
+import { NumCast, StrCast, BoolCast, Cast } from "../../../fields/Types";
import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
import { Scripting } from "../../util/Scripting";
import { ContextMenu } from "../ContextMenu";
@@ -28,7 +28,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@observable _childClickedScript: Opt<ScriptField>;
@observable _viewDefDivClick: Opt<ScriptField>;
async componentDidMount() {
- const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), "");
+ const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), "");
const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
runInAction(() => {
this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! });
@@ -84,7 +84,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@computed get contents() {
return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%", pointerEvents: this.props.active() ? undefined : "none" }} onPointerDown={this.contentsDown}>
- <CollectionFreeFormView {...this.props} childClickScript={this._childClickedScript} viewDefDivClick={this._viewDefDivClick} fitToBox={true} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
+ <CollectionFreeFormView {...this.props} childClickScript={this._childClickedScript} viewDefDivClick={this._viewDefDivClick} fitToBox={true} freezeChildDimensions={true} layoutEngine={this.layoutEngine} />
</div>;
}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index a00bb6bfb..2aac81146 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -81,7 +81,6 @@
position: relative;
text-overflow: ellipsis;
white-space: pre-wrap;
- overflow: hidden;
min-width: 10px;
// width:100%;//width: max-content;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d938bd7ad..3e99af724 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,21 +1,19 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faExpand, faMinus, faPlus, faTrash, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction, untracked } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc';
-import { Id } from '../../../new_fields/FieldSymbols';
-import { List } from '../../../new_fields/List';
-import { RichTextField } from '../../../new_fields/RichTextField';
-import { Document, listSpec } from '../../../new_fields/Schema';
-import { ComputedField, ScriptField } from '../../../new_fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types';
+import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { PrefetchProxy } from '../../../fields/Proxy';
+import { Document, listSpec } from '../../../fields/Schema';
+import { ComputedField, ScriptField } from '../../../fields/ScriptField';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentManager } from '../../util/DocumentManager';
+import { SnappingManager } from '../../util/SnappingManager';
import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
-import { makeTemplate } from '../../util/DropConverter';
import { Scripting } from '../../util/Scripting';
import { SelectionManager } from '../../util/SelectionManager';
import { Transform } from '../../util/Transform';
@@ -33,7 +31,8 @@ import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
import { CollectionViewType } from './CollectionView';
import React = require("react");
-
+import { makeTemplate } from '../../util/DropConverter';
+import { TraceMobx } from '../../../fields/util';
export interface TreeViewProps {
document: Doc;
@@ -42,7 +41,7 @@ export interface TreeViewProps {
containingCollection: Doc;
prevSibling?: Doc;
renderDepth: number;
- deleteDoc: (doc: Doc) => boolean;
+ deleteDoc: (doc: Doc | Doc[]) => boolean;
moveDocument: DragManager.MoveFunction;
dropAction: dropActionType;
addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
@@ -50,7 +49,7 @@ export interface TreeViewProps {
panelWidth: () => number;
panelHeight: () => number;
ChromeHeight: undefined | (() => number);
- addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean;
+ addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
indentDocument?: () => void;
outdentDocument?: () => void;
ScreenToLocalTransform: () => Transform;
@@ -61,24 +60,12 @@ export interface TreeViewProps {
active: (outsideReaction?: boolean) => boolean;
treeViewHideHeaderFields: () => boolean;
treeViewPreventOpen: boolean;
- renderedIds: string[];
+ renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
onCheckedClick?: ScriptField;
onChildClick?: ScriptField;
ignoreFields?: string[];
}
-library.add(faTrashAlt);
-library.add(faAngleRight);
-library.add(faBell);
-library.add(faTrash);
-library.add(faCamera);
-library.add(faExpand);
-library.add(faCaretDown);
-library.add(faCaretRight);
-library.add(faCaretSquareDown);
-library.add(faCaretSquareRight);
-library.add(faArrowsAltH);
-library.add(faPlus, faMinus);
@observer
/**
* Renders a treeView of a collection of documents
@@ -89,66 +76,59 @@ library.add(faPlus, faMinus);
* treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
*/
class TreeView extends React.Component<TreeViewProps> {
+ static _editTitleScript: ScriptField | undefined;
private _header?: React.RefObject<HTMLDivElement> = React.createRef();
private _treedropDisposer?: DragManager.DragDropDisposer;
private _dref = React.createRef<HTMLDivElement>();
private _tref = React.createRef<HTMLDivElement>();
+ private _docRef = React.createRef<DocumentView>();
get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
-
get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); }
@observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
- @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
+ @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.props.document.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
@computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
@computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
- @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; }
+ @computed get dataDoc() { return this.props.document[DataSym]; }
@computed get fieldKey() {
const splits = StrCast(Doc.LayoutField(this.props.document)).split("fieldKey={\'");
return splits.length > 1 ? splits[1].split("\'")[0] : "data";
}
childDocList(field: string) {
const layout = Doc.LayoutField(this.props.document) instanceof Doc ? Doc.LayoutField(this.props.document) as Doc : undefined;
- return ((this.props.dataDoc ? Cast(this.props.dataDoc[field], listSpec(Doc)) : undefined) ||
- (layout ? Cast(layout[field], listSpec(Doc)) : undefined) ||
- Cast(this.props.document[field], listSpec(Doc))) as Doc[];
+ return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
+ (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || // else if there's a layout doc, display it's fields
+ Cast(this.props.document[field], listSpec(Doc))) as Doc[]; // otherwise use the document's data field
}
@computed get childDocs() { return this.childDocList(this.fieldKey); }
@computed get childLinks() { return this.childDocList("links"); }
- @computed get templateDataDoc() {
- if (this.props.dataDoc === undefined && Doc.LayoutField(this.props.document) !== "string") {
- // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string),
- // then we render the layout document as a template and use this document as the data context for the template layout.
- return this.props.document;
- }
- return this.props.dataDoc;
- }
@computed get boundsOfCollectionDocument() {
return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined :
Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey]));
}
- @undoBatch delete = () => this.props.deleteDoc(this.props.document);
- @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath);
- @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
- @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => {
+ @undoBatch openRight = () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath);
+ @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
}
- @undoBatch @action remove = (document: Document, key: string) => {
- return Doc.RemoveDocFromList(this.dataDoc, key, document);
+ @undoBatch @action remove = (doc: Doc | Doc[], key: string) => {
+ return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) =>
+ flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
}
- @undoBatch @action removeDoc = (document: Document) => {
- return Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), document);
+ @undoBatch @action removeDoc = (doc: Doc | Doc[]) => {
+ return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) =>
+ flg && Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), doc), true);
}
protected createTreeDropTarget = (ele: HTMLDivElement) => {
- this._treedropDisposer && this._treedropDisposer();
+ this._treedropDisposer?.();
ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document);
}
onPointerEnter = (e: React.PointerEvent): void => {
this.props.active(true) && Doc.BrushDoc(this.dataDoc);
- if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
+ if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
this._header!.current!.className = "treeViewItem-header";
document.addEventListener("pointermove", this.onDragMove, true);
}
@@ -186,7 +166,7 @@ class TreeView extends React.Component<TreeViewProps> {
})}
OnFillDown={undoBatch((value: string) => {
Doc.SetInPlace(this.props.document, key, value, false);
- const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+ const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, _LODdisable: true, templates: new List<string>([Templates.Title.Layout]) });
Doc.SetInPlace(this.props.document, "editTitle", undefined, false);
Doc.SetInPlace(doc, "editTitle", true, false);
return this.props.addDocument(doc);
@@ -222,9 +202,10 @@ class TreeView extends React.Component<TreeViewProps> {
if (de.complete.docDragData) {
e.stopPropagation();
if (de.complete.docDragData.draggedDocuments[0] === this.props.document) return true;
- let addDoc = (doc: Doc) => this.props.addDocument(doc, undefined, before);
+ let addDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before);
if (inside) {
- addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc);
+ addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce(
+ ((flg: boolean, doc) => flg && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc)), true) || addDoc(doc);
}
const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments);
const move = de.complete.docDragData.dropAction === "move" || de.complete.docDragData.dropAction;
@@ -284,8 +265,9 @@ class TreeView extends React.Component<TreeViewProps> {
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))) {
- const remDoc = (doc: Doc) => this.remove(doc, key);
- const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
+ const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
+ const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce(
+ (flg, doc) => flg && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true), true);
contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
@@ -325,10 +307,12 @@ class TreeView extends React.Component<TreeViewProps> {
rtfHeight = () => this.rtfWidth() < Doc.Layout(this.props.document)?.[WidthSym]() ? Math.min(Doc.Layout(this.props.document)?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
@computed get renderContent() {
+ TraceMobx();
const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
if (expandKey !== undefined) {
- const remDoc = (doc: Doc) => this.remove(doc, expandKey);
- const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
+ const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey);
+ const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) =>
+ (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true);
const docs = expandKey === "links" ? this.childLinks : this.childDocs;
const sortKey = `${this.fieldKey}-sortAscending`;
return <ul key={expandKey + "more"} onClick={(e) => {
@@ -337,7 +321,7 @@ class TreeView extends React.Component<TreeViewProps> {
}}>
{!docs ? (null) :
TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
- this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
+ this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
StrCast(this.props.document.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
[...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields)}
@@ -353,27 +337,31 @@ class TreeView extends React.Component<TreeViewProps> {
return <div ref={this._dref} style={{ display: "inline-block", height: panelHeight() }} key={this.props.document[Id] + this.props.document.title}>
<ContentFittingDocumentView
Document={layoutDoc}
- DataDocument={this.templateDataDoc}
+ DataDoc={this.dataDoc}
LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
backgroundColor={this.props.backgroundColor}
fitToBox={this.boundsOfCollectionDocument !== undefined}
FreezeDimensions={true}
- NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
- NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
+ NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : returnZero}
+ NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : returnZero}
PanelWidth={panelWidth}
PanelHeight={panelHeight}
- getTransform={this.docTransform}
- CollectionDoc={this.props.containingCollection}
- CollectionView={undefined}
+ focus={returnFalse}
+ ScreenToLocalTransform={this.docTransform}
+ ContainingCollectionDoc={this.props.containingCollection}
+ ContainingCollectionView={undefined}
addDocument={returnFalse}
moveDocument={this.props.moveDocument}
removeDocument={returnFalse}
- active={this.props.active}
+ parentActive={this.props.active}
whenActiveChanged={emptyFunction}
addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres} />
+ pinToPres={this.props.pinToPres}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
+ />
</div>;
}
}
@@ -399,13 +387,16 @@ class TreeView extends React.Component<TreeViewProps> {
@computed
get renderBullet() {
const checked = this.props.document.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
- return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}>
+ return <div className="bullet"
+ title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
+ onClick={this.bulletClick}
+ style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}>
{<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
</div>;
}
showContextMenu = (e: React.MouseEvent) => {
- simulateMouseClick(this._docRef.current!.ContentDiv!, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ this._docRef.current?.ContentDiv && simulateMouseClick(this._docRef.current.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
e.stopPropagation();
}
focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true);
@@ -413,15 +404,13 @@ class TreeView extends React.Component<TreeViewProps> {
const focusScript = ScriptField.MakeFunction(`DocFocus(self)`);
return [{ script: focusScript!, label: "Focus" }];
}
- _docRef = React.createRef<DocumentView>();
/**
* Renders the EditableView title element for placement into the tree.
*/
@computed
get renderTitle() {
- const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
- const editTitle = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)");
-
+ TraceMobx();
+ (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(self, 'editTitle', true)"));
const headerElements = (
<>
<FontAwesomeIcon icon="cog" size="sm" onClick={e => this.showContextMenu(e)}></FontAwesomeIcon>
@@ -442,13 +431,12 @@ class TreeView extends React.Component<TreeViewProps> {
<FontAwesomeIcon title="open in pane on right" icon="angle-right" size="lg" />
</div>);
return <>
- <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`} onPointerDown={onItemDown}
+ <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`}
style={{
- background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
fontWeight: this.props.document.searchMatch ? "bold" : undefined,
textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined,
outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
- pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? undefined : "none"
+ pointerEvents: this.props.active() || SnappingManager.GetIsDragging() ? undefined : "none"
}} >
{Doc.GetT(this.props.document, "editTitle", "boolean", true) ?
this.editableView("title") :
@@ -456,12 +444,13 @@ class TreeView extends React.Component<TreeViewProps> {
ref={this._docRef}
Document={this.props.document}
DataDoc={undefined}
- LibraryPath={this.props.libraryPath || []}
+ treeViewId={this.props.treeViewId[Id]}
+ LibraryPath={this.props.libraryPath || emptyPath}
addDocument={undefined}
addDocTab={this.props.addDocTab}
rootSelected={returnTrue}
pinToPres={emptyFunction}
- onClick={this.props.onChildClick || editTitle}
+ onClick={this.props.onChildClick || TreeView._editTitleScript}
dropAction={this.props.dropAction}
moveDocument={this.move}
removeDocument={this.removeDoc}
@@ -473,11 +462,11 @@ class TreeView extends React.Component<TreeViewProps> {
NativeWidth={returnZero}
contextMenuItems={this.contextMenuItems}
renderDepth={1}
- focus={emptyFunction}
+ focus={returnTrue}
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
- dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)}
+ dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildViews)}
ContainingCollectionView={undefined}
ContainingCollectionDoc={this.props.containingCollection}
/>}
@@ -488,8 +477,9 @@ class TreeView extends React.Component<TreeViewProps> {
}
render() {
+ TraceMobx();
const sorting = this.props.document[`${this.fieldKey}-sortAscending`];
- setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
+ //setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
return <div className="treeViewItem-container" ref={this.createTreeDropTarget}>
<li className="collection-child">
<div className="treeViewItem-header" ref={this._header} onClick={e => {
@@ -497,12 +487,14 @@ class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
e.preventDefault();
}
- }} onPointerDown={e => {
- if (this.props.active(true)) {
- e.stopPropagation();
- e.preventDefault();
- }
- }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+ }}
+ onPointerDown={e => {
+ if (this.props.active(true)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }}
+ onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
{this.renderBullet}
{this.renderTitle}
</div>
@@ -520,8 +512,8 @@ class TreeView extends React.Component<TreeViewProps> {
key: string,
parentCollectionDoc: Doc | undefined,
parentPrevSibling: Doc | undefined,
- add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean,
- remove: ((doc: Doc) => boolean),
+ add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean,
+ remove: ((doc: Doc | Doc[]) => boolean),
move: DragManager.MoveFunction,
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => boolean,
@@ -610,7 +602,7 @@ class TreeView extends React.Component<TreeViewProps> {
remove(child);
}
};
- const addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
+ const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => {
return add(doc, relativeTo ? relativeTo : docs[i], before !== undefined ? before : false);
};
const childLayout = Doc.Layout(pair.layout);
@@ -680,22 +672,26 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
}
@action
- remove = (document: Document): boolean => {
- const children = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []);
- if (children.indexOf(document) !== -1) {
- children.splice(children.indexOf(document), 1);
+ remove = (doc: Doc | Doc[]): boolean => {
+ const docs = doc instanceof Doc ? [doc] : doc;
+ const targetDataDoc = this.props.Document[DataSym];
+ const value = DocListCast(targetDataDoc[this.props.fieldKey]);
+ const result = value.filter(v => !docs.includes(v));
+ if (result.length !== value.length) {
+ targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
return true;
}
return false;
}
@action
- addDoc = (doc: Document, relativeTo: Opt<Doc>, before?: boolean): boolean => {
- const doAddDoc = () =>
- Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false);
+ addDoc = (doc: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
+ const doAddDoc = (doc: Doc | Doc[]) =>
+ (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) =>
+ flg && Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false), true);
if (this.props.Document.resolvedDataDoc instanceof Promise) {
- this.props.Document.resolvedDataDoc.then((resolved: any) => doAddDoc());
+ this.props.Document.resolvedDataDoc.then((resolved: any) => doAddDoc(doc));
} else {
- doAddDoc();
+ doAddDoc(doc);
}
return true;
}
@@ -721,14 +717,6 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
}
ContextMenu.Instance.addItem({
description: "Buxton Layout", icon: "eye", event: () => {
- DocListCast(this.dataDoc[this.props.fieldKey]).map(d => {
- DocListCast(d.data).map((img, i) => {
- const caption = (d.captions as any)[i];
- if (caption) {
- Doc.GetProto(img).caption = caption;
- }
- });
- });
const { ImageDocument } = Docs.Create;
const { Document } = this.props;
const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
@@ -738,22 +726,27 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
heroView._showTitle = "title";
heroView._showTitleHover = "titlehover";
- Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data",
- Docs.Create.FontIconDocument({
- title: "hero view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias",
- dragFactory: heroView, removeDropProperties: new List<string>(["dropAction"]), icon: "portrait",
- onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
- }));
-
- Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data",
- Docs.Create.FontIconDocument({
- title: "detail view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias",
- dragFactory: detailView, removeDropProperties: new List<string>(["dropAction"]), icon: "file-alt",
- onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
- }));
-
- Document.childLayout = heroView;
- Document.childDetailView = detailView;
+ const doubleClickView = ImageDocument("http://cs.brown.edu/~bcz/face.gif", { _width: 400 }); // replace with desired double click target
+ DocListCast(this.dataDoc[this.props.fieldKey]).map(d => {
+ DocListCast(d.data).map((img, i) => {
+ const caption = (d.captions as any)[i];
+ if (caption) {
+ Doc.GetProto(img).caption = caption;
+ Doc.GetProto(img).doubleClickView = doubleClickView;
+ }
+ });
+ Doc.GetProto(d).type = "buxton";
+ Doc.GetProto(d).proto = heroView; // all devices "are" heroViews that share the same layout & defaults. Seems better than making them all be independent and copy a layout string // .layout = ImageBox.LayoutString("hero");
+ });
+
+ const iconBuxtonView = ImageDocument(fallbackImg, { title: "hero", _width: 60, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") });
+ iconBuxtonView.isTemplateDoc = makeTemplate(iconBuxtonView, true, "icon_buxton");
+ Doc.UserDoc()["template-icon-view-buxton"] = new PrefetchProxy(iconBuxtonView);
+ const tempIcons = Doc.GetProto(Cast(Doc.UserDoc()["template-icons"], Doc, null));
+ Doc.AddDocToList(tempIcons, "data", iconBuxtonView);
+
+ Document.childLayoutTemplate = heroView;
+ Document.childClickedOpenTemplateView = new PrefetchProxy(detailView);
Document._viewType = CollectionViewType.Time;
Document._forceActive = true;
Document._pivotField = "company";
@@ -774,16 +767,19 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
return <div id="toolbar" key="toolbar">
<button className="toolbar-button round-button" title="Empty"
onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}>
- <FontAwesomeIcon icon={faTrash} size="sm" />
+ <FontAwesomeIcon icon={"trash"} size="sm" />
</button>
</div >;
}
+ onKeyPress = (e: React.KeyboardEvent) => {
+ console.log(e);
+ }
render() {
if (!(this.props.Document instanceof Doc)) return (null);
const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType;
- const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
- const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
+ const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
+ const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(d, target, addDoc);
const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs;
return !childDocs ? (null) : (
<div className="collectionTreeView-dropTarget" id="body"
@@ -793,6 +789,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
paddingRight: `${NumCast(this.props.Document._xPadding, 10)}px`,
paddingTop: `${NumCast(this.props.Document._yPadding, 20)}px`
}}
+ onKeyPress={this.onKeyPress}
onContextMenu={this.onContextMenu}
onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
onDrop={this.onTreeDrop}
@@ -807,7 +804,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
SetValue={undoBatch((value: string) => Doc.SetInPlace(this.dataDoc, "title", value, false) || true)}
OnFillDown={undoBatch((value: string) => {
Doc.SetInPlace(this.dataDoc, "title", value, false);
- const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+ const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, _LODdisable: true, templates: new List<string>([Templates.Title.Layout]) });
EditableView.loadId = doc[Id];
Doc.SetInPlace(doc, "editTitle", true, false);
this.addDoc(doc, childDocs.length ? childDocs[0] : undefined, true);
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index d43dd387a..7877fe155 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -70,7 +70,7 @@
height: 30px;
position: absolute;
bottom: 15px;
- left: 15px;
+ right: 15px;
border: 2px solid black;
border-radius: 50%;
padding: 3px;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 801704673..3b2e5e4fc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -7,17 +7,15 @@ import { observer } from "mobx-react";
import * as React from 'react';
import Lightbox from 'react-image-lightbox-with-rotate';
import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
-import { DateField } from '../../../new_fields/DateField';
-import { DataSym, Doc, DocListCast, Field, Opt } from '../../../new_fields/Doc';
-import { List } from '../../../new_fields/List';
-import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types';
-import { ImageField } from '../../../new_fields/URLField';
-import { TraceMobx } from '../../../new_fields/util';
+import { DateField } from '../../../fields/DateField';
+import { DataSym, Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../fields/Types';
+import { ImageField } from '../../../fields/URLField';
+import { TraceMobx } from '../../../fields/util';
import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils';
import { DocumentType } from '../../documents/DocumentTypes';
-import { DocumentManager } from '../../util/DocumentManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
-import { SelectionManager } from '../../util/SelectionManager';
import { ContextMenu } from "../ContextMenu";
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { ScriptBox } from '../ScriptBox';
@@ -37,15 +35,14 @@ import { CollectionTimeView } from './CollectionTimeView';
import { CollectionTreeView } from "./CollectionTreeView";
import './CollectionView.scss';
import { CollectionViewBaseChrome } from './CollectionViewChromes';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { Id } from '../../../new_fields/FieldSymbols';
-import { listSpec } from '../../../new_fields/Schema';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { Id } from '../../../fields/FieldSymbols';
+import { listSpec } from '../../../fields/Schema';
import { Docs } from '../../documents/Documents';
-import { ScriptField, ComputedField } from '../../../new_fields/ScriptField';
+import { ScriptField, ComputedField } from '../../../fields/ScriptField';
import { InteractionUtils } from '../../util/InteractionUtils';
-import { ObjectField } from '../../../new_fields/ObjectField';
+import { ObjectField } from '../../../fields/ObjectField';
import CollectionMapView from './CollectionMapView';
-import { Transform } from 'prosemirror-transform';
import { CollectionPileView } from './CollectionPileView';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
@@ -71,18 +68,25 @@ export enum CollectionViewType {
Map = "map",
Pile = "pileup"
}
+export interface CollectionViewCustomProps {
+ filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ childLayoutTemplate?: () => Opt<Doc>; // specify a layout Doc template to use for children of the collection
+ childLayoutString?: string; // specify a layout string to use for children of the collection
+}
export interface CollectionRenderProps {
- addDocument: (document: Doc) => boolean;
- removeDocument: (document: Doc) => boolean;
- moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+ addDocument: (document: Doc | Doc[]) => boolean;
+ removeDocument: (document: Doc | Doc[]) => boolean;
+ moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
PanelWidth: () => number;
+ ChildLayoutTemplate?: () => Doc;
+ ChildLayoutString?: string;
}
@observer
-export class CollectionView extends Touchable<FieldViewProps> {
+export class CollectionView extends Touchable<FieldViewProps & CollectionViewCustomProps> {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
private _isChildActive = false; //TODO should this be observable?
@@ -112,31 +116,33 @@ export class CollectionView extends Touchable<FieldViewProps> {
whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
@action.bound
- addDocument(doc: Doc): boolean {
+ addDocument = (doc: Doc | Doc[]): boolean => {
+ if (doc instanceof Doc) {
+ if (this.props.filterAddDocument?.(doc) === false) {
+ return false;
+ }
+ }
+ const docs = doc instanceof Doc ? [doc] : doc;
const targetDataDoc = this.props.Document[DataSym];
const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
- !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
- // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
- doc.context = this.props.Document;
- targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
- Doc.GetProto(doc).lastOpened = new DateField;
+ const added = docs.filter(d => !docList.includes(d));
+ if (added.length) {
+ added.map(doc => doc.context = this.props.Document);
+ added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
+ targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+ targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ }
return true;
}
@action.bound
- removeDocument(doc: Doc): boolean {
+ removeDocument = (doc: any): boolean => {
+ const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
- const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
- docView && SelectionManager.DeselectDoc(docView);
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
- let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1);
- index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
-
- doc.context = undefined;
- ContextMenu.Instance?.clearItems();
- if (index !== -1) {
- value.splice(index, 1);
- targetDataDoc[this.props.fieldKey] = new List<Doc>(value);
+ const result = value.filter(v => !docs.includes(v));
+ if (result.length !== value.length) {
+ targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
return true;
}
return false;
@@ -147,7 +153,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
// otherwise, the document being moved must be able to be removed from its container before
// moving it into the target.
@action.bound
- moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean {
+ moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
return true;
}
@@ -155,10 +161,14 @@ export class CollectionView extends Touchable<FieldViewProps> {
}
showIsTagged = () => {
- const children = DocListCast(this.props.Document[this.props.fieldKey]);
- const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
- const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
- return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
+ return (null);
+ // this section would display an icon in the bototm right of a collection to indicate that all
+ // photos had been processed through Google's content analysis API and Google's tags had been
+ // assigned to the documents googlePhotosTags field.
+ // const children = DocListCast(this.props.Document[this.props.fieldKey]);
+ // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
+ // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
+ // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
}
private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
@@ -190,8 +200,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
// currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip
const chrome = this.props.Document._chromeStatus === "disabled" || this.props.Document._chromeStatus === "replaced" || type === CollectionViewType.Docking ? (null) :
- <CollectionViewBaseChrome CollectionView={this} key="chrome" PanelWidth={this.bodyPanelWidth} type={type} collapse={this.collapse} />;
- return [chrome, this.SubViewHelper(type, renderProps)];
+ <CollectionViewBaseChrome key="chrome" CollectionView={this} PanelWidth={this.bodyPanelWidth} type={type} collapse={this.collapse} />;
+ return <>{chrome} {this.SubViewHelper(type, renderProps)}</>;
}
@@ -224,7 +234,6 @@ export class CollectionView extends Touchable<FieldViewProps> {
onContextMenu = (e: React.MouseEvent): void => {
if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.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("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true);
this.setupViewTypes("Add a Perspective...", vtype => {
const newRendition = Doc.MakeAlias(this.props.Document);
newRendition._viewType = vtype;
@@ -238,8 +247,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
if (this.props.Document.childLayout instanceof Doc) {
layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
}
- if (this.props.Document.childDetailView instanceof Doc) {
- layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailView as Doc, "onRight"), icon: "project-diagram" });
+ if (this.props.Document.childClickedOpenTemplateView instanceof Doc) {
+ layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "onRight"), icon: "project-diagram" });
}
layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
@@ -247,15 +256,20 @@ export class CollectionView extends Touchable<FieldViewProps> {
const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
- const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }];
- DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick =>
- funcs.push({ key: "onChildClick", name: StrCast(childClick.title), script: ScriptCast(childClick.script) }));
+ const funcs = [
+ { key: "onChildClick", name: "On Child Clicked" },
+ { key: "onChildDoubleClick", name: "On Child Double Clicked" }];
funcs.map(func => onClicks.push({
description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => {
- func.script && (this.props.Document[func.key] = ObjectField.MakeCopy(func.script));
ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name });
}
}));
+ DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick =>
+ onClicks.push({
+ description: `Set child ${childClick.title}`,
+ icon: "edit",
+ event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
+ }));
!existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
const more = ContextMenu.Instance.findByDescription("More...");
@@ -462,6 +476,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
</div>
</div>;
}
+ childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
+ childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
render() {
TraceMobx();
@@ -471,7 +487,9 @@ export class CollectionView extends Touchable<FieldViewProps> {
moveDocument: this.moveDocument,
active: this.active,
whenActiveChanged: this.whenActiveChanged,
- PanelWidth: this.bodyPanelWidth
+ PanelWidth: this.bodyPanelWidth,
+ ChildLayoutTemplate: this.childLayoutTemplate,
+ ChildLayoutString: this.childLayoutString,
};
return (<div className={"collectionView"}
style={{
@@ -481,7 +499,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
}}
onContextMenu={this.onContextMenu}>
{this.showIsTagged()}
- <div style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
+ <div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
</div>
{this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index d26e3a38b..5dc0b09ac 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -2,11 +2,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Doc, DocListCast } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { listSpec } from "../../../fields/Schema";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils";
import { DragManager } from "../../util/DragManager";
import { undoBatch } from "../../util/UndoManager";
@@ -44,9 +44,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
initialize: emptyFunction,
};
_narrativeCommand = {
- params: ["target", "source"], title: "=> click item view",
- script: "this.target.childDetailView = getDocTemplate(this.source?.[0])",
- immediate: (source: Doc[]) => this.target.childDetailView = Doc.getDocTemplate(source?.[0]),
+ params: ["target", "source"], title: "=> click clicked open view",
+ script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])",
+ immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]),
initialize: emptyFunction,
};
_contentCommand = {
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 10c6ead1a..649406e6c 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -1,12 +1,12 @@
import * as React from "react";
import './ParentDocumentSelector.scss';
-import { Doc } from "../../../new_fields/Doc";
+import { Doc } from "../../../fields/Doc";
import { observer } from "mobx-react";
import { observable, action, runInAction, trace, computed, reaction, IReactionDisposer } from "mobx";
-import { Id } from "../../../new_fields/FieldSymbols";
+import { Id } from "../../../fields/FieldSymbols";
import { SearchUtil } from "../../util/SearchUtil";
import { CollectionDockingView } from "./CollectionDockingView";
-import { NumCast, StrCast } from "../../../new_fields/Types";
+import { NumCast, StrCast } from "../../../fields/Types";
import { CollectionViewType } from "./CollectionView";
import { DocumentButtonBar } from "../DocumentButtonBar";
import { DocumentManager } from "../../util/DocumentManager";
@@ -94,7 +94,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
}
@observer
-export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> {
+export class DockingViewButtonSelector extends React.Component<{ views: () => DocumentView[], Stack: any }> {
customStylesheet(styles: any) {
return {
...styles,
@@ -120,7 +120,7 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document
if (getComputedStyle(this._ref.current!).width !== "100%") {
e.stopPropagation(); e.preventDefault();
}
- this.props.views[0]?.select(false);
+ this.props.views()[0]?.select(false);
}} className="buttonSelector">
<Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
<FontAwesomeIcon icon={"cog"} size={"sm"} />
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 9a864078a..3860ce2d7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -1,15 +1,15 @@
-import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../new_fields/Doc";
-import { NumCast, StrCast, Cast } from "../../../../new_fields/Types";
+import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../fields/Doc";
+import { NumCast, StrCast, Cast } from "../../../../fields/Types";
import { ScriptBox } from "../../ScriptBox";
import { CompileScript } from "../../../util/Scripting";
-import { ScriptField } from "../../../../new_fields/ScriptField";
+import { ScriptField } from "../../../../fields/ScriptField";
import { OverlayView, OverlayElementOptions } from "../../OverlayView";
import { emptyFunction, aggregateBounds } from "../../../../Utils";
import React = require("react");
-import { Id, ToString } from "../../../../new_fields/FieldSymbols";
-import { ObjectField } from "../../../../new_fields/ObjectField";
-import { RefField } from "../../../../new_fields/RefField";
-import { listSpec } from "../../../../new_fields/Schema";
+import { Id, ToString } from "../../../../fields/FieldSymbols";
+import { ObjectField } from "../../../../fields/ObjectField";
+import { RefField } from "../../../../fields/RefField";
+import { listSpec } from "../../../../fields/Schema";
export interface ViewDefBounds {
type: string;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index cf12ef382..f3fc04752 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -1,5 +1,5 @@
import { observer } from "mobx-react";
-import { Doc } from "../../../../new_fields/Doc";
+import { Doc } from "../../../../fields/Doc";
import { Utils } from '../../../../Utils';
import { DocumentView } from "../../nodes/DocumentView";
import "./CollectionFreeFormLinkView.scss";
@@ -7,8 +7,9 @@ import React = require("react");
import v5 = require("uuid/v5");
import { DocumentType } from "../../../documents/DocumentTypes";
import { observable, action, reaction, IReactionDisposer } from "mobx";
-import { StrCast } from "../../../../new_fields/Types";
-import { Id } from "../../../../new_fields/FieldSymbols";
+import { StrCast, Cast } from "../../../../fields/Types";
+import { Id } from "../../../../fields/FieldSymbols";
+import { SnappingManager } from "../../../util/SnappingManager";
export interface CollectionFreeFormLinkViewProps {
A: DocumentView;
@@ -24,6 +25,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
componentDidMount() {
this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)],
action(() => {
+ if (SnappingManager.GetIsDragging()) return;
setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
@@ -40,7 +42,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const bpt = Utils.closestPtBetweenRectangles(bbounds.left, bbounds.top, bbounds.width, bbounds.height,
abounds.left, abounds.top, abounds.width, abounds.height,
apt.point.x, apt.point.y);
- const afield = StrCast(this.props.A.props.Document[StrCast(this.props.A.props.layoutKey, "layout")]).indexOf("anchor1") === -1 ? "anchor2" : "anchor1";
+ const afield = this.props.A.props.LayoutTemplateString?.indexOf("anchor1") === -1 ? "anchor2" : "anchor1";
const bfield = afield === "anchor1" ? "anchor2" : "anchor1";
// really hacky stuff to make the LinkAnchorBox display where we want it to:
@@ -79,11 +81,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
componentWillUnmount() {
this._anchorDisposer?.();
}
-
render() {
+ if (SnappingManager.GetIsDragging()) return null;
this.props.A.props.ScreenToLocalTransform().transform(this.props.B.props.ScreenToLocalTransform());
- const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
- const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
+ const acont = this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont");
+ const bcont = this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont");
const a = (acont.length ? acont[0] : this.props.A.ContentDiv!).getBoundingClientRect();
const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv!).getBoundingClientRect();
const apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
@@ -105,15 +107,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const bActive = this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document);
const text = StrCast(this.props.A.props.Document.linkRelationship);
return !a.width || !b.width || ((!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
- <text x={(pt1[0] + pt2[0]) / 2} y={(pt1[1] + pt2[1]) / 2}>
+ <text x={(Math.min(pt1[0], pt2[0]) * 2 + Math.max(pt1[0], pt2[0])) / 3} y={(pt1[1] + pt2[1]) / 2}>
{text !== "-ungrouped-" ? text : ""}
</text>
<path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
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]}`} />
- {/* <line key="linkLine" className="collectionfreeformlinkview-linkLine"
- style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
- x1={`${pt1[0]}`} y1={`${pt1[1]}`}
- x2={`${pt2[0]}`} y2={`${pt2[1]}`} /> */}
</>);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 4b5e977df..ae81b4b36 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,15 +1,15 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../../new_fields/Doc";
-import { Id } from "../../../../new_fields/FieldSymbols";
+import { Doc } from "../../../../fields/Doc";
+import { Id } from "../../../../fields/FieldSymbols";
import { DocumentManager } from "../../../util/DocumentManager";
import { DocumentView } from "../../nodes/DocumentView";
import "./CollectionFreeFormLinksView.scss";
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
import { Utils, emptyFunction } from "../../../../Utils";
-import { SelectionManager } from "../../../util/SelectionManager";
import { DocumentType } from "../../../documents/DocumentTypes";
+import { SnappingManager } from "../../../util/SnappingManager";
@observer
export class CollectionFreeFormLinksView extends React.Component {
@@ -30,13 +30,13 @@ export class CollectionFreeFormLinksView extends React.Component {
return drawnPairs;
}, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]);
return connections.filter(c =>
- c.a.props.layoutKey && c.b.props.layoutKey && c.a.props.Document.type === DocumentType.LINK &&
- c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed
+ c.a.props.Document.type === DocumentType.LINK &&
+ c.a.props.pinToPres !== emptyFunction && c.b.props.pinToPres !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed
).map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />);
}
render() {
- return SelectionManager.GetIsDragging() ? (null) : <div className="collectionfreeformlinksview-container">
+ return SnappingManager.GetIsDragging() ? (null) : <div className="collectionfreeformlinksview-container">
<svg className="collectionfreeformlinksview-svgCanvas">
{this.uniqueConnections}
</svg>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
index 92fa2781c..548ad78a5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
@@ -1,16 +1,16 @@
import { observer } from "mobx-react";
import * as mobxUtils from 'mobx-utils';
-import CursorField from "../../../../new_fields/CursorField";
-import { listSpec } from "../../../../new_fields/Schema";
-import { Cast } from "../../../../new_fields/Types";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
+import CursorField from "../../../../fields/CursorField";
+import { listSpec } from "../../../../fields/Schema";
+import { Cast } from "../../../../fields/Types";
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { CollectionViewProps } from "../CollectionSubView";
import "./CollectionFreeFormView.scss";
import React = require("react");
import v5 = require("uuid/v5");
import { computed } from "mobx";
-import { FieldResult } from "../../../../new_fields/Doc";
-import { List } from "../../../../new_fields/List";
+import { FieldResult } from "../../../../fields/Doc";
+import { List } from "../../../../fields/List";
@observer
export class CollectionFreeFormRemoteCursors extends React.Component<CollectionViewProps> {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d85233041..bf679309c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,21 +1,21 @@
import { library } from "@fortawesome/fontawesome-svg-core";
-import { faEye } from "@fortawesome/free-regular-svg-icons";
+import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons";
import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
-import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc";
-import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
-import { Id } from "../../../../new_fields/FieldSymbols";
-import { InkData, InkField, InkTool } from "../../../../new_fields/InkField";
-import { List } from "../../../../new_fields/List";
-import { RichTextField } from "../../../../new_fields/RichTextField";
-import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema";
-import { ScriptField } from "../../../../new_fields/ScriptField";
-import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
-import { TraceMobx } from "../../../../new_fields/util";
+import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc";
+import { documentSchema, collectionSchema } from "../../../../fields/documentSchemas";
+import { Id } from "../../../../fields/FieldSymbols";
+import { InkData, InkField, InkTool, PointData } from "../../../../fields/InkField";
+import { List } from "../../../../fields/List";
+import { RichTextField } from "../../../../fields/RichTextField";
+import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema";
+import { ScriptField, ComputedField } from "../../../../fields/ScriptField";
+import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
+import { TraceMobx } from "../../../../fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse, numberRange } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs } from "../../../documents/Documents";
@@ -45,6 +45,7 @@ import { MarqueeView } from "./MarqueeView";
import React = require("react");
import { CollectionViewType } from "../CollectionView";
import { Timeline } from "../../animationtimeline/Timeline";
+import { SnappingManager } from "../../../util/SnappingManager";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -66,11 +67,10 @@ export const panZoomSchema = createSchema({
fitH: "number"
});
-type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>;
-const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema);
+type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>;
+const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema);
export type collectionFreeformViewProps = {
forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
- childClickScript?: ScriptField;
viewDefDivClick?: ScriptField;
};
@@ -113,8 +113,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
this.Document.scale || 1)
- private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections
- private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections
+ private centeringShiftX = () => !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections
+ private centeringShiftY = () => !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
private getTransformOverlay = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1);
private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
@@ -123,11 +123,27 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
this.addDocument(newBox);
}
- private addDocument = (newBox: Doc) => {
- const added = this.props.addDocument(newBox);
- added && this.bringToFront(newBox);
- added && this.updateCluster(newBox);
- return added;
+ addDocument = (newBox: Doc | Doc[]) => {
+ const timecode = Cast(this.props.Document.timecode, "number", null);
+ if (timecode !== undefined) {
+ ((newBox instanceof Doc) ? [newBox] : newBox).map(doc => {
+ doc["x-indexed"] = new List<number>(numberRange(timecode + 1).map(i => NumCast(doc.x)));
+ doc["y-indexed"] = new List<number>(numberRange(timecode + 1).map(i => NumCast(doc.y)));
+ doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document });
+ doc.x = ComputedField.MakeInterpolated("x", "timecode");
+ doc.y = ComputedField.MakeInterpolated("y", "timecode");
+ });
+ }
+
+ if (newBox instanceof Doc) {
+ const added = this.props.addDocument(newBox);
+ added && this.bringToFront(newBox);
+ added && this.updateCluster(newBox);
+ return added;
+ } else {
+ return this.props.addDocument(newBox);
+ // bcz: deal with clusters
+ }
}
private selectDocuments = (docs: Doc[]) => {
SelectionManager.DeselectAll();
@@ -153,6 +169,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const xfo = this.getTransformOverlay();
const [xp, yp] = xf.transformPoint(de.x, de.y);
const [xpo, ypo] = xfo.transformPoint(de.x, de.y);
+ const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
if (super.onInternalDrop(e, de)) {
if (de.complete.docDragData) {
if (de.complete.docDragData.droppedDocuments.length) {
@@ -162,20 +179,25 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const y = (z ? ypo : yp) - de.complete.docDragData.offset[1];
const dropX = NumCast(firstDoc.x);
const dropY = NumCast(firstDoc.y);
- de.complete.docDragData.droppedDocuments.forEach(action((d: Doc) => {
- const layoutDoc = Doc.Layout(d);
- d.x = x + NumCast(d.x) - dropX;
- d.y = y + NumCast(d.y) - dropY;
- if (!NumCast(layoutDoc._width)) {
- layoutDoc._width = 300;
- }
- if (!NumCast(layoutDoc._height)) {
- const nw = NumCast(layoutDoc._nativeWidth);
- const nh = NumCast(layoutDoc._nativeHeight);
- layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
+ const droppedDocs = de.complete.docDragData.droppedDocuments;
+ runInAction(() => {
+ zsorted.forEach((doc, index) => doc.zIndex = index + 1);
+ for (let i = 0; i < droppedDocs.length; i++) {
+ const d = droppedDocs[i];
+ const layoutDoc = Doc.Layout(d);
+ d.x = x + NumCast(d.x) - dropX;
+ d.y = y + NumCast(d.y) - dropY;
+ if (!NumCast(layoutDoc._width)) {
+ layoutDoc._width = 300;
+ }
+ if (!NumCast(layoutDoc._height)) {
+ const nw = NumCast(layoutDoc._nativeWidth);
+ const nh = NumCast(layoutDoc._nativeHeight);
+ layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
+ }
+ d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
}
- d.isBackground === undefined && this.bringToFront(d);
- }));
+ });
(de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
}
@@ -328,6 +350,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
this._hitCluster = this.props.Document.useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false;
if (e.button === 0 && (!e.shiftKey || this._hitCluster) && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+
+ // if (!this.props.Document.aliasOf && !this.props.ContainingCollectionView) {
+ // this.props.addDocTab(this.props.Document, "replace");
+ // e.stopPropagation();
+ // e.preventDefault();
+ // return;
+ // }
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);
@@ -383,7 +412,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
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(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { title: "ink stroke", x: B.x, y: B.y, _width: B.width, _height: B.height });
+ const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, InkingControl.Instance.selectedWidth, points, { title: "ink stroke", x: B.x, y: B.y, _width: B.width, _height: B.height });
this.addDocument(inkDoc);
e.stopPropagation();
break;
@@ -552,7 +581,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
document.removeEventListener("pointerup", this.onPointerUp);
return;
}
- this.pan(e);
+ (!MarqueeView.DragMarquee || e.altKey) && this.pan(e);
}
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();
@@ -698,7 +727,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
zoom = (pointX: number, pointY: number, deltaY: number): void => {
- let deltaScale = deltaY > 0 ? (1 / 1.1) : 1.1;
+ let deltaScale = deltaY > 0 ? (1 / 1.05) : 1.05;
if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
deltaScale = 1 / this.zoomScaling();
}
@@ -706,7 +735,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const [x, y] = this.getTransform().transformPoint(pointX, pointY);
const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
- if (localTransform.Scale >= 0.15) {
+ if (localTransform.Scale >= 0.15 || localTransform.Scale > this.zoomScaling()) {
const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40);
this.props.Document.scale = Math.abs(safeScale);
this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
@@ -721,7 +750,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
else if (this.props.active(true)) {
e.stopPropagation();
- this.zoom(e.clientX, e.clientY, e.deltaY);
+ if (!e.ctrlKey && MarqueeView.DragMarquee) this.setPan(this.panX() + e.deltaX, this.panY() + e.deltaY, "None", true);
+ else this.zoom(e.clientX, e.clientY, e.deltaY);
}
this.props.Document.targetScale = NumCast(this.props.Document.scale);
}
@@ -760,20 +790,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
}
- bringToFront = (doc: Doc, sendToBack?: boolean) => {
+ bringToFront = action((doc: Doc, sendToBack?: boolean) => {
if (sendToBack || doc.isBackground) {
doc.zIndex = 0;
}
else {
const docs = this.childLayoutPairs.map(pair => pair.layout);
- docs.slice().sort((doc1, doc2) => {
- if (doc1 === doc) return 1;
- if (doc2 === doc) return -1;
- return NumCast(doc1.zIndex) - NumCast(doc2.zIndex);
- }).forEach((doc, index) => doc.zIndex = index + 1);
- doc.zIndex = docs.length + 1;
+ docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
+ let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1;
+ if (zlast - docs.length > 100) {
+ for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
+ zlast = docs.length + 1;
+ }
+ doc.zIndex = zlast + 1;
}
- }
+ });
scaleAtPt(docpt: number[], scale: number) {
const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
@@ -855,9 +886,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
@computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
- backgroundHalo = () => BoolCast(this.Document.useClusters);
+ @computed get onChildDoubleClickHandler() { return this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
@computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); }
- parentActive = () => this.props.active() || this.backgroundActive ? true : false;
+ backgroundHalo = () => BoolCast(this.Document.useClusters);
+ parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false;
getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
return {
...this.props,
@@ -867,12 +899,16 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
DataDoc: childData,
Document: childLayout,
LibraryPath: this.libraryPath,
+ LayoutTemplate: this.props.ChildLayoutTemplate,
+ LayoutTemplateString: this.props.ChildLayoutString,
FreezeDimensions: this.props.freezeChildDimensions,
layoutKey: undefined,
+ setupDragLines: this.setupDragLines,
+ dontRegisterView: this.props.dontRegisterView,
rootSelected: childData ? this.rootSelected : returnFalse,
dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
- //onClick: undefined, // this.props.onClick, // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
onClick: this.onChildClickHandler,
+ onDoubleClick: this.onChildDoubleClickHandler,
ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
renderDepth: this.props.renderDepth + 1,
PanelWidth: childLayout[WidthSym],
@@ -891,14 +927,22 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
addDocTab = action((doc: Doc, where: string) => {
if (where === "inParent") {
- const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
- doc.x = pt[0];
- doc.y = pt[1];
- this.props.addDocument(doc);
- return true;
+ if (doc instanceof Doc) {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ return this.props.addDocument(doc);
+ } else {
+ (doc as any as Doc[]).forEach(doc => {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ });
+ return this.props.addDocument(doc);
+ }
}
if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List<Doc>(doc as any as Doc[]);
return true;
}
return this.props.addDocTab(doc, where);
@@ -912,6 +956,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const { x, y, z, color, zIndex } = params.pair.layout;
return {
x: NumCast(x), y: NumCast(y), z: Cast(z, "number"), color: StrCast(color), zIndex: Cast(zIndex, "number"),
+ transition: StrCast(layoutDoc.transition),
width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number"), pair: params.pair, replica: ""
};
}
@@ -996,11 +1041,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return { newPool, computedElementData: this.doFreeformLayout(newPool) };
}
- childLayoutDocFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
get doLayoutComputation() {
const { newPool, computedElementData } = this.doInternalLayoutComputation;
- runInAction(() =>
- Array.from(newPool.entries()).map(entry => {
+ const array = Array.from(newPool.entries());
+ runInAction(() => {
+ for (const entry of array) {
const lastPos = this._cachedPool.get(entry[0]); // last computed pos
const newPos = entry[1];
if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) {
@@ -1009,7 +1054,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) {
this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height });
}
- }));
+ }
+ });
this._cachedPool.clear();
Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1]));
const elements: ViewDefResult[] = computedElementData.slice();
@@ -1022,7 +1068,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
replica={entry[1].replica}
dataProvider={this.childDataProvider}
sizeProvider={this.childSizeProvider}
- LayoutDoc={this.childLayoutDocFunc}
pointerEvents={
this.backgroundActive ?
true :
@@ -1035,11 +1080,16 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica)
}));
+ if (this.props.isAnnotationOverlay) {
+ this.props.Document.scale = Math.max(1, NumCast(this.props.Document.scale));
+ }
+
return elements;
}
+ @action
componentDidMount() {
- super.componentDidMount();
+ super.componentDidMount?.();
this._layoutComputeReaction = reaction(() => this.doLayoutComputation,
(elements) => this._layoutElements = elements || [],
{ fireImmediately: true, name: "doLayout" });
@@ -1056,12 +1106,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
promoteCollection = undoBatch(action(() => {
- this.childDocs.forEach(doc => {
+ const childDocs = this.childDocs.slice();
+ childDocs.forEach(doc => {
const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y));
doc.x = scr?.[0];
doc.y = scr?.[1];
- this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc);
});
+ this.props.addDocTab(childDocs as any as Doc, "inParent");
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
}));
layoutDocsInGrid = () => {
@@ -1085,23 +1136,69 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
});
}, "arrange contents");
}
+ @undoBatch
+ @action
+ toggleNativeDimensions = () => {
+ Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+ }
+
+ @undoBatch
+ @action
+ snaphsotInterpolated = (): void => {
+ if (this.props.Document.timecode === undefined) {
+ this.childDocs.map(doc => {
+ this.props.Document.timecode = 0;
+ doc["x-indexed"] = new List<number>([NumCast(doc.x)]);
+ doc["y-indexed"] = new List<number>([NumCast(doc.y)]);
+ doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document });
+ doc.x = ComputedField.MakeInterpolated("x", "timecode");
+ doc.y = ComputedField.MakeInterpolated("y", "timecode");
+ });
+ }
+ const timecode = NumCast(this.props.Document.timecode);
+ this.childDocs.map(doc => {
+ const xindexed = Cast(doc['x-indexed'], listSpec("number"), null);
+ const yindexed = Cast(doc['y-indexed'], listSpec("number"), null);
+ xindexed.length <= timecode + 1 && xindexed.push(NumCast(doc.x));
+ yindexed.length <= timecode + 1 && yindexed.push(NumCast(doc.y));
+ });
+ this.childDocs.map(doc => doc.transition = "transform 1s");
+ this.props.Document.timecode = Math.max(0, timecode + 1);
+ setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010);
+ }
+ @undoBatch
+ @action
+ backupInterpolated = (): void => {
+ this.childDocs.map(doc => doc.transition = "transform 1s");
+ this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1);
+ setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010);
+ }
+
private thumbIdentifier?: number;
onContextMenu = (e: React.MouseEvent) => {
- if (this.props.children && this.props.annotationsKey) return;
+ if (this.props.annotationsKey) return;
+
+ ContextMenu.Instance.addItem({
+ description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => {
+ this._timelineVisible = !this._timelineVisible;
+ }), icon: this._timelineVisible ? faEyeSlash : faEye
+ });
+ ContextMenu.Instance.addItem({ description: "Advance", event: this.snaphsotInterpolated, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
+ ContextMenu.Instance.addItem({ description: "Backup ", event: this.backupInterpolated, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
+
const options = ContextMenu.Instance.findByDescription("Options...");
const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
- this._timelineRef.current!.timelineContextMenu(e);
optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
- optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+ optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
+ optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
// layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
- optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" });
optionItems.push({
description: "Import document", icon: "upload", event: ({ x, y }) => {
const input = document.createElement("input");
@@ -1129,9 +1226,59 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
input.click();
}
});
- ContextMenu.Instance.addItem({ description: "Options ...", subitems: optionItems, icon: "eye" });
- this._timelineRef.current!.timelineContextMenu(e);
+ optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
+
+ }
+ @observable _timelineVisible = false;
+
+ intersectRect(r1: { left: number, top: number, width: number, height: number },
+ r2: { left: number, top: number, width: number, height: number }) {
+ return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top);
+ }
+
+ @action
+ setupDragLines = () => {
+ const activeDocs = this.getActiveDocuments();
+ if (activeDocs.length > 50) {
+ DragManager.SetSnapLines([], []);
+ return;
+ }
+ const size = this.getTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight());
+ const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] };
+ const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) });
+ const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => {
+ if (this.intersectRect(docDims(doc), rect)) {
+ snappableDocs.push(doc);
+ }
+ };
+ const snappableDocs: Doc[] = []; // the set of documents in the visible viewport that we will try to snap to;
+ const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) };
+ this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to
+ !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => isDocInView(doc, selRect)); // if not, see if there are background docs to snap to
+ !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => isDocInView(doc, otherBounds)); // if not, then why not snap to floating docs
+
+ const horizLines: number[] = [];
+ const vertLines: number[] = [];
+ snappableDocs.filter(doc => !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => {
+ const { left, top, width, height } = docDims(doc);
+ const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top);
+ const docSize = this.getTransform().inverse().transformDirection(width, height);
+
+ horizLines.push(topLeftInScreen[1], topLeftInScreen[1] + docSize[1] / 2, topLeftInScreen[1] + docSize[1]); // horiz center line
+ vertLines.push(topLeftInScreen[0], topLeftInScreen[0] + docSize[0] / 2, topLeftInScreen[0] + docSize[0]);// right line
+ });
+ DragManager.SetSnapLines(horizLines, vertLines);
}
+ onPointerOver = (e: React.PointerEvent) => {
+ if (SnappingManager.GetIsDragging()) {
+ this.setupDragLines();
+ }
+ e.stopPropagation();
+ }
+
+ @observable private _hLines: number[] | undefined;
+ @observable private _vLines: number[] | undefined;
private childViews = () => {
const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : [];
@@ -1165,13 +1312,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return false;
});
@computed get marqueeView() {
- return <MarqueeView {...this.props} nudge={this.nudge} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
- addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}>
+ return <MarqueeView {...this.props}
+ nudge={this.nudge}
+ addDocTab={this.addDocTab}
+ activeDocuments={this.getActiveDocuments}
+ selectDocuments={this.selectDocuments}
+ addDocument={this.addDocument}
+ addLiveTextDocument={this.addLiveTextBox}
+ getContainerTransform={this.getContainerTransform}
+ getTransform={this.getTransform}
+ isAnnotationOverlay={this.isAnnotationOverlay}>
<CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} shifted={!this.nativeHeight && !this.isAnnotationOverlay}
easing={this.easing} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
{this.children}
</CollectionFreeFormViewPannableContents>
- <Timeline ref={this._timelineRef} {...this.props} />
+ {this._timelineVisible ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
</MarqueeView>;
}
@@ -1183,7 +1338,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const wscale = nw ? this.props.PanelWidth() / nw : 1;
return wscale < hscale ? wscale : hscale;
}
- @computed get backgroundEvents() { return this.layoutDoc.isBackground && SelectionManager.GetIsDragging(); }
+ @computed get backgroundEvents() { return this.layoutDoc.isBackground && SnappingManager.GetIsDragging(); }
render() {
TraceMobx();
const clientRect = this._mainCont?.getBoundingClientRect();
@@ -1196,7 +1351,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
// otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document
return <div className={"collectionfreeformview-container"}
ref={this.createDashEventsTarget}
- onWheel={this.onPointerWheel} onClick={this.onClick} //pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
+ onPointerOver={this.onPointerOver}
+ onWheel={this.onPointerWheel} onClick={this.onClick} //pointerEvents: DraggingManager.GetIsDragging() ? "all" : undefined,
onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu}
style={{
pointerEvents: this.backgroundEvents ? "all" : undefined,
@@ -1220,7 +1376,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}}>
</div>
-
+ {// uncomment to show snap lines
+ <div className="snapLines" style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", pointerEvents: "none" }}>
+ <svg style={{ width: "100%", height: "100%" }}>
+ {this._hLines?.map(l => <line x1="0" y1={l} x2="1000" y2={l} stroke="black" />)}
+ {this._vLines?.map(l => <line y1="0" x1={l} y2="1000" x2={l} stroke="black" />)}
+ </svg>
+ </div>}
</div >;
}
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
index 1291e7dc1..a811dd15a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
@@ -7,6 +7,7 @@
height:100%;
overflow: hidden;
border-radius: inherit;
+ user-select: none;
}
.marqueeView:focus-within {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c70301b2f..492ba6ed6 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,37 +1,34 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, DataSym, WidthSym, HeightSym, Opt } from "../../../../new_fields/Doc";
-import { InkField, InkData } from "../../../../new_fields/InkField";
-import { List } from "../../../../new_fields/List";
-import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
-import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
+import { Doc, Opt } from "../../../../fields/Doc";
+import { InkData, InkField } from "../../../../fields/InkField";
+import { List } from "../../../../fields/List";
+import { RichTextField } from "../../../../fields/RichTextField";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
import { Utils } from "../../../../Utils";
-import { Docs, DocUtils, DocumentOptions } from "../../../documents/Documents";
+import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
+import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
import { ContextMenu } from "../../ContextMenu";
+import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { PreviewCursor } from "../../PreviewCursor";
import { SubCollectionViewProps } from "../CollectionSubView";
+import { CollectionView } from "../CollectionView";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
-import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
-import { RichTextField } from "../../../../new_fields/RichTextField";
-import { CollectionView } from "../CollectionView";
-import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
-import { ScriptField } from "../../../../new_fields/ScriptField";
+import { InteractionUtils } from "../../../util/InteractionUtils";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
getTransform: () => Transform;
- addDocument: (doc: Doc) => boolean;
activeDocuments: () => Doc[];
selectDocuments: (docs: Doc[], ink: { Document: Doc, Ink: Map<any, any> }[]) => void;
- removeDocument: (doc: Doc) => boolean;
addLiveTextDocument: (doc: Doc) => void;
isSelected: () => boolean;
- isAnnotationOverlay?: boolean;
nudge: (x: number, y: number) => boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
}
@@ -39,7 +36,7 @@ interface MarqueeViewProps {
@observer
export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
{
- private _mainCont = React.createRef<HTMLDivElement>();
+ @observable public static DragMarquee = false;
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@observable _downX: number = 0;
@@ -108,7 +105,11 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
});
} else if (!e.ctrlKey) {
FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
- const tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
+ const tbox = Docs.Create.TextDocument("", {
+ _width: 200, _height: 100, x: x, y: y, _autoHeight: true, _fontSize: NumCast(Doc.UserDoc().fontSize),
+ _backgroundColor: StrCast(Doc.UserDoc().backgroundColor),
+ title: "-typed text-"
+ });
const template = FormattedTextBox.DefaultLayout;
if (template instanceof Doc) {
tbox._width = NumCast(template._width);
@@ -164,12 +165,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
onPointerDown = (e: React.PointerEvent): void => {
this._downX = this._lastX = e.clientX;
this._downY = this._lastY = e.clientY;
- if (e.button === 2 || (e.button === 0 && e.altKey)) {
+ // allow marquee if right click OR alt+left click OR space bar + left click
+ if (e.button === 2 || (e.button === 0 && (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))))) {
+ // if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) {
this.setPreviewCursor(e.clientX, e.clientY, true);
- if (e.altKey) {
- //e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors.
- e.preventDefault();
- }
+ // (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors.
+ e.preventDefault();
+ // }
// bcz: do we need this? it kills the context menu on the main collection if !altKey
// e.stopPropagation();
}
@@ -191,14 +193,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this.cleanupInteractions(true); // stop listening for events if another lower-level handle (e.g. another Marquee) has stopPropagated this
}
- if (e.altKey) {
+ if (e.altKey || MarqueeView.DragMarquee) {
e.preventDefault();
}
}
@action
onPointerUp = (e: PointerEvent): void => {
- if (!this.props.active(true)) this.props.selectDocuments([this.props.Document], []);
if (this._visible) {
const mselect = this.marqueeSelect();
if (!e.shiftKey) {
@@ -209,6 +210,11 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const docs = mselect.length ? mselect : [this.props.Document];
this.props.selectDocuments(docs, []);
}
+ const hideMarquee = () => {
+ this.hideMarquee();
+ MarqueeOptionsMenu.Instance.fadeOut(true);
+ document.removeEventListener("pointerdown", hideMarquee);
+ };
if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100)) {
MarqueeOptionsMenu.Instance.createCollection = this.collection;
MarqueeOptionsMenu.Instance.delete = this.delete;
@@ -217,17 +223,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
MarqueeOptionsMenu.Instance.showMarquee = this.showMarquee;
MarqueeOptionsMenu.Instance.hideMarquee = this.hideMarquee;
MarqueeOptionsMenu.Instance.jumpTo(e.clientX, e.clientY);
+ document.addEventListener("pointerdown", hideMarquee);
+ } else {
+ this.hideMarquee();
}
this.cleanupInteractions(true, this._commandExecuted);
- const hideMarquee = () => {
- this.hideMarquee();
- MarqueeOptionsMenu.Instance.fadeOut(true);
- document.removeEventListener("pointerdown", hideMarquee);
- };
- document.addEventListener("pointerdown", hideMarquee);
-
- if (e.altKey) {
+ if (e.altKey || MarqueeView.DragMarquee) {
e.preventDefault();
}
}
@@ -300,10 +302,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
delete = () => {
- this.marqueeSelect(false).map(d => this.props.removeDocument(d));
- if (this.ink) {
- // this.marqueeInkDelete(this.ink.inkData);
- }
+ this.props.removeDocument(this.marqueeSelect(false));
SelectionManager.DeselectAll();
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -349,13 +348,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "c" : true) {
- selected.map(d => {
- this.props.removeDocument(d);
+ selected.map(action(d => {
+ //this.props.removeDocument(d);
d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
d.y = NumCast(d.y) - bounds.top - bounds.height / 2;
d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
return d;
- });
+ }));
+ this.props.removeDocument(selected);
}
const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined);
this.props.addDocument(newCollection);
@@ -551,7 +551,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
marqueeSelect(selectBackgrounds: boolean = true) {
const selRect = this.Bounds;
const selection: Doc[] = [];
- this.props.activeDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => {
+ this.props.activeDocuments().filter(doc => !doc.isBackground && !doc.z).map(doc => {
const layoutDoc = Doc.Layout(doc);
const x = NumCast(doc.x);
const y = NumCast(doc.y);
@@ -613,7 +613,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
render() {
return <div className="marqueeView"
- style={{ overflow: StrCast(this.props.Document.overflow), }}
+ style={{ overflow: StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
{this._visible ? this.marqueeDiv : null}
{this.props.children}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 9d09ecc3b..c0e1a0232 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,10 +1,10 @@
import { action, computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from "react";
-import { Doc } from '../../../../new_fields/Doc';
-import { documentSchema } from '../../../../new_fields/documentSchemas';
-import { makeInterface } from '../../../../new_fields/Schema';
-import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../new_fields/Types';
+import { Doc } from '../../../../fields/Doc';
+import { documentSchema } from '../../../../fields/documentSchemas';
+import { makeInterface } from '../../../../fields/Schema';
+import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../fields/Types';
import { DragManager, dropActionType } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
@@ -13,8 +13,8 @@ import { CollectionSubView } from '../CollectionSubView';
import "./collectionMulticolumnView.scss";
import ResizeBar from './MulticolumnResizer';
import WidthLabel from './MulticolumnWidthLabel';
-import { List } from '../../../../new_fields/List';
-import { returnZero } from '../../../../Utils';
+import { List } from '../../../../fields/List';
+import { returnZero, returnFalse, returnOne } from '../../../../Utils';
type MulticolumnDocument = makeInterface<[typeof documentSchema]>;
const MulticolumnDocument = makeInterface(documentSchema);
@@ -46,12 +46,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
*/
@computed
private get ratioDefinedDocs() {
- return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout.dimUnit, "*") === DimUnit.Ratio);
+ return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
}
/**
- * This loops through all childLayoutPairs and extracts the values for dimUnit
- * and dimMagnitude, ignoring any that are malformed. Additionally, it then
+ * This loops through all childLayoutPairs and extracts the values for _dimUnit
+ * and _dimMagnitude, ignoring any that are malformed. Additionally, it then
* normalizes the ratio values so that one * value is always 1, with the remaining
* values proportionate to that easily readable metric.
* @returns the list of the resolved width specifiers (unit and magnitude pairs)
@@ -62,8 +62,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
let starSum = 0;
const widthSpecifiers: WidthSpecifier[] = [];
this.childLayoutPairs.map(pair => {
- const unit = StrCast(pair.layout.dimUnit, "*");
- const magnitude = NumCast(pair.layout.dimMagnitude, 1);
+ const unit = StrCast(pair.layout._dimUnit, "*");
+ const magnitude = NumCast(pair.layout._dimMagnitude, 1);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
(unit === DimUnit.Ratio) && (starSum += magnitude);
widthSpecifiers.push({ magnitude, unit });
@@ -83,9 +83,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
setTimeout(() => {
const { ratioDefinedDocs } = this;
if (this.childLayoutPairs.length) {
- const minimum = Math.min(...ratioDefinedDocs.map(doc => NumCast(doc.dimMagnitude, 1)));
+ const minimum = Math.min(...ratioDefinedDocs.map(doc => NumCast(doc._dimMagnitude, 1)));
if (minimum !== 0) {
- ratioDefinedDocs.forEach(layout => layout.dimMagnitude = NumCast(layout.dimMagnitude, 1) / minimum, 1);
+ ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
}
}
});
@@ -161,8 +161,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
if (columnUnitLength === undefined) {
return 0; // we're still waiting on promises to resolve
}
- let width = NumCast(layout.dimMagnitude, 1);
- if (StrCast(layout.dimUnit, "*") === DimUnit.Ratio) {
+ let width = NumCast(layout._dimMagnitude, 1);
+ if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
width *= columnUnitLength;
}
return width;
@@ -194,8 +194,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (super.onInternalDrop(e, de)) {
de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
- d.dimUnit = "*";
- d.dimMagnitude = 1;
+ d._dimUnit = "*";
+ d._dimMagnitude = 1;
}));
}
return false;
@@ -203,6 +203,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+ @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); }
addDocTab = (doc: Doc, where: string) => {
@@ -215,9 +216,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
return <ContentFittingDocumentView
Document={layout}
- DataDocument={layout.resolvedDataDoc as Doc}
+ DataDoc={layout.resolvedDataDoc as Doc}
backgroundColor={this.props.backgroundColor}
- LayoutDoc={this.props.childLayoutTemplate}
+ LayoutTemplate={this.props.ChildLayoutTemplate}
+ LayoutTemplateString={this.props.ChildLayoutString}
LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
@@ -225,21 +227,24 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
PanelHeight={height}
NativeHeight={returnZero}
NativeWidth={returnZero}
- fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+ fitToBox={false}
rootSelected={this.rootSelected}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
onClick={this.onChildClickHandler}
- getTransform={dxf}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={dxf}
focus={this.props.focus}
- CollectionDoc={this.props.CollectionView?.props.Document}
- CollectionView={this.props.CollectionView}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
- active={this.props.active}
+ parentActive={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
addDocTab={this.addDocTab}
pinToPres={this.props.pinToPres}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
/>;
}
/**
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index af0cc3b5c..602246d07 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,12 +1,12 @@
import { observer } from 'mobx-react';
-import { makeInterface } from '../../../../new_fields/Schema';
-import { documentSchema } from '../../../../new_fields/documentSchemas';
+import { makeInterface } from '../../../../fields/Schema';
+import { documentSchema } from '../../../../fields/documentSchemas';
import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import * as React from "react";
-import { Doc } from '../../../../new_fields/Doc';
-import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types';
+import { Doc } from '../../../../fields/Doc';
+import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../fields/Types';
import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
-import { Utils, returnZero } from '../../../../Utils';
+import { Utils, returnZero, returnFalse, returnOne } from '../../../../Utils';
import "./collectionMultirowView.scss";
import { computed, trace, observable, action } from 'mobx';
import { Transform } from '../../../util/Transform';
@@ -14,7 +14,7 @@ import HeightLabel from './MultirowHeightLabel';
import ResizeBar from './MultirowResizer';
import { undoBatch } from '../../../util/UndoManager';
import { DragManager, dropActionType } from '../../../util/DragManager';
-import { List } from '../../../../new_fields/List';
+import { List } from '../../../../fields/List';
type MultirowDocument = makeInterface<[typeof documentSchema]>;
const MultirowDocument = makeInterface(documentSchema);
@@ -46,12 +46,12 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
*/
@computed
private get ratioDefinedDocs() {
- return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout.dimUnit, "*") === DimUnit.Ratio);
+ return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
}
/**
- * This loops through all childLayoutPairs and extracts the values for dimUnit
- * and dimUnit, ignoring any that are malformed. Additionally, it then
+ * This loops through all childLayoutPairs and extracts the values for _dimUnit
+ * and _dimUnit, ignoring any that are malformed. Additionally, it then
* normalizes the ratio values so that one * value is always 1, with the remaining
* values proportionate to that easily readable metric.
* @returns the list of the resolved width specifiers (unit and magnitude pairs)
@@ -62,8 +62,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
let starSum = 0;
const heightSpecifiers: HeightSpecifier[] = [];
this.childLayoutPairs.map(pair => {
- const unit = StrCast(pair.layout.dimUnit, "*");
- const magnitude = NumCast(pair.layout.dimMagnitude, 1);
+ const unit = StrCast(pair.layout._dimUnit, "*");
+ const magnitude = NumCast(pair.layout._dimMagnitude, 1);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
(unit === DimUnit.Ratio) && (starSum += magnitude);
heightSpecifiers.push({ magnitude, unit });
@@ -83,9 +83,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
setTimeout(() => {
const { ratioDefinedDocs } = this;
if (this.childLayoutPairs.length) {
- const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout.dimMagnitude, 1)));
+ const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout._dimMagnitude, 1)));
if (minimum !== 0) {
- ratioDefinedDocs.forEach(layout => layout.dimMagnitude = NumCast(layout.dimMagnitude, 1) / minimum);
+ ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum);
}
}
});
@@ -161,8 +161,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
if (rowUnitLength === undefined) {
return 0; // we're still waiting on promises to resolve
}
- let height = NumCast(layout.dimMagnitude, 1);
- if (StrCast(layout.dimUnit, "*") === DimUnit.Ratio) {
+ let height = NumCast(layout._dimMagnitude, 1);
+ if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
height *= rowUnitLength;
}
return height;
@@ -194,8 +194,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (super.onInternalDrop(e, de)) {
de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
- d.dimUnit = "*";
- d.dimMagnitude = 1;
+ d._dimUnit = "*";
+ d._dimMagnitude = 1;
}));
}
return false;
@@ -203,7 +203,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
-
+ @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); }
addDocTab = (doc: Doc, where: string) => {
if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
@@ -215,9 +215,10 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
return <ContentFittingDocumentView
Document={layout}
- DataDocument={layout.resolvedDataDoc as Doc}
+ DataDoc={layout.resolvedDataDoc as Doc}
backgroundColor={this.props.backgroundColor}
- LayoutDoc={this.props.childLayoutTemplate}
+ LayoutTemplate={this.props.ChildLayoutTemplate}
+ LayoutTemplateString={this.props.ChildLayoutString}
LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
@@ -225,21 +226,24 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
PanelHeight={height}
NativeHeight={returnZero}
NativeWidth={returnZero}
- fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+ fitToBox={false}
rootSelected={this.rootSelected}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
onClick={this.onChildClickHandler}
- getTransform={dxf}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={dxf}
focus={this.props.focus}
- CollectionDoc={this.props.CollectionView?.props.Document}
- CollectionView={this.props.CollectionView}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
- active={this.props.active}
+ parentActive={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
addDocTab={this.addDocTab}
pinToPres={this.props.pinToPres}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
/>;
}
/**
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
index e1e604686..734915a93 100644
--- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
@@ -1,8 +1,8 @@
import * as React from "react";
import { observer } from "mobx-react";
import { observable, action } from "mobx";
-import { Doc } from "../../../../new_fields/Doc";
-import { NumCast, StrCast } from "../../../../new_fields/Types";
+import { Doc } from "../../../../fields/Doc";
+import { NumCast, StrCast } from "../../../../fields/Types";
import { DimUnit } from "./CollectionMulticolumnView";
import { UndoManager } from "../../../util/UndoManager";
@@ -43,12 +43,12 @@ export default class ResizeBar extends React.Component<ResizerProps> {
const unitLength = columnUnitLength();
if (unitLength) {
if (toNarrow) {
- const scale = StrCast(toNarrow.dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
- toNarrow.dimMagnitude = Math.max(0.05, NumCast(toNarrow.dimMagnitude, 1) - Math.abs(movementX) / scale);
+ const scale = StrCast(toNarrow._dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
+ toNarrow._dimMagnitude = Math.max(0.05, NumCast(toNarrow._dimMagnitude, 1) - Math.abs(movementX) / scale);
}
if (toWiden) {
- const scale = StrCast(toWiden.dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
- toWiden.dimMagnitude = Math.max(0.05, NumCast(toWiden.dimMagnitude, 1) + Math.abs(movementX) / scale);
+ const scale = StrCast(toWiden._dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
+ toWiden._dimMagnitude = Math.max(0.05, NumCast(toWiden._dimMagnitude, 1) + Math.abs(movementX) / scale);
}
}
}
@@ -56,17 +56,17 @@ export default class ResizeBar extends React.Component<ResizerProps> {
private get isActivated() {
const { toLeft, toRight } = this.props;
if (toLeft && toRight) {
- if (StrCast(toLeft.dimUnit, "*") === DimUnit.Pixel && StrCast(toRight.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toLeft._dimUnit, "*") === DimUnit.Pixel && StrCast(toRight._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;
} else if (toLeft) {
- if (StrCast(toLeft.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toLeft._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;
} else if (toRight) {
- if (StrCast(toRight.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toRight._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx
index 5b2054428..9985a9fba 100644
--- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx
@@ -1,8 +1,8 @@
import * as React from "react";
import { observer } from "mobx-react";
import { computed } from "mobx";
-import { Doc } from "../../../../new_fields/Doc";
-import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types";
+import { Doc } from "../../../../fields/Doc";
+import { NumCast, StrCast, BoolCast } from "../../../../fields/Types";
import { EditableView } from "../../EditableView";
import { DimUnit } from "./CollectionMulticolumnView";
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx
index 899577fd5..aa5439fa4 100644
--- a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx
@@ -1,8 +1,8 @@
import * as React from "react";
import { observer } from "mobx-react";
import { computed } from "mobx";
-import { Doc } from "../../../../new_fields/Doc";
-import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types";
+import { Doc } from "../../../../fields/Doc";
+import { NumCast, StrCast, BoolCast } from "../../../../fields/Types";
import { EditableView } from "../../EditableView";
import { DimUnit } from "./CollectionMultirowView";
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
index 9df8cc3e2..d0bc4d01c 100644
--- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
@@ -1,8 +1,8 @@
import * as React from "react";
import { observer } from "mobx-react";
import { observable, action } from "mobx";
-import { Doc } from "../../../../new_fields/Doc";
-import { NumCast, StrCast } from "../../../../new_fields/Types";
+import { Doc } from "../../../../fields/Doc";
+import { NumCast, StrCast } from "../../../../fields/Types";
import { DimUnit } from "./CollectionMultirowView";
import { UndoManager } from "../../../util/UndoManager";
@@ -41,12 +41,12 @@ export default class ResizeBar extends React.Component<ResizerProps> {
const unitLength = columnUnitLength();
if (unitLength) {
if (toNarrow) {
- const scale = StrCast(toNarrow.dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
- toNarrow.dimMagnitude = Math.max(0.05, NumCast(toNarrow.dimMagnitude, 1) - Math.abs(movementY) / scale);
+ const scale = StrCast(toNarrow._dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
+ toNarrow._dimMagnitude = Math.max(0.05, NumCast(toNarrow._dimMagnitude, 1) - Math.abs(movementY) / scale);
}
if (toWiden) {
- const scale = StrCast(toWiden.dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
- toWiden.dimMagnitude = Math.max(0.05, NumCast(toWiden.dimMagnitude, 1) + Math.abs(movementY) / scale);
+ const scale = StrCast(toWiden._dimUnit, "*") === DimUnit.Ratio ? unitLength : 1;
+ toWiden._dimMagnitude = Math.max(0.05, NumCast(toWiden._dimMagnitude, 1) + Math.abs(movementY) / scale);
}
}
}
@@ -54,17 +54,17 @@ export default class ResizeBar extends React.Component<ResizerProps> {
private get isActivated() {
const { toTop, toBottom } = this.props;
if (toTop && toBottom) {
- if (StrCast(toTop.dimUnit, "*") === DimUnit.Pixel && StrCast(toBottom.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toTop._dimUnit, "*") === DimUnit.Pixel && StrCast(toBottom._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;
} else if (toTop) {
- if (StrCast(toTop.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toTop._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;
} else if (toBottom) {
- if (StrCast(toBottom.dimUnit, "*") === DimUnit.Pixel) {
+ if (StrCast(toBottom._dimUnit, "*") === DimUnit.Pixel) {
return false;
}
return true;