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.tsx24
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx130
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx17
-rw-r--r--src/client/views/collections/CollectionSchemaMovableTableHOC.tsx8
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx22
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx9
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx13
-rw-r--r--src/client/views/collections/CollectionSubView.tsx67
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx36
-rw-r--r--src/client/views/collections/CollectionView.tsx6
-rw-r--r--src/client/views/collections/CollectionViewChromes.tsx17
-rw-r--r--src/client/views/collections/ParentDocumentSelector.scss9
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx46
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss3
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx474
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx78
18 files changed, 463 insertions, 503 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 93eaab453..818a41009 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -12,7 +12,6 @@ import { ContextMenu } from '../ContextMenu';
import { FieldViewProps } from '../nodes/FieldView';
import './CollectionBaseView.scss';
import { DateField } from '../../../new_fields/DateField';
-import { DocumentType } from '../../documents/DocumentTypes';
import { ImageField } from '../../../new_fields/URLField';
export enum CollectionViewType {
@@ -81,12 +80,12 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
}
}
- @computed get dataDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc ? this.props.DataDoc : this.props.Document : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
+ @computed get dataDoc() { return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
@computed get dataField() { return this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; }
active = (): boolean => {
var isSelected = this.props.isSelected();
- return isSelected || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0 || BoolCast(this.props.Document.excludeFromLibrary);
+ return isSelected || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0;
}
//TODO should this be observable?
@@ -96,7 +95,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
this.props.whenActiveChanged(isActive);
}
- @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
+ @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
@action.bound
addDocument(doc: Doc, allowDuplicates: boolean = false): boolean {
@@ -105,7 +104,6 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
if (this.props.fieldExt) { // bcz: fieldExt !== undefined means this is an overlay layer
Doc.GetProto(doc).annotationOn = this.props.Document;
}
- allowDuplicates = true;
let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document;
let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey;
const value = Cast(targetDataDoc[targetField], listSpec(Doc));
@@ -128,7 +126,8 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document;
let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey;
let value = Cast(targetDataDoc[targetField], listSpec(Doc), []);
- let index = value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
+ 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);
PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn =>
annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined));
@@ -142,17 +141,16 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
return false;
}
+ // this is called with the document that was dragged and the collection to move it into.
+ // if the target collection is the same as this collection, then the move will be allowed.
+ // 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, addDocument: (doc: Doc) => boolean): boolean {
- let self = this;
- let targetDataDoc = this.props.Document;
- if (Doc.AreProtosEqual(targetDataDoc, targetCollection)) {
+ if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
return true;
}
- if (this.removeDocument(doc)) {
- return addDocument(doc);
- }
- return false;
+ return this.removeDocument(doc) ? addDocument(doc) : false;
}
showIsTagged = () => {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f184a3944..ef2681410 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,36 +1,35 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faFile } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import 'golden-layout/src/css/goldenlayout-base.css';
import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, Lambda, observable, reaction, trace, computed, runInAction } from "mobx";
+import { action, Lambda, observable, reaction, computed, runInAction } from "mobx";
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 } from "../../../new_fields/Doc";
import { Id } from '../../../new_fields/FieldSymbols';
+import { List } from '../../../new_fields/List';
import { FieldId } from "../../../new_fields/RefField";
import { listSpec } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { emptyFunction, returnTrue, Utils, returnOne, returnEmptyString } from "../../../Utils";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { emptyFunction, returnEmptyString, returnFalse, returnOne, returnTrue, Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
+import { Docs } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragLinksAsDocuments, DragManager } from "../../util/DragManager";
import { SelectionManager } from '../../util/SelectionManager';
import { Transform } from '../../util/Transform';
-import { undoBatch, UndoManager } from "../../util/UndoManager";
+import { undoBatch } from "../../util/UndoManager";
+import { MainView } from '../MainView';
import { DocumentView } from "../nodes/DocumentView";
import "./CollectionDockingView.scss";
import { SubCollectionViewProps } from "./CollectionSubView";
-import { ParentDocSelector } from './ParentDocumentSelector';
import React = require("react");
-import { MainView } from '../MainView';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faFile, faUnlockAlt } from '@fortawesome/free-solid-svg-icons';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { Docs } from '../../documents/Documents';
-import { DateField } from '../../../new_fields/DateField';
-import { List } from '../../../new_fields/List';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { ButtonSelector } from './ParentDocumentSelector';
library.add(faFile);
@observer
@@ -44,7 +43,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
width: width,
props: {
documentId: document[Id],
- dataDocumentId: dataDoc ? dataDoc[Id] : ""
+ dataDocumentId: dataDoc && dataDoc[Id] !== document[Id] ? dataDoc[Id] : ""
//collectionDockingView: CollectionDockingView.Instance
}
};
@@ -63,24 +62,22 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
constructor(props: SubCollectionViewProps) {
super(props);
- if (props.addDocTab === emptyFunction) {
- runInAction(() => CollectionDockingView.Instance = this);
- }
+ !CollectionDockingView.Instance && (CollectionDockingView.Instance = this);
//Why is this here?
(window as any).React = React;
(window as any).ReactDOM = ReactDOM;
}
hack: boolean = false;
undohack: any = null;
- public StartOtherDrag(e: any, dragDocs: Doc[], dragDataDocs: (Doc | undefined)[] = []) {
+ public StartOtherDrag(e: any, dragDocs: Doc[]) {
let config: any;
if (dragDocs.length === 1) {
- config = CollectionDockingView.makeDocumentConfig(dragDocs[0], dragDataDocs[0]);
+ config = CollectionDockingView.makeDocumentConfig(dragDocs[0], undefined);
} else {
config = {
type: 'row',
content: dragDocs.map((doc, i) => {
- CollectionDockingView.makeDocumentConfig(doc, dragDataDocs[i]);
+ CollectionDockingView.makeDocumentConfig(doc, undefined);
})
};
}
@@ -90,18 +87,13 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
dragSource.destroy();
});
dragSource._dragListener.onMouseDown(e);
- // dragSource.destroy();
- // this.hack = true;
- // this.undohack = UndoManager.StartBatch("goldenDrag");
- // dragDocs.map((dragDoc, i) =>
- // this.AddRightSplit(dragDoc, dragDataDocs[i], true).contentItems[0].tab._dragListener.
- // onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 }));
}
+ @undoBatch
@action
public OpenFullScreen(docView: DocumentView) {
let document = Doc.MakeAlias(docView.props.Document);
- let dataDoc = docView.dataDoc;
+ let dataDoc = docView.props.DataDoc;
let newItemStackConfig = {
type: 'stack',
content: [CollectionDockingView.makeDocumentConfig(document, dataDoc)]
@@ -113,6 +105,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
this._maximizedSrc = docView;
this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
this.stateChanged();
+ SelectionManager.DeselectAll();
}
public CloseFullScreen = () => {
@@ -131,21 +124,25 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
@undoBatch
@action
- public CloseRightSplit = (document: Doc): boolean => {
+ public static CloseRightSplit(document: Doc): boolean {
+ if (!CollectionDockingView.Instance) return false;
+ let instance = CollectionDockingView.Instance;
let retVal = false;
- if (this._goldenLayout.root.contentItems[0].isRow) {
- retVal = Array.from(this._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
+ if (instance._goldenLayout.root.contentItems[0].isRow) {
+ retVal = Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" &&
+ DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId) &&
Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)!.Document, document)) {
child.contentItems[0].remove();
- this.layoutChanged(document);
+ instance.layoutChanged(document);
return true;
} else {
Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => {
- if (Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)) {
+ if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId) &&
+ Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)) {
child.contentItems[j].remove();
child.config.activeItemIndex = Math.max(child.contentItems.length - 1, 0);
- let docs = Cast(this.props.Document.data, listSpec(Doc));
+ let docs = Cast(instance.props.Document.data, listSpec(Doc));
docs && docs.indexOf(document) !== -1 && docs.splice(docs.indexOf(document), 1);
return true;
}
@@ -156,7 +153,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
});
}
if (retVal) {
- this.stateChanged();
+ instance.stateChanged();
}
return retVal;
}
@@ -181,9 +178,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
//
// Creates a vertical split on the right side of the docking view, and then adds the Document to that split
//
+ @undoBatch
@action
- public AddRightSplit = (document: Doc, dataDoc: Doc | undefined, minimize: boolean = false) => {
- let docs = Cast(this.props.Document.data, listSpec(Doc));
+ public static AddRightSplit(document: Doc, dataDoc: Doc | undefined, minimize: boolean = false) {
+ if (!CollectionDockingView.Instance) return false;
+ let instance = CollectionDockingView.Instance;
+ let docs = Cast(instance.props.Document.data, listSpec(Doc));
if (docs) {
docs.push(document);
}
@@ -192,15 +192,15 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
content: [CollectionDockingView.makeDocumentConfig(document, dataDoc)]
};
- var newContentItem = this._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, this._goldenLayout);
+ var newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
- if (this._goldenLayout.root.contentItems.length === 0) {
- this._goldenLayout.root.addChild(newContentItem);
- } else if (this._goldenLayout.root.contentItems[0].isRow) {
- this._goldenLayout.root.contentItems[0].addChild(newContentItem);
+ if (instance._goldenLayout.root.contentItems.length === 0) {
+ instance._goldenLayout.root.addChild(newContentItem);
+ } else if (instance._goldenLayout.root.contentItems[0].isRow) {
+ instance._goldenLayout.root.contentItems[0].addChild(newContentItem);
} else {
- var collayout = this._goldenLayout.root.contentItems[0];
- var newRow = collayout.layoutManager.createContentItem({ type: "row" }, this._goldenLayout);
+ var collayout = instance._goldenLayout.root.contentItems[0];
+ var newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
collayout.parent.replaceChild(collayout, newRow);
newRow.addChild(newContentItem, undefined, true);
@@ -215,10 +215,11 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
// newContentItem.config.height = 10;
}
newContentItem.callDownwards('_$init');
- this.layoutChanged();
-
- return newContentItem;
+ instance.layoutChanged();
+ return true;
}
+
+ @undoBatch
@action
public AddTab = (stack: any, document: Doc, dataDocument: Doc | undefined) => {
Doc.GetProto(document).lastOpened = new DateField;
@@ -245,6 +246,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
stack.addChild(docContentConfig, undefined);
}
this.layoutChanged();
+ return true;
}
setupGoldenLayout() {
@@ -404,6 +406,10 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
dragSpan.style.bottom = "6px";
dragSpan.style.paddingLeft = "4px";
dragSpan.style.paddingRight = "2px";
+ let gearSpan = document.createElement("span");
+ gearSpan.style.position = "relative";
+ gearSpan.style.paddingLeft = "0px";
+ gearSpan.style.paddingRight = "12px";
let upDiv = document.createElement("span");
const stack = tab.contentItem.parent;
// shifts the focus to this tab when another tab is dragged over it
@@ -419,14 +425,19 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
e => {
e.preventDefault();
e.stopPropagation();
- DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc], [dataDoc]), e.clientX, e.clientY, {
+ DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY, {
handlers: { dragComplete: emptyFunction },
hideSource: false
});
}}><FontAwesomeIcon icon="file" size="lg" /></span>, dragSpan);
- ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={doc => CollectionDockingView.Instance.AddTab(stack, doc, dataDoc)} />, upDiv);
- tab.reactComponents = [dragSpan, upDiv];
+ ReactDOM.render(<ButtonSelector Document={doc} Stack={stack} />, gearSpan);
+ // ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={(doc, data, where) => {
+ // where === "onRight" ? CollectionDockingView.AddRightSplit(doc, dataDoc) : CollectionDockingView.Instance.AddTab(stack, doc, dataDoc);
+ // return true;
+ // }} />, upDiv);
+ tab.reactComponents = [dragSpan, gearSpan, upDiv];
tab.element.append(dragSpan);
+ tab.element.append(gearSpan);
tab.element.append(upDiv);
tab.reactionDisposer = reaction(() => [doc.title, Doc.IsBrushedDegree(doc)], () => {
tab.titleElement[0].textContent = doc.title, { fireImmediately: true };
@@ -538,11 +549,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
@observable private _isActive: boolean = false;
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) {
- return parent.parent.contentItems[1];
- }
- return parent;
+ return (this.props as any).glContainer.parent.parent;
}
constructor(props: any) {
super(props);
@@ -616,17 +623,18 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
}
return Transform.Identity();
}
- get previewPanelCenteringOffset() { return this.nativeWidth() && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth()) / 2 : 0; }
+ get previewPanelCenteringOffset() { return this.nativeWidth() && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() / this.ScreenToLocalTransform().Scale) / 2 : 0; }
- addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
+ addDocTab = (doc: Doc, dataDoc: Opt<Doc>, location: string) => {
if (doc.dockingConfig) {
MainView.Instance.openWorkspace(doc);
+ return true;
} else if (location === "onRight") {
- CollectionDockingView.Instance.AddRightSplit(doc, dataDoc);
+ return CollectionDockingView.AddRightSplit(doc, dataDoc);
} else if (location === "close") {
- CollectionDockingView.Instance.CloseRightSplit(doc);
+ return CollectionDockingView.CloseRightSplit(doc);
} else {
- CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc);
+ return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc);
}
}
@computed get docView() {
@@ -640,6 +648,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
bringToFront={emptyFunction}
addDocument={undefined}
removeDocument={undefined}
+ ruleProvider={undefined}
ContentScaling={this.contentScaling}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
@@ -652,6 +661,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
addDocTab={this.addDocTab}
pinToPres={this.PinDoc}
ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
zoomToScale={emptyFunction}
getScale={returnOne} />;
}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index c59107b53..4dac27e60 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -39,7 +39,7 @@ export interface CellProps {
Document: Doc;
fieldKey: string;
renderDepth: number;
- addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+ addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
pinToPres: (document: Doc) => void;
moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
isFocused: boolean;
@@ -149,7 +149,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
DataDoc: this.props.rowProps.original,
fieldKey: this.props.rowProps.column.id as string,
fieldExt: "",
+ ruleProvider: undefined,
ContainingCollectionView: this.props.CollectionView,
+ ContainingCollectionDoc: this.props.CollectionView.props.Document,
isSelected: returnFalse,
select: emptyFunction,
renderDepth: this.props.renderDepth + 1,
@@ -171,7 +173,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
let onItemDown = (e: React.PointerEvent) => {
if (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, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument, this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
+ this._document[props.fieldKey] instanceof Doc ? (doc: Doc, target: Doc, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument,
+ this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
}
};
let onPointerEnter = (e: React.PointerEvent): void => {
@@ -235,13 +238,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
return this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
}}
OnFillDown={async (value: string) => {
- let script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
- if (!script.compiled) {
- return;
+ const script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+ if (script.compiled) {
+ DocListCast(this.props.Document[this.props.fieldKey]).
+ forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, script.run));
}
- const run = script.run;
- const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]);
- val && val.forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, run));
}}
/>
</div >
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index ec40043cc..39abc41ec 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -201,12 +201,8 @@ export class MovableRow extends React.Component<MovableRowProps> {
@action
move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => {
let targetView = DocumentManager.Instance.getDocumentView(target);
- if (targetView) {
- let targetContainingColl = targetView.props.ContainingCollectionView; //.props.ContainingCollectionView.props.Document;
- if (targetContainingColl) {
- let targetContCollDoc = targetContainingColl.props.Document;
- return doc !== target && doc !== targetContCollDoc && this.props.removeDoc(doc) && addDoc(doc);
- }
+ if (targetView && targetView.props.ContainingCollectionDoc) {
+ return doc !== target && doc !== targetView.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
}
return doc !== target && this.props.removeDoc(doc) && addDoc(doc);
}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 9d83aa6c1..7bd2a1971 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,7 +14,7 @@ import { listSpec } from "../../../new_fields/Schema";
import { Docs, DocumentOptions } from "../../documents/Documents";
import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
import { Gateway } from "../../northstar/manager/Gateway";
-import { SetupDrag, DragManager } from "../../util/DragManager";
+import { DragManager } from "../../util/DragManager";
import { CompileScript, ts, Transformer } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
@@ -32,6 +32,7 @@ import { CellProps, CollectionSchemaCell, CollectionSchemaNumberCell, Collection
import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
+import { DocumentType } from "../../documents/DocumentTypes";
library.add(faCog, faPlus, faSortUp, faSortDown);
@@ -161,6 +162,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined}
childDocs={this.childDocs}
renderDepth={this.props.renderDepth}
+ ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider}
width={this.previewWidth}
height={this.previewHeight}
getTransform={this.getPreviewTransform}
@@ -194,6 +196,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
childDocs={this.childDocs}
CollectionView={this.props.CollectionView}
ContainingCollectionView={this.props.ContainingCollectionView}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
fieldKey={this.props.fieldKey}
renderDepth={this.props.renderDepth}
moveDocument={this.props.moveDocument}
@@ -245,6 +248,7 @@ export interface SchemaTableProps {
childDocs?: Doc[];
CollectionView: CollectionView | CollectionPDFView | CollectionVideoView;
ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
+ ContainingCollectionDoc: Opt<Doc>;
fieldKey: string;
renderDepth: number;
deleteDocument: (document: Doc) => boolean;
@@ -252,7 +256,7 @@ export interface SchemaTableProps {
ScreenToLocalTransform: () => Transform;
active: () => boolean;
onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
- addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+ addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
pinToPres: (document: Doc) => void;
isSelected: () => boolean;
isFocused: (document: Doc) => boolean;
@@ -901,6 +905,7 @@ interface CollectionSchemaPreviewProps {
fitToBox?: boolean;
width: () => number;
height: () => number;
+ ruleProvider: Doc | undefined;
showOverlays?: (doc: Doc) => { title?: string, caption?: string };
CollectionView?: CollectionView | CollectionPDFView | CollectionVideoView;
onClick?: ScriptField;
@@ -910,7 +915,7 @@ interface CollectionSchemaPreviewProps {
removeDocument: (document: Doc) => boolean;
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
- addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+ addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
pinToPres: (document: Doc) => void;
setPreviewScript: (script: string) => void;
previewScript?: string;
@@ -943,13 +948,12 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.data instanceof DragManager.DocumentDragData) {
- let docDrag = de.data;
- let computed = CompileScript("return this.image_data[0]", { params: { this: "Doc" } });
this.props.childDocs && this.props.childDocs.map(otherdoc => {
- let doc = docDrag.draggedDocuments[0];
let target = Doc.GetProto(otherdoc);
- target.layout = target.detailedLayout = Doc.MakeDelegate(doc);
- computed.compiled && (target.miniLayout = new ComputedField(computed));
+ let layoutNative = Doc.MakeTitled("layoutNative");
+ layoutNative.layout = ComputedField.MakeFunction("this.image_data[0]");
+ target.layoutNative = layoutNative;
+ target.layoutCUstom = target.layout = Doc.MakeDelegate(de.data.draggedDocuments[0]);
});
e.stopPropagation();
}
@@ -995,12 +999,14 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
Document={this.props.Document}
fitToBox={this.props.fitToBox}
onClick={this.props.onClick}
+ ruleProvider={this.props.ruleProvider}
showOverlays={this.props.showOverlays}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
moveDocument={this.props.moveDocument}
whenActiveChanged={this.props.whenActiveChanged}
ContainingCollectionView={this.props.CollectionView}
+ ContainingCollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
parentActive={this.props.active}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 91e10b0ac..ccf131797 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -29,7 +29,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
_masonryGridRef: HTMLDivElement | null = null;
_draggerRef = React.createRef<HTMLDivElement>();
_heightDisposer?: IReactionDisposer;
- _childLayoutDisposer?: IReactionDisposer;
_sectionFilterDisposer?: IReactionDisposer;
_docXfs: any[] = [];
_columnStart: number = 0;
@@ -87,10 +86,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
componentDidMount() {
- this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)],
- async (args) => args[1] instanceof Doc &&
- this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined)));
-
// is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported).
this._heightDisposer = reaction(() => {
if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) {
@@ -115,7 +110,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
);
}
componentWillUnmount() {
- this._childLayoutDisposer && this._childLayoutDisposer();
this._heightDisposer && this._heightDisposer();
this._sectionFilterDisposer && this._sectionFilterDisposer();
}
@@ -134,7 +128,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
- @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); }
+ @computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
let height = () => this.getDocHeight(layoutDoc);
@@ -144,6 +138,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
DataDocument={dataDoc}
showOverlays={this.overlays}
renderDepth={this.props.renderDepth}
+ ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider}
fitToBox={this.props.fitToBox}
onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler}
width={width}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index bc4fe7dd7..b3b7b40dd 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -155,6 +155,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
let key = StrCast(this.props.parent.props.Document.sectionFilter);
let newDoc = Docs.Create.TextDocument({ height: 18, width: 200, documentText: "@@@" + value, title: value, autoHeight: true });
newDoc[key] = this.getValue(this.props.heading);
+ let maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
+ let heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
+ newDoc.heading = heading;
return this.props.parent.props.addDocument(newDoc);
}
@@ -175,13 +178,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
let key = StrCast(this.props.parent.props.Document.sectionFilter);
let value = this.getValue(this._heading);
value = typeof value === "string" ? `"${value}"` : value;
- let script = `return doc.${key} === ${value}`;
- let compiled = CompileScript(script, { params: { doc: Doc.name } });
- if (compiled.compiled) {
- let scriptField = new ScriptField(compiled);
- alias.viewSpecScript = scriptField;
- let dragData = new DragManager.DocumentDragData([alias], [alias.proto]);
- DragManager.StartDocumentDrag([this._headerRef.current!], dragData, e.clientX, e.clientY);
+ alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name });
+ if (alias.viewSpecScript) {
+ DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
}
e.stopPropagation();
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 59fc11359..0680f6644 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
import * as rp from 'request-promise';
import CursorField from "../../../new_fields/CursorField";
import { Doc, DocListCast, HeightSym } from "../../../new_fields/Doc";
@@ -36,11 +36,14 @@ export interface CollectionViewProps extends FieldViewProps {
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: CollectionView | CollectionPDFView | CollectionVideoView;
+ ruleProvider: Doc | undefined;
}
export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
class CollectionSubView extends DocComponent<SubCollectionViewProps, T>(schemaCtor) {
private dropDisposer?: DragManager.DragDropDisposer;
+ private _childLayoutDisposer?: IReactionDisposer;
+
protected createDropTarget = (ele: HTMLDivElement) => {
this.dropDisposer && this.dropDisposer();
if (ele) {
@@ -51,33 +54,35 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
this.createDropTarget(ele);
}
- @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
+ componentDidMount() {
+ this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)],
+ async (args) => args[1] instanceof Doc &&
+ this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc))));
+ }
+ componentWillUnmount() {
+ this._childLayoutDisposer && this._childLayoutDisposer();
+ }
- get childDocs() {
- let self = this;
- //TODO tfs: This might not be what we want?
- //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue)
- let docs = DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]);
- let viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
- if (viewSpecScript) {
- let script = viewSpecScript.script;
- docs = docs.filter(d => {
- let res = script.run({ doc: d });
- if (res.success) {
- return res.result;
- }
- else {
- console.log(res.error);
- }
- });
- }
- return docs;
+ // The data field for rendeing this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
+ // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
+ // to its children which may be templates.
+ // The name of the data field comes from fieldExt if it's an extension, or fieldKey otherwise.
+ @computed get dataField() {
+ return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt)[this.props.fieldExt || this.props.fieldKey];
+ }
+
+
+ get childLayoutPairs() {
+ return this.childDocs.map(cd => Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, cd)).filter(pair => pair.layout).map(pair => ({ layout: pair.layout!, data: pair.data! }));
}
get childDocList() {
- //TODO tfs: This might not be what we want?
- //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue)
- return Cast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc));
+ return Cast(this.dataField, listSpec(Doc));
+ }
+ get childDocs() {
+ let docs = DocListCast(this.dataField);
+ const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
+ return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
}
@action
@@ -118,7 +123,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
if (de.data instanceof DragManager.DocumentDragData && !de.data.applyAsTemplate) {
if (de.mods === "AltKey" && de.data.draggedDocuments.length) {
this.childDocs.map(doc =>
- Doc.ApplyTemplateTo(de.data.draggedDocuments[0], doc, undefined)
+ Doc.ApplyTemplateTo(de.data.draggedDocuments[0], doc)
);
e.stopPropagation();
return true;
@@ -127,9 +132,11 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
if (de.data.dropAction || de.data.userDropAction) {
added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
} else if (de.data.moveDocument) {
- let movedDocs = de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments;
- added = movedDocs.reduce((added: boolean, d) =>
- de.data.moveDocument(d, this.props.Document, this.props.addDocument) || added, false);
+ let movedDocs = de.data.draggedDocuments;// de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments;
+ // note that it's possible the drag function might create a drop document that's not the same as the
+ // original dragged document. So we explicitly call addDocument() with a droppedDocument and
+ added = movedDocs.reduce((added: boolean, d, i) =>
+ de.data.moveDocument(d, this.props.Document, (doc: Doc) => this.props.addDocument(de.data.droppedDocuments[i])) || added, false);
} else {
added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
}
@@ -271,6 +278,10 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
promises.push(prom);
}
}
+ if (text) {
+ this.props.addDocument(Docs.Create.TextDocument({ ...options, documentText: "@@@" + text, width: 400, height: 315 }));
+ return;
+ }
if (promises.length) {
Promise.all(promises).finally(() => { completed && completed(); batch.end(); });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f5bb76966..e5313f68c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -37,9 +37,10 @@ export interface TreeViewProps {
containingCollection: Doc;
renderDepth: number;
deleteDoc: (doc: Doc) => boolean;
+ ruleProvider: Doc | undefined;
moveDocument: DragManager.MoveFunction;
dropAction: "alias" | "copy" | undefined;
- addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => void;
+ addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean;
pinToPres: (document: Doc) => void;
panelWidth: () => number;
panelHeight: () => number;
@@ -177,7 +178,7 @@ class TreeView extends React.Component<TreeViewProps> {
SetValue={undoBatch((value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true)}
OnFillDown={undoBatch((value: string) => {
Doc.GetProto(this.dataDoc)[key] = value;
- let doc = this.props.document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.detailedLayout)) : undefined;
+ let doc = this.props.document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.layoutCustom)) : undefined;
if (!doc) doc = Docs.Create.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);
@@ -200,6 +201,7 @@ class TreeView extends React.Component<TreeViewProps> {
ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
}
ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.Create.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" });
+ ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
e.stopPropagation();
e.preventDefault();
@@ -324,6 +326,7 @@ class TreeView extends React.Component<TreeViewProps> {
DataDocument={this.resolvedDataDoc}
renderDepth={this.props.renderDepth}
showOverlays={this.noOverlays}
+ ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider}
fitToBox={this.boundsOfCollectionDocument !== undefined}
width={this.docWidth}
height={this.docHeight}
@@ -344,7 +347,7 @@ class TreeView extends React.Component<TreeViewProps> {
@computed
get renderBullet() {
- return <div className="bullet" title="view inline" onClick={action(() => this.treeViewOpen = !this.treeViewOpen)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
+ return <div className="bullet" title="view inline" onClick={action((e: React.MouseEvent) => { this.treeViewOpen = !this.treeViewOpen; e.stopPropagation(); })} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
{<FontAwesomeIcon icon={!this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down")} />}
</div>;
}
@@ -402,7 +405,7 @@ class TreeView extends React.Component<TreeViewProps> {
</div>;
}
public static GetChildElements(
- docList: Doc[],
+ docs: Doc[],
treeViewId: string,
containingCollection: Doc,
dataDoc: Doc | undefined,
@@ -411,7 +414,7 @@ class TreeView extends React.Component<TreeViewProps> {
remove: ((doc: Doc) => boolean),
move: DragManager.MoveFunction,
dropAction: dropActionType,
- addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => void,
+ addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean,
pinToPres: (document: Doc) => void,
screenToLocalXf: () => Transform,
outerXf: () => { translateX: number, translateY: number },
@@ -422,19 +425,9 @@ class TreeView extends React.Component<TreeViewProps> {
preventTreeViewOpen: boolean,
renderedIds: string[]
) {
- let docs = docList.filter(child => !child.excludeFromLibrary && child.opacity !== 0);
- let viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
+ const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
if (viewSpecScript) {
- let script = viewSpecScript.script;
- docs = docs.filter(d => {
- let res = script.run({ doc: d });
- if (res.success) {
- return res.result;
- }
- else {
- console.log(res.error);
- }
- });
+ docs = docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
}
let ascending = Cast(containingCollection.sortAscending, "boolean", null);
@@ -491,6 +484,7 @@ class TreeView extends React.Component<TreeViewProps> {
dataDoc={pair.data}
containingCollection={containingCollection}
treeViewId={treeViewId}
+ ruleProvider={containingCollection.isRuleProvider && pair.layout.type !== DocumentType.TEXT ? containingCollection : containingCollection.ruleProvider as Doc}
key={child[Id]}
indentDocument={indent}
renderDepth={renderDepth}
@@ -544,7 +538,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
}
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
- if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document
+ if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) {
ContextMenu.Instance.addItem({ description: "Create Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.remove(this.props.Document), icon: "minus" });
e.stopPropagation();
@@ -559,8 +553,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
outerXf = () => Utils.GetScreenTransform(this._mainEle!);
onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
openNotifsCol = () => {
- if (CollectionTreeView.NotifsCol && CollectionDockingView.Instance) {
- CollectionDockingView.Instance.AddRightSplit(CollectionTreeView.NotifsCol, undefined);
+ if (CollectionTreeView.NotifsCol) {
+ this.props.addDocTab(CollectionTreeView.NotifsCol, undefined, "onRight");
}
}
@@ -610,7 +604,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
SetValue={undoBatch((value: string) => (Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true)}
OnFillDown={undoBatch((value: string) => {
Doc.GetProto(this.props.Document).title = value;
- let doc = this.props.Document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.detailedLayout)) : undefined;
+ let doc = this.props.Document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.layoutCustom)) : undefined;
if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
TreeView.loadId = doc[Id];
Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 94b49fb98..1f2dc9b5c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -105,6 +105,12 @@ export class CollectionView extends React.Component<FieldViewProps> {
subItems.push({ description: "Schema", event: () => this.props.Document.viewType = CollectionViewType.Schema, icon: "th-list" });
subItems.push({ description: "Treeview", event: () => this.props.Document.viewType = CollectionViewType.Tree, icon: "tree" });
subItems.push({ description: "Stacking", event: () => this.props.Document.viewType = CollectionViewType.Stacking, icon: "ellipsis-v" });
+ subItems.push({
+ description: "Stacking (AutoHeight)", event: () => {
+ this.props.Document.viewType = CollectionViewType.Stacking;
+ this.props.Document.autoHeight = true;
+ }, icon: "ellipsis-v"
+ });
subItems.push({ description: "Masonry", event: () => this.props.Document.viewType = CollectionViewType.Masonry, icon: "columns" });
switch (this.props.Document.viewType) {
case CollectionViewType.Freeform: {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index c897af17e..7510b86a0 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -215,14 +215,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
}
}
let fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ?
- `return ${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
- `return (${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
- "return true";
+ `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
+ `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
+ "true";
- let compiled = CompileScript(fullScript, { params: { doc: Doc.name }, typecheck: false });
- if (compiled.compiled) {
- this.props.CollectionView.props.Document.viewSpecScript = new ScriptField(compiled);
- }
+ this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name });
}
@action
@@ -283,11 +280,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
@action.bound
clearFilter = () => {
- let compiled = CompileScript("return true", { params: { doc: Doc.name }, typecheck: false });
- if (compiled.compiled) {
- this.props.CollectionView.props.Document.viewSpecScript = new ScriptField(compiled);
- }
-
+ this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name });
this._keyRestrictions = [];
this.addKeyRestrictions([]);
}
diff --git a/src/client/views/collections/ParentDocumentSelector.scss b/src/client/views/collections/ParentDocumentSelector.scss
index 2dd3e49f2..c186d15f8 100644
--- a/src/client/views/collections/ParentDocumentSelector.scss
+++ b/src/client/views/collections/ParentDocumentSelector.scss
@@ -19,4 +19,13 @@
border-right: 0px;
border-left: 0px;
}
+}
+.parentDocumentSelector-button {
+ pointer-events: all;
+}
+.buttonSelector {
+ position: absolute;
+ display: inline-block;
+ padding-left: 5px;
+ padding-right: 5px;
} \ No newline at end of file
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index d8475a467..7f2913214 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -8,8 +8,15 @@ import { SearchUtil } from "../../util/SearchUtil";
import { CollectionDockingView } from "./CollectionDockingView";
import { NumCast } from "../../../new_fields/Types";
import { CollectionViewType } from "./CollectionBaseView";
+import { DocumentButtonBar } from "../DocumentButtonBar";
+import { DocumentManager } from "../../util/DocumentManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faEdit } from "@fortawesome/free-solid-svg-icons";
+import { library } from "@fortawesome/fontawesome-svg-core";
-type SelectorProps = { Document: Doc, addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void };
+library.add(faEdit);
+
+type SelectorProps = { Document: Doc, Stack?: any, addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void };
@observer
export class SelectorContextMenu extends React.Component<SelectorProps> {
@observable private _docs: { col: Doc, target: Doc }[] = [];
@@ -83,7 +90,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
);
}
return (
- <span style={{ position: "relative", display: "inline-block", paddingLeft: "5px", paddingRight: "5px" }}
+ <span className="parentDocumentSelector-button" style={{ position: "relative", display: "inline-block", paddingLeft: "5px", paddingRight: "5px" }}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}>
<p>^</p>
@@ -92,3 +99,38 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
);
}
}
+
+@observer
+export class ButtonSelector extends React.Component<{ Document: Doc, Stack: any }> {
+ @observable hover = false;
+
+ @action
+ onMouseLeave = () => {
+ this.hover = false;
+ }
+
+ @action
+ onMouseEnter = () => {
+ this.hover = true;
+ }
+
+ render() {
+ let flyout;
+ if (this.hover) {
+ let view = DocumentManager.Instance.getDocumentView(this.props.Document);
+ flyout = !view ? (null) : (
+ <div className="PDS-flyout" title=" " onMouseLeave={this.onMouseLeave}>
+ <DocumentButtonBar views={[view]} stack={this.props.Stack} />
+ </div>
+ );
+ }
+ return (
+ <span className="buttonSelector"
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.onMouseLeave}>
+ {this.hover ? (null) : <FontAwesomeIcon icon={faEdit} size={"sm"} />}
+ {flyout}
+ </span>
+ );
+ }
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
index 2a64a7afb..cfd18ad35 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
@@ -1,8 +1,9 @@
.collectionfreeformlinkview-linkLine {
stroke: black;
transform: translate(10000px,10000px);
- // opacity: 0.5;
+ opacity: 0.8;
pointer-events: all;
+ stroke-width: 3px;
}
.collectionfreeformlinkview-linkCircle {
stroke: rgb(0,0,0);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 12771d11e..df089eb00 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -50,7 +50,6 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
return (
<>
<line key="linkLine" className="collectionfreeformlinkview-linkLine"
- style={{ strokeWidth: `${3}` }}
x1={`${x1}`} y1={`${y1}`}
x2={`${x2}`} y2={`${y2}`} />
{/* <circle key="linkCircle" className="collectionfreeformlinkview-linkCircle"
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index a25627dd1..a81f5315a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -79,15 +79,15 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
if (containerDoc) {
equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.proto!);
}
- if (view.props.ContainingCollectionView) {
- let collid = view.props.ContainingCollectionView.props.Document[Id];
+ if (view.props.ContainingCollectionDoc) {
+ let collid = view.props.ContainingCollectionDoc[Id];
DocListCast(this.props.Document[this.props.fieldKey]).
filter(child =>
child[Id] === collid).map(view =>
DocumentManager.Instance.getDocumentViews(view).map(view =>
equalViews.push(view)));
}
- return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document);
+ return equalViews.filter(sv => sv.props.ContainingCollectionDoc === this.props.Document);
}
@computed
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f7bda0a26..eb738d783 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -8,10 +8,10 @@ import { Id } from "../../../../new_fields/FieldSymbols";
import { InkField, StrokeData } from "../../../../new_fields/InkField";
import { createSchema, makeInterface } from "../../../../new_fields/Schema";
import { ScriptField } from "../../../../new_fields/ScriptField";
-import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue, DateCast } from "../../../../new_fields/Types";
import { emptyFunction, returnEmptyString, returnOne, Utils } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
-import { Docs } from "../../../documents/Documents";
+import { Docs, DocumentOptions } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { DocumentManager } from "../../../util/DocumentManager";
import { DragManager } from "../../../util/DragManager";
@@ -24,9 +24,9 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"
import { ContextMenu } from "../../ContextMenu";
import { ContextMenuProps } from "../../ContextMenuItem";
import { InkingCanvas } from "../../InkingCanvas";
-import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
+import { CollectionFreeFormDocumentView, positionSchema } from "../../nodes/CollectionFreeFormDocumentView";
import { DocumentContentsView } from "../../nodes/DocumentContentsView";
-import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView";
+import { DocumentViewProps, documentSchema } from "../../nodes/DocumentView";
import { pageSchema } from "../../nodes/ImageBox";
import { OverlayElementOptions, OverlayView } from "../../OverlayView";
import PDFMenu from "../../pdf/PDFMenu";
@@ -51,6 +51,9 @@ export const panZoomSchema = createSchema({
scale: "number",
arrangeScript: ScriptField,
arrangeInit: ScriptField,
+ useClusters: "boolean",
+ isRuleProvider: "boolean",
+ fitToBox: "boolean"
});
export interface ViewDefBounds {
@@ -161,6 +164,7 @@ export namespace PivotView {
y={pos.y}
width={pos.width}
height={pos.height}
+ transition={"transform 1s"}
jitterRotation={NumCast(target.props.Document.jitterRotation)}
{...target.getChildDocumentViewProps(doc)}
/>,
@@ -181,8 +185,8 @@ export namespace PivotView {
}
-type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>;
-const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema);
+type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>;
+const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema);
@observer
export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@@ -190,35 +194,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private _lastY: number = 0;
private get _pwidth() { return this.props.PanelWidth(); }
private get _pheight() { return this.props.PanelHeight(); }
- private inkKey = "ink";
- private _childLayoutDisposer?: IReactionDisposer;
- private _childDisposer?: IReactionDisposer;
-
- componentDidMount() {
- this._childDisposer = reaction(() => this.childDocs,
- async (childDocs) => {
- let childLayout = Cast(this.props.Document.childLayout, Doc) as Doc;
- childLayout && childDocs.map(async doc => {
- if (!Doc.AreProtosEqual(childLayout, (await doc).layout as Doc)) {
- Doc.ApplyTemplateTo(childLayout, doc, undefined);
- }
- });
- });
- this._childLayoutDisposer = reaction(() => Cast(this.props.Document.childLayout, Doc),
- async (childLayout) => {
- this.childDocs.map(async doc => {
- if (!Doc.AreProtosEqual(childLayout as Doc, (await doc).layout as Doc)) {
- Doc.ApplyTemplateTo(childLayout as Doc, doc, undefined);
- }
- });
- });
- }
- componentWillUnmount() {
- this._childDisposer && this._childDisposer();
- this._childLayoutDisposer && this._childLayoutDisposer();
- }
-
- get parentScaling() {
+ private get parentScaling() {
return (this.props as any).ContentScaling && this.fitToBox && !this.isAnnotationOverlay ? (this.props as any).ContentScaling() : 1;
}
@@ -249,7 +225,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
return res;
}
- @computed get fitToBox() { return this.props.fitToBox || this.props.Document.fitToBox; }
+ @computed get fitToBox() { return this.props.fitToBox || this.Document.fitToBox; }
@computed get nativeWidth() { return this.fitToBox ? 0 : this.Document.nativeWidth || 0; }
@computed get nativeHeight() { return this.fitToBox ? 0 : this.Document.nativeHeight || 0; }
public get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } // fieldExt will be "" or "annotation". should maybe generalize this, or make it more specific (ie, 'annotation' instead of 'fieldExt')
@@ -265,29 +241,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
private addLiveTextBox = (newBox: Doc) => {
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
- newBox.heading = 1;
- for (let child of this.childDocs) {
- if (child.heading === 1) {
- newBox.heading = 2;
- }
+ let maxHeading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
+ let heading = maxHeading === 0 || this.childDocs.length === 0 ? 1 : maxHeading === 1 ? 2 : 0;
+ if (heading === 0) {
+ let sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 :
+ DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0);
+ heading = !sorted.length ? Math.max(1, maxHeading) : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading);
}
- PromiseValue(Cast(this.props.Document.ruleProvider, Doc)).then(ruleProvider => {
- if (!ruleProvider) ruleProvider = this.props.Document;
- // saturation shift
- // let col = NumCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]);
- // let back = Utils.fromRGBAstr(StrCast(this.props.Document.backgroundColor));
- // let hsl = Utils.RGBToHSL(back.r, back.g, back.b);
- // let newcol = { h: hsl.h, s: hsl.s + col, l: hsl.l };
- // col && (Doc.GetProto(newBox).backgroundColor = Utils.toRGBAstr(Utils.HSLtoRGB(newcol.h, newcol.s, newcol.l)));
- // OR transparency set
- let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]);
- (newBox.backgroundColor === newBox.defaultBackgroundColor) && col && (Doc.GetProto(newBox).backgroundColor = col);
-
- let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]);
- round && (Doc.GetProto(newBox).borderRounding = round);
- newBox.ruleProvider = ruleProvider;
- this.addDocument(newBox, false);
- });
+ !this.Document.isRuleProvider && (newBox.heading = heading);
+ this.addDocument(newBox, false);
}
private addDocument = (newBox: Doc, allowDuplicates: boolean) => {
this.props.addDocument(newBox, false);
@@ -302,14 +264,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
public getActiveDocuments = () => {
const curPage = FieldValue(this.Document.curPage, -1);
- return this.childDocs.filter(doc => {
- var page = NumCast(doc.page, -1);
+ return this.childLayoutPairs.filter(pair => {
+ var page = NumCast(pair.layout.page, -1);
return page === curPage || page === -1;
- });
+ }).map(pair => pair.layout);
}
@computed get fieldExtensionDoc() {
- return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
+ return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey);
}
intersectRect(r1: { left: number, top: number, width: number, height: number },
@@ -342,8 +304,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (de.data instanceof DragManager.DocumentDragData) {
if (de.data.droppedDocuments.length) {
let z = NumCast(de.data.droppedDocuments[0].z);
- let x = (z ? xpo : xp) - de.data.xOffset;
- let y = (z ? ypo : yp) - de.data.yOffset;
+ let x = (z ? xpo : xp) - de.data.offset[0];
+ let y = (z ? ypo : yp) - de.data.offset[1];
let dropX = NumCast(de.data.droppedDocuments[0].x);
let dropY = NumCast(de.data.droppedDocuments[0].y);
de.data.droppedDocuments.forEach(d => {
@@ -366,8 +328,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
else if (de.data instanceof DragManager.AnnotationDragData) {
if (de.data.dropDocument) {
let dragDoc = de.data.dropDocument;
- let x = xp - de.data.xOffset;
- let y = yp - de.data.yOffset;
+ let x = xp - de.data.offset[0];
+ let y = yp - de.data.offset[1];
let dropX = NumCast(de.data.dropDocument.x);
let dropY = NumCast(de.data.dropDocument.y);
dragDoc.x = x + NumCast(dragDoc.x) - dropX;
@@ -383,7 +345,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
tryDragCluster(e: PointerEvent) {
let probe = this.getTransform().transformPoint(e.clientX, e.clientY);
- let cluster = this.childDocs.reduce((cluster, cd) => {
+ let cluster = this.childLayoutPairs.map(pair => pair.layout).reduce((cluster, cd) => {
let cx = NumCast(cd.x) - this._clusterDistance;
let cy = NumCast(cd.y) - this._clusterDistance;
let cw = NumCast(cd.width) + 2 * this._clusterDistance;
@@ -394,7 +356,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
return cluster;
}, -1);
if (cluster !== -1) {
- let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster);
+ let eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => NumCast(cd.cluster) === cluster);
// hacky way to get a list of DocumentViews in the current view given a list of Documents in the current view
let prevSelected = SelectionManager.SelectedDocuments();
@@ -403,13 +365,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
SelectionManager.DeselectAll();
prevSelected.map(dv => SelectionManager.SelectDoc(dv, true));
- let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined));
+ let de = new DragManager.DocumentDragData(eles);
de.moveDocument = this.props.moveDocument;
const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0);
- const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top);
+ de.offset = this.getTransform().transformDirection(e.x - left, e.y - top);
de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined;
- de.xOffset = xoff;
- de.yOffset = yoff;
DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, {
handlers: { dragComplete: action(emptyFunction) },
hideSource: !de.dropAction
@@ -423,9 +383,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@undoBatch
@action
- updateClusters() {
+ updateClusters(useClusters: boolean) {
+ this.Document.useClusters = useClusters;
this.sets.length = 0;
- this.childDocs.map(c => {
+ this.childLayoutPairs.map(pair => pair.layout).map(c => {
let included = [];
for (let i = 0; i < this.sets.length; i++) {
for (let member of this.sets[i]) {
@@ -453,20 +414,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@undoBatch
@action
updateCluster(doc: Doc) {
+ let childLayouts = this.childLayoutPairs.map(pair => pair.layout);
if (this.props.Document.useClusters) {
this.sets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
let preferredInd = NumCast(doc.cluster);
doc.cluster = -1;
this.sets.map((set, i) => set.map(member => {
- if (doc.cluster === -1 && Doc.IndexOf(member, this.childDocs) !== -1 && this.boundsOverlap(doc, member)) {
+ if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && this.boundsOverlap(doc, member)) {
doc.cluster = i;
}
}));
- if (doc.cluster === -1 && preferredInd !== -1 && (!this.sets[preferredInd] || !this.sets[preferredInd].filter(member => Doc.IndexOf(member, this.childDocs) !== -1).length)) {
+ if (doc.cluster === -1 && preferredInd !== -1 && (!this.sets[preferredInd] || !this.sets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
doc.cluster = preferredInd;
}
this.sets.map((set, i) => {
- if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, this.childDocs) !== -1).length) {
+ if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) {
doc.cluster = i;
}
});
@@ -481,22 +443,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
getClusterColor = (doc: Doc) => {
- if (this.props.Document.useClusters) {
- let cluster = NumCast(doc.cluster);
+ let clusterColor = "";
+ let cluster = NumCast(doc.cluster);
+ if (this.Document.useClusters) {
if (this.sets.length <= cluster) {
- setTimeout(() => this.updateCluster(doc), 0);// this.updateClusters(), 0);
- return "";
+ setTimeout(() => this.updateCluster(doc), 0);
+ } else {
+ // choose a cluster color from a palette
+ let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"];
+ clusterColor = colors[cluster % colors.length];
+ let set = this.sets.length > cluster ? this.sets[cluster].filter(s => s.backgroundColor && (s.backgroundColor !== s.defaultBackgroundColor)) : undefined;
+ // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document
+ set && set.filter(s => !s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
+ set && set.filter(s => s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
}
- let set = this.sets.length > cluster ? this.sets[cluster] : undefined;
- let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"];
- let clusterColor = colors[cluster % colors.length];
- set && set.filter(s => !s.isBackground).map(s =>
- s.backgroundColor && s.backgroundColor !== s.defaultBackgroundColor && (clusterColor = StrCast(s.backgroundColor)));
- set && set.filter(s => s.isBackground).map(s =>
- s.backgroundColor && s.backgroundColor !== s.defaultBackgroundColor && (clusterColor = StrCast(s.backgroundColor)));
- return clusterColor;
}
- return "";
+ return clusterColor;
}
@action
@@ -528,40 +490,39 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
let x = this.Document.panX || 0;
let y = this.Document.panY || 0;
- let docs = this.childDocs || [];
+ let docs = this.childLayoutPairs.map(pair => pair.layout);
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) + minx : minx;
- // let miny = docs.length ? NumCast(docs[0].y) : 0;
- // let maxy = docs.length ? NumCast(docs[0].height) + miny : miny;
- // let ranges = docs.filter(doc => doc).reduce((range, doc) => {
- // let x = NumCast(doc.x);
- // let xe = x + NumCast(doc.width);
- // let y = NumCast(doc.y);
- // let ye = y + NumCast(doc.height);
- // return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
- // [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
- // }, [[minx, maxx], [miny, maxy]]);
- // let ink = Cast(this.fieldExtensionDoc.ink, InkField);
- // if (ink && ink.inkData) {
- // ink.inkData.forEach((value: StrokeData, key: string) => {
- // let bounds = InkingCanvas.StrokeRect(value);
- // ranges[0] = [Math.min(ranges[0][0], bounds.left), Math.max(ranges[0][1], bounds.right)];
- // ranges[1] = [Math.min(ranges[1][0], bounds.top), Math.max(ranges[1][1], bounds.bottom)];
- // });
- // }
-
- // let panelDim = this.props.ScreenToLocalTransform().transformDirection(this._pwidth / this.zoomScaling(),
- // this._pheight / this.zoomScaling());
- // let panelwidth = panelDim[0];
- // let panelheight = panelDim[1];
- // if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2;
- // if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2;
- // if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2;
- // if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2;
- // }
+ if (!this.isAnnotationOverlay) {
+ PDFMenu.Instance.fadeOut(true);
+ let minx = docs.length ? NumCast(docs[0].x) : 0;
+ let maxx = docs.length ? NumCast(docs[0].width) + minx : minx;
+ let miny = docs.length ? NumCast(docs[0].y) : 0;
+ let maxy = docs.length ? NumCast(docs[0].height) + miny : miny;
+ let ranges = docs.filter(doc => doc).reduce((range, doc) => {
+ let x = NumCast(doc.x);
+ let xe = x + NumCast(doc.width);
+ let y = NumCast(doc.y);
+ let ye = y + NumCast(doc.height);
+ return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
+ [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
+ }, [[minx, maxx], [miny, maxy]]);
+ let ink = Cast(this.fieldExtensionDoc.ink, InkField);
+ if (ink && ink.inkData) {
+ ink.inkData.forEach((value: StrokeData, key: string) => {
+ let bounds = InkingCanvas.StrokeRect(value);
+ ranges[0] = [Math.min(ranges[0][0], bounds.left), Math.max(ranges[0][1], bounds.right)];
+ ranges[1] = [Math.min(ranges[1][0], bounds.top), Math.max(ranges[1][1], bounds.bottom)];
+ });
+ }
+
+ let cscale = this.props.ContainingCollectionDoc ? NumCast(this.props.ContainingCollectionDoc.scale) : 1;
+ let panelDim = this.props.ScreenToLocalTransform().transformDirection(this._pwidth / this.zoomScaling() * cscale,
+ this._pheight / this.zoomScaling() * cscale);
+ if (ranges[0][0] - dx > (this.panX() + panelDim[0] / 2)) x = ranges[0][1] + panelDim[0] / 2;
+ if (ranges[0][1] - dx < (this.panX() - panelDim[0] / 2)) x = ranges[0][0] - panelDim[0] / 2;
+ if (ranges[1][0] - dy > (this.panY() + panelDim[1] / 2)) y = ranges[1][1] + panelDim[1] / 2;
+ if (ranges[1][1] - dy < (this.panY() - panelDim[1] / 2)) y = ranges[1][0] - panelDim[1] / 2;
+ }
this.setPan(x - dx, y - dy);
this._lastX = e.pageX;
this._lastY = e.pageY;
@@ -575,31 +536,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (BoolCast(this.props.Document.lockedPosition)) return;
if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
e.stopPropagation();
- return;
}
-
- let childSelected = this.childDocs.some(doc => {
- var dv = DocumentManager.Instance.getDocumentView(doc);
- return dv && SelectionManager.IsSelected(dv) ? true : false;
- });
- if (!this.props.isSelected() && !childSelected && this.props.renderDepth > 0) {
- return;
- }
- e.stopPropagation();
-
- // bcz: this changes the nativewidth/height, but ImageBox will just revert it back to its defaults. need more logic to fix.
- // if (e.ctrlKey && this.props.Document.scrollHeight === undefined) {
- // let deltaScale = (1 - (e.deltaY / coefficient));
- // let nw = this.nativeWidth * deltaScale;
- // let nh = this.nativeHeight * deltaScale;
- // if (nw && nh) {
- // this.props.Document.nativeWidth = nw;
- // this.props.Document.nativeHeight = nh;
- // }
- // e.preventDefault();
- // }
- // else
- {
+ else if (this.props.active()) {
+ e.stopPropagation();
let deltaScale = e.deltaY > 0 ? (1 / 1.1) : 1.1;
if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
deltaScale = 1 / this.zoomScaling();
@@ -628,46 +567,38 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
@action
- onDrop = (e: React.DragEvent): void => {
+ onDrop = async (e: React.DragEvent): Promise<void> => {
var pt = this.getTransform().transformPoint(e.pageX, e.pageY);
- super.onDrop(e, { x: pt[0], y: pt[1] });
- }
-
- onDragOver = (): void => {
+ await super.onDrop(e, { x: pt[0], y: pt[1] });
}
bringToFront = (doc: Doc, sendToBack?: boolean) => {
if (sendToBack || doc.isBackground) {
doc.zIndex = 0;
- return;
}
- const docs = this.childDocs;
- 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;
+ 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;
+ }
}
- focusDocument = (doc: Doc, willZoom: boolean, scale?: number) => {
- const panX = this.Document.panX;
- const panY = this.Document.panY;
- const id = this.Document[Id];
+ focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
const state = HistoryUtil.getState();
- state.initializers = state.initializers || {};
// TODO This technically isn't correct if type !== "doc", as
// currently nothing is done, but we should probably push a new state
- if (state.type === "doc" && panX !== undefined && panY !== undefined) {
- const init = state.initializers[id];
+ if (state.type === "doc" && this.Document.panX !== undefined && this.Document.panY !== undefined) {
+ const init = state.initializers![this.Document[Id]];
if (!init) {
- state.initializers[id] = {
- panX, panY
- };
+ state.initializers![this.Document[Id]] = { panX: this.Document.panX, panY: this.Document.panY };
HistoryUtil.pushState(state);
- } else if (init.panX !== panX || init.panY !== panY) {
- init.panX = panX;
- init.panY = panY;
+ } else if (init.panX !== this.Document.panX || init.panY !== this.Document.panY) {
+ init.panX = this.Document.panX;
+ init.panY = this.Document.panY;
HistoryUtil.pushState(state);
}
}
@@ -675,8 +606,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2;
const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2;
const newState = HistoryUtil.getState();
- (newState.initializers || (newState.initializers = {}))[id] = { panX: newPanX, panY: newPanY };
+ newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY };
HistoryUtil.pushState(newState);
+
+ let px = this.Document.panX;
+ let py = this.Document.panY;
+ let s = this.Document.scale;
this.setPan(newPanX, newPanY);
this.props.Document.panTransformType = "Ease";
@@ -684,7 +619,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (willZoom) {
this.setScaleToZoom(doc, scale);
}
-
+ console.log("Focused " + this.Document.title + " " + s);
+ afterFocus && setTimeout(() => {
+ if (afterFocus && afterFocus()) {
+ console.log("UnFocused " + this.Document.title + " " + s);
+ this.Document.panX = px;
+ this.Document.panY = py;
+ this.Document.scale = s;
+ }
+ }, 1000);
}
setScaleToZoom = (doc: Doc, scale: number = 0.5) => {
@@ -716,13 +659,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
addDocument: this.props.addDocument,
removeDocument: this.props.removeDocument,
moveDocument: this.props.moveDocument,
- onClick: this.props.onClick,
+ ruleProvider: this.Document.isRuleProvider && childLayout.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider, //bcz: hack! - currently ruleProviders apply to documents in nested colleciton, not direct children of themselves
+ 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
ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
renderDepth: this.props.renderDepth + 1,
PanelWidth: childLayout[WidthSym],
PanelHeight: childLayout[HeightSym],
ContentScaling: returnOne,
ContainingCollectionView: this.props.CollectionView,
+ ContainingCollectionDoc: this.props.CollectionView.props.Document,
focus: this.focusDocument,
backgroundColor: this.getClusterColor,
parentActive: this.props.active,
@@ -741,6 +686,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
addDocument: this.props.addDocument,
removeDocument: this.props.removeDocument,
moveDocument: this.props.moveDocument,
+ ruleProvider: this.props.ruleProvider,
onClick: this.props.onClick,
ScreenToLocalTransform: this.getTransform,
renderDepth: this.props.renderDepth,
@@ -748,6 +694,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
PanelHeight: layoutDoc[HeightSym],
ContentScaling: returnOne,
ContainingCollectionView: this.props.CollectionView,
+ ContainingCollectionDoc: this.props.CollectionView.props.Document,
focus: this.focusDocument,
backgroundColor: returnEmptyString,
parentActive: this.props.active,
@@ -760,13 +707,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
};
}
- getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, state?: any } {
- const result = script.script.run(params);
- if (!result.success) {
- return {};
+ getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, transition?: string, state?: any } {
+ const script = this.Document.arrangeScript;
+ const result = script && script.script.run(params, console.log);
+ if (result && result.success) {
+ return { ...result, transition: "transform 1s" };
}
- let doc = params.doc;
- return result.result === undefined ? { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") } : result.result;
+ return { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(params.doc.width, "number"), height: Cast(params.doc.height, "number") };
}
viewDefsToJSX = (views: PivotView.PivotData[]) => {
@@ -829,14 +776,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (this.Document.usePivotLayout) return PivotView.elements(this);
let curPage = FieldValue(this.Document.curPage, -1);
const initScript = this.Document.arrangeInit;
- const script = this.Document.arrangeScript;
let state: any = undefined;
- let docs = this.childDocs;
- let overlayDocs = DocListCast(this.props.Document.localOverlays);
- overlayDocs && docs.push(...overlayDocs);
+ let pairs = this.childLayoutPairs;
let elements: ViewDefResult[] = [];
if (initScript) {
- const initResult = initScript.script.run({ docs, collection: this.Document });
+ const initResult = initScript.script.run({ docs: pairs.map(pair => pair.layout), collection: this.Document }, console.log);
if (initResult.success) {
const result = initResult.result;
const { state: scriptState, views } = result;
@@ -844,25 +788,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
elements = this.viewDefsToJSX(views);
}
}
- let docviews = docs.filter(doc => doc instanceof Doc).reduce((prev, doc) => {
- var page = NumCast(doc.page, -1);
- if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) {
- let minim = BoolCast(doc.isMinimized);
- if (minim === undefined || !minim) {
- const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) :
- { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") };
- state = pos.state === undefined ? state : pos.state;
- let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, doc);
- if (pair.layout && !(pair.data instanceof Promise)) {
- prev.push({
- ele: <CollectionFreeFormDocumentView key={doc[Id]}
- jitterRotation={NumCast(this.props.Document.jitterRotation)}
- x={script ? pos.x : undefined} y={script ? pos.y : undefined}
- width={script ? pos.width : undefined} height={script ? pos.height : undefined} {...this.getChildDocumentViewProps(pair.layout, pair.data)} />,
- bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) }
- });
- }
- }
+ let docviews = pairs.reduce((prev, pair) => {
+ var page = NumCast(pair.layout.page, -1);
+ if (!pair.layout.isMinimized && ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1)) {
+ const pos = this.getCalculatedPositions({ doc: pair.layout, index: prev.length, collection: this.Document, docs: pairs.map(pair => pair.layout), state });
+ state = pos.state === undefined ? state : pos.state;
+ prev.push({
+ ele: <CollectionFreeFormDocumentView key={pair.layout[Id]}
+ ruleProvider={this.Document.isRuleProvider ? this.props.Document : this.props.ruleProvider}
+ jitterRotation={NumCast(this.props.Document.jitterRotation)}
+ transition={pos.transition} x={pos.x} y={pos.y} width={pos.width} height={pos.height}
+ {...this.getChildDocumentViewProps(pair.layout, pair.data)} />,
+ bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: pos.width || 0, height: pos.height || 0 }
+ });
}
return prev;
}, elements);
@@ -872,22 +810,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@computed.struct
get views() {
- let source = this.elements;
- return source.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele);
+ return this.elements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele);
}
@computed.struct
get overlayViews() {
return this.elements.filter(ele => ele.bounds && ele.bounds.z).map(ele => ele.ele);
}
-
@action
onCursorMove = (e: React.PointerEvent) => {
super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
}
- fitToContainer = async () => this.props.Document.fitToBox = !this.fitToBox;
-
arrangeContents = async () => {
const docs = await DocListCastAsync(this.Document[this.props.fieldKey]);
UndoManager.RunInBatch(() => {
@@ -912,98 +846,86 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}, "arrange contents");
}
+ autoFormat = () => {
+ this.Document.isRuleProvider = !this.Document.isRuleProvider;
+ // find rule colorations when rule providing is turned on by looking at each document to see if it has a coloring -- if so, use it's color as the rule for its associated heading.
+ this.Document.isRuleProvider && this.childLayoutPairs.map(pair =>
+ // iterate over the children of a displayed document (or if the displayed document is a template, iterate over the children of that template)
+ DocListCast(pair.layout.layout instanceof Doc ? pair.layout.layout.data : pair.layout.data).map(heading => {
+ let headingPair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, heading);
+ let headingLayout = headingPair.layout && (pair.layout.data_ext instanceof Doc) && (pair.layout.data_ext[`Layout[${headingPair.layout[Id]}]`] as Doc) || headingPair.layout;
+ if (headingLayout && NumCast(headingLayout.heading) > 0 && headingLayout.backgroundColor !== headingLayout.defaultBackgroundColor) {
+ Doc.GetProto(this.props.Document)["ruleColor_" + NumCast(headingLayout.heading)] = headingLayout.backgroundColor;
+ }
+ })
+ );
+ }
+
analyzeStrokes = async () => {
- let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField);
- if (!data) {
- return;
+ let data = Cast(this.fieldExtensionDoc.ink, InkField);
+ if (data) {
+ CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, ["inkAnalysis", "handwriting"], data.inkData);
}
- let relevantKeys = ["inkAnalysis", "handwriting"];
- CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, relevantKeys, data.inkData);
}
onContextMenu = (e: React.MouseEvent) => {
let layoutItems: ContextMenuProps[] = [];
- if (this.childDocs.some(d => d.isTemplate)) {
- layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
+ if (this.childDocs.some(d => BoolCast(d.isTemplate))) {
+ layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
}
layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
- layoutItems.push({
- description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`,
- event: async () => {
- Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; // backward compatibility with databases that didn't have a default background color on prototypes
- Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white";
- this.props.Document.useClusters = !this.props.Document.useClusters;
- this.updateClusters();
- },
- icon: !this.props.Document.useClusters ? "braille" : "braille"
- });
- this.props.Document.useClusters && layoutItems.push({
- description: `${this.props.Document.clusterOverridesDefaultBackground ? "Use Default Backgrounds" : "Clusters Override Defaults"}`,
- event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground,
- icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard"
- });
+ layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: async () => this.Document.fitToBox = !this.fitToBox, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
+ layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+ layoutItems.push({ description: `${this.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, event: this.autoFormat, icon: "chalkboard" });
layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" });
layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
layoutItems.push({
- description: "Import document", icon: "upload", event: () => {
+ description: "Import document", icon: "upload", event: ({ x, y }) => {
const input = document.createElement("input");
input.type = "file";
input.accept = ".zip";
input.onchange = async _e => {
- const files = input.files;
- if (!files) return;
- const file = files[0];
- let formData = new FormData();
- formData.append('file', file);
- formData.append('remap', "true");
const upload = Utils.prepend("/uploadDoc");
- const response = await fetch(upload, { method: "POST", body: formData });
- const json = await response.json();
- if (json === "error") {
- return;
- }
- const doc = await DocServer.GetRefField(json);
- if (!doc || !(doc instanceof Doc)) {
- return;
+ let formData = new FormData();
+ const file = input.files && input.files[0];
+ if (file) {
+ formData.append('file', file);
+ formData.append('remap', "true");
+ const response = await fetch(upload, { method: "POST", body: formData });
+ const json = await response.json();
+ if (json !== "error") {
+ const doc = await DocServer.GetRefField(json);
+ if (doc instanceof Doc) {
+ const [xx, yy] = this.props.ScreenToLocalTransform().transformPoint(x, y);
+ doc.x = xx, doc.y = yy;
+ this.props.addDocument && this.props.addDocument(doc, false);
+ }
+ }
}
- const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
- doc.x = x, doc.y = y;
- this.props.addDocument &&
- this.props.addDocument(doc, false);
};
input.click();
}
});
- let noteItems: ContextMenuProps[] = [];
- if (CurrentUserUtils.UserDocument) {
- let notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data);
- notes.map((node, i) => noteItems.push({ description: (i + 1) + ": " + StrCast(node.title), event: () => this.createText(i), icon: "eye" }));
- }
- layoutItems.push({ description: "Add Note ...", subitems: noteItems, icon: "eye" });
+ layoutItems.push({
+ description: "Add Note ...",
+ subitems: DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data).map((note, i) => ({
+ description: (i + 1) + ": " + StrCast(note.title),
+ event: (args: { x: number, y: number }) => this.addLiveTextBox(Docs.Create.TextDocument({ width: 200, height: 100, x: this.getTransform().transformPoint(args.x, args.y)[0], y: this.getTransform().transformPoint(args.x, args.y)[1], autoHeight: true, layout: note, title: StrCast(note.title) })),
+ icon: "eye"
+ })) as ContextMenuProps[],
+ icon: "eye"
+ });
ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" });
}
- createText = (noteStyle: number) => {
- let pt = this.getTransform().transformPoint(ContextMenu.Instance.pageX, ContextMenu.Instance.pageY);
- if (CurrentUserUtils.UserDocument) {
- let notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data);
- let text = Docs.Create.TextDocument({ width: 200, height: 100, x: pt[0], y: pt[1], autoHeight: true, title: StrCast(notes[noteStyle % notes.length].title) });
- text.layout = notes[noteStyle % notes.length];
- this.addLiveTextBox(text);
- }
- }
private childViews = () => [
<CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
...this.views
]
- private overlayChildViews = () => {
- return [...this.overlayViews];
- }
public static AddCustomLayout(doc: Doc, dataKey: string): () => void {
return () => {
@@ -1034,15 +956,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
render() {
+ // update the actual dimensions of the collection so that they can inquired (e.g., by a minimap)
this.props.Document.fitX = this.actualContentBounds && this.actualContentBounds.x;
this.props.Document.fitY = this.actualContentBounds && this.actualContentBounds.y;
this.props.Document.fitW = this.actualContentBounds && (this.actualContentBounds.r - this.actualContentBounds.x);
this.props.Document.fitH = this.actualContentBounds && (this.actualContentBounds.b - this.actualContentBounds.y);
+ // if fieldExt is set, then children will be stored in the extension document for the fieldKey.
+ // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document
+ Doc.UpdateDocumentExtensionForField(this.props.DataDoc || this.props.Document, this.props.fieldKey);
const easing = () => this.props.Document.panTransformType === "Ease";
- Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
return (
<div className={"collectionfreeformview-container"} ref={this.createDropTarget} onWheel={this.onPointerWheel}
- onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onContextMenu={this.onContextMenu}>
+ onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu}>
<MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} isSelected={this.props.isSelected}
addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
@@ -1056,7 +981,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
<CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
</CollectionFreeFormViewPannableContents>
</MarqueeView>
- {this.overlayChildViews()}
+ {this.overlayViews}
<CollectionFreeFormOverlayView {...this.props} {...this.getDocumentViewProps(this.props.Document)} />
</div>
);
@@ -1077,7 +1002,6 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps &
@observer
class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps & { isSelected: () => boolean }> {
@computed get backgroundView() {
- let props = this.props;
return (<DocumentContentsView {...this.props} layoutKey={"backgroundLayout"}
renderDepth={this.props.renderDepth} isSelected={this.props.isSelected} select={emptyFunction} />);
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index fe48a3485..bbea4a555 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,28 +1,24 @@
-import * as htmlToImage from "html-to-image";
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, FieldResult, DocListCast } from "../../../../new_fields/Doc";
-import { Id } from "../../../../new_fields/FieldSymbols";
+import { Doc, DocListCast } from "../../../../new_fields/Doc";
import { InkField, StrokeData } from "../../../../new_fields/InkField";
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, NumCast, StrCast } from "../../../../new_fields/Types";
+import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
import { Utils } from "../../../../Utils";
-import { DocServer } from "../../../DocServer";
import { Docs } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
import { InkingCanvas } from "../../InkingCanvas";
import { PreviewCursor } from "../../PreviewCursor";
-import { Templates } from "../../Templates";
import { CollectionViewType } from "../CollectionBaseView";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
import "./MarqueeView.scss";
import React = require("react");
-import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHeaderField";
-import { string } from "prop-types";
-import { listSpec } from "../../../../new_fields/Schema";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -232,18 +228,14 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
}
- get ink() {
- let container = this.props.container.props.Document;
- let containerKey = this.props.container.props.fieldKey;
- let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true");
- return Cast(extensionDoc.ink, InkField);
+ get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored.
+ let cprops = this.props.container.props;
+ return Cast(Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink, InkField);
}
set ink(value: InkField | undefined) {
- let container = Doc.GetProto(this.props.container.props.Document);
- let containerKey = this.props.container.props.fieldKey;
- let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true");
- extensionDoc.ink = value;
+ let cprops = this.props.container.props;
+ Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink = value;
}
@undoBatch
@@ -287,7 +279,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let palette = Array.from(Cast(this.props.container.props.Document.colorPalette, listSpec("string")) as string[]);
let usedPaletted = new Map<string, number>();
[...this.props.activeDocuments(), this.props.container.props.Document].map(child => {
- let bg = StrCast(child.backgroundColor);
+ let bg = StrCast(child.layout instanceof Doc ? child.layout.backgroundColor : child.backgroundColor);
if (palette.indexOf(bg) !== -1) {
palette.splice(palette.indexOf(bg), 1);
if (usedPaletted.get(bg)) usedPaletted.set(bg, usedPaletted.get(bg)! + 1);
@@ -309,13 +301,13 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : chosenColor,
width: bounds.width,
height: bounds.height,
- title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection",
+ title: "a nested collection",
});
let dataExtensionField = Doc.CreateDocumentExtensionForField(newCollection, "data");
dataExtensionField.ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined;
this.marqueeInkDelete(inkData);
- if (e.key === "s") {
+ if (e.key === "s" || e.key === "S") {
selected.map(d => {
this.props.removeDocument(d);
d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
@@ -324,39 +316,23 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return d;
});
newCollection.chromeStatus = "disabled";
- let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
- newCollection.proto!.summaryDoc = summary;
- selected = [newCollection];
+ let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
+ Doc.GetProto(summary).summarizedDocs = new List<Doc>([newCollection]);
newCollection.x = bounds.left + bounds.width;
- summary.proto!.subBulletDocs = new List<Doc>(selected);
- summary.templates = new List<string>([Templates.Bullet.Layout]);
- let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" });
- container.viewType = CollectionViewType.Stacking;
- container.autoHeight = true;
- this.props.addLiveTextDocument(container);
- // });
- } else if (e.key === "S") {
- 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;
- });
- newCollection.chromeStatus = "disabled";
- let summary = Docs.Create.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"
- summary.autoHeight = true;
-
- this.props.addLiveTextDocument(summary);
+ Doc.GetProto(newCollection).summaryDoc = summary;
+ Doc.GetProto(newCollection).title = ComputedField.MakeFunction(`summaryTitle(this);`);
+ if (e.key === "s") { // summary is wrapped in an expand/collapse container that also contains the summarized documents in a free form view.
+ let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" });
+ container.viewType = CollectionViewType.Stacking;
+ container.autoHeight = true;
+ Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "onRight"
+ this.props.addLiveTextDocument(container);
+ } else if (e.key === "S") { // the summary stands alone, but is linked to a collection of the summarized documents - set the OnCLick behavior to link follow to access them
+ Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight"
+ this.props.addLiveTextDocument(summary);
+ }
}
else {
- newCollection.ruleProvider = this.props.container.props.Document;
this.props.addDocument(newCollection, false);
this.props.selectDocuments([newCollection]);
}