diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/ContextMenu.scss | 19 | ||||
-rw-r--r-- | src/client/views/ContextMenu.tsx | 14 | ||||
-rw-r--r-- | src/client/views/ContextMenuItem.tsx | 9 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 28 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 27 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 25 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 11 | ||||
-rw-r--r-- | src/server/index.ts | 1 |
9 files changed, 98 insertions, 37 deletions
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 234f82eb9..ea40c8e99 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -3,16 +3,16 @@ display: flex; z-index: 1000; box-shadow: #AAAAAA .2vw .2vw .4vw; + flex-direction: column; } .contextMenu-item { - width: 10vw; - height: 4vh; - background: #DDDDDD; + width: auto; + height: auto; + background: #F0F8FF; display: flex; - justify-content: center; + justify-content: left; align-items: center; - flex-direction: column; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; @@ -20,11 +20,18 @@ -ms-user-select: none; user-select: none; transition: all .1s; + border-width: .11px; + border-style: none; + border-color: rgb(187, 186, 186); + border-bottom-style: solid; + padding: 10px; + white-space: nowrap; + font-size: 1.5vw; } .contextMenu-item:hover { transition: all .1s; - background: #AAAAAA + background: #B0E0E6; } .contextMenu-description { diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 9459d45f8..fcb934860 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -12,6 +12,8 @@ export class ContextMenu extends React.Component { @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: string = "none"; + @observable private _searchString: string = ""; + private ref: React.RefObject<HTMLDivElement>; @@ -45,6 +47,8 @@ export class ContextMenu extends React.Component { this._pageX = x this._pageY = y + this._searchString = ""; + this._display = "flex" } @@ -62,10 +66,18 @@ export class ContextMenu extends React.Component { render() { return ( <div className="contextMenu-cont" style={{ left: this._pageX, top: this._pageY, display: this._display }} ref={this.ref}> - {this._items.map(prop => { + <input className="contextMenu-item" type="text" placeholder="Search . . ." value={this._searchString} onChange={this.onChange}></input> + {this._items.filter(prop => { + return prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1; + }).map(prop => { return <ContextMenuItem {...prop} key={prop.description} /> })} </div> ) } + + @action + onChange = (e: React.ChangeEvent<HTMLInputElement>) => { + this._searchString = e.target.value; + } }
\ No newline at end of file diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 91fc96c19..4801c1555 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -5,6 +5,15 @@ export interface ContextMenuProps { event: (e: React.MouseEvent<HTMLDivElement>) => void; } +export interface SubmenuProps { + description: string; + subitems: ContextMenuProps[]; +} + +export interface ContextMenuItemProps { + type: ContextMenuProps | SubmenuProps +} + export class ContextMenuItem extends React.Component<ContextMenuProps> { render() { return ( diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 737e5998b..49f95c014 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -9,6 +9,7 @@ import { Field } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { CompileScript, ToField } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; +import { ContextMenu } from "../ContextMenu"; import { EditableView } from "../EditableView"; import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index eb502f611..1dbc3c3e3 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -89,29 +89,43 @@ export class CollectionView extends React.Component<CollectionViewProps> { Document.SetData(KeyStore.ViewType, type, NumberField); } + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) + ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) + ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) + ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) + } render() { let viewType = this.collectionViewType; - + let subView: JSX.Element; switch (viewType) { case CollectionViewType.Freeform: - return (<CollectionFreeFormView {...this.props} + subView = (<CollectionFreeFormView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} - CollectionView={this} />); + CollectionView={this} />) + break; case CollectionViewType.Schema: - return (<CollectionSchemaView {...this.props} + subView = (<CollectionSchemaView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} CollectionView={this} />) + break; case CollectionViewType.Docking: - return (<CollectionDockingView {...this.props} + subView = (<CollectionDockingView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} CollectionView={this} />) + break; case CollectionViewType.Tree: - return (<CollectionTreeView {...this.props} + subView = (<CollectionTreeView {...this.props} addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active} CollectionView={this} />) + break; default: - return <div></div> + subView = <div></div> + break; } + return (<div onContextMenu={this.specificContextMenu}> + {subView} + </div>) } }
\ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2fc00f15d..e01e1d4cd 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -20,18 +20,16 @@ import { KeyValueBox } from "./KeyValueBox" import { WebBox } from "../nodes/WebBox"; import "./DocumentView.scss"; import React = require("react"); -const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? +const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? export interface DocumentViewProps { ContainingCollectionView: Opt<CollectionView>; - Document: Document; AddDocument?: (doc: Document) => void; RemoveDocument?: (doc: Document) => boolean; ScreenToLocalTransform: () => Transform; isTopMost: boolean; - //tfs: This shouldn't be necessary I don't think ContentScaling: () => number; PanelWidth: () => number; PanelHeight: () => number; @@ -82,20 +80,16 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { @observer export class DocumentView extends React.Component<DocumentViewProps> { - private _mainCont = React.createRef<HTMLDivElement>(); private _documentBindings: any = null; private _downX: number = 0; private _downY: number = 0; - @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); } @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; } @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); } @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); } @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); } - screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); - onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; @@ -115,7 +109,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { } } } - onPointerMove = (e: PointerEvent): void => { if (e.cancelBubble) { return; @@ -140,7 +133,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { e.stopPropagation(); e.preventDefault(); } - onPointerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onPointerMove) document.removeEventListener("pointerup", this.onPointerUp) @@ -189,9 +181,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }) ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }) ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) - ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) - ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) - ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) if (!this.topMost) { @@ -203,7 +192,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) SelectionManager.SelectDoc(this, e.ctrlKey); } - @computed get mainContent() { return <JsxParser components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox }} @@ -223,8 +211,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { } render() { - if (!this.props.Document) - return <div></div> + if (!this.props.Document) return <div></div> let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); if (!lkeys || lkeys === "<Waiting>") { return <p>Error loading layout keys</p>; @@ -236,14 +223,13 @@ export class DocumentView extends React.Component<DocumentViewProps> { focus: this.props.focus }; for (const key of this.layoutKeys) { - this._documentBindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data + this._documentBindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } for (const key of this.layoutFields) { let field = this.props.Document.Get(key); this._documentBindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; } this._documentBindings.bindings = this._documentBindings; - var scaling = this.props.ContentScaling(); var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); @@ -253,13 +239,12 @@ export class DocumentView extends React.Component<DocumentViewProps> { width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%", height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%", transformOrigin: "left top", - transform: `scale(${scaling},${scaling})` + transform: `scale(${scaling} , ${scaling})` }} onContextMenu={this.onContextMenu} - onPointerDown={this.onPointerDown} - > + onPointerDown={this.onPointerDown} > {this.mainContent} </div> ) } -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e65615af4..04eb2052d 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -10,6 +10,7 @@ import "./FormattedTextBox.scss"; import React = require("react") import { RichTextField } from "../../../fields/RichTextField"; import { FieldViewProps, FieldView } from "./FieldView"; +import { ContextMenu } from "../../views/ContextMenu"; @@ -112,12 +113,36 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { e.stopPropagation(); } } + + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE + textCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); + // ContextMenu.Instance.addItem({ + // description: "Submenu", + // items: [ + // { + // description: "item 1", event: + // }, + // { + // description: "item 2", event: + // } + // ] + // }) + // e.stopPropagation() + + } + onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); } + render() { return (<div className="formattedTextBox-cont" onPointerDown={this.onPointerDown} + onContextMenu={this.specificContextMenu} onWheel={this.onPointerWheel} ref={this._ref} />) } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e206bf8d5..8c44395f4 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -7,6 +7,7 @@ import { ImageField } from '../../../fields/ImageField'; import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; import { observer } from "mobx-react" +import { ContextMenu } from "../../views/ContextMenu"; import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; @@ -88,13 +89,21 @@ export class ImageBox extends React.Component<FieldViewProps> { } } + //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE + imageCapability = (e: React.MouseEvent): void => { + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability }); + } + render() { let field = this.props.doc.Get(this.props.fieldKey); let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1); return ( - <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} > + <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} onContextMenu={this.specificContextMenu}> <img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} /> {this.lightbox(path)} </div>) diff --git a/src/server/index.ts b/src/server/index.ts index eb0527ee7..56881e254 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -125,7 +125,6 @@ function deleteAll() { function barReceived(guid: String) { clients[guid.toString()] = new Client(guid.toString()); - // Database.Instance.print() } function addDocument(document: Document) { |