diff options
author | madelinegr <laura_wilson@brown.edu> | 2019-02-27 15:52:59 -0500 |
---|---|---|
committer | madelinegr <laura_wilson@brown.edu> | 2019-02-27 15:52:59 -0500 |
commit | 4d356d098e44d3d736358d166e905aec1de9c4d6 (patch) | |
tree | b4d00bebaa3bd76378ef0205855ea810b0e44e89 /src | |
parent | f7829f425e1ccbc6baa2059c91fa914d21963440 (diff) | |
parent | c6ce284c0938587df5a0fa759587b33f8beaa68f (diff) |
merged
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/Main.scss | 11 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 91 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.scss | 18 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 69 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 19 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 25 | ||||
-rw-r--r-- | src/debug/Test.tsx | 46 | ||||
-rw-r--r-- | src/fields/Key.ts | 1 |
14 files changed, 204 insertions, 101 deletions
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 6540af5b2..4334ed299 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -38,3 +38,14 @@ p { border-radius: 2px; background-color: rgba(0,0,0,.5); } + +.main-buttonDiv { + position: absolute; + width: 150px; + left: 0px; +} +.main-undoButtons { + position: absolute; + width: 150px; + right: 0px; +} diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 305627c19..16e95ad82 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,33 +1,26 @@ -import { action, configure, reaction, computed } from 'mobx'; +import { action, configure } from 'mobx'; import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { DocumentDecorations } from './DocumentDecorations'; -import { Documents } from '../documents/Documents'; import { Document } from '../../fields/Document'; import { KeyStore } from '../../fields/KeyStore'; -import "./Main.scss"; -import { ContextMenu } from './ContextMenu'; -import { DocumentView } from './nodes/DocumentView'; -import { Server } from '../Server'; +import { DocumentTransfer, MessageStore } from '../../server/Message'; import { Utils } from '../../Utils'; -import { ServerUtils } from '../../server/ServerUtil'; -import { MessageStore, DocumentTransfer } from '../../server/Message'; +import { Documents } from '../documents/Documents'; +import { Server } from '../Server'; +import { setupDrag } from '../util/DragManager'; import { Transform } from '../util/Transform'; -import { CollectionDockingView } from './collections/CollectionDockingView'; import { UndoManager } from '../util/UndoManager'; -import { setupDrag } from '../util/DragManager'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { ContextMenu } from './ContextMenu'; +import { DocumentDecorations } from './DocumentDecorations'; +import { DocumentView } from './nodes/DocumentView'; +import "./Main.scss"; -configure({ - enforceActions: "observed" -}); -window.addEventListener("drop", function (e) { - e.preventDefault(); -}, false) -window.addEventListener("dragover", function (e) { - e.preventDefault(); -}, false) +configure({ enforceActions: "observed" }); // causes errors to be generated when modifying an observable outside of an action +window.addEventListener("drop", (e) => e.preventDefault(), false) +window.addEventListener("dragover", (e) => e.preventDefault(), false) document.addEventListener("pointerdown", action(function (e: PointerEvent) { if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { ContextMenu.Instance.clearItems() @@ -35,31 +28,14 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { }), true) -//runInAction(() => -// let doc1 = Documents.TextDocument({ title: "hello" }); -// let doc2 = doc1.MakeDelegate(); -// doc2.Set(KS.X, new NumberField(150)); -// doc2.Set(KS.Y, new NumberField(20)); -// let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { -// x: 450, y: 100, title: "cat 1" -// }); -// doc3.Set(KeyStore.Data, new ImageField); -// const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { -// x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v -// })); -// schemaDocs[0].SetData(KS.Author, "Tyler", TextField); -// schemaDocs[4].SetData(KS.Author, "Bob", TextField); -// schemaDocs.push(doc2); -// const doc7 = Documents.SchemaDocument(schemaDocs) - const mainDocId = "mainDoc"; +let mainContainer: Document; +let mainfreeform: Document; +console.log("HELLO WORLD") Documents.initProtos(mainDocId, (res?: Document) => { - console.log("HELLO WORLD") - console.log("RESPONSE: " + res) - let mainContainer: Document; - let mainfreeform: Document; - if (res) { - mainContainer = res as Document; + console.log("Response => " + JSON.stringify(res as Document)) + if (res instanceof Document) { + mainContainer = res; mainContainer.GetAsync(KeyStore.ActiveFrame, field => mainfreeform = field as Document); } else { @@ -71,8 +47,8 @@ Documents.initProtos(mainDocId, (res?: Document) => { mainfreeform = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(mainfreeform.ToJson())); - var docs = [mainfreeform].map(doc => CollectionDockingView.makeDocumentConfig(doc)); - mainContainer.SetText(KeyStore.Data, JSON.stringify({ content: [{ type: 'row', content: docs }] })); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(mainfreeform)] }] }; + mainContainer.SetText(KeyStore.Data, JSON.stringify(dockingLayout)); mainContainer.Set(KeyStore.ActiveFrame, mainfreeform); }, 0); } @@ -86,12 +62,7 @@ Documents.initProtos(mainDocId, (res?: Document) => { let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" })); let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addClick = (creator: any) => action(() => { - var img = creator(); - img.SetNumber(KeyStore.X, 0); - img.SetNumber(KeyStore.Y, 0); - mainfreeform.GetList<Document>(KeyStore.Data, []).push(img); - }); + let addClick = (creator: () => Document) => action(() => mainfreeform.GetList<Document>(KeyStore.Data, []).push(creator())); let imgRef = React.createRef<HTMLDivElement>(); let webRef = React.createRef<HTMLDivElement>(); @@ -107,22 +78,24 @@ Documents.initProtos(mainDocId, (res?: Document) => { PanelWidth={() => 0} PanelHeight={() => 0} isTopMost={true} + SelectOnLoad={false} ContainingCollectionView={undefined} /> <DocumentDecorations /> <ContextMenu /> - <div style={{ position: 'absolute', bottom: '0px', left: '0px', width: '150px' }} ref={imgRef} > + <div className="main-buttonDiv" style={{ bottom: '0px' }} ref={imgRef} > <button onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>Add Image</button></div> - <div style={{ position: 'absolute', bottom: '25px', left: '0px', width: '150px' }} ref={webRef} > + <div className="main-buttonDiv" style={{ bottom: '25px' }} ref={webRef} > <button onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>Add Web</button></div> - <div style={{ position: 'absolute', bottom: '50px', left: '0px', width: '150px' }} ref={textRef}> + <div className="main-buttonDiv" style={{ bottom: '50px' }} ref={textRef}> <button onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>Add Text</button></div> - <div style={{ position: 'absolute', bottom: '75px', left: '0px', width: '150px' }} ref={colRef}> + <div className="main-buttonDiv" style={{ bottom: '75px' }} ref={colRef}> <button onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>Add Collection</button></div> - <div style={{ position: 'absolute', bottom: '100px', left: '0px', width: '150px' }} ref={schemaRef}> + <div className="main-buttonDiv" style={{ bottom: '100px' }} ref={schemaRef}> <button onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>Add Schema</button></div> - <button style={{ position: 'absolute', bottom: '125px', left: '0px', width: '150px' }} onClick={clearDatabase}>Clear Database</button> - <button style={{ position: 'absolute', bottom: '25px', right: '0px', width: '150px' }} onClick={() => UndoManager.Undo()}>Undo</button> - <button style={{ position: 'absolute', bottom: '0px', right: '0px', width: '150px' }} onClick={() => UndoManager.Redo()}>Redo</button> + <div className="main-buttonDiv" style={{ bottom: '125px' }} > + <button onClick={clearDatabase}>Clear Database</button></div> + <button className="main-undoButtons" style={{ bottom: '25px' }} onClick={() => UndoManager.Undo()}>Undo</button> + <button className="main-undoButtons" style={{ bottom: '0px' }} onClick={() => UndoManager.Redo()}>Redo</button> </div>), document.getElementById('root')); }) diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 3d7e46a01..915e33533 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -218,7 +218,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp render() { return ( <div className="collectiondockingview-container" id="menuContainer" - onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef} + onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} ref={this._containerRef} style={{ width: "100%", height: "100%", @@ -268,6 +268,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { PanelHeight={this._nativeHeight} ScreenToLocalTransform={this.ScreenToLocalTransform} isTopMost={true} + SelectOnLoad={false} ContainingCollectionView={undefined} /> </div> diff --git a/src/client/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss index e86295c26..f432e8cc3 100644 --- a/src/client/views/collections/CollectionFreeFormView.scss +++ b/src/client/views/collections/CollectionFreeFormView.scss @@ -20,4 +20,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 909321bb1..29d254e56 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -1,4 +1,4 @@ -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"; @@ -19,6 +19,7 @@ import { WebBox } from "../nodes/WebBox"; 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? @@ -27,9 +28,17 @@ export class CollectionFreeFormView extends CollectionViewBase { private _canvasRef = React.createRef<HTMLDivElement>(); private _lastX: number = 0; private _lastY: number = 0; + private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type) + + @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 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); } @@ -62,8 +71,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; } } @@ -73,21 +84,24 @@ 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; + //select is not already selected if (!this.props.isSelected()) { this.props.select(false); } } + } @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble && this.props.active()) { - e.preventDefault(); e.stopPropagation(); 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; @@ -145,6 +159,24 @@ export class CollectionFreeFormView extends CollectionViewBase { } @action + onKeyDown = (e: React.KeyboardEvent<Element>) => { + //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" }); + // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself + this._selectOnLoaded = newBox.Id; + //set text to be the typed key and get focus on text box + this.props.CollectionView.addDocument(newBox); + //remove cursor from screen + this._previewCursorVisible = false; + } + } + } + + @action bringToFront(doc: Document) { const { fieldKey: fieldKey, Document: Document } = this.props; @@ -182,15 +214,15 @@ export class CollectionFreeFormView extends CollectionViewBase { } @computed get views() { - const { fieldKey, Document } = this.props; - const lvalue = Document.GetT<ListField<Document>>(fieldKey, ListField); + const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField); if (lvalue && lvalue != FieldWaiting) { return lvalue.Data.map(doc => { - return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc} + return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc} ref={focus} AddDocument={this.props.addDocument} RemoveDocument={this.props.removeDocument} ScreenToLocalTransform={this.getTransform} isTopMost={false} + SelectOnLoad={doc.Id === this._selectOnLoaded} ContentScaling={this.noScaling} PanelWidth={doc.Width} PanelHeight={doc.Height} @@ -227,23 +259,42 @@ export class CollectionFreeFormView extends CollectionViewBase { getLocalTransform = (): Transform => Transform.Identity.translate(-this.panX, -this.panY).scale(1 / this.scale); noScaling = () => 1; + //when focus is lost, this will remove the preview cursor + @action + onBlur = (e: React.FocusEvent<HTMLInputElement>): void => { + this._previewCursorVisible = false; + } + render() { //TODO: put KVP stuff in this function + + //determines whether preview text cursor should be visible (ie when user taps this collection it should) + let cursor = null; + if (this._previewCursorVisible) { + //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} + onBlur={this.onBlur} 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/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 03110a9c7..5bcd501cc 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -39,7 +39,8 @@ export class CollectionSchemaView extends CollectionViewBase { isSelected: () => false, select: () => { }, isTopMost: false, - bindings: {} + bindings: {}, + selectOnLoad: false, } let contents = ( <FieldView {...props} /> @@ -185,6 +186,7 @@ export class CollectionSchemaView extends CollectionViewBase { <DocumentView Document={selected} AddDocument={this.props.addDocument} RemoveDocument={this.props.removeDocument} isTopMost={false} + SelectOnLoad={false} ScreenToLocalTransform={this.getTransform} ContentScaling={this.getContentScaling} PanelWidth={this.getPanelWidth} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2e48bd57a..f938d2237 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"; @@ -30,7 +30,7 @@ export class CollectionView extends React.Component<CollectionViewProps> { public static LayoutString(fieldKey: string = "DataKey") { return `<CollectionView Document={Document} ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} BackgroundView={BackgroundView} />`; + isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} />`; } public active = () => { var isSelected = this.props.isSelected(); @@ -89,13 +89,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/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 217536e2b..7067724c8 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -67,7 +67,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); if (html && html.indexOf("<img") != 0) { - let htmlDoc = Documents.HtmlDocument(html, { ...options }); + let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 }); htmlDoc.SetText(KeyStore.DocumentText, text); this.props.addDocument(htmlDoc); return; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fcafea987..d1706c80c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -40,6 +40,7 @@ export interface DocumentViewProps { ContentScaling: () => number; PanelWidth: () => number; PanelHeight: () => number; + SelectOnLoad: boolean; } export interface JsxArgs extends DocumentViewProps { Keys: { [name: string]: Key } @@ -88,7 +89,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { private _mainCont = React.createRef<HTMLDivElement>(); private _documentBindings: any = null; - private _contextMenuCanOpen = false; private _downX: number = 0; private _downY: number = 0; @@ -107,7 +107,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e); e.stopPropagation(); } else { - this._contextMenuCanOpen = true; if (this.active && !e.isDefaultPrevented()) { e.stopPropagation(); if (e.buttons === 2) { @@ -123,15 +122,12 @@ export class DocumentView extends React.Component<DocumentViewProps> { onPointerMove = (e: PointerEvent): void => { if (e.cancelBubble) { - this._contextMenuCanOpen = false; return; } if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { document.removeEventListener("pointermove", this.onPointerMove) document.removeEventListener("pointerup", this.onPointerUp) - this._contextMenuCanOpen = false; if (this._mainCont.current != null && !this.topMost) { - this._contextMenuCanOpen = false; const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); let dragData: { [id: string]: any } = {}; dragData["documentView"] = this; @@ -139,7 +135,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { dragData["yOffset"] = e.y - top; DragManager.StartDrag(this._mainCont.current, dragData, { handlers: { - dragComplete: action((e: DragManager.DragCompleteEvent) => { }), + dragComplete: action(() => { }), }, hideSource: true }) @@ -158,7 +154,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { } } - deleteClicked = (e: React.MouseEvent): void => { + deleteClicked = (): void => { if (this.props.RemoveDocument) { this.props.RemoveDocument(this.props.Document); } @@ -185,13 +181,14 @@ export class DocumentView extends React.Component<DocumentViewProps> { @action onContextMenu = (e: React.MouseEvent): void => { - e.preventDefault() e.stopPropagation(); - if (!SelectionManager.IsSelected(this) || !this._contextMenuCanOpen) { + let moved = Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3; + if (moved || e.isDefaultPrevented()) { + e.preventDefault() return; } + e.preventDefault() - ContextMenu.Instance.clearItems() ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) ContextMenu.Instance.addItem({ description: "Fields", event: () => this.fieldsClicked }) ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) @@ -211,7 +208,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { } @computed get mainContent() { - var val = this.props.Document.Id; return <JsxParser components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox }} bindings={this._documentBindings} @@ -220,6 +216,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/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index a883fa672..f372258f8 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -12,7 +12,6 @@ import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; import { WebBox } from "./WebBox"; -import { HtmlField } from "../../../fields/HtmlField"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. @@ -25,12 +24,15 @@ export interface FieldViewProps { isSelected: () => boolean; select: () => void; isTopMost: boolean; + selectOnLoad: boolean; bindings: any; } @observer export class FieldView extends React.Component<FieldViewProps> { - public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} bindings={bindings} fieldKey={${fieldStr}} isSelected={isSelected} select={select} isTopMost={isTopMost} />`; } + public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { + return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} bindings={bindings} fieldKey={${fieldStr}} isSelected={isSelected} select={select} selectOnLoad={SelectOnLoad} isTopMost={isTopMost} />`; + } @computed get field(): FieldValue<Field> { diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index f06fdae24..21bd43b6e 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -9,7 +9,7 @@ } .formattedTextBox-cont { - background: rgb(218, 215, 215); + background: white; padding: 1; border: black; border-width: 10; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a58e1955f..e65615af4 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -3,15 +3,17 @@ import { baseKeymap } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { schema } from "prosemirror-schema-basic"; -import { EditorState, Transaction } from "prosemirror-state"; +import { EditorState, Transaction, } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import { Opt, FieldWaiting, FieldValue } from "../../../fields/Field"; +import { Opt, FieldWaiting } from "../../../fields/Field"; import "./FormattedTextBox.scss"; import React = require("react") import { RichTextField } from "../../../fields/RichTextField"; import { FieldViewProps, FieldView } from "./FieldView"; + + // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // // HTML Markup: <FormattedTextBox Doc={Document's ID} FieldKey={Key's name + "Key"} @@ -39,7 +41,6 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { super(props); this._ref = React.createRef(); - this.onChange = this.onChange.bind(this); } @@ -47,25 +48,23 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { if (this._editorView) { const state = this._editorView.state.apply(tx); this._editorView.updateState(state); - const { doc, fieldKey } = this.props; - doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); + this.props.doc.SetData(this.props.fieldKey, JSON.stringify(state.toJSON()), RichTextField); } } componentDidMount() { let state: EditorState; - const { doc, fieldKey } = this.props; const config = { schema, plugins: [ history(), keymap({ "Mod-z": undo, "Mod-y": redo }), - keymap(baseKeymap) + keymap(baseKeymap), ] }; - let field = doc.GetT(fieldKey, RichTextField); - if (field && field != FieldWaiting) { // bcz: don't think this works + let field = this.props.doc.GetT(this.props.fieldKey, RichTextField); + if (field && field != FieldWaiting) { state = EditorState.fromJSON(config, JSON.parse(field.Data)); } else { state = EditorState.create(config); @@ -85,6 +84,10 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))); } }) + if (this.props.selectOnLoad) { + this.props.select(); + this._editorView!.focus(); + } } componentWillUnmount() { @@ -102,11 +105,9 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { @action onChange(e: React.ChangeEvent<HTMLInputElement>) { - const { fieldKey, doc } = this.props; - doc.SetData(fieldKey, e.target.value, RichTextField); + this.props.doc.SetData(this.props.fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { - let me = this; if (e.buttons === 1 && this.props.isSelected()) { e.stopPropagation(); } diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx new file mode 100644 index 000000000..7bc70615f --- /dev/null +++ b/src/debug/Test.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +class TestInternal extends React.Component { + onContextMenu = (e: React.MouseEvent) => { + console.log("Internal"); + e.stopPropagation(); + } + + onPointerDown = (e: React.MouseEvent) => { + console.log("pointer down") + e.preventDefault(); + } + + render() { + return <div onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} + onPointerUp={this.onPointerDown}>Hello world</div> + } +} + +class TestChild extends React.Component { + onContextMenu = () => { + console.log("Child"); + } + + render() { + return <div onContextMenu={this.onContextMenu}><TestInternal /></div> + } +} + +class TestParent extends React.Component { + onContextMenu = () => { + console.log("Parent"); + } + + render() { + return <div onContextMenu={this.onContextMenu}><TestChild /></div> + } +} + +ReactDOM.render(( + <div style={{ position: "absolute", width: "100%", height: "100%" }}> + <TestParent /> + </div>), + document.getElementById('root') +);
\ No newline at end of file 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 { |