diff options
Diffstat (limited to 'src/client/views/collections')
8 files changed, 102 insertions, 73 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index cb978c1ba..915e33533 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -10,7 +10,6 @@ import { FieldId, Opt, Field } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { Utils } from "../../../Utils"; import { Server } from "../../Server"; -import { DragManager } from "../../util/DragManager"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; @@ -34,10 +33,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp } private _goldenLayout: any = null; - private _dragDiv: any = null; - private _dragParent: HTMLElement | null = null; - private _dragElement: HTMLElement | undefined; - private _dragFakeElement: HTMLElement | undefined; private _containerRef = React.createRef<HTMLDivElement>(); private _fullScreen: any = null; @@ -47,28 +42,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp (window as any).React = React; (window as any).ReactDOM = ReactDOM; } - - public StartOtherDrag(dragElement: HTMLElement, dragDoc: Document) { - this._dragElement = dragElement; - this._dragParent = dragElement.parentElement; - // bcz: we want to copy this document into the header, not move it there. - // However, GoldenLayout is setup to move things, so we have to do some kludgy stuff: - - // - create a temporary invisible div and register that as a DragSource with GoldenLayout - this._dragDiv = document.createElement("div"); - this._dragDiv.style.opacity = 0; - DragManager.Root().appendChild(this._dragDiv); - this._goldenLayout.createDragSource(this._dragDiv, CollectionDockingView.makeDocumentConfig(dragDoc)); - - // - add our document to that div so that GoldenLayout will get the move events its listening for - this._dragDiv.appendChild(this._dragElement); - - // - add a duplicate of our document to the original document's container - // (GoldenLayout will be removing our original one) - this._dragFakeElement = dragElement.cloneNode(true) as HTMLElement; - this._dragParent!.appendChild(this._dragFakeElement); - - // all of this must be undone when the document has been dropped (see tabCreated) + public StartOtherDrag(dragDoc: Document, e: any) { + this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: e.button }) } @action @@ -98,7 +73,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp // Creates a vertical split on the right side of the docking view, and then adds the Document to that split // @action - public AddRightSplit(document: Document) { + public AddRightSplit(document: Document, minimize: boolean = false) { this._goldenLayout.emit('stateChanged'); let newItemStackConfig = { type: 'stack', @@ -121,10 +96,15 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp collayout.config["width"] = 50; newContentItem.config["width"] = 50; } + if (minimize) { + newContentItem.config["width"] = 10; + newContentItem.config["height"] = 10; + } newContentItem.callDownwards('_$init'); this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]); this._goldenLayout.emit('stateChanged'); this.stateChanged(); + return newContentItem; } setupGoldenLayout() { @@ -218,13 +198,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp this.stateChanged(); } tabCreated = (tab: any) => { - if (this._dragDiv) { - this._dragDiv.removeChild(this._dragElement); - this._dragParent!.removeChild(this._dragFakeElement!); - this._dragParent!.appendChild(this._dragElement!); - DragManager.Root().removeChild(this._dragDiv); - this._dragDiv = null; - } tab.closeElement.off('click') //unbind the current click handler .click(function () { tab.contentItem.remove(); @@ -295,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 737f28318..f432e8cc3 100644 --- a/src/client/views/collections/CollectionFreeFormView.scss +++ b/src/client/views/collections/CollectionFreeFormView.scss @@ -1,15 +1,5 @@ .collectionfreeformview-container { - ::-webkit-scrollbar { - -webkit-appearance: none; - height:5px; - width:5px; - } - ::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: rgba(0,0,0,.5); - } - .collectionfreeformview > .jsx-parser{ position:absolute; height: 100%; @@ -30,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 1f8d76432..63255dd90 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"; @@ -10,16 +10,16 @@ import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionSchemaView } from "../collections/CollectionSchemaView"; -import { CollectionTreeView } from "../collections/CollectionTreeView"; import { CollectionView } from "../collections/CollectionView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { DocumentView } from "../nodes/DocumentView"; -import { WebView } from "../nodes/WebView"; import { FormattedTextBox } from "../nodes/FormattedTextBox"; import { ImageBox } from "../nodes/ImageBox"; +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? @@ -28,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); } @@ -63,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; } } @@ -74,10 +84,14 @@ 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 @@ -87,7 +101,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; @@ -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; @@ -177,15 +209,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} @@ -199,7 +231,7 @@ export class CollectionFreeFormView extends CollectionViewBase { get backgroundView() { return !this.backgroundLayout ? (null) : (<JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox }} bindings={this.props.bindings} jsx={this.backgroundLayout} showWarnings={true} @@ -210,7 +242,7 @@ export class CollectionFreeFormView extends CollectionViewBase { get overlayView() { return !this.overlayLayout ? (null) : (<JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox }} bindings={this.props.bindings} jsx={this.overlayLayout} showWarnings={true} @@ -222,21 +254,41 @@ 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() { + + //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} 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.scss b/src/client/views/collections/CollectionSchemaView.scss index 995d60f74..d40e6d314 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -6,15 +6,6 @@ position: absolute; width: 100%; height: 100%; - ::-webkit-scrollbar { - -webkit-appearance: none; - height:5px; - width:5px; - } - ::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: rgba(0,0,0,.5); - } .collectionSchemaView-previewRegion { position: relative; background: black; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 106a5c4f5..5bcd501cc 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -39,15 +39,16 @@ export class CollectionSchemaView extends CollectionViewBase { isSelected: () => false, select: () => { }, isTopMost: false, - bindings: {} + bindings: {}, + selectOnLoad: false, } let contents = ( <FieldView {...props} /> ) let reference = React.createRef<HTMLDivElement>(); - let onItemDown = setupDrag(reference, props.doc); + let onItemDown = setupDrag(reference, () => props.doc); return ( - <div onPointerDown={onItemDown} ref={reference}> + <div onPointerDown={onItemDown} key={props.doc.Id} ref={reference}> <EditableView contents={contents} height={36} GetValue={() => { let field = props.doc.Get(props.fieldKey); @@ -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/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 64f4c0970..55c804337 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -33,7 +33,7 @@ class TreeView extends React.Component<TreeViewProps> { var children = childDocument.GetT<ListField<Document>>(KeyStore.Data, ListField); let title = childDocument.GetT<TextField>(KeyStore.Title, TextField); - let onItemDown = setupDrag(reference, childDocument); + let onItemDown = setupDrag(reference, () => childDocument); if (title && title != FieldWaiting) { let subView = !children || this.collapsed || children === FieldWaiting ? (null) : diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 03e1f1fa4..8332249c9 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(); @@ -87,13 +87,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; |
