aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Main.tsx10
-rw-r--r--src/documents/Documents.ts30
-rw-r--r--src/fields/Document.ts28
-rw-r--r--src/fields/Key.ts28
-rw-r--r--src/util/DragManager.ts14
-rw-r--r--src/views/collections/CollectionDockingView.tsx3
-rw-r--r--src/views/collections/CollectionFreeFormView.tsx16
-rw-r--r--src/views/collections/CollectionSchemaView.scss0
-rw-r--r--src/views/collections/CollectionSchemaView.tsx49
-rw-r--r--src/views/nodes/DocumentView.tsx26
-rw-r--r--src/views/nodes/FieldTextBox.tsx11
-rw-r--r--src/views/nodes/FieldView.tsx31
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