diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/PreviewTextCursor.tsx | 15 | ||||
-rw-r--r-- | src/client/util/SelectionManager.ts | 6 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.scss | 18 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 66 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 24 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss | 4 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 34 | ||||
-rw-r--r-- | src/fields/Key.ts | 1 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 6 | ||||
-rw-r--r-- | src/server/database.ts | 11 |
11 files changed, 177 insertions, 13 deletions
diff --git a/src/PreviewTextCursor.tsx b/src/PreviewTextCursor.tsx new file mode 100644 index 000000000..6818bf28c --- /dev/null +++ b/src/PreviewTextCursor.tsx @@ -0,0 +1,15 @@ +import React = require("react"); +import { observer } from "mobx-react"; + +@observer +export class PreviewTextCursor extends React.Component { + + render() { + return ( + <div> + + </div> + ) + }; + +}
\ No newline at end of file diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1a711ae64..d5d9b29b2 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -8,6 +8,12 @@ export namespace SelectionManager { @action SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + + //remove preview cursor from collection + if (doc.props.ContainingCollectionView != undefined) { + doc.props.ContainingCollectionView.hidePreviewCursor(); + } + // if doc is not in SelectedDocuments, add it if (!ctrlPressed) { manager.SelectedDocuments = []; diff --git a/src/client/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss index d583a8218..df9b1030c 100644 --- a/src/client/views/collections/CollectionFreeFormView.scss +++ b/src/client/views/collections/CollectionFreeFormView.scss @@ -29,4 +29,22 @@ width:100%; height: 100% } +} + +.border { + border-style: solid; + box-sizing: border-box; + width: 100%; + height: 100%; +} + +//this is an animation for the blinking cursor! +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +#prevCursor { + animation: blink 1s infinite; }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 12909c151..c2d2b0f7b 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -1,7 +1,9 @@ -import { action, computed } from "mobx"; +import { observable, action, computed } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting } from "../../../fields/Field"; +import { Server } from "tls"; +import { RichTextField } from "../../../fields/RichTextField"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; import { TextField } from "../../../fields/TextField"; @@ -20,6 +22,7 @@ import { ImageBox } from "../nodes/ImageBox"; import "./CollectionFreeFormView.scss"; import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; +import { Documents } from "../../documents/Documents"; import React = require("react"); const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? @@ -28,9 +31,18 @@ export class CollectionFreeFormView extends CollectionViewBase { private _canvasRef = React.createRef<HTMLDivElement>(); private _lastX: number = 0; private _lastY: number = 0; + + @observable private _downX: number = 0; + @observable private _downY: number = 0; + //determines whether the blinking cursor for indicating whether a text will be made on key down is visible + @observable + private _previewCursorVisible: boolean = false; + + @computed get colFocus(): boolean { return this.props.CollectionView.isFocusOn() } + @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); } @@ -63,8 +75,10 @@ export class CollectionFreeFormView extends CollectionViewBase { document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); - this._downX = this._lastX = e.pageX; - this._downY = this._lastY = e.pageY; + this._lastX = e.pageX; + this._lastY = e.pageY; + this._downX = e.pageX; + this._downY = e.pageY; } } @@ -74,10 +88,15 @@ export class CollectionFreeFormView extends CollectionViewBase { document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); if (Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) { + //show preview text cursor on tap + this._previewCursorVisible = true; + this.props.CollectionView.showPreviewCursor(); + //select is not already selected if (!this.props.isSelected()) { this.props.select(false); } } + } @action @@ -88,7 +107,7 @@ export class CollectionFreeFormView extends CollectionViewBase { let x = this.props.Document.GetNumber(KeyStore.PanX, 0); let y = this.props.Document.GetNumber(KeyStore.PanY, 0); let [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - + this._previewCursorVisible = false; this.SetPan(x + dx, y + dy); } this._lastX = e.pageX; @@ -146,6 +165,26 @@ export class CollectionFreeFormView extends CollectionViewBase { } @action + onKeyDown = (e: React.KeyboardEvent<Element>) => { + console.log("KEY PRESSED"); + //if not these keys, make a textbox if preview cursor is active! + if (!e.ctrlKey && !e.altKey && !e.shiftKey) { + if (this._previewCursorVisible) { + //make textbox and add it to this collection + let [x, y] = this.getTransform().transformPoint(this._downX, this._downY); (this._downX, this._downY); + let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "new" }); + //set text to be the typed key and get focus on text box + this.props.CollectionView.addDocument(newBox); + newBox.SetText(KeyStore.Data, e.key); + newBox.SetNumber(KeyStore.SelectOnLoaded, 1); + + //remove cursor from screen + this._previewCursorVisible = false; + } + } + } + + @action bringToFront(doc: Document) { const { fieldKey: fieldKey, Document: Document } = this.props; @@ -223,22 +262,41 @@ export class CollectionFreeFormView extends CollectionViewBase { getLocalTransform = (): Transform => Transform.Identity.translate(-this.panX, -this.panY).scale(1 / this.scale); noScaling = () => 1; + //hides the preview cursor for generating new text boxes - called when other docs are selected/dragged + @action + hidePreviewCursor() { + this._previewCursorVisible = false; + } + render() { + + let cursor = null; + //toggle for preview cursor -> will be on when user taps freeform + if (this._previewCursorVisible && this.props.CollectionView.isFocusOn) { + //get local position and place cursor there! + let [x, y] = this.getTransform().transformPoint(this._downX, this._downY); + cursor = <div id="prevCursor" onKeyPress={this.onKeyDown} style={{ color: "black", position: "absolute", transformOrigin: "left top", transform: `translate(${x}px, ${y}px)` }}>I</div> + } + const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0) + this.centeringShiftX; const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0) + this.centeringShiftY; + return ( <div className="collectionfreeformview-container" onPointerDown={this.onPointerDown} + onKeyPress={this.onKeyDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px`, }} + tabIndex={0} ref={this.createDropTarget}> <div className="collectionfreeformview" style={{ transformOrigin: "left top", transform: ` translate(${panx}px, ${pany}px) scale(${this.zoomScaling}, ${this.zoomScaling})` }} ref={this._canvasRef}> {this.backgroundView} + {cursor} {this.views} </div> {this.overlayView} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 03e1f1fa4..6ab0f15c0 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { ListField } from "../../../fields/ListField"; @@ -11,6 +11,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; import { CollectionDockingView } from "./CollectionDockingView"; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionViewProps } from "./CollectionViewBase"; +var ReactDOM = require('react-dom'); import { CollectionTreeView } from "./CollectionTreeView"; import { Field } from "../../../fields/Field"; @@ -27,6 +28,8 @@ export const COLLECTION_BORDER_WIDTH = 2; @observer export class CollectionView extends React.Component<CollectionViewProps> { + private _focusOn: boolean = false; + public static LayoutString(fieldKey: string = "DataKey") { return `<CollectionView Document={Document} ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} @@ -70,6 +73,21 @@ export class CollectionView extends React.Component<CollectionViewProps> { return false } + + + @computed + get isFocusOn() { return this._focusOn; } + + @action + showPreviewCursor() { + this._focusOn = true; + } + + @action + hidePreviewCursor() { + this._focusOn = false; + } + get collectionViewType(): CollectionViewType { let Document = this.props.Document; let viewField = Document.GetT(KeyStore.ViewType, NumberField); @@ -87,13 +105,15 @@ export class CollectionView extends React.Component<CollectionViewProps> { Document.SetData(KeyStore.ViewType, type, NumberField); } + render() { let viewType = this.collectionViewType; + switch (viewType) { case CollectionViewType.Freeform: return (<CollectionFreeFormView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} - CollectionView={this} />) + CollectionView={this} />); case CollectionViewType.Schema: return (<CollectionSchemaView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 87f2e205b..a7632b008 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -119,6 +119,10 @@ export class DocumentView extends React.Component<DocumentViewProps> { return; } if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { + //remove preview cursor from collection + if (this.props.ContainingCollectionView != undefined) { + this.props.ContainingCollectionView.hidePreviewCursor(); + } this._contextMenuCanOpen = false; if (this._mainCont.current != null && !this.topMost) { this._contextMenuCanOpen = false; @@ -206,6 +210,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { onError={(test: any) => { console.log(test) }} /> } + render() { if (!this.props.Document) return <div></div> diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 0389a3f85..10cbf8557 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -9,8 +9,8 @@ } .formattedTextBox-cont { - background: beige; - padding: 0; + background: white; + padding: 1vw; overflow-y: scroll; overflow-x: hidden; color: initial; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a58e1955f..63d00a310 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -3,13 +3,21 @@ import { baseKeymap } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { schema } from "prosemirror-schema-basic"; +import { Transform } from "prosemirror-transform"; import { EditorState, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; +import { Node } from "prosemirror-model"; import { Opt, FieldWaiting, FieldValue } from "../../../fields/Field"; import "./FormattedTextBox.scss"; +import { KeyStore } from "../../../fields/KeyStore"; import React = require("react") import { RichTextField } from "../../../fields/RichTextField"; import { FieldViewProps, FieldView } from "./FieldView"; +import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; +import { observer } from "mobx-react"; +import { Schema, DOMParser } from "prosemirror-model" +import { Plugin } from 'prosemirror-state' +import { Decoration, DecorationSet } from 'prosemirror-view' // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document @@ -34,6 +42,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { private _ref: React.RefObject<HTMLDivElement>; private _editorView: Opt<EditorView>; private _reactionDisposer: Opt<IReactionDisposer>; + private _lastTextState = ""; constructor(props: FieldViewProps) { super(props); @@ -49,9 +58,24 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { this._editorView.updateState(state); const { doc, fieldKey } = this.props; doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); + this._lastTextState = JSON.stringify(state.toJSON); } } + //enables textboxes to be created with preexisting text or placeholder text + //this method is passed in as part of the config the editor state in componentDidMount() + placeholderPlugin(text: string) { + return new Plugin({ + props: { + decorations(state) { + let doc = state.doc + if (doc.childCount == 1 && doc.firstChild && doc.firstChild.isTextblock && doc.firstChild.content.size == 0) + return DecorationSet.create(doc, [Decoration.widget(1, document.createTextNode(text))]) + } + } + }) + } + componentDidMount() { let state: EditorState; const { doc, fieldKey } = this.props; @@ -60,7 +84,8 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { plugins: [ history(), keymap({ "Mod-z": undo, "Mod-y": redo }), - keymap(baseKeymap) + keymap(baseKeymap), + //sets the placeholder text to what's in KeyStore.Text! ] }; @@ -85,6 +110,12 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))); } }) + + //if tagged to be selected when created, then select & focus + if (this.props.doc.GetNumber(KeyStore.SelectOnLoaded, 0)) { + this.props.select(); + this._editorView!.focus(); + } } componentWillUnmount() { @@ -103,6 +134,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { @action onChange(e: React.ChangeEvent<HTMLInputElement>) { const { fieldKey, doc } = this.props; + this._lastTextState = e.target.value; doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index c16a00878..00d78d516 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -2,7 +2,6 @@ import { Field, FieldId } from "./Field" import { Utils } from "../Utils"; import { observable } from "mobx"; import { Types } from "../server/Message"; -import { ObjectID } from "bson"; import { Server } from "../client/Server"; export class Key extends Field { diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index a3b39735d..6b5fafe05 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -26,4 +26,10 @@ export namespace KeyStore { export const Caption = new Key("Caption"); export const ActiveFrame = new Key("ActiveFrame"); export const DocumentText = new Key("DocumentText"); + //used for setting the text of a text document + export const Text = new Key("Text"); + //determines whether doc views will be selected when they are first loaded + //should be NumberField where 0 = false and 1 = true + //currently only implemented for FormattedTextView + export const SelectOnLoaded = new Key("SelectOnLoaded"); } diff --git a/src/server/database.ts b/src/server/database.ts index 07c5819ab..dbf335c0a 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,6 +1,6 @@ import { action, configure } from 'mobx'; -import * as mongodb from 'mongodb'; -import { ObjectID } from 'mongodb'; +import * as mongodb from "mongodb" +import { ObjectID } from "mongodb" import { Transferable } from './Message'; import { Utils } from '../Utils'; @@ -8,10 +8,15 @@ export class Database { public static Instance = new Database() private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; + private db?: mongodb.Db; constructor() { this.MongoClient.connect(this.url, (err, client) => { + if (err) { + console.log(err.message); + throw err; + } this.db = client.db() }) } @@ -78,4 +83,4 @@ export class Database { public print() { console.log("db says hi!") } -} +}
\ No newline at end of file |