diff options
author | madelinegr <laura_wilson@brown.edu> | 2019-02-28 00:20:14 -0500 |
---|---|---|
committer | madelinegr <laura_wilson@brown.edu> | 2019-02-28 00:20:14 -0500 |
commit | 23387df535e9ab87a08196aab19de6f937ae9bba (patch) | |
tree | ef5ea77a362d0884ee1cbfe7fa87bfe88c6f4e87 | |
parent | 4d356d098e44d3d736358d166e905aec1de9c4d6 (diff) |
finished kvp
-rw-r--r-- | package-lock.json | 21 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 16 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 14 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValuePair.tsx | 68 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValuePane.tsx | 176 | ||||
-rw-r--r-- | src/fields/KVPField | 0 | ||||
-rw-r--r-- | src/fields/KVPField.ts | 30 |
10 files changed, 198 insertions, 138 deletions
diff --git a/package-lock.json b/package-lock.json index d03e78a2d..75e6cae17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3285,11 +3285,6 @@ } } }, - "font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" - }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3399,13 +3394,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3422,8 +3415,7 @@ }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", @@ -3552,7 +3544,6 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -10434,14 +10425,6 @@ "scheduler": "^0.12.0" } }, - "react-fontawesome": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/react-fontawesome/-/react-fontawesome-1.6.1.tgz", - "integrity": "sha1-7dzhfn3HMaoJ/UoYZoimF5OhbFw=", - "requires": { - "prop-types": "^15.5.6" - } - }, "react-golden-layout": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-golden-layout/-/react-golden-layout-1.0.6.tgz", diff --git a/package.json b/package.json index 8568a7bef..ae7a7b25c 100644 --- a/package.json +++ b/package.json @@ -116,4 +116,4 @@ "url-loader": "^1.1.2", "uuid": "^3.3.2" } -}
\ No newline at end of file +} diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ba13cc31b..41f1c9b3f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -13,6 +13,8 @@ import { CollectionView, CollectionViewType } from "../views/collections/Collect import { HtmlField } from "../../fields/HtmlField"; import { Key } from "../../fields/Key" import { Field } from "../../fields/Field"; +import { KeyValuePane } from "../views/nodes/KeyValuePane" +import { KVPField } from "../../fields/KVPField"; export interface DocumentOptions { x?: number; @@ -35,10 +37,12 @@ export namespace Documents { let imageProto: Document; let webProto: Document; let collProto: Document; + let kvpProto: Document; const textProtoId = "textProto"; const imageProtoId = "imageProto"; const webProtoId = "webProto"; const collProtoId = "collectionProto"; + const kvpProtoId = "kvpProto"; export function initProtos(mainDocId: string, callback: (mainDoc?: Document) => void) { Server.GetFields([collProtoId, textProtoId, imageProtoId, mainDocId], (fields) => { @@ -46,6 +50,7 @@ export namespace Documents { imageProto = fields[imageProtoId] as Document; textProto = fields[textProtoId] as Document; webProto = fields[webProtoId] as Document; + kvpProto = fields[kvpProtoId] as Document; callback(fields[mainDocId] as Document) }); } @@ -98,6 +103,12 @@ export namespace Documents { { panx: 0, pany: 0, scale: 1, layoutKeys: [KeyStore.Data] }); } + function GetKVPPrototype(): Document { + return kvpProto ? kvpProto : + kvpProto = setupPrototypeOptions(kvpProtoId, "KVP_PROTO", KeyValuePane.LayoutString(), + { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }) + } + export function ImageDocument(url: string, options: DocumentOptions = {}) { let doc = SetInstanceOptions(GetImagePrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }, new URL(url), ImageField); @@ -124,6 +135,11 @@ export namespace Documents { export function DockDocument(config: string, options: DocumentOptions, id?: string) { return SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Docking }, config, TextField, id) } + export function KVPDocument(document: Document, options: DocumentOptions = {}, id?: string) { + var deleg = GetKVPPrototype().MakeDelegate(id); + deleg.Set(KeyStore.Data, document); + return assignOptions(deleg, options); + } diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 29d254e56..137bcf706 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -194,12 +194,6 @@ export class CollectionFreeFormView extends CollectionViewBase { }); } - @action - addKVP(doc: Document) { - let fields = doc.fields; - //TODO: return kvpg - } - @computed get backgroundLayout(): string | undefined { let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField); if (field && field !== "<Waiting>") { @@ -266,7 +260,6 @@ export class CollectionFreeFormView extends CollectionViewBase { } 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; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d1706c80c..23cfa6df3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -20,13 +20,9 @@ import { KeyValuePane } from "../nodes/KeyValuePane" import { WebBox } from "../nodes/WebBox"; import "./DocumentView.scss"; import React = require("react"); +import { CollectionViewProps } from "../collections/CollectionViewBase"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? -/* - if containingcollectionview is CollectionFreeformView: - (ContainingCollectionView as CollectionFreeformView)?.addKVP -*/ - export interface DocumentViewProps { ContainingCollectionView: Opt<CollectionView>; @@ -161,8 +157,8 @@ export class DocumentView extends React.Component<DocumentViewProps> { } fieldsClicked = (e: React.MouseEvent): void => { - if (this.props.ContainingCollectionView) { - (this.props.ContainingCollectionView as unknown as CollectionFreeFormView).addKVP(this.props.Document); + if (this.props.AddDocument) { + this.props.AddDocument(Documents.KVPDocument(this.props.Document)); } } fullScreenClicked = (e: React.MouseEvent): void => { @@ -190,7 +186,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { e.preventDefault() ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) - ContextMenu.Instance.addItem({ description: "Fields", event: () => this.fieldsClicked }) + ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }) 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) }) @@ -209,7 +205,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { @computed get mainContent() { return <JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValuePane }} bindings={this._documentBindings} jsx={this.layout} showWarnings={true} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f372258f8..056f834d1 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -12,6 +12,8 @@ import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; import { WebBox } from "./WebBox"; +import { KVPField } from "../../../fields/KVPField"; +import { KeyValuePane } from "./KeyValuePane"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx new file mode 100644 index 000000000..bc407f137 --- /dev/null +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -0,0 +1,68 @@ +import Lightbox from 'react-image-lightbox'; +import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app +import "./KeyValuePane.scss"; +import React = require("react") +import { FieldViewProps, FieldView } from './FieldView'; +import { FieldWaiting, Opt, Field } from '../../../fields/Field'; +import { observer } from "mobx-react" +import { observable, action, IReactionDisposer, reaction, ObservableMap } from 'mobx'; +import { KeyStore } from '../../../fields/KeyStore'; +import { RichTextField } from "../../../fields/RichTextField"; +import { element } from 'prop-types'; +import { props } from 'bluebird'; +import { EditorView } from 'prosemirror-view'; +import { Transaction, EditorState } from 'prosemirror-state'; +import { schema } from 'prosemirror-schema-basic'; +import { keymap } from 'prosemirror-keymap'; +import { undo, redo } from 'prosemirror-history'; +import { baseKeymap } from 'prosemirror-commands'; +import { KVPField } from '../../../fields/KVPField'; +import { Document } from '../../../fields/Document'; +import { Key } from '../../../fields/Key'; +import { JSXElement } from 'babel-types'; +import { Server } from "../../Server" + +// Represents one row in a key value plane + +export interface KeyValuePairProps { + fieldId: string; + doc: Document; +} +@observer +export class KeyValuePair extends React.Component<KeyValuePairProps> { + + @observable + private key: Opt<Key> + + constructor(props: KeyValuePairProps) { + super(props); + Server.GetField(this.props.fieldId, + action((field: Opt<Field>) => { + if (field) { + this.key = field as Key; + } + })); + + } + + + + render() { + if (!this.key) { + return <tr><td>error</td><td></td></tr> + + } + let props: FieldViewProps = { + doc: this.props.doc, + fieldKey: this.key, + isSelected: () => false, + select: () => { }, + isTopMost: false, + bindings: {}, + selectOnLoad: false, + } + return ( + <tr><td>{this.key.Name}</td><td><FieldView {...props} /></td></tr> + ) + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/KeyValuePane.tsx b/src/client/views/nodes/KeyValuePane.tsx index 26d5ed9fd..90f5b653c 100644 --- a/src/client/views/nodes/KeyValuePane.tsx +++ b/src/client/views/nodes/KeyValuePane.tsx @@ -4,121 +4,93 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once import "./KeyValuePane.scss"; import React = require("react") import { FieldViewProps, FieldView } from './FieldView'; -import { FieldWaiting } from '../../../fields/Field'; +import { FieldWaiting, Opt, Field } from '../../../fields/Field'; import { observer } from "mobx-react" -import { observable, action } from 'mobx'; +import { observable, action, IReactionDisposer, reaction, ObservableMap } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; +import { RichTextField } from "../../../fields/RichTextField"; import { element } from 'prop-types'; import { props } from 'bluebird'; +import { EditorView } from 'prosemirror-view'; +import { Transaction, EditorState } from 'prosemirror-state'; +import { schema } from 'prosemirror-schema-basic'; +import { keymap } from 'prosemirror-keymap'; +import { undo, redo } from 'prosemirror-history'; +import { baseKeymap } from 'prosemirror-commands'; +import { KVPField } from '../../../fields/KVPField'; +import { Document } from '../../../fields/Document'; +import { Key } from '../../../fields/Key'; +import { JSXElement } from 'babel-types'; +import { KeyValuePair } from "./KeyValuePair" @observer -export class KeyValuePane extends React.Component/*<FieldViewProps>*/ { +export class KeyValuePane extends React.Component<FieldViewProps> { - public static LayoutString() { return FieldView.LayoutString(KeyValuePane) } - //private _ref: React.RefObject<HTMLDivElement>; - // private _downX: number = 0; - // private _downY: number = 0; - // private _lastTap: number = 0; - // @observable private _photoIndex: number = 0; - // @observable private _isOpen: boolean = false; + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValuePane, fieldStr) } + private _ref: React.RefObject<HTMLDivElement>; + private _editorView: Opt<EditorView>; + private _reactionDisposer: Opt<IReactionDisposer>; - constructor() { + + constructor(props: FieldViewProps) { super(props); + + this._ref = React.createRef(); + } + + + + shouldComponentUpdate() { + return false; + } + + + onPointerDown = (e: React.PointerEvent): void => { + if (e.buttons === 1 && this.props.isSelected()) { + e.stopPropagation(); + } + } + onPointerWheel = (e: React.WheelEvent): void => { + e.stopPropagation(); + } + + createTable = () => { + let table: Array<JSX.Element> = [] + let ret = "waiting" + let doc = this.props.doc.GetT(KeyStore.Data, Document); + if (!doc || doc == "<Waiting>") { + return <tr><td>Loading...</td></tr> + } + let realDoc = doc; + + let ids: { [key: string]: string } = {}; + let protos = doc.GetAllPrototypes(); + for (const proto of protos) { + proto._proxies.forEach((val, key) => { + if (!(key in ids)) { + ids[key] = key; + } + }) + } + + let rows: JSX.Element[] = []; + for (let key in ids) { + rows.push(<KeyValuePair doc={realDoc} fieldId={key} />) + } + return rows; } - // constructor(props: FieldViewProps) { - // super(props); - - // // this._ref = React.createRef(); - // // this._imgRef = React.createRef(); - // // this.state = { - // // photoIndex: 0, - // // isOpen: false, - // // }; - // } - - // @action - // onLoad = (target: any) => { - // var h = this._imgRef.current!.naturalHeight; - // var w = this._imgRef.current!.naturalWidth; - // this.props.doc.SetNumber(KeyStore.NativeHeight, this.props.doc.GetNumber(KeyStore.NativeWidth, 0) * h / w) - // } - - // componentDidMount() { - // } - - // componentWillUnmount() { - // } - - // onPointerDown = (e: React.PointerEvent): void => { - // if (Date.now() - this._lastTap < 300) { - // if (e.buttons === 1 && this.props.isSelected()) { - // e.stopPropagation(); - // this._downX = e.clientX; - // this._downY = e.clientY; - // document.removeEventListener("pointerup", this.onPointerUp); - // document.addEventListener("pointerup", this.onPointerUp); - // } - // } else { - // this._lastTap = Date.now(); - // } - // } - // @action - // onPointerUp = (e: PointerEvent): void => { - // document.removeEventListener("pointerup", this.onPointerUp); - // if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { - // this._isOpen = true; - // } - // e.stopPropagation(); - // } - - // lightbox = (path: string) => { - // const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"]; - // if (this._isOpen && this.props.isSelected()) { - // return (<Lightbox - // mainSrc={images[this._photoIndex]} - // nextSrc={images[(this._photoIndex + 1) % images.length]} - // prevSrc={images[(this._photoIndex + images.length - 1) % images.length]} - // onCloseRequest={action(() => - // this._isOpen = false - // )} - // onMovePrevRequest={action(() => - // this._photoIndex = (this._photoIndex + images.length - 1) % images.length - // )} - // onMoveNextRequest={action(() => - // this._photoIndex = (this._photoIndex + 1) % images.length - // )} - // />) - // } - // } + 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} > - // <img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} /> - // {this.lightbox(path)} - // </div>) - console.log("bleh"); + return (<table> - <tr> - <th>Key</th> - <th>Fields</th> - </tr> - <tr> - <td>Jill</td> - <td>Smith</td> - </tr> - <tr> - <td>Eve</td> - <td>Jackson</td> - </tr> - <tr> - <td>John</td> - <td>Doe</td> - </tr> + <tbody> + <tr> + <th>Key</th> + <th>Fields</th> + </tr> + {this.createTable()} + </tbody> </table>) } }
\ No newline at end of file diff --git a/src/fields/KVPField b/src/fields/KVPField new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/fields/KVPField diff --git a/src/fields/KVPField.ts b/src/fields/KVPField.ts new file mode 100644 index 000000000..a7ecc0768 --- /dev/null +++ b/src/fields/KVPField.ts @@ -0,0 +1,30 @@ +import { BasicField } from "./BasicField" +import { FieldId } from "./Field"; +import { Types } from "../server/Message"; +import { Document } from "./Document" + +export class KVPField extends BasicField<Document> { + constructor(data: Document | undefined = undefined, id?: FieldId, save: boolean = true) { + super(data == undefined ? new Document() : data, save, id); + } + + toString(): string { + return this.Data.Title; + } + + ToScriptString(): string { + return `new KVPField("${this.Data}")`; + } + + Copy() { + return new KVPField(this.Data); + } + + ToJson(): { type: Types, data: Document, _id: string } { + return { + type: Types.Text, + data: this.Data, + _id: this.Id + } + } +}
\ No newline at end of file |