diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Main.tsx | 10 | ||||
-rw-r--r-- | src/documents/Documents.ts | 30 | ||||
-rw-r--r-- | src/fields/Document.ts | 28 | ||||
-rw-r--r-- | src/fields/Key.ts | 28 | ||||
-rw-r--r-- | src/util/DragManager.ts | 14 | ||||
-rw-r--r-- | src/views/collections/CollectionDockingView.tsx | 3 | ||||
-rw-r--r-- | src/views/collections/CollectionFreeFormView.tsx | 16 | ||||
-rw-r--r-- | src/views/collections/CollectionSchemaView.scss | 0 | ||||
-rw-r--r-- | src/views/collections/CollectionSchemaView.tsx | 49 | ||||
-rw-r--r-- | src/views/nodes/DocumentView.tsx | 26 | ||||
-rw-r--r-- | src/views/nodes/FieldTextBox.tsx | 11 | ||||
-rw-r--r-- | src/views/nodes/FieldView.tsx | 31 |
12 files changed, 192 insertions, 54 deletions
diff --git a/src/Main.tsx b/src/Main.tsx index 56065b946..8c91399b1 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -16,6 +16,7 @@ import { CollectionFreeFormView } from './views/collections/CollectionFreeFormVi import { ListField } from './fields/ListField'; import { DocumentView } from './views/nodes/DocumentView'; import { ContextMenu } from './views/ContextMenu'; +import { TextField } from './fields/TextField'; configure({ enforceActions: "observed" @@ -48,7 +49,14 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { x: 450, y: 500, title: "cat 1" }); - let docset = new Array<Document>(doc1, doc2, doc3); + 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].SetFieldValue(KS.Author, "Tyler", TextField); + schemaDocs[4].SetFieldValue(KS.Author, "Bob", TextField); + schemaDocs.push(doc2); + const doc7 = Documents.SchemaDocument(schemaDocs) + const docset = [doc1, doc2, doc3, doc7]; let doc4 = Documents.CollectionDocument(docset, { x: 0, y: 400, title: "mini collection" }); diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts index 318a6d7a3..73cf483ef 100644 --- a/src/documents/Documents.ts +++ b/src/documents/Documents.ts @@ -5,6 +5,7 @@ import { NumberField } from "../fields/NumberField"; import { ListField } from "../fields/ListField"; import { FieldTextBox } from "../views/nodes/FieldTextBox"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { CollectionSchemaView } from "../views/collections/CollectionSchemaView"; interface DocumentOptions { x?: number; @@ -45,7 +46,7 @@ export namespace Documents { textProto.SetField(KeyStore.Width, new NumberField(300)); textProto.SetField(KeyStore.Height, new NumberField(150)); textProto.SetField(KeyStore.Layout, new TextField(FieldTextBox.LayoutString())); - textProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ])); + textProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return textProto; } @@ -57,6 +58,27 @@ export namespace Documents { return doc; } + let schemaProto: Document; + function GetSchemaPrototype(): Document { + if (!schemaProto) { + schemaProto = new Document(); + schemaProto.SetField(KeyStore.X, new NumberField(0)); + schemaProto.SetField(KeyStore.Y, new NumberField(0)); + schemaProto.SetField(KeyStore.Width, new NumberField(300)); + schemaProto.SetField(KeyStore.Height, new NumberField(150)); + schemaProto.SetField(KeyStore.Layout, new TextField(CollectionSchemaView.LayoutString())); + schemaProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); + } + return schemaProto; + } + + export function SchemaDocument(documents: Array<Document>, options: DocumentOptions = {}): Document { + let doc = GetSchemaPrototype().MakeDelegate(); + setupOptions(doc, options); + doc.SetField(KeyStore.Data, new ListField(documents)); + return doc; + } + let dockProto: Document; function GetDockPrototype(): Document { @@ -67,7 +89,7 @@ export namespace Documents { dockProto.SetField(KeyStore.Width, new NumberField(300)); dockProto.SetField(KeyStore.Height, new NumberField(150)); dockProto.SetField(KeyStore.Layout, new TextField(CollectionDockingView.LayoutString())); - dockProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ])); + dockProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return dockProto; } @@ -90,7 +112,7 @@ export namespace Documents { imageProto.SetField(KeyStore.Height, new NumberField(300)); imageProto.SetField(KeyStore.Layout, new TextField('<img src={Data} draggable="false" width="100%" alt="Image not found"/>')); // imageProto.SetField(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />')); - imageProto.SetField(KeyStore.LayoutFields, new ListField([ KeyStore.Data ])); + imageProto.SetField(KeyStore.LayoutFields, new ListField([KeyStore.Data])); } return imageProto; } @@ -114,7 +136,7 @@ export namespace Documents { collectionProto.SetField(KeyStore.Width, new NumberField(300)); collectionProto.SetField(KeyStore.Height, new NumberField(300)); collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>')); - collectionProto.SetField(KeyStore.LayoutKeys, new ListField([ KeyStore.Data ])); + collectionProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return collectionProto; } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 9580ab5c0..5c0a9caf0 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -1,7 +1,9 @@ import { Field, Cast, Opt } from "./Field" import { Key, KeyStore } from "./Key" +import { NumberField } from "./NumberField"; import { ObservableMap, computed } from "mobx"; import { TextField } from "./TextField"; +import { ListField } from "./ListField"; export class Document extends Field { private fields: ObservableMap<Key, Field> = new ObservableMap(); @@ -30,17 +32,39 @@ export class Document extends Field { return field; } - GetFieldT<T extends Field = Field>(key: Key, ctor: { new(): T }, ignoreProto?: boolean): Opt<T> { + GetFieldT<T extends Field = Field>(key: Key, ctor: { new(): T }, ignoreProto: boolean = false): Opt<T> { return Cast(this.GetField(key, ignoreProto), ctor); } + GetFieldOrCreate<T extends Field>(key: Key, ctor: { new(): T }, ignoreProto: boolean = false): T { + const field = this.GetFieldT(key, ctor, ignoreProto); + if (field) { + return field; + } + const newField = new ctor(); + this.SetField(key, newField); + return newField; + } + GetFieldValue<T, U extends { Data: T }>(key: Key, ctor: { new(): U }, defaultVal: T): T { let val = this.GetField(key); let vval = (val && val instanceof ctor) ? val.Data : defaultVal; return vval; } - SetField(key: Key, field: Opt<Field>): void { + GetNumberField(key: Key, defaultVal: number): number { + return this.GetFieldValue(key, NumberField, defaultVal); + } + + GetTextField(key: Key, defaultVal: string): string { + return this.GetFieldValue(key, TextField, defaultVal); + } + + GetListField<T extends Field>(key: Key, defaultVal: T[]): T[] { + return this.GetFieldValue<T[], ListField<T>>(key, ListField, defaultVal) + } + + SetField(key: Key, field: Field | undefined): void { if (field) { this.fields.set(key, field); } else { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 61b3cdd37..4da800fac 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -31,17 +31,19 @@ export class Key extends Field { } export namespace KeyStore { - export let Prototype = new Key("Prototype"); - export let X = new Key("X"); - export let Y = new Key("Y"); - export let Title = new Key("Title"); - export let PanX = new Key("PanX"); - export let PanY = new Key("PanY"); - export let Scale = new Key("Scale"); - export let Width = new Key("Width"); - export let Height = new Key("Height"); - export let Data = new Key("Data"); - export let Layout = new Key("Layout"); - export let LayoutKeys = new Key("LayoutKeys"); - export let LayoutFields = new Key("LayoutFields"); + export const Prototype = new Key("Prototype"); + export const X = new Key("X"); + export const Y = new Key("Y"); + export const Title = new Key("Title"); + export const Author = new Key("Author"); + export const PanX = new Key("PanX"); + export const PanY = new Key("PanY"); + export const Scale = new Key("Scale"); + export const Width = new Key("Width"); + export const Height = new Key("Height"); + export const Data = new Key("Data"); + export const Layout = new Key("Layout"); + export const LayoutKeys = new Key("LayoutKeys"); + export const LayoutFields = new Key("LayoutFields"); + export const ColumnsKey = new Key("SchemaColumns"); }
\ No newline at end of file diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts index a864a2bbe..5b7609819 100644 --- a/src/util/DragManager.ts +++ b/src/util/DragManager.ts @@ -42,7 +42,7 @@ export namespace DragManager { } export class DropEvent { - constructor(readonly x: number, readonly y: number, readonly data: { [ id: string ]: any }) { } + constructor(readonly x: number, readonly y: number, readonly data: { [id: string]: any }) { } } export interface DropHandlers { @@ -53,7 +53,7 @@ export namespace DragManager { if ("canDrop" in element.dataset) { throw new Error("Element is already droppable, can't make it droppable again"); } - element.dataset[ "canDrop" ] = "true"; + element.dataset["canDrop"] = "true"; const handler = (e: Event) => { const ce = e as CustomEvent<DropEvent>; options.handlers.drop(e, ce.detail); @@ -61,14 +61,14 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset[ "canDrop" ] + delete element.dataset["canDrop"] }; } let _lastPointerX: number = 0; let _lastPointerY: number = 0; - export function StartDrag(ele: HTMLElement, dragData: { [ id: string ]: any }, options: DragOptions) { + export function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options: DragOptions) { if (!dragDiv) { dragDiv = document.createElement("div"); DragManager.Root().appendChild(dragDiv); @@ -84,8 +84,8 @@ export namespace DragManager { dragElement.style.transformOrigin = "0 0"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragDiv.appendChild(dragElement); - _lastPointerX = dragData[ "xOffset" ] + rect.left; - _lastPointerY = dragData[ "yOffset" ] + rect.top; + _lastPointerX = dragData["xOffset"] + rect.left; + _lastPointerY = dragData["yOffset"] + rect.top; let hideSource = false; if (typeof options.hideSource === "boolean") { @@ -117,7 +117,7 @@ export namespace DragManager { document.addEventListener("pointerup", upHandler); } - function FinishDrag(dragEle: HTMLElement, e: PointerEvent, options: DragOptions, dragData: { [ index: string ]: any }) { + function FinishDrag(dragEle: HTMLElement, e: PointerEvent, options: DragOptions, dragData: { [index: string]: any }) { dragDiv.removeChild(dragEle); const target = document.elementFromPoint(e.x, e.y); if (!target) { diff --git a/src/views/collections/CollectionDockingView.tsx b/src/views/collections/CollectionDockingView.tsx index d4965645c..a547ea1e8 100644 --- a/src/views/collections/CollectionDockingView.tsx +++ b/src/views/collections/CollectionDockingView.tsx @@ -44,8 +44,7 @@ export class CollectionDockingView extends React.Component<CollectionViewProps> const { fieldKey, Document: Document } = this.props; const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []); var docs = value.map(doc => { - var d = { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } }; - return d; + return { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } }; }); return new GoldenLayout({ settings: { diff --git a/src/views/collections/CollectionFreeFormView.tsx b/src/views/collections/CollectionFreeFormView.tsx index 39a8fc44f..ffb39426d 100644 --- a/src/views/collections/CollectionFreeFormView.tsx +++ b/src/views/collections/CollectionFreeFormView.tsx @@ -35,14 +35,14 @@ export class CollectionFreeFormView extends React.Component<CollectionViewProps> } drop = (e: Event, de: DragManager.DropEvent) => { - const doc = de.data[ "document" ]; + const doc = de.data["document"]; if (doc instanceof DocumentView) { if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) { doc.props.ContainingCollectionView.removeDocument(doc.props.Document); this.addDocument(doc.props.Document); } - const xOffset = de.data[ "xOffset" ] as number || 0; - const yOffset = de.data[ "yOffset" ] as number || 0; + const xOffset = de.data["xOffset"] as number || 0; + const yOffset = de.data["yOffset"] as number || 0; const { scale, translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); let sscale = this.props.ContainingDocumentView!.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)) const screenX = de.x - xOffset; @@ -124,7 +124,7 @@ export class CollectionFreeFormView extends React.Component<CollectionViewProps> e.stopPropagation() e.preventDefault() let fReader = new FileReader() - let file = e.dataTransfer.items[ 0 ].getAsFile(); + let file = e.dataTransfer.items[0].getAsFile(); let that = this; const panx: number = this.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); const pany: number = this.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); @@ -175,10 +175,10 @@ export class CollectionFreeFormView extends React.Component<CollectionViewProps> render() { const { fieldKey, Document: Document } = this.props; - const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []); - const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); - const pany: number = Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); - const currScale: number = Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + const value: Document[] = Document.GetListField<Document>(fieldKey, []); + const panx: number = Document.GetNumberField(KeyStore.PanX, 0); + const pany: number = Document.GetNumberField(KeyStore.PanY, 0); + const currScale: number = Document.GetNumberField(KeyStore.Scale, 1); console.log("DocsR " + value.length); return ( <div className="border" style={{ diff --git a/src/views/collections/CollectionSchemaView.scss b/src/views/collections/CollectionSchemaView.scss new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/views/collections/CollectionSchemaView.scss diff --git a/src/views/collections/CollectionSchemaView.tsx b/src/views/collections/CollectionSchemaView.tsx new file mode 100644 index 000000000..01a5ab639 --- /dev/null +++ b/src/views/collections/CollectionSchemaView.tsx @@ -0,0 +1,49 @@ +import { CollectionViewProps, DocumentFieldViewProps } from "../nodes/DocumentView"; +import React = require("react") +import ReactTable, { ReactTableDefaults, CellInfo } from "react-table"; +import { observer } from "mobx-react"; +import { KeyStore as KS, Key } from "../../fields/Key"; +import { Document } from "../../fields/Document"; +import { FieldView } from "../nodes/FieldView"; +import "react-table/react-table.css" + +@observer +export class CollectionSchemaView extends React.Component<CollectionViewProps> { + public static LayoutString() { return '<CollectionSchemaView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>'; } + + renderCell = (rowProps: CellInfo) => { + if (!this.props.ContainingDocumentView) { + return <div></div> + } + let props: DocumentFieldViewProps = { + doc: rowProps.value[0], + fieldKey: rowProps.value[1], + containingDocumentView: this.props.ContainingDocumentView + } + return <FieldView {...props} /> + } + + render() { + const { Document, fieldKey } = this.props; + const children = Document.GetListField<Document>(fieldKey, []); + const columns = Document.GetListField(KS.ColumnsKey, + [KS.Title, KS.Data, KS.Author]) + return ( + <ReactTable + data={children} + columns={columns.map(col => { + return ( + { + Header: col.Name, + accessor: (doc: Document) => [doc, col], + id: col.Id + }) + })} + column={{ + ...ReactTableDefaults.column, + Cell: this.renderCell + }} + /> + ) + } +}
\ No newline at end of file diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index 147727a67..634cd78be 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -6,6 +6,8 @@ import { Key, KeyStore } from "../../fields/Key"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; +import { CollectionSchemaView } from "../collections/CollectionSchemaView" +import "./NodeView.scss" import { DragManager } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { Utils } from "../../Utils"; @@ -31,6 +33,16 @@ export interface CollectionViewProps { ContainingDocumentView: Opt<DocumentView>; } +// +// these properties get assigned through the render() method of the DocumentView when it creates this node. +// However, that only happens because the properties are "defined" in FieldTextBox's LayoutString() method +// +export interface DocumentFieldViewProps { + fieldKey: Key; + doc: Document; + containingDocumentView: DocumentView +} + export const COLLECTION_BORDER_WIDTH = 2; interface CollectionView { @@ -61,16 +73,16 @@ class DocumentContents extends React.Component<DocumentViewProps> { let doc = this.props.Document; let bindings = { ...this.props } as any; for (const key of this.layoutKeys) { - bindings[ key.Name + "Key" ] = key; + bindings[key.Name + "Key"] = key; } for (const key of this.layoutFields) { let field = doc.GetField(key); if (field) { - bindings[ key.Name ] = field.GetValue(); + bindings[key.Name] = field.GetValue(); } } return <JsxParser - components={{ FieldTextBox, CollectionFreeFormView, CollectionDockingView }} + components={{ FieldTextBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} bindings={bindings} jsx={this.layout} showWarnings={true} @@ -262,10 +274,10 @@ export class DocumentView extends React.Component<DocumentViewProps> { if (this._mainCont.current != null && this.props.ContainingCollectionView != null) { this._contextMenuCanOpen = false; const rect = this.screenRect; - let dragData: { [ id: string ]: any } = {}; - dragData[ "document" ] = this; - dragData[ "xOffset" ] = e.x - rect.left; - dragData[ "yOffset" ] = e.y - rect.top; + let dragData: { [id: string]: any } = {}; + dragData["document"] = this; + dragData["xOffset"] = e.x - rect.left; + dragData["yOffset"] = e.y - rect.top; DragManager.StartDrag(this._mainCont.current, dragData, { handlers: { dragComplete: this.dragComplete, diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx index 45493f0ec..9809f3aed 100644 --- a/src/views/nodes/FieldTextBox.tsx +++ b/src/views/nodes/FieldTextBox.tsx @@ -10,19 +10,10 @@ import { Opt } from "../../fields/Field"; import { Key } from "../../fields/Key"; import { TextField } from "../../fields/TextField"; import { SelectionManager } from "../../util/SelectionManager"; -import { DocumentView } from "./DocumentView"; +import { DocumentView, DocumentFieldViewProps } from "./DocumentView"; import "./FieldTextBox.scss"; import React = require("react") -// -// these properties get assigned through the render() method of the DocumentView when it creates this node. -// However, that only happens because the properties are "defined" in FieldTextBox's LayoutString() method -// -interface DocumentFieldViewProps { - fieldKey: Key; - doc: Document; - containingDocumentView: DocumentView -} // FieldTextBox: Displays an editable plain text node that maps to a specified Key of a Document // diff --git a/src/views/nodes/FieldView.tsx b/src/views/nodes/FieldView.tsx new file mode 100644 index 000000000..1c4164089 --- /dev/null +++ b/src/views/nodes/FieldView.tsx @@ -0,0 +1,31 @@ +import React = require("react") +import { DocumentFieldViewProps } from "./DocumentView"; +import { observer } from "mobx-react"; +import { computed } from "mobx"; +import { Field, Opt } from "../../fields/Field"; +import { TextField } from "../../fields/TextField"; +import { NumberField } from "../../fields/NumberField"; + +@observer +export class FieldView extends React.Component<DocumentFieldViewProps> { + @computed + get field(): Opt<Field> { + const { doc, fieldKey } = this.props; + return doc.GetField(fieldKey); + } + render() { + const field = this.field; + if (!field) { + return <p>{'<null>'}</p> + } + if (field instanceof TextField) { + return <p>{field.Data}</p> + } + else if (field instanceof NumberField) { + return <p>{field.Data}</p> + } else { + return <p>{field.GetValue}</p> + } + } + +}
\ No newline at end of file |