diff options
| author | madelinegr <mgriswold99@gmail.com> | 2019-02-12 18:55:11 -0500 |
|---|---|---|
| committer | madelinegr <mgriswold99@gmail.com> | 2019-02-12 18:55:11 -0500 |
| commit | 1d667d19f5402dc9f9069e0a57008dac96f6de2a (patch) | |
| tree | 59572ebc84ae0dea9780c96a6d43a811a21fed10 /src/views | |
| parent | 7a93f60c9529e5d175e617fc7c07145a9b33e572 (diff) | |
set up web box classes
Diffstat (limited to 'src/views')
| -rw-r--r-- | src/views/freeformcanvas/CollectionFreeFormView.scss | 15 | ||||
| -rw-r--r-- | src/views/freeformcanvas/CollectionFreeFormView.tsx | 98 | ||||
| -rw-r--r-- | src/views/freeformcanvas/FreeFormCanvas.scss | 15 | ||||
| -rw-r--r-- | src/views/freeformcanvas/FreeFormCanvas.tsx | 86 | ||||
| -rw-r--r-- | src/views/nodes/DocumentView.tsx | 134 | ||||
| -rw-r--r-- | src/views/nodes/FieldTextBox.tsx | 117 | ||||
| -rw-r--r-- | src/views/nodes/NodeView.scss | 31 | ||||
| -rw-r--r-- | src/views/nodes/RichTextView.tsx | 0 | ||||
| -rw-r--r-- | src/views/nodes/TextNodeView.tsx | 28 | ||||
| -rw-r--r-- | src/views/nodes/TopBar.tsx | 46 | ||||
| -rw-r--r-- | src/views/nodes/VideoNodeView.scss | 5 | ||||
| -rw-r--r-- | src/views/nodes/VideoNodeView.tsx | 29 |
12 files changed, 604 insertions, 0 deletions
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.scss b/src/views/freeformcanvas/CollectionFreeFormView.scss new file mode 100644 index 000000000..cb4805eb3 --- /dev/null +++ b/src/views/freeformcanvas/CollectionFreeFormView.scss @@ -0,0 +1,15 @@ +.collectionfreeformview-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + + .collectionfreeformview { + position: absolute; + top: 0; + left: 0; + } +} + diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx new file mode 100644 index 000000000..d5343536d --- /dev/null +++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx @@ -0,0 +1,98 @@ +import { observer } from "mobx-react"; +import { Key, KeyStore } from "../../fields/Key"; +import "./FreeFormCanvas.scss"; +import React = require("react"); +import { action } from "mobx"; +import { Document } from "../../fields/Document"; +import { DocumentViewModel } from "../../viewmodels/DocumentViewModel"; +import { DocumentView } from "../nodes/DocumentView"; +import { ListField } from "../../fields/ListField"; +import { NumberField } from "../../fields/NumberField"; +import { SSL_OP_SINGLE_DH_USE } from "constants"; + +interface IProps { + fieldKey: Key; + doc: Document; +} + +@observer +export class CollectionFreeFormView extends React.Component<IProps> { + + private _isPointerDown: boolean = false; + + constructor(props: IProps) { + super(props); + } + + @action + onPointerDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + this._isPointerDown = true; + document.removeEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + } + + @action + onPointerUp = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + this._isPointerDown = false; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + } + } + + @action + onPointerMove = (e: PointerEvent): void => { + e.preventDefault(); + e.stopPropagation(); + if (!this._isPointerDown) { + return; + } + const { doc } = this.props; + let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + doc.SetFieldValue(KeyStore.PanX, x + e.movementX, NumberField); + doc.SetFieldValue(KeyStore.PanY, y + e.movementY, NumberField); + } + + @action + onPointerWheel = (e: React.WheelEvent): void => { + e.stopPropagation(); + + let scaleAmount = 1 - (e.deltaY / 1000); + //this.props.store.Scale *= scaleAmount; + } + + render() { + const { fieldKey, doc } = this.props; + const value: Document[] = doc.GetFieldValue(fieldKey, ListField, []); + const panx: number = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + const pany: number = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + return ( + + <div className="border" style={{ + borderStyle: "solid", + borderWidth: "2px" + }}> + <div className="collectionfreeformview-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()} style={{ + width: "100%", + height: "calc(100% - 4px)", + overflow: "hidden" + }}> + <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px)`, transformOrigin: '50% 50%' }}> + <div className="node-container"> + {value.map(doc => { + return (<DocumentView key={doc.Id} dvm={new DocumentViewModel(doc)} />); + })} + </div> + </div> + </div> + </div> + ); + } +}
\ No newline at end of file diff --git a/src/views/freeformcanvas/FreeFormCanvas.scss b/src/views/freeformcanvas/FreeFormCanvas.scss new file mode 100644 index 000000000..884ef90e6 --- /dev/null +++ b/src/views/freeformcanvas/FreeFormCanvas.scss @@ -0,0 +1,15 @@ +.freeformcanvas-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + + .freeformcanvas { + position: absolute; + top: 0; + left: 0; + } +} + diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx new file mode 100644 index 000000000..9ef5ab8f7 --- /dev/null +++ b/src/views/freeformcanvas/FreeFormCanvas.tsx @@ -0,0 +1,86 @@ +import { observer } from "mobx-react"; +import { Key } from "../../fields/Key"; +import { NodeCollectionStore } from "../../stores/NodeCollectionStore"; +import "./FreeFormCanvas.scss"; +import React = require("react"); +import { action } from "mobx"; +import { Document } from "../../fields/Document"; +import {DocumentViewModel} from "../../viewmodels/DocumentViewModel"; +import {DocumentView} from "../nodes/DocumentView"; +import {TextField} from "../../fields/TextField"; +import {ListField} from "../../fields/ListField"; +import {Field} from "../../fields/Field"; + +interface IProps { + store: NodeCollectionStore; +} + +@observer +export class FreeFormCanvas extends React.Component<IProps> { + + private _isPointerDown: boolean = false; + + constructor(props:IProps) { + super(props); + } + + @action + onPointerDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + this._isPointerDown = true; + document.removeEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + } + + @action + onPointerUp = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + this._isPointerDown = false; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + } + + // let doc = this.props.store.Docs[0]; + // let dataField = doc.GetFieldT(KeyStore.Data, TextField); + // let data = dataField ? dataField.Data : ""; + // this.props.store.Docs[0].SetFieldValue(KeyStore.Data, data + " hello", TextField); + } + + @action + onPointerMove = (e: PointerEvent): void => { + e.stopPropagation(); + if (!this._isPointerDown) { + return; + } + this.props.store.X += e.movementX; + this.props.store.Y += e.movementY; + } + + @action + onPointerWheel = (e: React.WheelEvent): void => { + e.stopPropagation(); + + let scaleAmount = 1 - (e.deltaY / 1000); + this.props.store.Scale *= scaleAmount; + } + + render() { + let store = this.props.store; + return ( + <div className="freeformcanvas-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()}> + <div className="freeformcanvas" style={{ transform: store.Transform, transformOrigin: '50% 50%' }}> + <div className="node-container"> + {this.props.store.Docs.map(doc => { + return (<DocumentView key={doc.Id} dvm={new DocumentViewModel(doc)} />); + })} + </div> + </div> + </div> + ); + } +}
\ No newline at end of file diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx new file mode 100644 index 000000000..f955a8c39 --- /dev/null +++ b/src/views/nodes/DocumentView.tsx @@ -0,0 +1,134 @@ +import { observer } from "mobx-react"; +import React = require("react"); +import { computed } from "mobx"; +import { KeyStore, Key } from "../../fields/Key"; +import { NumberField } from "../../fields/NumberField"; +import { TextField } from "../../fields/TextField"; +import { DocumentViewModel } from "../../viewmodels/DocumentViewModel"; +import { ListField } from "../../fields/ListField"; +import { FieldTextBox } from "../nodes/FieldTextBox" +import { FreeFormCanvas } from "../freeformcanvas/FreeFormCanvas" +import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView" +import "./NodeView.scss" +const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? + +interface IProps { + dvm: DocumentViewModel; +} + +@observer +export class DocumentView extends React.Component<IProps> { + @computed + get x(): number { + return this.props.dvm.Doc.GetFieldValue(KeyStore.X, NumberField, Number(0)); + } + + @computed + get y(): number { + return this.props.dvm.Doc.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + } + + set x(x: number) { + this.props.dvm.Doc.SetFieldValue(KeyStore.X, x, NumberField) + } + + set y(y: number) { + this.props.dvm.Doc.SetFieldValue(KeyStore.Y, y, NumberField) + } + + @computed + get transform(): string { + return `translate(${this.x}px, ${this.y}px)`; + } + + @computed + get width(): number { + return this.props.dvm.Doc.GetFieldValue(KeyStore.Width, NumberField, Number(0)); + } + + @computed + get height(): number { + return this.props.dvm.Doc.GetFieldValue(KeyStore.Height, NumberField, Number(0)); + } + + @computed + get layout(): string { + return this.props.dvm.Doc.GetFieldValue(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>")); + } + + @computed + get layoutKeys(): Key[] { + return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array<Key>()); + } + + @computed + get layoutFields(): Key[] { + return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutFields, ListField, new Array<Key>()); + } + + private _isPointerDown = false; + + onPointerDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + this._isPointerDown = true; + document.removeEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + } + + onPointerUp = (e: PointerEvent): void => { + e.stopPropagation(); + if (e.button === 2) { + e.preventDefault(); + this._isPointerDown = false; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + } + } + + onPointerMove = (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + if (!this._isPointerDown) { + return; + } + this.x += e.movementX; + this.y += e.movementY; + } + + render() { + let doc = this.props.dvm.Doc; + let bindings: any = { + doc: doc + }; + for (const key of this.layoutKeys) { + bindings[key.Name + "Key"] = key; + } + for (const key of this.layoutFields) { + let field = doc.GetField(key); + if (field) { + bindings[key.Name] = field.GetValue(); + } + } + return ( + <div className="node" style={{ + transform: this.transform, + width: this.width, + height: this.height + }} onPointerDown={this.onPointerDown} onContextMenu={ + (e) => { + e.preventDefault() + }}> + <JsxParser + components={{ FieldTextBox, FreeFormCanvas, CollectionFreeFormView }} + bindings={bindings} + jsx={this.layout} + /> + </div> + ); + } + +}
\ No newline at end of file diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx new file mode 100644 index 000000000..dbac3906a --- /dev/null +++ b/src/views/nodes/FieldTextBox.tsx @@ -0,0 +1,117 @@ +import { Key, KeyStore } from "../../fields/Key"; +import { Document } from "../../fields/Document"; +import { observer } from "mobx-react"; +import { TextField } from "../../fields/TextField"; +import React = require("react") +import { action, observable, reaction, IReactionDisposer } from "mobx"; + +import {schema} from "prosemirror-schema-basic"; +import {EditorState, Transaction} from "prosemirror-state" +import {EditorView} from "prosemirror-view" +import {keymap} from "prosemirror-keymap" +import {baseKeymap} from "prosemirror-commands" +import {undo, redo, history} from "prosemirror-history" +import { Opt } from "../../fields/Field"; + +interface IProps { + fieldKey:Key; + doc:Document; +} + +// FieldTextBox: Displays an editable plain text node that maps to a specified Key of a Document +// +// HTML Markup: <FieldTextBox Doc={Document's ID} FieldKey={Key's name + "Key"} +// +// In Code, the node's HTML is specified in the document's parameterized structure as: +// document.SetField(KeyStore.Layout, "<FieldTextBox doc={doc} fieldKey={<KEYNAME>Key} />"); +// and the node's binding to the specified document KEYNAME as: +// document.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.<KEYNAME>])); +// The Jsx parser at run time will bind: +// 'fieldKey' property to the Key stored in LayoutKeys +// and 'doc' property to the document that is being rendered +// +// When rendered() by React, this extracts the TextController from the Document stored at the +// specified Key and assigns it to an HTML input node. When changes are made tot his node, +// this will edit the document and assign the new value to that field. +// +@observer +export class FieldTextBox extends React.Component<IProps> { + private _ref: React.RefObject<HTMLDivElement>; + private _editorView: Opt<EditorView>; + private _reactionDisposer: Opt<IReactionDisposer>; + + constructor(props:IProps) { + super(props); + + this._ref = React.createRef(); + + this.onChange = this.onChange.bind(this); + } + + dispatchTransaction = (tx: Transaction) => { + if(this._editorView) { + const state = this._editorView.state.apply(tx); + this._editorView.updateState(state); + const {doc, fieldKey} = this.props; + doc.SetFieldValue(fieldKey, JSON.stringify(state.toJSON()), TextField); + } + } + + componentDidMount() { + let state:EditorState; + const {doc, fieldKey} = this.props; + const config = { + schema, + plugins: [ + history(), + keymap({"Mod-z": undo, "Mod-y": redo}), + keymap(baseKeymap) + ] + }; + + let field = doc.GetFieldT(fieldKey, TextField); + if(field) { + 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 + }); + } + + this._reactionDisposer = reaction(() => { + const field = this.props.doc.GetFieldT(this.props.fieldKey, TextField); + return field ? field.Data : undefined; + }, (field) => { + if(field && this._editorView) { + this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))); + } + }) + } + + componentWillUnmount() { + if(this._editorView) { + this._editorView.destroy(); + } + if(this._reactionDisposer) { + this._reactionDisposer(); + } + } + + shouldComponentUpdate() { + return false; + } + + @action + onChange(e: React.ChangeEvent<HTMLInputElement>) { + const {fieldKey, doc} = this.props; + doc.SetFieldValue(fieldKey, e.target.value, TextField); + } + + render() { + return (<div ref={this._ref} />) + } +}
\ No newline at end of file diff --git a/src/views/nodes/NodeView.scss b/src/views/nodes/NodeView.scss new file mode 100644 index 000000000..a68335f87 --- /dev/null +++ b/src/views/nodes/NodeView.scss @@ -0,0 +1,31 @@ +.node { + position: absolute; + background: #cdcdcd; + + overflow: hidden; + + + &.minimized { + width: 30px; + height: 30px; + } + + .top { + background: #232323; + height: 20px; + cursor: pointer; + } + + .content { + padding: 20px 20px; + height: auto; + box-sizing: border-box; + + } + + .scroll-box { + overflow-y: scroll; + height: calc(100% - 20px); + } +} + diff --git a/src/views/nodes/RichTextView.tsx b/src/views/nodes/RichTextView.tsx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/views/nodes/RichTextView.tsx diff --git a/src/views/nodes/TextNodeView.tsx b/src/views/nodes/TextNodeView.tsx new file mode 100644 index 000000000..4831e658c --- /dev/null +++ b/src/views/nodes/TextNodeView.tsx @@ -0,0 +1,28 @@ +import { observer } from "mobx-react"; +import { StaticTextNodeStore } from "../../stores/StaticTextNodeStore"; +import "./NodeView.scss"; +import { TopBar } from "./TopBar"; +import React = require("react"); + +interface IProps { + store: StaticTextNodeStore; +} + +@observer +export class TextNodeView extends React.Component<IProps> { + + render() { + let store = this.props.store; + return ( + <div className="node text-node" style={{ transform: store.Transform }}> + <TopBar store={store} /> + <div className="scroll-box"> + <div className="content"> + <h3 className="title">{store.Title}</h3> + <p className="paragraph">{store.Text}</p> + </div> + </div> + </div> + ); + } +}
\ No newline at end of file diff --git a/src/views/nodes/TopBar.tsx b/src/views/nodes/TopBar.tsx new file mode 100644 index 000000000..bb126e8b5 --- /dev/null +++ b/src/views/nodes/TopBar.tsx @@ -0,0 +1,46 @@ +import { observer } from "mobx-react"; +import { NodeStore } from "../../stores/NodeStore"; +import "./NodeView.scss"; +import React = require("react"); + +interface IProps { + store: NodeStore; +} + +@observer +export class TopBar extends React.Component<IProps> { + + private _isPointerDown = false; + + onPointerDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + this._isPointerDown = true; + document.removeEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + + onPointerUp = (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + this._isPointerDown = false; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + } + + onPointerMove = (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + if (!this._isPointerDown) { + return; + } + this.props.store.X += e.movementX; + this.props.store.Y += e.movementY; + } + + render() { + return <div className="top" onPointerDown={this.onPointerDown}></div> + } +} diff --git a/src/views/nodes/VideoNodeView.scss b/src/views/nodes/VideoNodeView.scss new file mode 100644 index 000000000..f412c3519 --- /dev/null +++ b/src/views/nodes/VideoNodeView.scss @@ -0,0 +1,5 @@ +.node { + video { + width: 100%; + } +}
\ No newline at end of file diff --git a/src/views/nodes/VideoNodeView.tsx b/src/views/nodes/VideoNodeView.tsx new file mode 100644 index 000000000..0a7b3d174 --- /dev/null +++ b/src/views/nodes/VideoNodeView.tsx @@ -0,0 +1,29 @@ +import { observer } from "mobx-react"; +import { VideoNodeStore } from "../../stores/VideoNodeStore"; +import "./NodeView.scss"; +import { TopBar } from "./TopBar"; +import "./VideoNodeView.scss"; +import React = require("react"); + +interface IProps { + store: VideoNodeStore; +} + +@observer +export class VideoNodeView extends React.Component<IProps> { + + render() { + let store = this.props.store; + return ( + <div className="node text-node" style={{ transform: store.Transform }}> + <TopBar store={store} /> + <div className="scroll-box"> + <div className="content"> + <h3 className="title">{store.Title}</h3> + <video src={store.Url} controls /> + </div> + </div> + </div> + ); + } +}
\ No newline at end of file |
