aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authorFawn <fangrui_tong@brown.edu>2019-04-22 00:09:25 -0400
committerFawn <fangrui_tong@brown.edu>2019-04-22 00:09:25 -0400
commit97dcec0e5ac07deb9af9acb16948cc6678778cba (patch)
tree74dd3d2bd938a5ab5b3bb082a8fc2846eefa5999 /src/client/views/collections
parente794b4b38e8ab2f4e7a79f223f9488cc845c724f (diff)
parentb63bcb791013766d5d16e4f38964499268f904c4 (diff)
merge
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx96
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx56
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss143
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx300
-rw-r--r--src/client/views/collections/CollectionSubView.tsx44
-rw-r--r--src/client/views/collections/CollectionTreeView.scss6
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx9
-rw-r--r--src/client/views/collections/CollectionView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx376
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx17
14 files changed, 522 insertions, 554 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index bff56e8c3..eec01bb3f 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -8,6 +8,7 @@ import { ListField } from '../../../fields/ListField';
import { NumberField } from '../../../fields/NumberField';
import { ContextMenu } from '../ContextMenu';
import { FieldViewProps } from '../nodes/FieldView';
+import { TextField } from '../../../fields/TextField';
export enum CollectionViewType {
Invalid,
@@ -22,7 +23,7 @@ export interface CollectionRenderProps {
removeDocument: (document: Document) => boolean;
moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
active: () => boolean;
- onActiveChanged: (isActive: boolean) => void;
+ whenActiveChanged: (isActive: boolean) => void;
}
export interface CollectionViewProps extends FieldViewProps {
@@ -55,19 +56,22 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
//TODO should this be observable?
private _isChildActive = false;
- onActiveChanged = (isActive: boolean) => {
+ whenActiveChanged = (isActive: boolean) => {
this._isChildActive = isActive;
- this.props.onActiveChanged(isActive);
+ this.props.whenActiveChanged(isActive);
}
createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
- let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
- for (const doc of data) {
+ if (!(documentToAdd instanceof Document)) {
+ return false;
+ }
+ let data = documentToAdd.GetList(KeyStore.Data, [] as Document[]);
+ for (const doc of data.filter(d => d instanceof Document)) {
if (this.createsCycle(doc, containerDocument)) {
return true;
}
}
- let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
+ let annots = documentToAdd.GetList(KeyStore.Annotations, [] as Document[]);
for (const annot of annots) {
if (this.createsCycle(annot, containerDocument)) {
return true;
@@ -84,56 +88,50 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
@action.bound
addDocument(doc: Document, allowDuplicates: boolean = false): boolean {
- let props = this.props;
- var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
+ var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
- if (this.isAnnotationOverlay) {
- doc.SetOnPrototype(KeyStore.Zoom, new NumberField(this.props.Document.GetNumber(KeyStore.Scale, 1)));
- }
if (curPage >= 0) {
- doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
+ doc.SetOnPrototype(KeyStore.AnnotationOn, this.props.Document);
}
- if (props.Document.Get(props.fieldKey) instanceof Field) {
- //TODO This won't create the field if it doesn't already exist
- const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>());
- if (!this.createsCycle(doc, props.Document)) {
+ if (this.props.Document.Get(this.props.fieldKey) instanceof Field) {
+ const value = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+ if (!this.createsCycle(doc, this.props.Document)) {
if (!value.some(v => v.Id === doc.Id) || allowDuplicates) {
value.push(doc);
+ doc.SetNumber(KeyStore.ZoomBasis, this.props.Document.GetNumber(KeyStore.Scale, 1));
}
- }
- else {
- return false;
- }
- } else {
- let proto = props.Document.GetPrototype();
- if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) {
- const field = new ListField([doc]);
- // const script = CompileScript(`
- // if(added) {
- // console.log("added " + field.Title + " " + doc.Title);
- // } else {
- // console.log("removed " + field.Title + " " + doc.Title);
- // }
- // `, {
- // addReturn: false,
- // params: {
- // field: Document.name,
- // added: "boolean"
- // },
- // capturedVariables: {
- // doc: this.props.Document
- // }
- // });
- // if (script.compiled) {
- // field.addScript(new ScriptField(script));
- // }
- props.Document.SetOnPrototype(props.fieldKey, field);
- }
- else {
- return false;
+ return true;
}
}
- return true;
+ // bcz: What is this code trying to do?
+ // else {
+ // let proto = props.Document.GetPrototype();
+ // if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) {
+ // const field = new ListField([doc]);
+ // // const script = CompileScript(`
+ // // if(added) {
+ // // console.log("added " + field.Title + " " + doc.Title);
+ // // } else {
+ // // console.log("removed " + field.Title + " " + doc.Title);
+ // // }
+ // // `, {
+ // // addReturn: false,
+ // // params: {
+ // // field: Document.name,
+ // // added: "boolean"
+ // // },
+ // // capturedVariables: {
+ // // doc: this.props.Document
+ // // }
+ // // });
+ // // if (script.compiled) {
+ // // field.addScript(new ScriptField(script));
+ // // }
+ // props.Document.SetOnPrototype(props.fieldKey, field);
+ // return true;
+ // }
+ // }
+ return false;
}
@action.bound
@@ -181,7 +179,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
removeDocument: this.removeDocument,
moveDocument: this.moveDocument,
active: this.active,
- onActiveChanged: this.onActiveChanged,
+ whenActiveChanged: this.whenActiveChanged,
};
const viewtype = this.collectionViewType;
return (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2b96e7678..e4c647635 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -19,6 +19,7 @@ import { ServerUtils } from "../../../server/ServerUtil";
import { DragManager, DragLinksAsDocuments } from "../../util/DragManager";
import { TextField } from "../../../fields/TextField";
import { ListField } from "../../../fields/ListField";
+import { Transform } from '../../util/Transform'
@observer
export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
@@ -263,7 +264,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
let counter: any = this.htmlToElement(`<div class="messageCounter">${count}</div>`);
tab.element.append(counter);
counter.DashDocId = tab.contentItem.config.props.documentId;
- (tab as any).reactionDisposer = reaction(() => [f.GetT(KeyStore.LinkedFromDocs, ListField), f.GetT(KeyStore.LinkedToDocs, ListField)],
+ tab.reactionDisposer = reaction(() => [f.GetT(KeyStore.LinkedFromDocs, ListField), f.GetT(KeyStore.LinkedToDocs, ListField)],
(lists) => {
let count = (lists.length > 0 && lists[0] && lists[0]!.Data ? lists[0]!.Data.length : 0) +
(lists.length > 1 && lists[1] && lists[1]!.Data ? lists[1]!.Data.length : 0);
@@ -315,7 +316,7 @@ interface DockedFrameProps {
@observer
export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
- private _mainCont = React.createRef<HTMLDivElement>();
+ _mainCont = React.createRef<HTMLDivElement>();
@observable private _panelWidth = 0;
@observable private _panelHeight = 0;
@observable private _document: Opt<Document>;
@@ -325,38 +326,49 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
Server.GetField(this.props.documentId, action((f: Opt<Field>) => this._document = f as Document));
}
- private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth);
- private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight);
- private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth);
+ nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth);
+ nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight);
+ contentScaling = () => {
+ let wscale = this._panelWidth / (this.nativeWidth() ? this.nativeWidth() : this._panelWidth);
+ if (wscale * this.nativeHeight() > this._panelHeight)
+ return this._panelHeight / (this.nativeHeight() ? this.nativeHeight() : this._panelHeight);
+ return wscale;
+ }
ScreenToLocalTransform = () => {
- let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!);
- return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling());
+ if (this._mainCont.current && this._mainCont.current.children) {
+ let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!.children[0].firstChild as HTMLElement);
+ scale = Utils.GetScreenTransform(this._mainCont.current!).scale;
+ return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling());
+ }
+ return Transform.Identity();
}
+ get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; }
- render() {
- if (!this._document) {
- return (null);
- }
- var content =
- <div className="collectionDockingView-content" ref={this._mainCont}>
- <DocumentView key={this._document.Id} Document={this._document}
+ get content() {
+ return (
+ <div className="collectionDockingView-content" ref={this._mainCont}
+ style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}>
+ <DocumentView key={this._document!.Id} Document={this._document!}
addDocument={undefined}
removeDocument={undefined}
- ContentScaling={this._contentScaling}
- PanelWidth={this._nativeWidth}
- PanelHeight={this._nativeHeight}
+ ContentScaling={this.contentScaling}
+ PanelWidth={this.nativeWidth}
+ PanelHeight={this.nativeHeight}
ScreenToLocalTransform={this.ScreenToLocalTransform}
isTopMost={true}
selectOnLoad={false}
parentActive={returnTrue}
- onActiveChanged={emptyFunction}
+ whenActiveChanged={emptyFunction}
focus={emptyDocFunction}
ContainingCollectionView={undefined} />
- </div>;
+ </div>);
+ }
- return <Measure onResize={action((r: any) => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}>
- {({ measureRef }) => <div ref={measureRef}> {content} </div>}
- </Measure>;
+ render() {
+ return !this._document ? (null) :
+ <Measure onResize={action((r: any) => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}>
+ {({ measureRef }) => <div ref={measureRef}> {this.content} </div>}
+ </Measure>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 40e49bb5f..cfdb3ab22 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -1,56 +1,6 @@
@import "../globalCssVariables";
-//options menu styling
-#schemaOptionsMenuBtn {
- position: absolute;
- height: 20px;
- width: 20px;
- border-radius: 50%;
- z-index: 21;
- right: 4px;
- top: 4px;
- pointer-events: auto;
- background-color:black;
- display:inline-block;
- padding: 0px;
- font-size: 100%;
-}
-#schema-options-header {
- text-align: center;
- padding: 0px;
- margin: 0px;
-}
-.schema-options-subHeader {
- color: $intermediate-color;
- margin-bottom: 5px;
-}
-#schemaOptionsMenuBtn:hover {
- transform: scale(1.15);
-}
-
-#preview-schema-checkbox-div {
- margin-left: 20px;
- font-size: 12px;
-}
- #options-flyout-div {
- text-align: left;
- padding:0px;
- z-index: 100;
- font-family: $sans-serif;
- padding-left: 5px;
- }
-
- #schema-col-checklist {
- overflow: scroll;
- text-align: left;
- //background-color: $light-color-secondary;
- line-height: 25px;
- max-height: 175px;
- font-family: $sans-serif;
- font-size: 12px;
- }
-
.collectionSchemaView-container {
border-width: $COLLECTION_BORDER_WIDTH;
@@ -61,18 +11,31 @@
position: absolute;
width: 100%;
height: 100%;
-
- .collectionSchemaView-content {
- position: absolute;
- height: 100%;
- width: 100%;
- overflow: auto;
+
+ .collectionSchemaView-cellContents {
+ height: $MAX_ROW_HEIGHT;
}
+
.collectionSchemaView-previewRegion {
position: relative;
background: $light-color;
float: left;
height: 100%;
+ .collectionSchemaView-previewDoc {
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ }
+ .collectionSchemaView-input {
+ position: absolute;
+ max-width: 150px;
+ width: 100%;
+ bottom: 0px;
+ }
+ .documentView-node:first-child {
+ position: relative;
+ background: $light-color;
+ }
}
.collectionSchemaView-previewHandle {
position: absolute;
@@ -146,7 +109,7 @@
}
.rt-tr-group {
direction: ltr;
- max-height: 44px;
+ max-height: $MAX_ROW_HEIGHT;
}
.rt-td {
border-width: 1px;
@@ -178,7 +141,7 @@
}
.ReactTable .rt-th,
.ReactTable .rt-td {
- max-height: 44;
+ max-height: $MAX_ROW_HEIGHT;
padding: 3px 7px;
font-size: 13px;
text-align: center;
@@ -188,13 +151,71 @@
border-bottom-style: solid;
border-bottom-width: 1;
}
+ .documentView-node-topmost {
+ text-align:left;
+ transform-origin: center top;
+ display: inline-block;
+ }
.documentView-node:first-child {
background: $light-color;
- .imageBox-cont img {
- object-fit: contain;
- }
}
}
+//options menu styling
+#schemaOptionsMenuBtn {
+ position: absolute;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ z-index: 21;
+ right: 4px;
+ top: 4px;
+ pointer-events: auto;
+ background-color:black;
+ display:inline-block;
+ padding: 0px;
+ font-size: 100%;
+}
+
+ul {
+ list-style-type: disc;
+}
+
+#schema-options-header {
+ text-align: center;
+ padding: 0px;
+ margin: 0px;
+}
+.schema-options-subHeader {
+ color: $intermediate-color;
+ margin-bottom: 5px;
+}
+#schemaOptionsMenuBtn:hover {
+ transform: scale(1.15);
+}
+
+#preview-schema-checkbox-div {
+ margin-left: 20px;
+ font-size: 12px;
+}
+
+ #options-flyout-div {
+ text-align: left;
+ padding:0px;
+ z-index: 100;
+ font-family: $sans-serif;
+ padding-left: 5px;
+ }
+
+ #schema-col-checklist {
+ overflow: scroll;
+ text-align: left;
+ //background-color: $light-color-secondary;
+ line-height: 25px;
+ max-height: 175px;
+ font-family: $sans-serif;
+ font-size: 12px;
+ }
+
.Resizer {
box-sizing: border-box;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 4f4068e7a..90077b053 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -4,15 +4,15 @@ import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, untracked } from "mobx";
import { observer } from "mobx-react";
-import Measure from "react-measure";
import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
+import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'
import "react-table/react-table.css";
import { Document } from "../../../fields/Document";
import { Field, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
-import { emptyDocFunction, emptyFunction, returnFalse, returnOne } from "../../../Utils";
+import { emptyDocFunction, emptyFunction, returnFalse } from "../../../Utils";
import { Server } from "../../Server";
import { SetupDrag } from "../../util/DragManager";
import { CompileScript, ToField } from "../../util/Scripting";
@@ -34,42 +34,35 @@ import { CollectionSubView } from "./CollectionSubView";
class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggle: (key: Key) => void }> {
@observable key: Key | undefined;
- componentWillReceiveProps() {
- Server.GetField(this.props.keyId, action((field: Opt<Field>) => {
- if (field instanceof Key) {
- this.key = field;
- }
- }));
+ constructor(props: any) {
+ super(props);
+ Server.GetField(this.props.keyId, action((field: Opt<Field>) => field instanceof Key && (this.key = field)));
}
render() {
- if (this.key) {
- return (<div key={this.key.Id}>
+ return !this.key ? (null) :
+ (<div key={this.key.Id}>
<input type="checkbox" checked={this.props.checked} onChange={() => this.key && this.props.toggle(this.key)} />
{this.key.Name}
</div>);
- }
- return (null);
}
}
@observer
export class CollectionSchemaView extends CollectionSubView {
- private _mainCont = React.createRef<HTMLDivElement>();
+ private _mainCont?: HTMLDivElement;
private _startSplitPercent = 0;
private DIVIDER_WIDTH = 4;
@observable _columns: Array<Key> = [KeyStore.Title, KeyStore.Data, KeyStore.Author];
- @observable _contentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ContentScaling prop of the DocumentView
- @observable _dividerX = 0;
- @observable _panelWidth = 0;
- @observable _panelHeight = 0;
@observable _selectedIndex = 0;
@observable _columnsPercentage = 0;
@observable _keys: Key[] = [];
+ @observable _newKeyName: string = "";
@computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0); }
-
+ @computed get columns() { return this.props.Document.GetList(KeyStore.ColumnsKey, [] as Key[]); }
+ @computed get borderWidth() { return COLLECTION_BORDER_WIDTH; }
renderCell = (rowProps: CellInfo) => {
let props: FieldViewProps = {
@@ -83,7 +76,7 @@ export class CollectionSchemaView extends CollectionSubView {
ScreenToLocalTransform: Transform.Identity,
focus: emptyDocFunction,
active: returnFalse,
- onActiveChanged: emptyFunction,
+ whenActiveChanged: emptyFunction,
};
let contents = (
<FieldView {...props} />
@@ -107,11 +100,11 @@ export class CollectionSchemaView extends CollectionSubView {
return false;
};
return (
- <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.Document.Id} ref={reference}>
+ <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} key={props.Document.Id} ref={reference}>
<EditableView
display={"inline"}
contents={contents}
- height={56}
+ height={Number(MAX_ROW_HEIGHT)}
GetValue={() => {
let field = props.Document.Get(props.fieldKey);
if (field && field instanceof Field) {
@@ -165,9 +158,9 @@ export class CollectionSchemaView extends CollectionSubView {
};
}
- @computed
- get columns() {
- return this.props.Document.GetList<Key>(KeyStore.ColumnsKey, []);
+ private createTarget = (ele: HTMLDivElement) => {
+ this._mainCont = ele;
+ super.CreateDropTarget(ele);
}
@action
@@ -187,31 +180,12 @@ export class CollectionSchemaView extends CollectionSubView {
//toggles preview side-panel of schema
@action
toggleExpander = (event: React.ChangeEvent<HTMLInputElement>) => {
- this._startSplitPercent = this.splitPercentage;
- if (this._startSplitPercent === this.splitPercentage) {
- this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0);
- }
- }
-
- @computed
- get findAllDocumentKeys(): { [id: string]: boolean } {
- const docs = this.props.Document.GetList<Document>(this.props.fieldKey, []);
- let keys: { [id: string]: boolean } = {};
- if (this._optionsActivated > -1) {
- // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields.
- // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be
- // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked.
- // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu
- // is displayed (unlikely) it won't show up until something else changes.
- untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false))));
- }
- this.columns.forEach(key => keys[key.Id] = true);
- return keys;
+ this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0);
}
@action
onDividerMove = (e: PointerEvent): void => {
- let nativeWidth = this._mainCont.current!.getBoundingClientRect();
+ let nativeWidth = this._mainCont!.getBoundingClientRect();
this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, Math.max(0, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100)));
}
@action
@@ -230,155 +204,149 @@ export class CollectionSchemaView extends CollectionSubView {
document.addEventListener('pointerup', this.onDividerUp);
}
- @observable _tableWidth = 0;
- @action
- setTableDimensions = (r: any) => {
- this._tableWidth = r.entry.width;
- }
- @action
- setScaling = (r: any) => {
- const children = this.props.Document.GetList<Document>(this.props.fieldKey, []);
- const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined;
- this._panelWidth = r.entry.width;
- this._panelHeight = r.entry.height ? r.entry.height : this._panelHeight;
- this._contentScaling = r.entry.width / selected!.GetNumber(KeyStore.NativeWidth, r.entry.width);
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ if (this.props.isSelected())
+ e.stopPropagation();
+ else e.preventDefault();
+ }
}
- @computed
- get borderWidth() { return COLLECTION_BORDER_WIDTH; }
- getContentScaling = (): number => this._contentScaling;
- getPanelWidth = (): number => this._panelWidth;
- getPanelHeight = (): number => this._panelHeight;
- getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX, - this.borderWidth).scale(1 / this._contentScaling);
- getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - this.borderWidth).scale(1 / this._contentScaling);
-
- onPointerDown = (e: React.PointerEvent): void => {
- if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ onWheel = (e: React.WheelEvent): void => {
+ if (this.props.active()) {
e.stopPropagation();
}
}
@action
addColumn = () => {
- this.columns.push(new Key(this.newKeyName));
- this.newKeyName = "";
+ this.columns.push(new Key(this._newKeyName));
+ this._newKeyName = "";
}
- @observable
- newKeyName: string = "";
-
@action
newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.newKeyName = e.currentTarget.value;
- }
- onWheel = (e: React.WheelEvent): void => {
- if (this.props.active()) {
- e.stopPropagation();
- }
- }
-
- @observable _optionsActivated: number = 0;
- @action
- OptionsMenuDown = (e: React.PointerEvent) => {
- this._optionsActivated++;
+ this._newKeyName = e.currentTarget.value;
}
- @observable previewScript: string = "this";
+ @observable previewScript: string = "";
@action
onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.previewScript = e.currentTarget.value;
}
- render() {
- library.add(faCog);
- library.add(faPlus);
- const columns = this.columns;
- const children = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+ get previewDocument(): Document | undefined {
+ const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined;
- //all the keys/columns that will be displayed in the schema
- const allKeys = this.findAllDocumentKeys;
- let doc: any = selected ? selected.Get(new Key(this.previewScript)) : undefined;
+ return selected ? (this.previewScript ? selected.Get(new Key(this.previewScript)) as Document : selected) : undefined;
+ }
+ get tableWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * (1 - this.splitPercentage / 100); }
+ get previewRegionHeight() { return this.props.PanelHeight() - 2 * this.borderWidth; }
+ get previewRegionWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * this.splitPercentage / 100; }
+
+ private previewDocNativeWidth = () => this.previewDocument!.GetNumber(KeyStore.NativeWidth, this.previewRegionWidth);
+ private previewDocNativeHeight = () => this.previewDocument!.GetNumber(KeyStore.NativeHeight, this.previewRegionHeight);
+ private previewContentScaling = () => {
+ let wscale = this.previewRegionWidth / (this.previewDocNativeWidth() ? this.previewDocNativeWidth() : this.previewRegionWidth);
+ if (wscale * this.previewDocNativeHeight() > this.previewRegionHeight)
+ return this.previewRegionHeight / (this.previewDocNativeHeight() ? this.previewDocNativeHeight() : this.previewRegionHeight);
+ return wscale;
+ }
+ private previewPanelWidth = () => this.previewDocNativeWidth() * this.previewContentScaling();
+ private previewPanelHeight = () => this.previewDocNativeHeight() * this.previewContentScaling();
+ get previewPanelCenteringOffset() { return (this.previewRegionWidth - this.previewDocNativeWidth() * this.previewContentScaling()) / 2; }
+ getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
+ - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth - this.previewPanelCenteringOffset,
+ - this.borderWidth).scale(1 / this.previewContentScaling());
+ @computed
+ get previewPanel() {
// let doc = CompileScript(this.previewScript, { this: selected }, true)();
- let content = this._selectedIndex === -1 || !selected ? (null) : (
- <Measure onResize={this.setScaling}>
- {({ measureRef }) =>
- <div className="collectionSchemaView-content" ref={measureRef}>
- {doc instanceof Document ?
- <DocumentView Document={doc}
- addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
- isTopMost={false}
- selectOnLoad={false}
- ScreenToLocalTransform={this.getPreviewTransform}
- ContentScaling={this.getContentScaling}
- PanelWidth={this.getPanelWidth}
- PanelHeight={this.getPanelHeight}
- ContainingCollectionView={this.props.CollectionView}
- focus={emptyDocFunction}
- parentActive={this.props.active}
- onActiveChanged={this.props.onActiveChanged} /> : null}
- <input value={this.previewScript} onChange={this.onPreviewScriptChange}
- style={{ position: 'absolute', bottom: '0px' }} />
- </div>
- }
- </Measure>
- );
- let dividerDragger = this.splitPercentage === 0 ? (null) :
- <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} />;
-
- //options button and menu
- let optionsMenu = !this.props.active() ? (null) : (<Flyout
- anchorPoint={anchorPoints.LEFT_TOP}
- content={<div>
- <div id="schema-options-header"><h5><b>Options</b></h5></div>
- <div id="options-flyout-div">
- <h6 className="schema-options-subHeader">Preview Window</h6>
- <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.splitPercentage !== 0} onChange={this.toggleExpander} /> Show Preview </div>
- <h6 className="schema-options-subHeader" >Displayed Columns</h6>
- <ul id="schema-col-checklist" >
- {Array.from(Object.keys(allKeys)).map(item =>
- (<KeyToggle checked={allKeys[item]} key={item} keyId={item} toggle={this.toggleKey} />))}
- </ul>
- <input value={this.newKeyName} onChange={this.newKeyChange} />
- <button onClick={this.addColumn}><FontAwesomeIcon style={{ color: "white" }} icon="plus" size="lg" /></button>
+ return !this.previewDocument ? (null) : (
+ <div className="collectionSchemaView-previewRegion" style={{ width: `${this.previewRegionWidth}px` }}>
+ <div className="collectionSchemaView-previewDoc" style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}>
+ <DocumentView Document={this.previewDocument} isTopMost={false} selectOnLoad={false}
+ addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={this.getPreviewTransform}
+ ContentScaling={this.previewContentScaling}
+ PanelWidth={this.previewPanelWidth} PanelHeight={this.previewPanelHeight}
+ ContainingCollectionView={this.props.CollectionView}
+ focus={emptyDocFunction}
+ parentActive={this.props.active}
+ whenActiveChanged={this.props.whenActiveChanged}
+ />
</div>
+ <input className="collectionSchemaView-input" value={this.previewScript} onChange={this.onPreviewScriptChange}
+ style={{ left: `calc(50% - ${Math.min(75, this.previewPanelWidth() / 2)}px)` }} />
</div>
- }>
- <button id="schemaOptionsMenuBtn" onPointerDown={this.OptionsMenuDown}><FontAwesomeIcon style={{ color: "white" }} icon="cog" size="sm" /></button>
- </Flyout>);
+ );
+ }
- return (
- <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} onWheel={this.onWheel} ref={this._mainCont}>
- <div className="collectionSchemaView-dropTarget" onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget}>
- <Measure onResize={this.setTableDimensions}>
- {({ measureRef }) =>
- <div className="collectionSchemaView-tableContainer" ref={measureRef} style={{ width: `calc(100% - ${this.splitPercentage}%)` }}>
- <ReactTable
- data={children}
- pageSize={children.length}
- page={0}
- showPagination={false}
- columns={columns.map(col => ({
- Header: col.Name,
- accessor: (doc: Document) => [doc, col],
- id: col.Id
- }))}
- column={{
- ...ReactTableDefaults.column,
- Cell: this.renderCell,
+ get documentKeysCheckList() {
+ const docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+ let keys: { [id: string]: boolean } = {};
+ // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+ // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be
+ // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked.
+ // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu
+ // is displayed (unlikely) it won't show up until something else changes.
+ untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false))));
+
+ this.columns.forEach(key => keys[key.Id] = true);
+ return Array.from(Object.keys(keys)).map(item =>
+ (<KeyToggle checked={keys[item]} key={item} keyId={item} toggle={this.toggleKey} />));
+ }
- }}
- getTrProps={this.getTrProps}
- />
- </div>}
- </Measure>
- {dividerDragger}
- <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0)}% - ${this.DIVIDER_WIDTH}px)` }}>
- {content}
+ get tableOptionsPanel() {
+ return !this.props.active() ? (null) :
+ (<Flyout
+ anchorPoint={anchorPoints.LEFT_TOP}
+ content={<div>
+ <div id="schema-options-header"><h5><b>Options</b></h5></div>
+ <div id="options-flyout-div">
+ <h6 className="schema-options-subHeader">Preview Window</h6>
+ <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.splitPercentage !== 0} onChange={this.toggleExpander} /> Show Preview </div>
+ <h6 className="schema-options-subHeader" >Displayed Columns</h6>
+ <ul id="schema-col-checklist" >
+ {this.documentKeysCheckList}
+ </ul>
+ <input value={this._newKeyName} onChange={this.newKeyChange} />
+ <button onClick={this.addColumn}><FontAwesomeIcon style={{ color: "white" }} icon="plus" size="lg" /></button>
</div>
- {optionsMenu}
</div>
- </div >
+ }>
+ <button id="schemaOptionsMenuBtn" ><FontAwesomeIcon style={{ color: "white" }} icon="cog" size="sm" /></button>
+ </Flyout>);
+ }
+
+ @computed
+ get dividerDragger() {
+ return this.splitPercentage === 0 ? (null) :
+ <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} />;
+ }
+
+ render() {
+ library.add(faCog);
+ library.add(faPlus);
+ const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+ return (
+ <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
+ onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createTarget}>
+ <div className="collectionSchemaView-tableContainer" style={{ width: `${this.tableWidth}px` }}>
+ <ReactTable data={children} page={0} pageSize={children.length} showPagination={false}
+ columns={this.columns.map(col => ({
+ Header: col.Name,
+ accessor: (doc: Document) => [doc, col],
+ id: col.Id
+ }))}
+ column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }}
+ getTrProps={this.getTrProps}
+ />
+ </div>
+ {this.dividerDragger}
+ {this.previewPanel}
+ {this.tableOptionsPanel}
+ </div>
);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d3d69b1af..ead559bd9 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -15,7 +15,6 @@ import { ServerUtils } from "../../../server/ServerUtil";
import { Server } from "../../Server";
import { FieldViewProps } from "../nodes/FieldView";
import * as rp from 'request-promise';
-import { emptyFunction } from "../../../Utils";
import { CollectionView } from "./CollectionView";
import { CollectionPDFView } from "./CollectionPDFView";
import { CollectionVideoView } from "./CollectionVideoView";
@@ -24,6 +23,8 @@ export interface CollectionViewProps extends FieldViewProps {
addDocument: (document: Document, allowDuplicates?: boolean) => boolean;
removeDocument: (document: Document) => boolean;
moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
+ PanelWidth: () => number;
+ PanelHeight: () => number;
}
export interface SubCollectionViewProps extends CollectionViewProps {
@@ -42,6 +43,9 @@ export class CollectionSubView extends React.Component<SubCollectionViewProps> {
this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
}
}
+ protected CreateDropTarget(ele: HTMLDivElement) {
+ this.createDropTarget(ele);
+ }
@action
protected setCursorPosition(position: [number, number]) {
@@ -155,10 +159,7 @@ export class CollectionSubView extends React.Component<SubCollectionViewProps> {
e.preventDefault();
if (html && html.indexOf("<img") !== 0 && !html.startsWith("<a")) {
- console.log("not good");
- let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 });
- htmlDoc.SetText(KeyStore.DocumentText, text);
- this.props.addDocument(htmlDoc, false);
+ this.props.addDocument(Documents.HtmlDocument(html, { ...options, width: 300, height: 300, documentText: text }), false);
return;
}
@@ -184,36 +185,17 @@ export class CollectionSubView extends React.Component<SubCollectionViewProps> {
let type = item.type;
if (item.kind === "file") {
let file = item.getAsFile();
- let formData = new FormData();
-
- if (file) {
- formData.append('file', file);
- }
let dropFileName = file ? file.name : "-empty-";
+ let formData = new FormData();
+ if (file) formData.append('file', file);
- let prom = fetch(upload, {
+ promises.push(fetch(upload, {
method: 'POST',
body: formData
- }).then(async (res: Response) => {
- (await res.json()).map(action((file: any) => {
- let path = window.location.origin + file;
- let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName });
-
- docPromise.then(action((doc?: Document) => {
- let docs = this.props.Document.GetT(KeyStore.Data, ListField);
- if (docs !== FieldWaiting) {
- if (!docs) {
- docs = new ListField<Document>();
- this.props.Document.Set(KeyStore.Data, docs);
- }
- if (doc) {
- docs.Data.push(doc);
- }
- }
- }));
- }));
- });
- promises.push(prom);
+ }).then(async (res: Response) =>
+ (await res.json()).map(action((file: any) =>
+ this.getDocumentFromType(type, window.location.origin + file, { ...options, nativeWidth: 600, width: 300, title: dropFileName }).
+ then(doc => doc && this.props.addDocument(doc, false))))));
}
}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 973eead97..8ecc5b67b 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -50,15 +50,15 @@
.docContainer:hover {
.delete-button {
display: inline;
- width: auto;
+ // width: auto;
}
}
.delete-button {
color: $intermediate-color;
- float: right;
+ // float: right;
margin-left: 15px;
- margin-top: 3px;
+ // margin-top: 3px;
display: inline;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 51a02fc25..e0387f4b4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,20 +1,17 @@
import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable, trace } from "mobx";
+import { action, observable } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { FieldWaiting } from "../../../fields/Field";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
-import { SetupDrag, DragManager } from "../../util/DragManager";
+import { DragManager, SetupDrag } from "../../util/DragManager";
import { EditableView } from "../EditableView";
-import "./CollectionTreeView.scss";
-import { CollectionView } from "./CollectionView";
-import * as globalCssVariables from "../../views/globalCssVariables.scss";
import { CollectionSubView } from "./CollectionSubView";
+import "./CollectionTreeView.scss";
import React = require("react");
-import { props } from 'bluebird';
export interface TreeViewProps {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1f69a69e8..675e720e2 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -10,6 +10,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_
import { KeyStore } from '../../../fields/KeyStore';
import { observer } from 'mobx-react';
import { undoBatch } from '../../util/UndoManager';
+import { trace } from 'mobx';
@observer
export class CollectionView extends React.Component<FieldViewProps> {
@@ -28,8 +29,10 @@ export class CollectionView extends React.Component<FieldViewProps> {
return (null);
}
+ get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+
onContextMenu = (e: React.MouseEvent): void => {
- if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+ if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) });
ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) });
ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 081b3eb6c..20c5a84bf 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
let l = this.props.LinkDocs;
let a = this.props.A;
let b = this.props.B;
- let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2);
- let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2);
- let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2);
- let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2);
+ let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Width() / 2);
+ let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Height() / 2);
+ let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Width() / 2);
+ let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Height() / 2);
return (
<line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 2f684a54e..ebdb0c75c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -16,9 +16,9 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
_brushReactionDisposer?: IReactionDisposer;
componentDidMount() {
- this._brushReactionDisposer = reaction(() => this.props.Document.GetList<Document>(this.props.fieldKey, []).map(doc => doc.GetNumber(KeyStore.X, 0)),
+ this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)),
() => {
- let views = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+ let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc.GetText(KeyStore.BackgroundLayout, "").indexOf("istogram") !== -1);
for (let i = 0; i < views.length; i++) {
for (let j = 0; j < views.length; j++) {
let srcDoc = views[j];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
index 751ea8190..cf0a6de00 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
@@ -12,7 +12,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component<CollectionV
protected getCursors(): CursorEntry[] {
let doc = this.props.Document;
let id = CurrentUserUtils.id;
- let cursors = doc.GetList<CursorEntry>(KeyStore.Cursors, []);
+ let cursors = doc.GetList(KeyStore.Cursors, [] as CursorEntry[]);
let notMe = cursors.filter(entry => entry.Data[0][0] !== id);
return id ? notMe : [];
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 26c794e91..57706b51e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -1,11 +1,4 @@
@import "../../globalCssVariables";
-.collectionfreeformview-measure {
- position: inherit;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- }
.collectionfreeformview {
position: inherit;
top: 0;
@@ -48,10 +41,11 @@
}
.formattedTextBox-cont {
background: $light-color-secondary;
+ overflow: visible;
}
opacity: 0.99;
- border-width: 0;
+ border-width: 0;
border-color: transparent;
border-style: solid;
border-radius: $border-radius;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4db3bf81b..83b7f9be4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,10 +1,7 @@
-import { action, computed, observable, runInAction, untracked } from "mobx";
+import { action, computed, observable, trace } from "mobx";
import { observer } from "mobx-react";
-import Measure from "react-measure";
import { Document } from "../../../../fields/Document";
-import { FieldWaiting } from "../../../../fields/Field";
import { KeyStore } from "../../../../fields/KeyStore";
-import { TextField } from "../../../../fields/TextField";
import { emptyFunction, returnFalse, returnOne } from "../../../../Utils";
import { DocumentManager } from "../../../util/DocumentManager";
import { DragManager } from "../../../util/DragManager";
@@ -13,43 +10,52 @@ import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
import { InkingCanvas } from "../../InkingCanvas";
-import { Main } from "../../Main";
-import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewProps } from "../../nodes/CollectionFreeFormDocumentView";
+import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
import { DocumentContentsView } from "../../nodes/DocumentContentsView";
import { DocumentViewProps } from "../../nodes/DocumentView";
-import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
+import { CollectionSubView } from "../CollectionSubView";
import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView";
import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import v5 = require("uuid/v5");
-import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { BooleanField } from "../../../../fields/BooleanField";
@observer
export class CollectionFreeFormView extends CollectionSubView {
- public _canvasRef = React.createRef<HTMLDivElement>();
private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
+ private _lastX: number = 0;
+ private _lastY: number = 0;
+ private get _pwidth() { return this.props.PanelWidth(); }
+ private get _pheight() { return this.props.PanelHeight(); }
- public addLiveTextBox = (newBox: Document) => {
- // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself and receive text input
- this._selectOnLoaded = newBox.Id;
+ @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+ @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
+ private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
+ private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+ private childViews = () => this.views;
+ private panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0);
+ private panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0);
+ private zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1);
+ private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0; // shift so pan position is at center of window for non-overlay collections
+ private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
+ private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
+ private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
+ private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+ private addLiveTextBox = (newBox: Document) => {
+ this._selectOnLoaded = newBox.Id;// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
this.addDocument(newBox, false);
}
-
- public addDocument = (newBox: Document, allowDuplicates: boolean) => {
- if (this.isAnnotationOverlay) {
- newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1));
- }
+ private addDocument = (newBox: Document, allowDuplicates: boolean) => {
return this.props.addDocument(this.bringToFront(newBox), false);
}
-
- public selectDocuments = (docs: Document[]) => {
+ private selectDocuments = (docs: Document[]) => {
SelectionManager.DeselectAll;
docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv =>
SelectionManager.SelectDoc(dv!, true));
}
-
public getActiveDocuments = () => {
var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => {
@@ -61,42 +67,35 @@ export class CollectionFreeFormView extends CollectionSubView {
}, [] as Document[]);
}
- @observable public DownX: number = 0;
- @observable public DownY: number = 0;
- @observable private _lastX: number = 0;
- @observable private _lastY: number = 0;
- @observable private _pwidth: number = 0;
- @observable private _pheight: number = 0;
-
- @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); }
- @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); }
- @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
- @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
- @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
- @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
- @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
- @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this._pwidth / 2 : 0; } // shift so pan position is at center of window for non-overlay collections
- @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this._pheight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections
-
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) {
- const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset);
if (de.data.droppedDocuments.length) {
- let dropX = de.data.droppedDocuments[0].GetNumber(KeyStore.X, 0);
- let dropY = de.data.droppedDocuments[0].GetNumber(KeyStore.Y, 0);
+ let dragDoc = de.data.droppedDocuments[0];
+ let zoom = dragDoc.GetNumber(KeyStore.ZoomBasis, 1);
+ let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ let x = xp - de.data.xOffset / zoom;
+ let y = yp - de.data.yOffset / zoom;
+
+ let dropX = dragDoc.GetNumber(KeyStore.X, 0);
+ let dropY = dragDoc.GetNumber(KeyStore.Y, 0);
de.data.droppedDocuments.map(d => {
- d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX));
- d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY));
- if (!d.GetNumber(KeyStore.Width, 0)) {
- d.SetNumber(KeyStore.Width, 300);
- }
- if (!d.GetNumber(KeyStore.Height, 0)) {
- d.SetNumber(KeyStore.Height, 300);
+ d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX);
+ d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY);
+ if (!d.GetBoolean(KeyStore.IsMinimized, false)) {
+ if (!d.GetNumber(KeyStore.Width, 0)) {
+ d.SetNumber(KeyStore.Width, 300);
+ }
+ if (!d.GetNumber(KeyStore.Height, 0)) {
+ let nw = d.GetNumber(KeyStore.NativeWidth, 0);
+ let nh = d.GetNumber(KeyStore.NativeHeight, 0);
+ d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300);
+ }
}
this.bringToFront(d);
});
+ SelectionManager.ReselectAll();
}
return true;
}
@@ -111,13 +110,17 @@ export class CollectionFreeFormView extends CollectionSubView {
@action
onPointerDown = (e: React.PointerEvent): void => {
- if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || e.button === 0) && this.props.active()) {
+ let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+ var dv = DocumentManager.Instance.getDocumentView(doc);
+ return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+ }, false);
+ if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
document.removeEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointerup", this.onPointerUp);
- this._lastX = this.DownX = e.pageX;
- this._lastY = this.DownY = e.pageY;
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
}
}
@@ -130,38 +133,36 @@ export class CollectionFreeFormView extends CollectionSubView {
@action
onPointerMove = (e: PointerEvent): void => {
- if (!e.cancelBubble && this.props.active()) {
- if ((!this.isAnnotationOverlay || this.zoomScaling !== 1) && !e.shiftKey) {
- let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
- let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
- let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
- let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- if (!this.isAnnotationOverlay) {
- let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
- let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
- let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
- let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
- let ranges = docs.filter(doc => doc).reduce((range, doc) => {
- let x = doc.GetNumber(KeyStore.X, 0);
- let xe = x + doc.GetNumber(KeyStore.Width, 0);
- let y = doc.GetNumber(KeyStore.Y, 0);
- let ye = y + doc.GetNumber(KeyStore.Height, 0);
- 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 panelwidth = this._pwidth / this.scale / 2;
- let panelheight = this._pheight / this.scale / 2;
- if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
- if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
- if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
- if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
- }
- this.SetPan(x - dx, y - dy);
- this._lastX = e.pageX;
- this._lastY = e.pageY;
- e.stopPropagation();
- e.preventDefault();
+ if (!e.cancelBubble) {
+ let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
+ let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
+ let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+ let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
+ if (!this.isAnnotationOverlay) {
+ let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
+ let maxx = docs.length ? docs[0].Width() + minx : minx;
+ let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
+ let maxy = docs.length ? docs[0].Height() + miny : miny;
+ let ranges = docs.filter(doc => doc).reduce((range, doc) => {
+ let x = doc.GetNumber(KeyStore.X, 0);
+ let xe = x + doc.GetNumber(KeyStore.Width, 0);
+ let y = doc.GetNumber(KeyStore.Y, 0);
+ let ye = y + doc.GetNumber(KeyStore.Height, 0);
+ 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 panelwidth = this._pwidth / this.zoomScaling() / 2;
+ let panelheight = this._pheight / this.zoomScaling() / 2;
+ if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
+ if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
+ if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
+ if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
}
+ this.setPan(x - dx, y - dy);
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ e.stopPropagation();
+ e.preventDefault();
}
}
@@ -170,45 +171,45 @@ export class CollectionFreeFormView extends CollectionSubView {
// if (!this.props.active()) {
// return;
// }
+ let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+ var dv = DocumentManager.Instance.getDocumentView(doc);
+ return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+ }, false);
+ if (!this.props.isSelected() && !childSelected && !this.props.isTopMost) {
+ return;
+ }
e.stopPropagation();
- let coefficient = 1000;
+ const coefficient = 1000;
if (e.ctrlKey) {
- var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
- var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
- const coefficient = 1000;
let deltaScale = (1 - (e.deltaY / coefficient));
- this.props.Document.SetNumber(KeyStore.NativeWidth, nativeWidth * deltaScale);
- this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight * deltaScale);
+ this.props.Document.SetNumber(KeyStore.NativeWidth, this.nativeWidth * deltaScale);
+ this.props.Document.SetNumber(KeyStore.NativeHeight, this.nativeHeight * deltaScale);
e.stopPropagation();
e.preventDefault();
} else {
// if (modes[e.deltaMode] === 'pixels') coefficient = 50;
// else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height??
- let transform = this.getTransform();
-
let deltaScale = (1 - (e.deltaY / coefficient));
- if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) {
- deltaScale = 1 / this.zoomScaling;
+ if (deltaScale < 0) deltaScale = -deltaScale;
+ if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
+ deltaScale = 1 / this.zoomScaling();
}
- let [x, y] = transform.transformPoint(e.clientX, e.clientY);
-
- let localTransform = this.getLocalTransform();
- localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y);
- // console.log(localTransform)
+ let [x, y] = this.getTransform().transformPoint(e.clientX, e.clientY);
+ let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
- this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
- this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
+ let safeScale = Math.abs(localTransform.Scale);
+ this.props.Document.SetNumber(KeyStore.Scale, Math.abs(safeScale));
+ this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
e.stopPropagation();
}
}
@action
- private SetPan(panX: number, panY: number) {
- MainOverlayTextBox.Instance.SetTextDoc();
- var x1 = this.getLocalTransform().inverse().Scale;
- const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX));
- const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY));
+ setPan(panX: number, panY: number) {
+ var scale = this.getLocalTransform().inverse().Scale;
+ const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
+ const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY));
this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX);
this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY);
}
@@ -224,39 +225,18 @@ export class CollectionFreeFormView extends CollectionSubView {
@action
bringToFront(doc: Document) {
- const { fieldKey: fieldKey, Document: Document } = this.props;
-
- const value: Document[] = Document.GetList<Document>(fieldKey, []).slice();
- value.sort((doc1, doc2) => {
- if (doc1 === doc) {
- return 1;
- }
- if (doc2 === doc) {
- return -1;
- }
+ this.props.Document.GetList(this.props.fieldKey, [] as Document[]).slice().sort((doc1, doc2) => {
+ if (doc1 === doc) return 1;
+ if (doc2 === doc) return -1;
return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
- }).map((doc, index) =>
- doc.SetNumber(KeyStore.ZIndex, index + 1));
+ }).map((doc, index) => doc.SetNumber(KeyStore.ZIndex, index + 1));
return doc;
}
- @computed get backgroundLayout(): string | undefined {
- let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
- if (field && field !== FieldWaiting) {
- return field.Data;
- }
- }
- @computed get overlayLayout(): string | undefined {
- let field = this.props.Document.GetT(KeyStore.OverlayLayout, TextField);
- if (field && field !== FieldWaiting) {
- return field.Data;
- }
- }
-
focusDocument = (doc: Document) => {
- let x = doc.GetNumber(KeyStore.X, 0) + doc.GetNumber(KeyStore.Width, 0) / 2;
- let y = doc.GetNumber(KeyStore.Y, 0) + doc.GetNumber(KeyStore.Height, 0) / 2;
- this.SetPan(x, y);
+ this.setPan(
+ doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2,
+ doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2);
this.props.focus(this.props.Document);
}
@@ -271,11 +251,11 @@ export class CollectionFreeFormView extends CollectionSubView {
selectOnLoad: document.Id === this._selectOnLoaded,
PanelWidth: document.Width,
PanelHeight: document.Height,
- ContentScaling: this.noScaling,
+ ContentScaling: returnOne,
ContainingCollectionView: this.props.CollectionView,
focus: this.focusDocument,
parentActive: this.props.active,
- onActiveChanged: this.props.active,
+ whenActiveChanged: this.props.active,
};
}
@@ -284,79 +264,93 @@ export class CollectionFreeFormView extends CollectionSubView {
var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
var page = doc.GetNumber(KeyStore.Page, -1);
- var zoom = doc.GetNumber(KeyStore.Zoom, 1);
- var dv = DocumentManager.Instance.getDocumentView(doc);
- let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 :
- Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale));
if (page === curPage || page === -1) {
- prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
+ let minim = doc.GetT(KeyStore.IsMinimized, BooleanField);
+ if (minim === undefined || (minim && !minim.Data))
+ prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
}
return prev;
}, [] as JSX.Element[]);
- setTimeout(() => { // bcz: surely there must be a better way ....
- this._selectOnLoaded = "";
- }, 600);
+ setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way ....
return docviews;
}
- @computed
- get backgroundView() {
- return !this.backgroundLayout ? (null) :
- (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
- layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+ @action
+ onCursorMove = (e: React.PointerEvent) => {
+ super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
}
- @computed
- get overlayView() {
- return !this.overlayLayout ? (null) :
- (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
- layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+
+ render() {
+ const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
+ return (
+ <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
+ onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} >
+ <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
+ addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
+ getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
+ <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
+ zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
+ <CollectionFreeFormBackgroundView {...this.getDocumentViewProps(this.props.Document)} />
+ <CollectionFreeFormLinksView {...this.props} key="freeformLinks">
+ <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
+ {this.childViews}
+ </InkingCanvas>
+ </CollectionFreeFormLinksView>
+ <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
+ </CollectionFreeFormViewPannableContents>
+ <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} />
+ </MarqueeView>
+ </div>
+ );
}
+}
- @computed
- get borderWidth() {
- return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
+@observer
+class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
+ @computed get overlayView() {
+ let overlayLayout = this.props.Document.GetText(KeyStore.OverlayLayout, "");
+ return !overlayLayout ? (null) :
+ (<DocumentContentsView {...this.props} layoutKey={KeyStore.OverlayLayout}
+ isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+ }
+ render() {
+ return this.overlayView;
}
- getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform());
- getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
- getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY);
- noScaling = () => 1;
- childViews = () => this.views;
+}
+@observer
+class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps> {
+ @computed get backgroundView() {
+ let backgroundLayout = this.props.Document.GetText(KeyStore.BackgroundLayout, "");
+ return !backgroundLayout ? (null) :
+ (<DocumentContentsView {...this.props} layoutKey={KeyStore.BackgroundLayout}
+ isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+ }
render() {
- const [dx, dy] = [this.centeringShiftX, this.centeringShiftY];
- const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0);
- const pany: number = -this.props.Document.GetNumber(KeyStore.PanY, 0);
- const zoom: number = this.zoomScaling;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
- const backgroundView = this.backgroundView; // needs to be a variable outside of the <Measure> otherwise, reactions won't fire
- const overlayView = this.overlayView;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
+ return this.backgroundView;
+ }
+}
- return (
- <Measure onResize={(r: any) => runInAction(() => { this._pwidth = r.entry.width; this._pheight = r.entry.height; })}>
- {({ measureRef }) => (
- <div className={`collectionfreeformview-measure`} ref={measureRef}>
- <div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`}
- onPointerDown={this.onPointerDown} onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))}
- onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel} ref={this.createDropTarget}>
- <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
- addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
- getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
- <div className="collectionfreeformview" ref={this._canvasRef}
- style={{ transform: `translate(${dx}px, ${dy}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
- {backgroundView}
- <CollectionFreeFormLinksView {...this.props}>
- <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
- {this.childViews}
- </InkingCanvas>
- </CollectionFreeFormLinksView>
- <CollectionFreeFormRemoteCursors {...this.props} />
- </div>
- {overlayView}
- </MarqueeView>
- </div>
- </div>)}
- </Measure>
- );
+interface CollectionFreeFormViewPannableContentsProps {
+ centeringShiftX: () => number;
+ centeringShiftY: () => number;
+ panX: () => number;
+ panY: () => number;
+ zoomScaling: () => number;
+}
+
+@observer
+class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+ render() {
+ const cenx = this.props.centeringShiftX();
+ const ceny = this.props.centeringShiftY();
+ const panx = -this.props.panX();
+ const pany = -this.props.panY();
+ const zoom = this.props.zoomScaling();// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
+ return <div className="collectionfreeformview" style={{ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
+ {this.props.children}
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index dbab790d4..318adbe85 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -11,6 +11,7 @@ import { undoBatch } from "../../../util/UndoManager";
import { InkingCanvas } from "../../InkingCanvas";
import { PreviewCursor } from "../../PreviewCursor";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
+import { MINIMIZED_ICON_SIZE } from '../../../views/globalCssVariables.scss'
import "./MarqueeView.scss";
import React = require("react");
@@ -147,26 +148,24 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
d.SetNumber(KeyStore.Page, -1);
- d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0));
return d;
});
let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined;
- //setTimeout(() => {
+ let zoomBasis = this.props.container.props.Document.GetNumber(KeyStore.Scale, 1);
let newCollection = Documents.FreeformDocument(selected, {
x: bounds.left,
y: bounds.top,
panx: 0,
pany: 0,
- width: bounds.width,
- height: bounds.height,
- backgroundColor: "Transparent",
+ scale: zoomBasis,
+ width: bounds.width * zoomBasis,
+ height: bounds.height * zoomBasis,
ink: inkData ? this.marqueeInkSelect(inkData) : undefined,
title: "a nested collection"
});
this.props.addDocument(newCollection, false);
this.marqueeInkDelete(inkData);
- // }, 100);
this.cleanupInteractions();
SelectionManager.DeselectAll();
}
@@ -209,11 +208,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let selRect = this.Bounds;
let selection: Document[] = [];
this.props.activeDocuments().map(doc => {
- var z = doc.GetNumber(KeyStore.Zoom, 1);
+ var z = doc.GetNumber(KeyStore.ZoomBasis, 1);
var x = doc.GetNumber(KeyStore.X, 0);
var y = doc.GetNumber(KeyStore.Y, 0);
- var w = doc.GetNumber(KeyStore.Width, 0) / z;
- var h = doc.GetNumber(KeyStore.Height, 0) / z;
+ var w = doc.Width() / z;
+ var h = doc.Height() / z;
if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
selection.push(doc);
}