aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-04-08 19:17:19 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-04-08 19:17:19 -0400
commit0c76a60386cc0693b1572b5a8cf23b37243e5ab7 (patch)
tree01c9e105e43ca6a992e498d1e29ed3fe89396796
parent3925f2ca6f313ba3ced747f05c4ab69a323755a7 (diff)
parenta72fcdd0ebc06a3c851007c6ed89ab13a9a0d835 (diff)
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into propsRefactor
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/SelectionManager.ts2
-rw-r--r--src/client/views/InkingCanvas.scss3
-rw-r--r--src/client/views/Main.scss23
-rw-r--r--src/client/views/Main.tsx66
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx91
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx90
8 files changed, 187 insertions, 92 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index c3d63f887..f95b2c29d 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,7 +1,5 @@
import { action } from "mobx";
import { Document } from "../../fields/Document";
-import { ImageField } from "../../fields/ImageField";
-import { KeyStore } from "../../fields/KeyStore";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { CollectionView } from "../views/collections/CollectionView";
import { DocumentDecorations } from "../views/DocumentDecorations";
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 5e1fa9576..1bb15c86a 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,6 +1,7 @@
import { observable, action } from "mobx";
import { DocumentView } from "../views/nodes/DocumentView";
import { Document } from "../../fields/Document";
+import { Main } from "../views/Main";
export namespace SelectionManager {
class Manager {
@@ -47,6 +48,7 @@ export namespace SelectionManager {
manager.DeselectAll()
if (found) manager.SelectDoc(found, false);
+ Main.Instance.SetTextDoc(undefined, undefined);
}
export function SelectedDocuments(): Array<DocumentView> {
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index c5a2a50cb..42ae38c73 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,5 +1,8 @@
@import "global_variables";
+.inkingCanvas {
+ opacity:0.99;
+}
.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect {
position: absolute;
top: 0;
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 594803aab..fe7f007b0 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -4,7 +4,7 @@ html,
body {
width: 100%;
height: 100%;
- overflow: hidden;
+ overflow: auto;
font-family: $sans-serif;
margin: 0;
position:absolute;
@@ -157,12 +157,33 @@ button:hover {
cursor: pointer;
}
}
+#root {
+ overflow: visible;
+}
#main-div {
width:100%;
height:100%;
position:absolute;
top: 0;
left:0;
+ overflow: scroll;
+}
+.mainDiv-textInput {
+ background:pink;
+ width: 200px;
+ height: 200px;
+ position:absolute;
+ overflow: visible;
+ top: 0;
+ left: 0;
+ .formattedTextBox-cont {
+ background:pink;
+ width: 100%;
+ height: 100%;
+ position:absolute;
+ top: 0;
+ left: 0;
+ }
}
#mainContent-div {
width:100%;
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index b78d5a8f9..9868f6c74 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -1,7 +1,7 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, observable, runInAction } from 'mobx';
+import { action, computed, configure, observable, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import "normalize.css";
import * as React from 'react';
@@ -37,6 +37,7 @@ import { DocumentDecorations } from './DocumentDecorations';
import { InkingControl } from './InkingControl';
import "./Main.scss";
import { DocumentView } from './nodes/DocumentView';
+import { FormattedTextBox } from './nodes/FormattedTextBox';
@observer
export class Main extends React.Component {
@@ -201,6 +202,30 @@ export class Main extends React.Component {
focusDocument = (doc: Document) => { }
noScaling = () => 1;
+ @observable _textDoc?: Document = undefined;
+ _textRect: any;
+ @action
+ SetTextDoc(textDoc?: Document, div?: HTMLDivElement) {
+ this._textDoc = undefined;
+ this._textDoc = textDoc;
+ if (div)
+ this._textRect = div.getBoundingClientRect();
+ }
+
+ @computed
+ get activeTextBox() {
+ if (this._textDoc) {
+ let x: number = this._textRect.x;
+ let y: number = this._textRect.y;
+ let w: number = this._textRect.width;
+ let h: number = this._textRect.height;
+ return <div className="mainDiv-textInput" style={{ transform: `translate(${x}px, ${y}px)`, width: `${w}px`, height: `${h}px` }} >
+ <FormattedTextBox fieldKey={KeyStore.Archives} Document={this._textDoc} isSelected={returnTrue} select={emptyFunction} isTopMost={true} selectOnLoad={true} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={Transform.Identity} focus={(doc) => { }} />
+ </ div>
+ }
+ else return (null);
+ }
+
@computed
get mainContent() {
return !this.mainContainer ? (null) :
@@ -296,24 +321,27 @@ export class Main extends React.Component {
isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} />
}
return (
- <div id="main-div">
- <DocumentDecorations />
- <Measure onResize={(r: any) => runInAction(() => {
- this.pwidth = r.entry.width;
- this.pheight = r.entry.height;
- })}>
- {({ measureRef }) =>
- <div ref={measureRef} id="mainContent-div">
- {this.mainContent}
- </div>
- }
- </Measure>
- <ContextMenu />
- {this.nodesMenu}
- {this.miscButtons}
- {workspaceMenu}
- <InkingControl />
- </div>
+ [
+ <div id="main-div">
+ <DocumentDecorations />
+ <Measure onResize={(r: any) => runInAction(() => {
+ this.pwidth = r.entry.width;
+ this.pheight = r.entry.height;
+ })}>
+ {({ measureRef }) =>
+ <div ref={measureRef} id="mainContent-div">
+ {this.mainContent}
+ </div>
+ }
+ </Measure>
+ <ContextMenu />
+ {this.nodesMenu}
+ {this.miscButtons}
+ {workspaceMenu}
+ <InkingControl />
+ </div>,
+ this.activeTextBox
+ ]
);
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 39cc816f3..abc6cecff 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,4 +1,4 @@
-import { computed, reaction, runInAction, trace } from "mobx";
+import { computed, reaction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
import { FieldWaiting } from "../../../../fields/Field";
@@ -11,59 +11,60 @@ import { CollectionViewProps } from "../CollectionViewBase";
import "./CollectionFreeFormLinksView.scss";
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
-import v5 = require("uuid/v5");
-import { find } from "async";
@observer
export class CollectionFreeFormLinksView extends React.Component<CollectionViewProps> {
+ HackToAvoidReactionFiringUnnecessarily?: Document = undefined;
componentDidMount() {
- reaction(() => {
- return DocumentManager.Instance.getAllDocumentViews(this.props.Document).map(dv => dv.props.Document.GetNumber(KeyStore.X, 0))
- }, () => {
- let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document);
- for (let i = 0; i < views.length; i++) {
- for (let j = 0; j < views.length; j++) {
- let srcDoc = views[j].props.Document;
- let dstDoc = views[i].props.Document;
- let x1 = srcDoc.GetNumber(KeyStore.X, 0);
- let x1w = srcDoc.GetNumber(KeyStore.Width, -1);
- let x2 = dstDoc.GetNumber(KeyStore.X, 0);
- let x2w = dstDoc.GetNumber(KeyStore.Width, -1);
- if (x1w < 0 || x2w < 0 || i === j)
- continue;
- let dstTarg = dstDoc;
- let srcTarg = srcDoc;
- let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => {
- let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : [];
- return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false)
- });
- let brushAction = (field: ListField<Document>) => {
- let found = findBrush(field);
- if (found !== -1) {
- console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title);
- field.Data.splice(found, 1);
- }
- };
- if (Math.abs(x1 + x1w - x2) < 20) {
- let linkDoc: Document = new Document();
- linkDoc.SetText(KeyStore.Title, "Histogram Brush");
- linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title);
- linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
-
- brushAction = brushAction = (field: ListField<Document>) => {
- if (findBrush(field) === -1) {
- console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title);
- (findBrush(field) === -1) && field.Data.push(linkDoc);
+ this.HackToAvoidReactionFiringUnnecessarily = this.props.Document
+ reaction(() =>
+ DocumentManager.Instance.getAllDocumentViews(this.HackToAvoidReactionFiringUnnecessarily!).
+ map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)),
+ () => {
+ let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document);
+ for (let i = 0; i < views.length; i++) {
+ for (let j = 0; j < views.length; j++) {
+ let srcDoc = views[j].props.Document;
+ let dstDoc = views[i].props.Document;
+ let x1 = srcDoc.GetNumber(KeyStore.X, 0);
+ let x1w = srcDoc.GetNumber(KeyStore.Width, -1);
+ let x2 = dstDoc.GetNumber(KeyStore.X, 0);
+ let x2w = dstDoc.GetNumber(KeyStore.Width, -1);
+ if (x1w < 0 || x2w < 0 || i === j)
+ continue;
+ let dstTarg = dstDoc;
+ let srcTarg = srcDoc;
+ let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => {
+ let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : [];
+ return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false)
+ });
+ let brushAction = (field: ListField<Document>) => {
+ let found = findBrush(field);
+ if (found !== -1) {
+ console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title);
+ field.Data.splice(found, 1);
}
};
- }
- dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
- srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+ if (Math.abs(x1 + x1w - x2) < 20) {
+ let linkDoc: Document = new Document();
+ linkDoc.SetText(KeyStore.Title, "Histogram Brush");
+ linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title);
+ linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
+ brushAction = brushAction = (field: ListField<Document>) => {
+ if (findBrush(field) === -1) {
+ console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title);
+ (findBrush(field) === -1) && field.Data.push(linkDoc);
+ }
+ };
+ }
+ dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+ srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+
+ }
}
- }
- })
+ })
}
documentAnchors(view: DocumentView) {
let equalViews = [view];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 52e40d64a..d542b8bc2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -23,6 +23,7 @@ import { PreviewCursor } from "./PreviewCursor";
import { DocumentManager } from "../../../util/DocumentManager";
import { SelectionManager } from "../../../util/SelectionManager";
import { NumberField } from "../../../../fields/NumberField";
+import { Main } from "../../Main";
@observer
export class CollectionFreeFormView extends CollectionViewBase {
@@ -196,6 +197,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
private SetPan(panX: number, panY: number) {
+ Main.Instance.SetTextDoc(undefined, undefined);
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));
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 263343da0..ebac61c78 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -2,19 +2,19 @@ import { action, IReactionDisposer, reaction } from "mobx";
import { baseKeymap } from "prosemirror-commands";
import { history, redo, undo } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
-import { schema } from "../../util/RichTextSchema";
-import { EditorState, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
-import { Opt, FieldWaiting } from "../../../fields/Field";
-import "./FormattedTextBox.scss";
-import React = require("react");
+import { FieldWaiting, Opt } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
import { RichTextField } from "../../../fields/RichTextField";
-import { FieldViewProps, FieldView } from "./FieldView";
-import { Plugin } from "prosemirror-state";
-import { Decoration, DecorationSet } from "prosemirror-view";
+import { inpRules } from "../../util/RichTextRules";
+import { schema } from "../../util/RichTextSchema";
import { TooltipTextMenu } from "../../util/TooltipTextMenu";
import { ContextMenu } from "../../views/ContextMenu";
-import { inpRules } from "../../util/RichTextRules";
+import { Main } from "../Main";
+import { FieldView, FieldViewProps } from "./FieldView";
+import "./FormattedTextBox.scss";
+import React = require("react");
const { buildMenuItems } = require("prosemirror-example-setup");
const { menuBar } = require("prosemirror-menu");
@@ -41,6 +41,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
private _ref: React.RefObject<HTMLDivElement>;
private _editorView: Opt<EditorView>;
private _reactionDisposer: Opt<IReactionDisposer>;
+ private _inputReactionDisposer: Opt<IReactionDisposer>;
constructor(props: FieldViewProps) {
super(props);
@@ -53,9 +54,8 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
if (this._editorView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- const { Document, fieldKey } = this.props;
- Document.SetDataOnPrototype(
- fieldKey,
+ this.FieldDoc.SetDataOnPrototype(
+ this.FieldKey,
JSON.stringify(state.toJSON()),
RichTextField
);
@@ -63,8 +63,10 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
}
};
+ get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.Document; }
+ get FieldKey() { return this.props.fieldKey === KeyStore.Archives ? KeyStore.Data : this.props.fieldKey; }
+
componentDidMount() {
- let state: EditorState;
const config = {
schema,
inpRules, //these currently don't do anything, but could eventually be helpful
@@ -76,22 +78,20 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
]
};
- let field = this.props.Document.GetT(this.props.fieldKey, RichTextField);
- if (field && field !== FieldWaiting && field.Data) {
- state = EditorState.fromJSON(config, JSON.parse(field.Data));
- } else {
- state = EditorState.create(config);
- }
- if (this._ref.current) {
- this._editorView = new EditorView(this._ref.current, {
- state,
- dispatchTransaction: this.dispatchTransaction
- });
+ if (this.props.fieldKey === KeyStore.Archives) {
+ this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id,
+ () => {
+ if (this._editorView)
+ this._editorView!.destroy();
+
+ this.setupEditor(config);
+ }
+ )
}
this._reactionDisposer = reaction(
() => {
- const field = this.props.Document.GetT(this.props.fieldKey, RichTextField);
+ const field = this.FieldDoc.GetT(this.FieldKey, RichTextField);
return field && field !== FieldWaiting ? field.Data : undefined;
},
field => {
@@ -102,6 +102,25 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
}
}
);
+ this.setupEditor(config);
+ }
+
+ private setupEditor(config: any) {
+
+ let state: EditorState;
+ let field = this.FieldDoc.GetT(this.FieldKey, RichTextField);
+ if (field && field !== FieldWaiting && field.Data) {
+ state = EditorState.fromJSON(config, JSON.parse(field.Data));
+ } else {
+ state = EditorState.create(config);
+ }
+ if (this._ref.current) {
+ this._editorView = new EditorView(this._ref.current, {
+ state,
+ dispatchTransaction: this.dispatchTransaction
+ });
+ }
+
if (this.props.selectOnLoad) {
this.props.select(false);
this._editorView!.focus();
@@ -115,6 +134,9 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
if (this._reactionDisposer) {
this._reactionDisposer();
}
+ if (this._inputReactionDisposer) {
+ this._inputReactionDisposer();
+ }
}
shouldComponentUpdate() {
@@ -131,7 +153,24 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
e.stopPropagation();
}
+ if (e.buttons === 1 && this.props.fieldKey !== KeyStore.Archives)
+ e.preventDefault();
};
+ onPointerUp = (e: React.PointerEvent): void => {
+ if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
+ e.stopPropagation();
+ }
+ if (this.props.fieldKey !== KeyStore.Archives) {
+ e.preventDefault();
+ Main.Instance.SetTextDoc(this.props.Document, this._ref.current!);
+ }
+ };
+
+ onFocused = (e: React.FocusEvent): void => {
+ if (this.props.fieldKey !== KeyStore.Archives) {
+ Main.Instance.SetTextDoc(this.props.Document, this._ref.current!);
+ }
+ }
//REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
textCapability = (e: React.MouseEvent): void => { };
@@ -179,6 +218,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
className="formattedTextBox-cont"
onKeyDown={this.onKeyPress}
onKeyPress={this.onKeyPress}
+ onPointerUp={this.onPointerUp}
onPointerDown={this.onPointerDown}
onContextMenu={this.specificContextMenu}
// tfs: do we need this event handler