aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx29
-rw-r--r--src/client/views/collections/CollectionPDFView.tsx79
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx59
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx56
-rw-r--r--src/client/views/collections/CollectionSubView.tsx33
-rw-r--r--src/client/views/collections/CollectionTreeView.scss58
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx373
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx66
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx51
11 files changed, 462 insertions, 346 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 5238ad114..1e42593d1 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -130,7 +130,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
@action.bound
removeDocument(doc: Doc): boolean {
- let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView)
+ let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
docView && SelectionManager.DeselectDoc(docView);
const props = this.props;
//TODO This won't create the field if it doesn't already exist
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 51e29cb54..69b9e77eb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -9,7 +9,7 @@ import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
import { Id } from '../../../new_fields/FieldSymbols';
import { FieldId } from "../../../new_fields/RefField";
import { listSpec } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
import { emptyFunction, returnTrue, Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { DocumentManager } from '../../util/DocumentManager';
@@ -45,10 +45,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
private _containerRef = React.createRef<HTMLDivElement>();
private _flush: boolean = false;
private _ignoreStateChange = "";
+ private _isPointerDown = false;
constructor(props: SubCollectionViewProps) {
super(props);
- CollectionDockingView.Instance = this;
+ if (props.addDocTab === emptyFunction) CollectionDockingView.Instance = this;
+ //Why is this here?
(window as any).React = React;
(window as any).ReactDOM = ReactDOM;
}
@@ -248,6 +250,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
@action
onPointerUp = (e: React.PointerEvent): void => {
+ this._isPointerDown = false;
if (this._flush) {
this._flush = false;
setTimeout(() => this.stateChanged(), 10);
@@ -255,6 +258,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
}
@action
onPointerDown = (e: React.PointerEvent): void => {
+ this._isPointerDown = true;
var className = (e.target as any).className;
if (className === "messageCounter") {
e.stopPropagation();
@@ -335,6 +339,15 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
tab.element.append(counter);
let upDiv = document.createElement("span");
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) return;
+ var activeContentItem = tab.header.parent.getActiveContentItem();
+ if (tab.contentItem !== activeContentItem) {
+ tab.header.parent.setActiveContentItem(tab.contentItem);
+ }
+ tab.setActive(true);
+ };
ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={(doc, location) => CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv);
tab.reactComponents = [upDiv];
tab.element.append(upDiv);
@@ -419,8 +432,9 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
@observable private _document: Opt<Doc>;
get _stack(): any {
let parent = (this.props as any).glContainer.parent.parent;
- if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1)
+ if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) {
return parent.parent.contentItems[1];
+ }
return parent;
}
constructor(props: any) {
@@ -429,7 +443,11 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
}
nativeWidth = () => NumCast(this._document!.nativeWidth, this._panelWidth);
- nativeHeight = () => NumCast(this._document!.nativeHeight, this._panelHeight);
+ nativeHeight = () => {
+ let nh = NumCast(this._document!.nativeHeight, this._panelHeight);
+ let res = BoolCast(this._document!.ignoreAspect) ? this._panelHeight : nh;
+ return res;
+ }
contentScaling = () => {
const nativeH = this.nativeHeight();
const nativeW = this.nativeWidth();
@@ -450,6 +468,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
let docHeight = NumCast(this._document!.height);
if (NumCast(this._document!.nativeWidth) || !docWidth || !this._panelWidth || !this._panelHeight) return 1;
if (StrCast(this._document!.layout).indexOf("Collection") === -1 ||
+ !BoolCast(this._document!.fitToContents, false) ||
NumCast(this._document!.viewType) !== CollectionViewType.Freeform) return 1;
let scaling = Math.max(1, this._panelWidth / docWidth * docHeight > this._panelHeight ?
this._panelHeight / docHeight : this._panelWidth / docWidth);
@@ -498,4 +517,4 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
{({ measureRef }) => <div ref={measureRef}> {theContent} </div>}
</Measure>;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index bf887ce7c..b2d016934 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,60 +1,70 @@
-import { action, observable } from "mobx";
+import { action, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
+import { WidthSym } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { NumCast } from "../../../new_fields/Types";
+import { emptyFunction } from "../../../Utils";
import { ContextMenu } from "../ContextMenu";
+import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from "./CollectionBaseView";
+import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
import "./CollectionPDFView.scss";
import React = require("react");
-import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import { FieldView, FieldViewProps } from "../nodes/FieldView";
-import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView";
-import { emptyFunction } from "../../../Utils";
-import { NumCast } from "../../../new_fields/Types";
-import { Id } from "../../../new_fields/FieldSymbols";
+import { PDFBox } from "../nodes/PDFBox";
@observer
export class CollectionPDFView extends React.Component<FieldViewProps> {
+ private _pdfBox?: PDFBox;
+ private _reactionDisposer?: IReactionDisposer;
+ private _buttonTray: React.RefObject<HTMLDivElement>;
+
+ constructor(props: FieldViewProps) {
+ super(props);
+
+ this._buttonTray = React.createRef();
+ }
+
+ componentDidMount() {
+ this._reactionDisposer = reaction(
+ () => NumCast(this.props.Document.scrollY),
+ () => {
+ // let transform = this.props.ScreenToLocalTransform();
+ if (this._buttonTray.current) {
+ // console.log(this._buttonTray.current.offsetHeight);
+ // console.log(NumCast(this.props.Document.scrollY));
+ let scale = this.nativeWidth() / this.props.Document[WidthSym]();
+ this.props.Document.panY = NumCast(this.props.Document.scrollY);
+ // console.log(scale);
+ }
+ // console.log(this.props.Document[HeightSym]());
+ },
+ { fireImmediately: true }
+ );
+ }
public static LayoutString(fieldKey: string = "data") {
return FieldView.LayoutString(CollectionPDFView, fieldKey);
}
@observable _inThumb = false;
- private set curPage(value: number) { this.props.Document.curPage = value; }
+ private set curPage(value: number) { this._pdfBox && this._pdfBox.GotoPage(value); }
private get curPage() { return NumCast(this.props.Document.curPage, -1); }
private get numPages() { return NumCast(this.props.Document.numPages); }
- @action onPageBack = () => this.curPage > 1 ? (this.props.Document.curPage = this.curPage - 1) : -1;
- @action onPageForward = () => this.curPage < this.numPages ? (this.props.Document.curPage = this.curPage + 1) : -1;
+ @action onPageBack = () => this._pdfBox && this._pdfBox.BackPage();
+ @action onPageForward = () => this._pdfBox && this._pdfBox.ForwardPage();
- @action
- onThumbDown = (e: React.PointerEvent) => {
- document.addEventListener("pointermove", this.onThumbMove, false);
- document.addEventListener("pointerup", this.onThumbUp, false);
- e.stopPropagation();
- this._inThumb = true;
- }
- @action
- onThumbMove = (e: PointerEvent) => {
- let pso = (e.clientY - (e as any).target.parentElement.getBoundingClientRect().top) / (e as any).target.parentElement.getBoundingClientRect().height;
- this.curPage = Math.trunc(Math.min(this.numPages, pso * this.numPages + 1));
- e.stopPropagation();
- }
- @action
- onThumbUp = (e: PointerEvent) => {
- this._inThumb = false;
- document.removeEventListener("pointermove", this.onThumbMove);
- document.removeEventListener("pointerup", this.onThumbUp);
- }
nativeWidth = () => NumCast(this.props.Document.nativeWidth);
nativeHeight = () => NumCast(this.props.Document.nativeHeight);
private get uIButtons() {
let ratio = (this.curPage - 1) / this.numPages * 100;
return (
- <div className="collectionPdfView-buttonTray" key="tray" style={{ height: "100%" }}>
+ <div className="collectionPdfView-buttonTray" ref={this._buttonTray} key="tray" style={{ height: "100%" }}>
<button className="collectionPdfView-backward" onClick={this.onPageBack}>{"<"}</button>
<button className="collectionPdfView-forward" onClick={this.onPageForward}>{">"}</button>
- <div className="collectionPdfView-slider" onPointerDown={this.onThumbDown} style={{ top: 60, left: -20, width: 50, height: `calc(100% - 80px)` }} >
+ {/* <div className="collectionPdfView-slider" onPointerDown={this.onThumbDown} style={{ top: 60, left: -20, width: 50, height: `calc(100% - 80px)` }} >
<div className="collectionPdfView-thumb" onPointerDown={this.onThumbDown} style={{ top: `${ratio}%`, width: 50, height: 50 }} />
- </div>
+ </div> */}
</div>
);
}
@@ -65,11 +75,14 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
}
}
+ setPdfBox = (pdfBox: PDFBox) => { this._pdfBox = pdfBox; };
+
+
private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => {
let props = { ...this.props, ...renderProps };
return (
<>
- <CollectionFreeFormView {...props} CollectionView={this} />
+ <CollectionFreeFormView {...props} setPdfBox={this.setPdfBox} CollectionView={this} />
{renderProps.active() ? this.uIButtons : (null)}
</>
);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b9e5a5b65..9cc8961e3 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -2,36 +2,33 @@ import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, untracked, runInAction, trace } from "mobx";
+import { action, computed, observable, trace, untracked } from "mobx";
import { observer } from "mobx-react";
import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
-import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
import "react-table/react-table.css";
+import { Doc, DocListCast, DocListCastAsync, Field } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { List } from "../../../new_fields/List";
+import { listSpec } from "../../../new_fields/Schema";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
import { emptyFunction, returnFalse, returnZero } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
+import { Gateway } from "../../northstar/manager/Gateway";
import { SetupDrag } from "../../util/DragManager";
import { CompileScript } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
-import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss";
+import { COLLECTION_BORDER_WIDTH, MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
+import { ContextMenu } from "../ContextMenu";
import { anchorPoints, Flyout } from "../DocumentDecorations";
import '../DocumentDecorations.scss';
import { EditableView } from "../EditableView";
import { DocumentView } from "../nodes/DocumentView";
import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import { CollectionPDFView } from "./CollectionPDFView";
import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { listSpec } from "../../../new_fields/Schema";
-import { List } from "../../../new_fields/List";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { Gateway } from "../../northstar/manager/Gateway";
-import { Docs } from "../../documents/Documents";
-import { ContextMenu } from "../ContextMenu";
-import { CollectionView } from "./CollectionView";
-import { CollectionPDFView } from "./CollectionPDFView";
import { CollectionVideoView } from "./CollectionVideoView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch } from "../../util/UndoManager";
+import { CollectionView } from "./CollectionView";
library.add(faCog);
@@ -90,8 +87,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
let columnDocs = DocListCast(schemaDoc.data);
if (columnDocs) {
let ddoc = columnDocs.find(doc => doc.title === columnName);
- if (ddoc)
+ if (ddoc) {
return ddoc;
+ }
}
}
return this.props.Document;
@@ -288,7 +286,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
}
getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
- - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth);
+ - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth)
get documentKeysCheckList() {
@@ -337,7 +335,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
columns={this.tableColumns}
column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }}
getTrProps={this.getTrProps}
- />
+ />;
}
@computed
@@ -355,6 +353,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
height={this.previewHeight}
getTransform={this.getPreviewTransform}
CollectionView={this.props.CollectionView}
+ moveDocument={this.props.moveDocument}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
active={this.props.active}
@@ -362,7 +361,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
addDocTab={this.props.addDocTab}
setPreviewScript={this.setPreviewScript}
previewScript={this.previewScript}
- />
+ />;
}
@action
setPreviewScript = (script: string) => {
@@ -386,9 +385,10 @@ interface CollectionSchemaPreviewProps {
Document?: Doc;
width: () => number;
height: () => number;
- CollectionView: CollectionView | CollectionPDFView | CollectionVideoView;
+ CollectionView?: CollectionView | CollectionPDFView | CollectionVideoView;
getTransform: () => Transform;
addDocument: (document: Doc, allowDuplicates?: boolean) => boolean;
+ moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
removeDocument: (document: Doc) => boolean;
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
@@ -410,26 +410,12 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
}
private PanelWidth = () => this.nativeWidth * this.contentScaling();
private PanelHeight = () => this.nativeHeight * this.contentScaling();
- private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling())
+ private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
get centeringOffset() { return (this.props.width() - this.nativeWidth * this.contentScaling()) / 2; }
@action
onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.props.setPreviewScript(e.currentTarget.value);
}
- @undoBatch
- @action
- public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => {
- SelectionManager.DeselectAll();
- if (expandedDocs) {
- let isMinimized: boolean | undefined;
- expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
- if (isMinimized === undefined) {
- isMinimized = BoolCast(maximizedDoc.isMinimized, false);
- }
- maximizedDoc.isMinimized = !isMinimized;
- });
- }
- }
render() {
let input = this.props.previewScript === undefined ? (null) :
<input className="collectionSchemaView-input" value={this.props.previewScript} onChange={this.onPreviewScriptChange}
@@ -438,7 +424,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
{!this.props.Document || !this.props.width ? (null) : (
<div className="collectionSchemaView-previewDoc" style={{ transform: `translate(${this.centeringOffset}px, 0px)`, height: "100%" }}>
<DocumentView Document={this.props.Document} isTopMost={false} selectOnLoad={false}
- addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
+ addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} moveDocument={this.props.moveDocument}
ScreenToLocalTransform={this.getTransform}
ContentScaling={this.contentScaling}
PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight}
@@ -448,7 +434,6 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
whenActiveChanged={this.props.whenActiveChanged}
bringToFront={emptyFunction}
addDocTab={this.props.addDocTab}
- collapseToPoint={this.collapseToPoint}
/>
</div>)}
{input}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index cad7cd50c..368e94a8c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,17 +1,16 @@
import React = require("react");
-import { action, computed, IReactionDisposer, reaction, trace } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
import { observer } from "mobx-react";
import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { BoolCast, NumCast } from "../../../new_fields/Types";
import { emptyFunction, returnOne, Utils } from "../../../Utils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
import { DocumentView } from "../nodes/DocumentView";
import { CollectionSchemaPreview } from "./CollectionSchemaView";
import "./CollectionStackingView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { ContextMenu } from "../ContextMenu";
+import { auto } from "async";
@observer
export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -22,7 +21,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
@computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); }
@computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); }
@computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); }
- @computed get columnWidth() { return this.singleColumn ? this.props.PanelWidth() - 2 * this.xMargin : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); }
+ @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); }
singleColDocHeight(d: Doc) {
let nw = NumCast(d.nativeWidth);
@@ -62,20 +61,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this._masonryGridRef = ele;
this.createDropTarget(ele!);
}
- @undoBatch
- @action
- public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => {
- SelectionManager.DeselectAll();
- if (expandedDocs) {
- let isMinimized: boolean | undefined;
- expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
- if (isMinimized === undefined) {
- isMinimized = BoolCast(maximizedDoc.isMinimized, false);
- }
- maximizedDoc.isMinimized = !isMinimized;
- });
- }
- }
@computed
get singleColumnChildren() {
@@ -97,6 +82,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
getTransform={dxf}
CollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
active={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
@@ -111,22 +97,27 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
get children() {
return this.childDocs.filter(d => !d.isMinimized).map((d, i) => {
let dref = React.createRef<HTMLDivElement>();
- let dxf = () => this.getDocTransform(d, dref.current!);
- let rowSpan = Math.ceil((this.columnWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this._gridSize + this.gridGap));
+ let dxf = () => this.getDocTransform(d, dref.current!).scale(this.columnWidth / d[WidthSym]());
+ let renderScale = this.columnWidth / NumCast(d.nativeWidth, this.columnWidth);
+ let aspect = NumCast(d.nativeWidth) / NumCast(d.nativeHeight);
+ let width = () => this.columnWidth;
+ let height = () => aspect ? width() / aspect : d[HeightSym]()
+ let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap));
let childFocus = (doc: Doc) => {
doc.libraryBrush = true;
this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered.
- }
+ };
return (<div className="collectionStackingView-masonryDoc"
key={d[Id]}
ref={dref}
style={{
- width: NumCast(d.nativeWidth, d[WidthSym]()),
- height: NumCast(d.nativeHeight, d[HeightSym]()),
+ width: width(),
+ height: height(),
+ overflow: "auto",
transformOrigin: "top left",
gridRowEnd: `span ${rowSpan}`,
gridColumnEnd: `span 1`,
- transform: `scale(${this.columnWidth / NumCast(d.nativeWidth, d[WidthSym]())}, ${this.columnWidth / NumCast(d.nativeWidth, d[WidthSym]())})`
+ transform: `scale(${renderScale})`
}} >
<DocumentView key={d[Id]} Document={d}
addDocument={this.props.addDocument}
@@ -137,17 +128,16 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
ScreenToLocalTransform={dxf}
focus={childFocus}
ContentScaling={returnOne}
- PanelWidth={d[WidthSym]}
- PanelHeight={d[HeightSym]}
+ PanelWidth={width}
+ PanelHeight={height}
selectOnLoad={false}
parentActive={this.props.active}
addDocTab={this.props.addDocTab}
bringToFront={emptyFunction}
whenActiveChanged={this.props.whenActiveChanged}
- collapseToPoint={this.collapseToPoint}
/>
</div>);
- })
+ });
}
onContextMenu = (e: React.MouseEvent): void => {
if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
@@ -163,10 +153,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
let templatecols = "";
for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `;
return (
- <div className="collectionStackingView">
+ <div className="collectionStackingView" ref={this.createRef} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
<div className={`collectionStackingView-masonry${this.singleColumn ? "Single" : "Grid"}`}
- onContextMenu={this.onContextMenu}
- ref={this.createRef} onWheel={(e: React.WheelEvent) => e.stopPropagation()}
+
style={{
padding: this.singleColumn ? `${this.yMargin}px ${this.xMargin}px ${this.yMargin}px ${this.xMargin}px` : `${this.yMargin}px ${this.xMargin}px`,
margin: "auto",
@@ -179,7 +168,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}}
>
{this.singleColumn ? this.singleColumnChildren : this.children}
- </div></div>
+ </div>
+ </div>
);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d6b1aa29d..070abb51b 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,9 +34,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
class CollectionSubView extends DocComponent<SubCollectionViewProps, T>(schemaCtor) {
private dropDisposer?: DragManager.DragDropDisposer;
protected createDropTarget = (ele: HTMLDivElement) => {
- if (this.dropDisposer) {
- this.dropDisposer();
- }
+ this.dropDisposer && this.dropDisposer();
if (ele) {
this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
}
@@ -106,6 +104,9 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
e.stopPropagation();
return added;
}
+ else if (de.data instanceof DragManager.AnnotationDragData) {
+ return this.props.addDocument(de.data.dropDocument);
+ }
return false;
}
@@ -185,10 +186,28 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
}
return;
}
- if (html && html.indexOf("<img") !== 0 && !html.startsWith("<a")) {
- let htmlDoc = Docs.HtmlDocument(html, { ...options, width: 300, height: 300, documentText: text });
- this.props.addDocument(htmlDoc, false);
- return;
+ if (html && !html.startsWith("<a")) {
+ if (html.indexOf("<img") === 0) {
+ let split = html.split("\"")[1];
+ let doc = Docs.ImageDocument(split, { ...options, width: 300 });
+ this.props.addDocument(doc, false);
+ return;
+ } else {
+ let path = window.location.origin + "/doc/";
+ if (text.startsWith(path)) {
+ let docid = text.replace(DocServer.prepend("/doc/"), "").split("?")[0];
+ DocServer.GetRefField(docid).then(f => {
+ if (f instanceof Doc) {
+ if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
+ (f instanceof Doc) && this.props.addDocument(f, false);
+ }
+ });
+ } else {
+ let htmlDoc = Docs.HtmlDocument(html, { ...options, width: 300, height: 300, documentText: text });
+ this.props.addDocument(htmlDoc, false);
+ }
+ return;
+ }
}
if (text && text.indexOf("www.youtube.com/watch") !== -1) {
const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 2dc4b2e80..a85604e58 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -4,15 +4,15 @@
border-width: $COLLECTION_BORDER_WIDTH;
border-color: transparent;
border-style: solid;
- border-radius: $border-radius;
+ border-radius: inherit;
box-sizing: border-box;
height: 100%;
- padding: 20px;
+ padding-top: 20px;
padding-left: 10px;
padding-right: 0px;
background: $light-color-secondary;
font-size: 13px;
- overflow: scroll;
+ overflow: auto;
ul {
list-style: none;
@@ -25,12 +25,10 @@
}
.bullet {
- float: left;
position: relative;
width: 15px;
- display: block;
color: $intermediate-color;
- margin-top: 8px;
+ margin-top: 4px;
transform: scale(1.3, 1.3);
}
.editableView-container {
@@ -46,43 +44,47 @@
}
- .docContainer:hover {
- .delete-button {
- display: inline;
- // width: auto;
- }
- }
-
.coll-title {
width: max-content;
display: block;
font-size: 24px;
}
- .collectionTreeView-keyHeader {
- font-style: italic;
- font-size: 8pt;
- }
+}
+.collectionTreeView-keyHeader {
+ font-style: italic;
+ font-size: 8pt;
+ margin-left: 3px;
+ display:none;
+ background: lightgray;
}
.docContainer {
- margin-left: 10px;
- display: block;
+ position: relative;
+ text-overflow: ellipsis;
+ white-space: pre-wrap;
+ overflow: hidden;
// width:100%;//width: max-content;
- .treeViewItem-openRight {
- margin-left: 5px;
- display: none;
- }
}
-#docContainer-data {
- margin-top: 5px;
+.treeViewItem-openRight {
+ display: none;
+}
+
+.treeViewItem-border {
+ display:inherit;
+ border-left: dashed 1px #00000042;
}
-.docContainer:hover {
+.treeViewItem-header:hover {
+ .collectionTreeView-keyHeader {
+ display:inherit;
+ }
.treeViewItem-openRight {
display: inline-block;
height:13px;
+ margin-top:2px;
+ margin-left: 5px;
// display: inline;
svg {
display:block;
@@ -94,16 +96,14 @@
.treeViewItem-header {
border: transparent 1px solid;
+ display:flex;
}
.treeViewItem-header-above {
- border: transparent 1px solid;
border-top: black 1px solid;
}
.treeViewItem-header-below {
- border: transparent 1px solid;
border-bottom: black 1px solid;
}
.treeViewItem-header-inside {
- border: transparent 1px solid;
border: black 1px solid;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8a6764c58..c51c16883 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,51 +1,55 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt, faCaretSquareRight, faCaretSquareDown } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable, trace } from "mobx";
+import { action, observable, computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
+import { List } from '../../../new_fields/List';
import { Document, listSpec } from '../../../new_fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast, PromiseValue } from '../../../new_fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types';
+import { emptyFunction, Utils } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
+import { SelectionManager } from '../../util/SelectionManager';
+import { Transform } from '../../util/Transform';
import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { EditableView } from "../EditableView";
import { MainView } from '../MainView';
+import { Templates } from '../Templates';
import { CollectionViewType } from './CollectionBaseView';
import { CollectionDockingView } from './CollectionDockingView';
+import { CollectionSchemaPreview } from './CollectionSchemaView';
import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
import React = require("react");
-import { Transform } from '../../util/Transform';
-import { SelectionManager } from '../../util/SelectionManager';
export interface TreeViewProps {
document: Doc;
- deleteDoc: (doc: Doc) => void;
+ deleteDoc: (doc: Doc) => boolean;
moveDocument: DragManager.MoveFunction;
dropAction: "alias" | "copy" | undefined;
addDocTab: (doc: Doc, where: string) => void;
+ panelWidth: () => number;
+ panelHeight: () => number;
addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean;
+ indentDocument?: () => void;
ScreenToLocalTransform: () => Transform;
+ outerXf: () => { translateX: number, translateY: number };
treeViewId: string;
parentKey: string;
active: () => boolean;
}
-export enum BulletType {
- Collapsed,
- Collapsible,
- List
-}
-
library.add(faTrashAlt);
library.add(faAngleRight);
library.add(faCaretDown);
library.add(faCaretRight);
+library.add(faCaretSquareDown);
+library.add(faCaretSquareRight);
@observer
/**
@@ -53,26 +57,25 @@ library.add(faCaretRight);
*/
class TreeView extends React.Component<TreeViewProps> {
private _header?: React.RefObject<HTMLDivElement> = React.createRef();
- private treedropDisposer?: DragManager.DragDropDisposer;
+ private _treedropDisposer?: DragManager.DragDropDisposer;
+ private _dref = React.createRef<HTMLDivElement>();
+ @observable _chosenKey: string = "data";
+ @observable _collapsed: boolean = true;
+
protected createTreeDropTarget = (ele: HTMLDivElement) => {
- this.treedropDisposer && this.treedropDisposer();
+ this._treedropDisposer && this._treedropDisposer();
if (ele) {
- this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
+ this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
}
}
- @observable _isOver: boolean = false;
- @observable _collapsed: boolean = true;
-
@undoBatch delete = () => this.props.deleteDoc(this.props.document);
@undoBatch openRight = async () => this.props.addDocTab(this.props.document, "openRight");
- @action onMouseEnter = () => { this._isOver = true; }
- @action onMouseLeave = () => { this._isOver = false; }
-
+ onPointerDown = (e: React.PointerEvent) => e.stopPropagation()
onPointerEnter = (e: React.PointerEvent): void => {
this.props.active() && (this.props.document.libraryBrush = true);
- if (e.buttons === 1) {
+ if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
this._header!.current!.className = "treeViewItem-header";
document.addEventListener("pointermove", this.onDragMove, true);
}
@@ -88,41 +91,86 @@ class TreeView extends React.Component<TreeViewProps> {
let rect = this._header!.current!.getBoundingClientRect();
let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
let before = x[1] < bounds[1];
- let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible);
- this._header!.current!.className = "treeViewItem-header"
- if (inside && this._bulletType != BulletType.List) this._header!.current!.className = "treeViewItem-header-inside";
- else if (before) this._header!.current!.className = "treeViewItem-header-above";
- else if (!before) this._header!.current!.className = "treeViewItem-header-below";
- e.stopPropagation();
- }
- onPointerDown = (e: React.PointerEvent) => {
+ let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
+ this._header!.current!.className = "treeViewItem-header";
+ if (inside) this._header!.current!.className += " treeViewItem-header-inside";
+ else if (before) this._header!.current!.className += " treeViewItem-header-above";
+ else if (!before) this._header!.current!.className += " treeViewItem-header-below";
e.stopPropagation();
}
@action
- remove = (document: Document, key: string) => {
+ remove = (document: Document, key: string): boolean => {
let children = Cast(this.props.document[key], listSpec(Doc), []);
- children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1);
+ if (children.indexOf(document) !== -1) {
+ children.splice(children.indexOf(document), 1);
+ return true;
+ }
+ return false;
}
@action
- move: DragManager.MoveFunction = (document: Doc, target: Doc, addDoc) => {
- if (this.props.document !== target) {
- //TODO This should check if it was removed
- this.props.deleteDoc(document);
- return addDoc(document);
+ move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => {
+ return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
+ }
+ @action
+ indent = () => this.props.addDocument(this.props.document) && this.delete();
+
+ renderBullet() {
+ let docList = Cast(this.props.document["data"], listSpec(Doc));
+ let doc = Cast(this.props.document["data"], Doc);
+ let isDoc = doc instanceof Doc || docList;
+ return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)}>
+ {<FontAwesomeIcon icon={this._collapsed ? (isDoc ? "caret-square-right" : "caret-right") : (isDoc ? "caret-square-down" : "caret-down")} />}
+ </div>;
+ }
+
+ titleClicked = (e: React.MouseEvent) => {
+ if (this._collapsed) return false;
+ else {
+ this.props.document.embed = !BoolCast(this.props.document.embed);
+ return true;
}
- return true;
}
+ static loadId = "";
+ editableView = (key: string, style?: string) => (<EditableView
+ oneLine={true}
+ display={"inline"}
+ editing={this.props.document[Id] === TreeView.loadId}
+ contents={StrCast(this.props.document[key])}
+ onClick={this.titleClicked}
+ height={36}
+ fontStyle={style}
+ GetValue={() => StrCast(this.props.document[key])}
+ SetValue={(value: string) => (Doc.GetProto(this.props.document)[key] = value) ? true : true}
+ OnFillDown={(value: string) => {
+ Doc.GetProto(this.props.document)[key] = value;
+ let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
+ TreeView.loadId = doc[Id];
+ return this.props.addDocument(doc);
+ }}
+ OnTab={() => this.props.indentDocument && this.props.indentDocument()}
+ />)
- renderBullet(type: BulletType) {
- let onClicked = action(() => this._collapsed = !this._collapsed);
- let bullet: IconProp | undefined = undefined;
- switch (type) {
- case BulletType.Collapsed: bullet = "caret-right"; break;
- case BulletType.Collapsible: bullet = "caret-down"; break;
+ @computed get keyList() {
+ let keys = Array.from(Object.keys(this.props.document));
+ if (this.props.document.proto instanceof Doc) {
+ keys.push(...Array.from(Object.keys(this.props.document.proto)));
+ while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
}
- return <div className="bullet" onClick={onClicked}>{bullet ? <FontAwesomeIcon icon={bullet} /> : ""} </div>;
+ let keyList: string[] = [];
+ keys.map(key => {
+ let docList = Cast(this.props.document[key], listSpec(Doc));
+ let doc = Cast(this.props.document[key], Doc);
+ if (doc instanceof Doc || docList) {
+ keyList.push(key);
+ }
+ });
+ if (keyList.indexOf("data") !== -1) {
+ keyList.splice(keyList.indexOf("data"), 1);
+ }
+ keyList.splice(0, 0, "data");
+ return keyList;
}
/**
* Renders the EditableView title element for placement into the tree.
@@ -130,36 +178,34 @@ class TreeView extends React.Component<TreeViewProps> {
renderTitle() {
let reference = React.createRef<HTMLDivElement>();
let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true);
- let editableView = (titleString: string) =>
- (<EditableView
- oneLine={!this._isOver ? true : false}
- display={"inline"}
- contents={titleString}
- height={36}
- GetValue={() => StrCast(this.props.document.title)}
- SetValue={(value: string) => {
- let target = this.props.document.proto ? this.props.document.proto : this.props.document;
- target.title = value;
- return true;
- }}
- />);
+
+ let headerElements = (
+ <span className="collectionTreeView-keyHeader" key={this._chosenKey}
+ onPointerDown={action(() => {
+ let ind = this.keyList.indexOf(this._chosenKey);
+ ind = (ind + 1) % this.keyList.length;
+ this._chosenKey = this.keyList[ind];
+ })} >
+ {this._chosenKey}
+ </span>);
let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : [];
let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
<div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
<FontAwesomeIcon icon="angle-right" size="lg" />
- {/* <FontAwesomeIcon icon="angle-right" size="lg" /> */}
</div>);
- return (
- <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}
+ return <>
+ <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
style={{
background: BoolCast(this.props.document.protoBrush, false) ? "#06123232" : BoolCast(this.props.document.libraryBrush, false) ? "#06121212" : "0",
pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
}}
>
- {editableView(StrCast(this.props.document.title))}
- {openRight}
+ {this.editableView("title")}
{/* {<div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>} */}
- </div >);
+ </div >
+ {headerElements}
+ {openRight}
+ </>;
}
onWorkspaceContextMenu = (e: React.MouseEvent): void => {
@@ -176,7 +222,7 @@ class TreeView extends React.Component<TreeViewProps> {
} else {
ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.props.document)) });
}
- ContextMenu.Instance.displayMenu(e.pageX - 156, e.pageY - 15);
+ ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
e.stopPropagation();
}
}
@@ -185,27 +231,22 @@ class TreeView extends React.Component<TreeViewProps> {
let rect = this._header!.current!.getBoundingClientRect();
let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
let before = x[1] < bounds[1];
- let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible);
+ let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
if (de.data instanceof DragManager.DocumentDragData) {
let addDoc = (doc: Doc) => this.props.addDocument(doc, this.props.document, before);
if (inside) {
let docList = Cast(this.props.document.data, listSpec(Doc));
if (docList !== undefined) {
- addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }
+ addDoc = (doc: Doc) => { docList && docList.push(doc); return true; };
}
}
- let added = false;
- if (de.data.dropAction || de.data.userDropAction) {
- added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false);
- } else if (de.data.moveDocument) {
- let movedDocs = de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments;
- added = movedDocs.reduce((added: boolean, d) =>
- de.data.moveDocument(d, this.props.document, addDoc) || added, false);
- } else {
- added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false);
- }
e.stopPropagation();
- return added;
+ let movedDocs = (de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments);
+ return (de.data.dropAction || de.data.userDropAction) ?
+ de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false)
+ : (de.data.moveDocument) ?
+ movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.props.document, addDoc) || added, false)
+ : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false);
}
return false;
}
@@ -220,46 +261,55 @@ class TreeView extends React.Component<TreeViewProps> {
return true;
}
- _bulletType: BulletType = BulletType.List;
+ docTransform = () => {
+ let { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!);
+ let outerXf = this.props.outerXf();
+ let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
+ let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
+ return finalXf;
+ }
+
render() {
- let bulletType = BulletType.List;
- let contentElement: (JSX.Element | null)[] = [];
- let keys = Array.from(Object.keys(this.props.document));
- if (this.props.document.proto instanceof Doc) {
- keys.push(...Array.from(Object.keys(this.props.document.proto)));
- while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
- }
- keys.map(key => {
- let docList = Cast(this.props.document[key], listSpec(Doc));
- let remDoc = (doc: Doc) => this.remove(doc, key);
- let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, key, doc, addBefore, before);
- let doc = Cast(this.props.document[key], Doc);
- if (doc instanceof Doc || docList) {
- if (!this._collapsed) {
- bulletType = BulletType.Collapsible;
- contentElement.push(<ul key={key + "more"}>
- {(key === "data") ? (null) :
- <span className="collectionTreeView-keyHeader" style={{ display: "block", marginTop: "7px" }} key={key}>{key}</span>}
- <div style={{ display: "block" }}>
- {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move,
- this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active)}
- </div>
- </ul >);
- } else {
- bulletType = BulletType.Collapsed;
- }
+ let contentElement: (JSX.Element | null) = null;
+ let docList = Cast(this.props.document[this._chosenKey], listSpec(Doc));
+ let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey);
+ let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before);
+ let doc = Cast(this.props.document[this._chosenKey], Doc);
+ let docWidth = () => NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5;
+ if (!this._collapsed) {
+ if (!this.props.document.embed) {
+ contentElement = <ul key={this._chosenKey + "more"}>
+ {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this._chosenKey, addDoc, remDoc, this.move,
+ this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth)}
+ </ul >;
+ } else {
+ contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.props.panelHeight() }} key={this.props.document[Id]}>
+ <CollectionSchemaPreview
+ Document={this.props.document}
+ width={docWidth}
+ height={this.props.panelHeight}
+ getTransform={this.docTransform}
+ CollectionView={undefined}
+ addDocument={emptyFunction as any}
+ moveDocument={this.props.moveDocument}
+ removeDocument={emptyFunction as any}
+ active={this.props.active}
+ whenActiveChanged={emptyFunction as any}
+ addDocTab={this.props.addDocTab}
+ setPreviewScript={emptyFunction}>
+ </CollectionSchemaPreview>
+ </div>
}
- });
- this._bulletType = bulletType;
- return <div className="treeViewItem-container"
- ref={this.createTreeDropTarget}
- onContextMenu={this.onWorkspaceContextMenu}>
+ }
+ return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
<li className="collection-child">
<div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
- {this.renderBullet(bulletType)}
+ {this.renderBullet()}
{this.renderTitle()}
</div>
- {contentElement}
+ <div className="treeViewItem-border">
+ {contentElement}
+ </div>
</li>
</div>;
}
@@ -268,35 +318,77 @@ class TreeView extends React.Component<TreeViewProps> {
treeViewId: string,
key: string,
add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean,
- remove: ((doc: Doc) => void),
+ remove: ((doc: Doc) => boolean),
move: DragManager.MoveFunction,
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => void,
screenToLocalXf: () => Transform,
- active: () => boolean
+ outerXf: () => { translateX: number, translateY: number },
+ active: () => boolean,
+ panelWidth: () => number,
) {
- return docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)).map(child =>
- <TreeView document={child} treeViewId={treeViewId} key={child[Id]} deleteDoc={remove} addDocument={add} moveDocument={move}
- dropAction={dropAction} addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} parentKey={key} active={active} />);
+ let docList = docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized));
+ let rowWidth = () => panelWidth() - 20;
+ return docList.map((child, i) => {
+ let indent = i === 0 ? undefined : () => {
+ if (StrCast(docList[i - 1].layout).indexOf("CollectionView") !== -1) {
+ let fieldKeysub = StrCast(docList[i - 1].layout).split("fieldKey")[1];
+ let fieldKey = fieldKeysub.split("\"")[1];
+ TreeView.AddDocToList(docList[i - 1], fieldKey, child);
+ remove(child);
+ }
+ }
+ let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
+ return add(doc, relativeTo ? relativeTo : docList[i], before !== undefined ? before : false);
+ }
+ let rowHeight = () => {
+ let aspect = NumCast(child.nativeWidth, 0) / NumCast(child.nativeHeight, 0);
+ return aspect ? Math.min(child[WidthSym](), rowWidth()) / aspect : child[HeightSym]();
+ }
+ return <TreeView
+ document={child}
+ treeViewId={treeViewId}
+ key={child[Id]}
+ indentDocument={indent}
+ deleteDoc={remove}
+ addDocument={addDocument}
+ panelWidth={rowWidth}
+ panelHeight={rowHeight}
+ moveDocument={move}
+ dropAction={dropAction}
+ addDocTab={addDocTab}
+ ScreenToLocalTransform={screenToLocalXf}
+ outerXf={outerXf}
+ parentKey={key}
+ active={active} />;
+ });
}
}
@observer
export class CollectionTreeView extends CollectionSubView(Document) {
private treedropDisposer?: DragManager.DragDropDisposer;
+ private _mainEle?: HTMLDivElement;
+
protected createTreeDropTarget = (ele: HTMLDivElement) => {
- if (this.treedropDisposer) {
- this.treedropDisposer();
- }
- if (ele) {
+ this.treedropDisposer && this.treedropDisposer();
+ if (this._mainEle = ele) {
this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
}
}
+ componentWillUnmount() {
+ this.treedropDisposer && this.treedropDisposer();
+ }
+
@action
- remove = (document: Document) => {
+ remove = (document: Document): boolean => {
let children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []);
- children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1);
+ if (children.indexOf(document) !== -1) {
+ children.splice(children.indexOf(document), 1);
+ return true;
+ }
+ return false;
}
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
@@ -306,22 +398,16 @@ export class CollectionTreeView extends CollectionSubView(Document) {
}
}
- onTreeDrop = (e: React.DragEvent) => {
- this.onDrop(e, {});
- }
+ outerXf = () => Utils.GetScreenTransform(this._mainEle!);
+ onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
+
render() {
- let dropAction = Cast(this.props.Document.dropAction, "string") as dropActionType;
- if (!this.childDocs) {
- return (null);
- }
+ let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
- let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove,
- moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active);
- return (
+ return !this.childDocs ? (null) : (
<div id="body" className="collectionTreeView-dropTarget"
- style={{ borderRadius: "inherit" }}
onContextMenu={this.onContextMenu}
onWheel={(e: React.WheelEvent) => this.props.isSelected() && e.stopPropagation()}
onDrop={this.onTreeDrop}
@@ -332,14 +418,19 @@ export class CollectionTreeView extends CollectionSubView(Document) {
display={"inline"}
height={72}
GetValue={() => StrCast(this.props.Document.title)}
- SetValue={(value: string) => {
- let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
- target.title = value;
- return true;
+ SetValue={(value: string) => (Doc.GetProto(this.props.Document).title = value) ? true : true}
+ OnFillDown={(value: string) => {
+ Doc.GetProto(this.props.Document).title = value;
+ let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
+ TreeView.loadId = doc[Id];
+ TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
}} />
</div>
<ul className="no-indent">
- {childElements}
+ {
+ TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove,
+ moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth)
+ }
</ul>
</div >
);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 481202dfc..be75c6c5c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -109,7 +109,7 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
}
return match || found;
}, false)) {
- drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] });
+ drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] });
}
});
return drawnPairs;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0fa6ebc1e..a977f4090 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -25,9 +25,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import v5 = require("uuid/v5");
-// import { BooleanField } from "../../../../fields/BooleanField";
-import { Timeline } from "../../nodes/Timeline";
-import { Docs } from "../../../documents/Documents";
+import PDFMenu from "../../pdf/PDFMenu";
export const panZoomSchema = createSchema({
panX: "number",
@@ -83,30 +81,45 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) {
- if (de.data.droppedDocuments.length) {
- let dragDoc = de.data.droppedDocuments[0];
- let zoom = NumCast(dragDoc.zoomBasis, 1);
- let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
- let x = xp - de.data.xOffset / zoom;
- let y = yp - de.data.yOffset / zoom;
- let dropX = NumCast(de.data.droppedDocuments[0].x);
- let dropY = NumCast(de.data.droppedDocuments[0].y);
- de.data.droppedDocuments.forEach(d => {
- d.x = x + NumCast(d.x) - dropX;
- d.y = y + NumCast(d.y) - dropY;
- if (!NumCast(d.width)) {
- d.width = 300;
- }
- if (!NumCast(d.height)) {
- let nw = NumCast(d.nativeWidth);
- let nh = NumCast(d.nativeHeight);
- d.height = nw && nh ? nh / nw * NumCast(d.width) : 300;
- }
- this.bringToFront(d);
- });
+ if (super.drop(e, de)) {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ if (de.data.droppedDocuments.length) {
+ let dragDoc = de.data.droppedDocuments[0];
+ let zoom = NumCast(dragDoc.zoomBasis, 1);
+ let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ let x = xp - de.data.xOffset / zoom;
+ let y = yp - de.data.yOffset / zoom;
+ let dropX = NumCast(de.data.droppedDocuments[0].x);
+ let dropY = NumCast(de.data.droppedDocuments[0].y);
+ de.data.droppedDocuments.forEach(d => {
+ d.x = x + NumCast(d.x) - dropX;
+ d.y = y + NumCast(d.y) - dropY;
+ if (!NumCast(d.width)) {
+ d.width = 300;
+ }
+ if (!NumCast(d.height)) {
+ let nw = NumCast(d.nativeWidth);
+ let nh = NumCast(d.nativeHeight);
+ d.height = nw && nh ? nh / nw * NumCast(d.width) : 300;
+ }
+ this.bringToFront(d);
+ });
+ }
+ }
+ else if (de.data instanceof DragManager.AnnotationDragData) {
+ if (de.data.dropDocument) {
+ let dragDoc = de.data.dropDocument;
+ let zoom = NumCast(dragDoc.zoomBasis, 1);
+ let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ let x = xp - de.data.xOffset / zoom;
+ let y = yp - de.data.yOffset / zoom;
+ let dropX = NumCast(de.data.dropDocument.x);
+ let dropY = NumCast(de.data.dropDocument.y);
+ dragDoc.x = x + NumCast(dragDoc.x) - dropX;
+ dragDoc.y = y + NumCast(dragDoc.y) - dropY;
+ this.bringToFront(dragDoc);
+ }
}
- return true;
}
return false;
}
@@ -136,6 +149,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
let docs = this.childDocs || [];
let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
if (!this.isAnnotationOverlay) {
+ PDFMenu.Instance.fadeOut(true);
let minx = docs.length ? NumCast(docs[0].x) : 0;
let maxx = docs.length ? NumCast(docs[0].width) / NumCast(docs[0].zoomBasis, 1) + minx : minx;
let miny = docs.length ? NumCast(docs[0].y) : 0;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5f2a732b9..3f7efcb66 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -50,7 +50,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
document.removeEventListener("pointerup", this.onPointerUp, true);
document.removeEventListener("pointermove", this.onPointerMove, true);
}
- if (rem_keydown) {
+ if (all) {
document.removeEventListener("keydown", this.marqueeCommand, true);
}
this._visible = false;
@@ -275,13 +275,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
panY: 0,
borderRounding: e.key === "e" ? -1 : undefined,
backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white",
- scale: zoomBasis,
- width: bounds.width * zoomBasis,
- height: bounds.height * zoomBasis,
+ width: bounds.width,
+ height: bounds.height,
ink: inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined,
title: e.key === "s" || e.key === "S" ? "-summary-" : e.key === "p" ? "-summary-" : "a nested collection",
});
- newCollection.zoomBasis = zoomBasis;
this.marqueeInkDelete(inkData);
if (e.key === "s") {
@@ -304,35 +302,22 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
this.props.addLiveTextDocument(container);
// });
} else if (e.key === "S") {
- await htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 0.2 }).then((dataUrl) => {
- selected.map(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.page = -1;
- return d;
- });
- let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
- SearchBox.convertDataUri(dataUrl, "icon" + summary[Id] + "_image").then((returnedFilename) => {
- if (returnedFilename) {
- let url = DocServer.prepend(returnedFilename);
- let imageSummary = Docs.ImageDocument(url, {
- x: bounds.left, y: bounds.top + 100 / zoomBasis,
- width: 150, height: bounds.height / bounds.width * 150, title: "-summary image-"
- });
- summary.imageSummary = imageSummary;
- this.props.addDocument(imageSummary, false);
- }
- })
- newCollection.proto!.summaryDoc = summary;
- selected = [newCollection];
- newCollection.x = bounds.left + bounds.width;
- //this.props.addDocument(newCollection, false);
- summary.proto!.summarizedDocs = new List<Doc>(selected);
- summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight"
-
- this.props.addLiveTextDocument(summary);
+ selected.map(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.page = -1;
+ return d;
});
+ let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
+ newCollection.proto!.summaryDoc = summary;
+ selected = [newCollection];
+ newCollection.x = bounds.left + bounds.width;
+ //this.props.addDocument(newCollection, false);
+ summary.proto!.summarizedDocs = new List<Doc>(selected);
+ summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight"
+
+ this.props.addLiveTextDocument(summary);
}
else {
this.props.addDocument(newCollection, false);