From ab8b4ffd7f3b89600a71d3167490c40a59be433e Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 21 Apr 2019 01:46:02 -0400 Subject: More changes/fixes --- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 945c01059..32104b49d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,5 @@ import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { KeyStore } from "../../../../fields/KeyStore"; import { emptyFunction, returnFalse, returnOne } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager } from "../../../util/DragManager"; @@ -13,7 +11,7 @@ import { InkingCanvas } from "../../InkingCanvas"; import { MainOverlayTextBox } from "../../MainOverlayTextBox"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; +import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView"; import { CollectionSubView } from "../CollectionSubView"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; @@ -21,17 +19,28 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); -import { BooleanField } from "../../../../fields/BooleanField"; +import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { Doc } from "../../../../new_fields/Doc"; +import { FieldValue } from "../../../../new_fields/Types"; + +export const panZoomSchema = createSchema({ + panX: "number", + panY: "number", + zoom: "number" +}); + +type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema]>; +const PanZoomDocument: (doc: Doc) => PanZoomDocument = makeInterface(panZoomSchema, positionSchema); @observer -export class CollectionFreeFormView extends CollectionSubView { +export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type) private _lastX: number = 0; private _lastY: number = 0; private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } - @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } + @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? -- cgit v1.2.3-70-g09d2 From 5a9e437bbd175b36a161e1d96c8ae873dfe6d105 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 22 Apr 2019 03:39:39 -0400 Subject: More --- src/client/views/collections/CollectionSubView.tsx | 6 +++ .../collectionFreeForm/CollectionFreeFormView.tsx | 43 +++++++++++----------- src/client/views/nodes/ImageBox.tsx | 2 +- src/debug/Test.tsx | 13 +------ src/new_fields/Doc.ts | 13 +++++-- src/new_fields/List.ts | 5 ++- src/new_fields/Schema.ts | 20 ++++++++-- src/new_fields/Types.ts | 27 ++++++++------ 8 files changed, 74 insertions(+), 55 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 3add288fd..1a839fdcb 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -20,6 +20,8 @@ import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; import { Doc } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; +import { listSpec } from "../../../new_fields/Schema"; +import { Cast } from "../../../new_fields/Types"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -50,6 +52,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } + get children() { + return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)); + } + @action protected setCursorPosition(position: [number, number]) { let ind; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 32104b49d..ee7d65d23 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -20,17 +20,19 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface } from "../../../../new_fields/Schema"; -import { Doc } from "../../../../new_fields/Doc"; -import { FieldValue } from "../../../../new_fields/Types"; +import { Doc, Id } from "../../../../new_fields/Doc"; +import { FieldValue, Cast } from "../../../../new_fields/Types"; +import { pageSchema } from "../../nodes/ImageBox"; +import { List } from "../../../../new_fields/List"; export const panZoomSchema = createSchema({ panX: "number", panY: "number", - zoom: "number" + scale: "number" }); -type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema]>; -const PanZoomDocument: (doc: Doc) => PanZoomDocument = makeInterface(panZoomSchema, positionSchema); +type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>; +const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema); @observer export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @@ -41,24 +43,24 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private get _pheight() { return this.props.PanelHeight(); } @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } - @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } + @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } - private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? + private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } private childViews = () => this.views; - private panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0); - private panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0); - private zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1); + private panX = () => FieldValue(this.Document.panX, 0); + private panY = () => FieldValue(this.Document.panY, 0); + private zoomScaling = () => FieldValue(this.Document.scale, 1); private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0; // shift so pan position is at center of window for non-overlay collections private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform()); private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); - private addLiveTextBox = (newBox: Document) => { - this._selectOnLoaded = newBox.Id;// track the new text box so we can give it a prop that tells it to focus itself when it's displayed + private addLiveTextBox = (newBox: Doc) => { + this._selectOnLoaded = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed this.addDocument(newBox, false); } - private addDocument = (newBox: Document, allowDuplicates: boolean) => { - newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); + private addDocument = (newBox: Doc, allowDuplicates: boolean) => { + newBox.zoom = FieldValue(this.Document.scale, 1); return this.props.addDocument(this.bringToFront(newBox), false); } private selectDocuments = (docs: Document[]) => { @@ -67,14 +69,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { SelectionManager.SelectDoc(dv!, true)); } public getActiveDocuments = () => { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); - return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => { - var page = doc.GetNumber(KeyStore.Page, -1); - if (page === curPage || page === -1) { - active.push(doc); - } - return active; - }, [] as Document[]); + const curPage = FieldValue(this.Document.curPage, -1); + return FieldValue(this.children, [] as Doc[]).filter(doc => { + var page = Cast(doc.page, "number", -1); + return page === curPage || page === -1; + }); } @undoBatch diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c11aee56e..cd003ba71 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -71,7 +71,7 @@ export class ImageBox extends DocComponent(ImageD @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - de.data.droppedDocuments.map(action((drop: Document) => { + de.data.droppedDocuments.forEach(action((drop: Document) => { let layout = drop.GetText(KeyStore.BackgroundLayout, ""); if (layout.indexOf(ImageBox.name) !== -1) { let imgData = this.props.Document.Get(KeyStore.Data); diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 22a39f31e..179f987e0 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,12 +1,10 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { SerializationHelper } from '../client/util/SerializationHelper'; -import { createSchema, makeInterface, makeStrictInterface } from '../new_fields/Schema'; +import { createSchema, makeInterface, makeStrictInterface, listSpec } from '../new_fields/Schema'; import { ImageField } from '../new_fields/URLField'; import { Doc } from '../new_fields/Doc'; -import { ListSpec } from '../new_fields/Types'; import { List } from '../new_fields/List'; -const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? const schema1 = createSchema({ hello: "number", @@ -22,7 +20,7 @@ type TestDoc = makeInterface<[typeof schema1]>; const schema2 = createSchema({ hello: ImageField, test: "boolean", - fields: { List: "number" } as ListSpec, + fields: listSpec("number"), url: "number", testDoc: ImageField }); @@ -30,13 +28,6 @@ const schema2 = createSchema({ const Test2Doc = makeStrictInterface(schema2); type Test2Doc = makeStrictInterface; -const schema3 = createSchema({ - test: "boolean", -}); - -const Test3Doc = makeStrictInterface(schema3); -type Test3Doc = makeStrictInterface; - const assert = (bool: boolean) => { if (!bool) throw new Error(); }; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5d18cbb2e..60abccce6 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -4,7 +4,7 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/ import { Utils } from "../Utils"; import { DocServer } from "../client/DocServer"; import { setter, getter, getField } from "./util"; -import { Cast, FieldCtor } from "./Types"; +import { Cast, ToConstructor } from "./Types"; export type FieldId = string; export const HandleUpdate = Symbol("HandleUpdate"); @@ -28,6 +28,7 @@ export const Parent = Symbol("Parent"); export class ObjectField { protected [OnUpdate]?: (diff?: any) => void; private [Parent]?: Doc; + readonly [Id] = ""; } export type Field = number | string | boolean | ObjectField | RefField; @@ -71,7 +72,7 @@ export namespace Doc { const self = doc[Self]; return new Promise(res => getField(self, key, ignoreProto, res)); } - export function GetTAsync(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): Promise { + export function GetTAsync(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): Promise { return new Promise(async res => { const field = await GetAsync(doc, key, ignoreProto); return Cast(field, ctor); @@ -81,9 +82,15 @@ export namespace Doc { const self = doc[Self]; return getField(self, key, ignoreProto); } - export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): T | null | undefined { + export function GetT(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): T | null | undefined { return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined; } + export async function SetOnPrototype(doc: Doc, key: string, value: Field) { + const proto = await Cast(doc.prototype, Doc); + if (proto) { + proto[key] = value; + } + } export function MakeDelegate(doc: Opt): Opt { if (!doc) { return undefined; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 58b252f7b..f3ec9e2c5 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -6,8 +6,9 @@ import { observable } from "mobx"; @Deserializable("list") class ListImpl extends ObjectField { - constructor() { + constructor(fields: T[] = []) { super(); + this.__fields = fields; const list = new Proxy(this, { set: setter, get: getter, @@ -21,7 +22,7 @@ class ListImpl extends ObjectField { @serializable(alias("fields", list(autoObject()))) @observable - private __fields: (T | null | undefined)[] = []; + private __fields: (T | null | undefined)[]; private [Update] = (diff: any) => { console.log(diff); diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 3b7078cb0..59c6db0bd 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -1,5 +1,7 @@ -import { Interface, ToInterface, Cast, FieldCtor, ToConstructor, HasTail, Head, Tail } from "./Types"; +import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType } from "./Types"; import { Doc, Field, ObjectField } from "./Doc"; +import { URLField } from "./URLField"; +import { List } from "./List"; type AllToInterface = { 1: ToInterface> & AllToInterface>, @@ -10,10 +12,10 @@ export const emptySchema = createSchema({}); export const Document = makeInterface(emptySchema); export type Document = makeInterface<[typeof emptySchema]>; -export type makeInterface = Partial> & U; +export type makeInterface = Partial> & Doc; // export function makeInterface(schemas: T): (doc: U) => All; // export function makeInterface(schema: T): (doc: U) => makeInterface; -export function makeInterface(...schemas: T): (doc: U) => makeInterface { +export function makeInterface(...schemas: T): (doc: Doc) => makeInterface { let schema: Interface = {}; for (const s of schemas) { for (const key in s) { @@ -33,7 +35,10 @@ export function makeInterface(...schemas: return true; } }); - return function (doc: any) { + return function (doc: Doc) { + if (!(doc instanceof Doc)) { + throw new Error("Currently wrapping a schema in another schema isn't supported"); + } const obj = Object.create(proto, { doc: { value: doc, writable: false } }); return obj; }; @@ -59,6 +64,9 @@ export function makeStrictInterface(schema: T): (doc: Doc) }); } return function (doc: any) { + if (!(doc instanceof Doc)) { + throw new Error("Currently wrapping a schema in another schema isn't supported"); + } const obj = Object.create(proto); obj.__doc = doc; return obj; @@ -69,3 +77,7 @@ export function createSchema(schema: T): T & { prototype: T schema.prototype = Doc; return schema as any; } + +export function listSpec>(type: U): ListSpec> { + return { List: type as any };//TODO Types +} \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index f4f66fe5c..fbf002c84 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -1,25 +1,28 @@ import { Field, Opt, FieldWaiting, FieldResult } from "./Doc"; import { List } from "./List"; -export type ToType = +export type ToType | ListSpec> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends ListSpec ? List : // T extends { new(...args: any[]): infer R } ? (R | Promise) : never; + T extends { new(...args: any[]): List } ? never : T extends { new(...args: any[]): infer R } ? R : never; -export type ToConstructor = +export type ToConstructor = T extends string ? "string" : T extends number ? "number" : - T extends boolean ? "boolean" : new (...args: any[]) => T; + T extends boolean ? "boolean" : + T extends List ? ListSpec : + new (...args: any[]) => T; -export type ToInterface = { +export type ToInterface = { [P in keyof T]: ToType; }; -// type ListSpec = { List: FieldCtor> | ListSpec> }; -export type ListSpec = { List: FieldCtor }; +// type ListSpec = { List: ToContructor> | ListSpec> }; +export type ListSpec = { List: ToConstructor }; // type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; @@ -34,11 +37,9 @@ export interface Interface { // [key: string]: ToConstructor | ListSpec; } -export type FieldCtor = T extends List ? ListSpec : ToConstructor; - -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult>; -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType): ToType; -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType): FieldResult> | undefined { +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult>; +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType): ToType; +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType): FieldResult> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) : defaultVal; } @@ -58,7 +59,9 @@ export function Cast>(field: Field | FieldWaiting | u return defaultVal; } -export function FieldValue(field: Opt | Promise>, defaultValue: U): T; +type WithoutList = T extends List ? R[] : T; + +export function FieldValue>(field: Opt | Promise>, defaultValue: U): WithoutList; export function FieldValue(field: Opt | Promise>): Opt; export function FieldValue(field: Opt | Promise>, defaultValue?: T): Opt { return field instanceof Promise ? defaultValue : field; -- cgit v1.2.3-70-g09d2 From 2e2377aaee0801ab20134b54e5105815c59f38e8 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Apr 2019 20:50:53 -0400 Subject: Freeform view done --- .../collectionFreeForm/CollectionFreeFormView.tsx | 105 ++++++------- src/new_fields/Types.ts | 2 +- src/server/ServerUtil.ts | 62 -------- test/test.ts | 166 ++------------------- 4 files changed, 69 insertions(+), 266 deletions(-) delete mode 100644 src/server/ServerUtil.ts (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ee7d65d23..3a9c9780b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -19,7 +19,7 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); -import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; import { Doc, Id } from "../../../../new_fields/Doc"; import { FieldValue, Cast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; @@ -83,19 +83,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; - let dropX = dragDoc.GetNumber(KeyStore.X, 0); - let dropY = dragDoc.GetNumber(KeyStore.Y, 0); + let dropX = Cast(dragDoc.x, "number", 0); + let dropY = Cast(dragDoc.y, "number", 0); de.data.droppedDocuments.map(d => { - d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX); - d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY); - if (!d.GetBoolean(KeyStore.IsMinimized, false)) { - if (!d.GetNumber(KeyStore.Width, 0)) { - d.SetNumber(KeyStore.Width, 300); + d.x = x + Cast(d.x, "number", 0) - dropX; + d.y = y + Cast(d.y, "number", 0) - dropY; + if (!Cast(d.isMinimized, "boolean", false)) { + if (!Cast(d.width, "number", 0)) { + d.width = 300; } - if (!d.GetNumber(KeyStore.Height, 0)) { - let nw = d.GetNumber(KeyStore.NativeWidth, 0); - let nh = d.GetNumber(KeyStore.NativeHeight, 0); - d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + if (!Cast(d.height, "number", 0)) { + let nw = Cast(d.nativeWidth, "number", 0); + let nh = Cast(d.nativeHeight, "number", 0); + d.height = nw && nh ? nh / nw * Cast(d.width, "number", 0) : 300; } } this.bringToFront(d); @@ -115,7 +115,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerDown = (e: React.PointerEvent): void => { - let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => { + let childSelected = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), [] as Doc[]).filter(doc => doc).reduce((childSelected, doc) => { var dv = DocumentManager.Instance.getDocumentView(doc); return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); }, false); @@ -139,20 +139,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { - let x = this.props.Document.GetNumber(KeyStore.PanX, 0); - let y = this.props.Document.GetNumber(KeyStore.PanY, 0); - let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); + let x = Cast(this.props.Document.panX, "number", 0); + let y = Cast(this.props.Document.panY, "number", 0); + let docs = this.children || []; let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); if (!this.isAnnotationOverlay) { - let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0; - let maxx = docs.length ? docs[0].Width() + minx : minx; - let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0; - let maxy = docs.length ? docs[0].Height() + miny : miny; + let minx = docs.length ? Cast(docs[0].x, "number", 0) : 0; + let maxx = docs.length ? Cast(docs[0].width, "number", 0) + minx : minx; + let miny = docs.length ? Cast(docs[0].y, "number", 0) : 0; + let maxy = docs.length ? Cast(docs[0].height, "number", 0) + miny : miny; let ranges = docs.filter(doc => doc).reduce((range, doc) => { - let x = doc.GetNumber(KeyStore.X, 0); - let xe = x + doc.GetNumber(KeyStore.Width, 0); - let y = doc.GetNumber(KeyStore.Y, 0); - let ye = y + doc.GetNumber(KeyStore.Height, 0); + let x = Cast(doc.x, "number", 0); + let xe = x + Cast(doc.width, "number", 0); + let y = Cast(doc.y, "number", 0); + let ye = y + Cast(doc.height, "number", 0); return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); @@ -176,10 +176,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if (!this.props.active()) { // return; // } - let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => { + let childSelected = (this.children || []).filter(doc => doc).some(doc => { var dv = DocumentManager.Instance.getDocumentView(doc); - return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); - }, false); + return dv && SelectionManager.IsSelected(dv) ? true : false; + }); if (!this.props.isSelected() && !childSelected && !this.props.isTopMost) { return; } @@ -188,8 +188,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (e.ctrlKey) { let deltaScale = (1 - (e.deltaY / coefficient)); - this.props.Document.SetNumber(KeyStore.NativeWidth, this.nativeWidth * deltaScale); - this.props.Document.SetNumber(KeyStore.NativeHeight, this.nativeHeight * deltaScale); + this.props.Document.nativeWidth = this.nativeWidth * deltaScale; + this.props.Document.nativeHeight = this.nativeHeight * deltaScale; e.stopPropagation(); e.preventDefault(); } else { @@ -204,7 +204,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); let safeScale = Math.abs(localTransform.Scale); - this.props.Document.SetNumber(KeyStore.Scale, Math.abs(safeScale)); + this.props.Document.scale = Math.abs(safeScale); this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); e.stopPropagation(); } @@ -216,8 +216,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); - this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX); - this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY); + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; } @action @@ -230,23 +230,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } @action - bringToFront(doc: Document) { - this.props.Document.GetList(this.props.fieldKey, [] as Document[]).slice().sort((doc1, doc2) => { + bringToFront(doc: Doc) { + (this.children || []).slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; - return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); - }).map((doc, index) => doc.SetNumber(KeyStore.ZIndex, index + 1)); + return Cast(doc1.zIndex, "number", 0) - Cast(doc2.zIndex, "number", 0); + }).forEach((doc, index) => doc.zIndex = index + 1); return doc; } - focusDocument = (doc: Document) => { + focusDocument = (doc: Doc) => { this.setPan( - doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2, - doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2); + Cast(doc.x, "number", 0) + Cast(doc.width, "number", 0) / 2, + Cast(doc.y, "number", 0) + Cast(doc.height, "number", 0) / 2); this.props.focus(this.props.Document); } - getDocumentViewProps(document: Document): DocumentViewProps { + getDocumentViewProps(document: Doc): DocumentViewProps { return { Document: document, addDocument: this.props.addDocument, @@ -255,8 +255,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ScreenToLocalTransform: this.getTransform, isTopMost: false, selectOnLoad: document.Id === this._selectOnLoaded, - PanelWidth: document.Width, - PanelHeight: document.Height, + PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions + PanelHeight: () => Cast(document.height, "number", 0), ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, @@ -267,13 +267,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get views() { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); - let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { - var page = doc.GetNumber(KeyStore.Page, -1); + let curPage = FieldValue(this.Document.curPage, -1); + let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { + var page = Cast(doc.page, "number", -1); if (page === curPage || page === -1) { - let minim = doc.GetT(KeyStore.IsMinimized, BooleanField); - if (minim === undefined || (minim && !minim.Data)) - prev.push(); + let minim = Cast(doc.isMinimized, "boolean"); + if (minim === undefined || !minim) { + prev.push(); + } } return prev; }, [] as JSX.Element[]); @@ -316,9 +317,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @observer class CollectionFreeFormOverlayView extends React.Component { @computed get overlayView() { - let overlayLayout = this.props.Document.GetText(KeyStore.OverlayLayout, ""); + let overlayLayout = Cast(this.props.Document.overlayLayout, "string", ""); return !overlayLayout ? (null) : - (); } render() { @@ -329,9 +330,9 @@ class CollectionFreeFormOverlayView extends React.Component { @observer class CollectionFreeFormBackgroundView extends React.Component { @computed get backgroundView() { - let backgroundLayout = this.props.Document.GetText(KeyStore.BackgroundLayout, ""); + let backgroundLayout = Cast(this.props.Document.backgroundLayout, "string", ""); return !backgroundLayout ? (null) : - (); } render() { diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 55083765a..4ad8dcade 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -38,7 +38,7 @@ export interface Interface { } export function Cast | ListSpec>(field: FieldResult, ctor: T): FieldResult>; -export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: ToType): ToType; +export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: WithoutList>): WithoutList>; export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal?: ToType): FieldResult> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal; diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts deleted file mode 100644 index 79ca5e55d..000000000 --- a/src/server/ServerUtil.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; -import { AudioField } from "../fields/AudioField"; -import { BooleanField } from "../fields/BooleanField"; -import { HtmlField } from "../fields/HtmlField"; -import { InkField } from "../fields/InkField"; -import { PDFField } from "../fields/PDFField"; -import { ScriptField } from "../fields/ScriptField"; -import { TupleField } from "../fields/TupleField"; -import { VideoField } from "../fields/VideoField"; -import { WebField } from "../fields/WebField"; -import { Utils } from "../Utils"; -import { Document } from "./../fields/Document"; -import { Field } from "./../fields/Field"; -import { ImageField } from "./../fields/ImageField"; -import { Key } from "./../fields/Key"; -import { ListField } from "./../fields/ListField"; -import { NumberField } from "./../fields/NumberField"; -import { RichTextField } from "./../fields/RichTextField"; -import { TextField } from "./../fields/TextField"; -import { Transferable, Types } from "./Message"; -import { IconField } from "../fields/IconFIeld"; - -export class ServerUtils { - public static prepend(extension: string): string { - return window.location.origin + extension; - } - - public static FromJson(json: Transferable): Field { - - if (!(json.data !== undefined && json.id && json.type !== undefined)) { - console.log( - "how did you manage to get an object that doesn't have a data or an id?" - ); - return new TextField("Something to fill the space", Utils.GenerateGuid()); - } - - switch (json.type) { - case Types.Boolean: return new BooleanField(json.data, json.id, false); - case Types.Number: return new NumberField(json.data, json.id, false); - case Types.Text: return new TextField(json.data, json.id, false); - case Types.Icon: return new IconField(json.data, json.id, false); - case Types.Html: return new HtmlField(json.data, json.id, false); - case Types.Web: return new WebField(new URL(json.data), json.id, false); - case Types.RichText: return new RichTextField(json.data, json.id, false); - case Types.Key: return new Key(json.data, json.id, false); - case Types.Image: return new ImageField(new URL(json.data), json.id, false); - case Types.HistogramOp: return HistogramField.FromJson(json.id, json.data); - case Types.PDF: return new PDFField(new URL(json.data), json.id, false); - case Types.List: return ListField.FromJson(json.id, json.data); - case Types.Script: return ScriptField.FromJson(json.id, json.data); - case Types.Audio: return new AudioField(new URL(json.data), json.id, false); - case Types.Video: return new VideoField(new URL(json.data), json.id, false); - case Types.Tuple: return new TupleField(json.data, json.id, false); - case Types.Ink: return InkField.FromJson(json.id, json.data); - case Types.Document: return Document.FromJson(json.data, json.id, false); - default: - throw Error( - "Error, unrecognized field type received from server. If you just created a new field type, be sure to add it here" - ); - } - } -} diff --git a/test/test.ts b/test/test.ts index 16cace026..91dc43379 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,171 +1,35 @@ -import { NumberField } from "../src/fields/NumberField"; import { expect } from 'chai'; import 'mocha'; -import { Key } from "../src/fields/Key"; -import { Document } from "../src/fields/Document"; import { autorun, reaction } from "mobx"; -import { DocumentReference } from "../src/fields/DocumentReference"; -import { TextField } from "../src/fields/TextField"; -import { Field, FieldWaiting } from "../src/fields/Field"; - -describe('Number Controller', () => { - it('Should be constructable', () => { - const numController = new NumberField(15); - expect(numController.Data).to.equal(15); - }); - - it('Should update', () => { - const numController = new NumberField(15); - let ran = false; - reaction(() => numController.Data, (data) => { ran = true; }); - expect(ran).to.equal(false); - numController.Data = 5; - expect(ran).to.equal(true); - }); -}); +import { Doc } from '../src/new_fields/Doc'; +import { Cast } from '../src/new_fields/Types'; describe("Document", () => { it('should hold fields', () => { - let key = new Key("Test"); - let key2 = new Key("Test2"); - let field = new NumberField(15); - let doc = new Document(); - doc.Set(key, field); - let getField = doc.GetT(key, NumberField); - let getField2 = doc.GetT(key2, NumberField); + let key = "Test"; + let key2 = "Test2"; + let field = 15; + let doc = new Doc(); + doc[key] = field; + let getField = Cast(doc[key], "number"); + let getField2 = Cast(doc[key2], "number"); expect(getField).to.equal(field); expect(getField2).to.equal(undefined); }); it('should update', () => { - let doc = new Document(); - let key = new Key("Test"); - let key2 = new Key("Test2"); + let doc = new Doc(); + let key = "Test"; + let key2 = "Test2"; let ran = false; - reaction(() => doc.Get(key), (field) => { ran = true; }); + reaction(() => doc[key], (field) => { ran = true; }); expect(ran).to.equal(false); - doc.Set(key2, new NumberField(4)); + doc[key2] = 4; expect(ran).to.equal(false); - doc.Set(key, new NumberField(5)); + doc[key] = 5; expect(ran).to.equal(true); }); }); - -describe("Reference", () => { - it('should dereference', () => { - let doc = new Document(); - let doc2 = new Document(); - const key = new Key("test"); - const key2 = new Key("test2"); - - const numCont = new NumberField(55); - doc.Set(key, numCont); - let ref = new DocumentReference(doc, key); - let ref2 = new DocumentReference(doc, key2); - doc2.Set(key2, ref); - - let ref3 = new DocumentReference(doc2, key2); - let ref4 = new DocumentReference(doc2, key); - - expect(ref.Dereference()).to.equal(numCont); - expect(ref.DereferenceToRoot()).to.equal(numCont); - expect(ref2.Dereference()).to.equal(undefined); - expect(ref2.DereferenceToRoot()).to.equal(undefined); - expect(ref3.Dereference()).to.equal(ref); - expect(ref3.DereferenceToRoot()).to.equal(numCont); - expect(ref4.Dereference()).to.equal(undefined); - expect(ref4.DereferenceToRoot()).to.equal(undefined); - }); - - it('should work with prototypes', () => { - let doc = new Document; - let doc2 = doc.MakeDelegate(); - let key = new Key("test"); - expect(doc.Get(key)).to.equal(undefined); - expect(doc2.Get(key)).to.equal(undefined); - let num = new NumberField(55); - let num2 = new NumberField(56); - - doc.Set(key, num); - expect(doc.Get(key)).to.equal(num); - expect(doc2.Get(key)).to.equal(num); - - doc2.Set(key, num2); - expect(doc.Get(key)).to.equal(num); - expect(doc2.Get(key)).to.equal(num2); - }); - - it('should update through layers', () => { - let doc = new Document(); - let doc2 = new Document(); - let doc3 = new Document(); - const key = new Key("test"); - const key2 = new Key("test2"); - const key3 = new Key("test3"); - - const numCont = new NumberField(55); - doc.Set(key, numCont); - const ref = new DocumentReference(doc, key); - doc2.Set(key2, ref); - const ref3 = new DocumentReference(doc2, key2); - doc3.Set(key3, ref3); - - let ran = false; - reaction(() => { - let field = ((doc3.Get(key3)).DereferenceToRoot()).GetValue(); - return field; - }, (field) => { - ran = true; - }); - expect(ran).to.equal(false); - - numCont.Data = 44; - expect(ran).to.equal(true); - ran = false; - - doc.Set(key, new NumberField(33)); - expect(ran).to.equal(true); - ran = false; - - doc.Set(key2, new NumberField(4)); - expect(ran).to.equal(false); - - doc2.Set(key2, new TextField("hello")); - expect(ran).to.equal(true); - ran = false; - - doc3.Set(key3, new TextField("world")); - expect(ran).to.equal(true); - ran = false; - }); - - it('should update with prototypes', () => { - let doc = new Document(); - let doc2 = doc.MakeDelegate(); - const key = new Key("test"); - - const numCont = new NumberField(55); - - let ran = false; - reaction(() => { - let field = doc2.GetT(key, NumberField); - if (field && field !== FieldWaiting) { - return field.Data; - } - return undefined; - }, (field) => { - ran = true; - }); - expect(ran).to.equal(false); - - doc.Set(key, numCont); - expect(ran).to.equal(true); - - ran = false; - numCont.Data = 1; - expect(ran).to.equal(true); - }); -}); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f01b842a5d6ef6b9deb9807fa0c3a8cd2c81a25a Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 26 Apr 2019 17:08:38 -0400 Subject: TreeView and others --- src/client/documents/Documents.ts | 3 +- src/client/views/collections/CollectionView.tsx | 9 ++- .../collections/collectionFreeForm/MarqueeView.tsx | 80 +++++++++++----------- src/client/views/nodes/LinkBox.tsx | 77 +++++++++------------ src/new_fields/Doc.ts | 2 +- src/new_fields/InkField.ts | 7 +- src/new_fields/Types.ts | 4 ++ 7 files changed, 91 insertions(+), 91 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ed76f32ff..9511027d3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -29,11 +29,12 @@ import { Cast } from "../../new_fields/Types"; import { IconField } from "../../new_fields/IconField"; import { listSpec } from "../../new_fields/Schema"; import { DocServer } from "../DocServer"; +import { StrokeData, InkField } from "../../new_fields/InkField"; export interface DocumentOptions { x?: number; y?: number; - // ink?: Map; + ink?: InkField; width?: number; height?: number; nativeWidth?: number; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 675e720e2..e7bf1e121 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -7,7 +7,6 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionTreeView } from './CollectionTreeView'; import { ContextMenu } from '../ContextMenu'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { KeyStore } from '../../../fields/KeyStore'; import { observer } from 'mobx-react'; import { undoBatch } from '../../util/UndoManager'; import { trace } from 'mobx'; @@ -29,13 +28,13 @@ export class CollectionView extends React.Component { return (null); } - get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? + get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } // bcz: ? Why do we need to compare Id's? onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }); - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }); - ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }); + ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform) }); + ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema) }); + ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree) }); } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c6681e014..644a8784c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,10 +1,6 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; -import { InkField, StrokeData } from "../../../../fields/InkField"; -import { KeyStore } from "../../../../fields/KeyStore"; -import { Documents } from "../../../documents/Documents"; +import { Docs } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; @@ -14,16 +10,19 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); import { Utils } from "../../../../Utils"; +import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, Cast } from "../../../../new_fields/Types"; +import { InkField, StrokeData } from "../../../../new_fields/InkField"; interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; container: CollectionFreeFormView; - addDocument: (doc: Document, allowDuplicates: false) => boolean; - activeDocuments: () => Document[]; - selectDocuments: (docs: Document[]) => void; - removeDocument: (doc: Document) => boolean; - addLiveTextDocument: (doc: Document) => void; + addDocument: (doc: Doc, allowDuplicates: false) => boolean; + activeDocuments: () => Doc[]; + selectDocuments: (docs: Doc[]) => void; + removeDocument: (doc: Doc) => boolean; + addLiveTextDocument: (doc: Doc) => void; } @observer @@ -49,7 +48,7 @@ export class MarqueeView extends React.Component onKeyPress = (e: KeyboardEvent) => { //make textbox and add it to this collection let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY); - let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); + let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); this.props.addLiveTextDocument(newBox); e.stopPropagation(); } @@ -64,8 +63,9 @@ export class MarqueeView extends React.Component document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } - if (e.altKey) + if (e.altKey) { e.preventDefault(); + } } @action @@ -80,8 +80,9 @@ export class MarqueeView extends React.Component e.preventDefault(); } } - if (e.altKey) + if (e.altKey) { e.preventDefault(); + } } @action @@ -94,8 +95,9 @@ export class MarqueeView extends React.Component this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } this.cleanupInteractions(true); - if (e.altKey) + if (e.altKey) { e.preventDefault(); + } } @action @@ -127,11 +129,11 @@ export class MarqueeView extends React.Component @undoBatch @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { + if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") { this.marqueeSelect().map(d => this.props.removeDocument(d)); - let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - if (ink && ink !== FieldWaiting) { - this.marqueeInkDelete(ink.Data); + let ink = Cast(this.props.container.props.Document.ink, InkField); + if (ink) { + this.marqueeInkDelete(ink.inkData); } this.cleanupInteractions(true); e.stopPropagation(); @@ -141,33 +143,33 @@ export class MarqueeView extends React.Component let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); - d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2); - d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2); - d.SetNumber(KeyStore.Page, -1); + d.x = NumCast(d.X) - bounds.left - bounds.width / 2; + d.y = NumCast(d.Y) - bounds.top - bounds.height / 2; + d.page = -1; return d; }); - let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined; - let zoomBasis = this.props.container.props.Document.GetNumber(KeyStore.Scale, 1); - let newCollection = Documents.FreeformDocument(selected, { + let ink = Cast(this.props.container.props.Document.ink, InkField); + let inkData = ink ? ink.inkData : undefined; + let zoomBasis = NumCast(this.props.container.props.Document.scale, 1); + let newCollection = Docs.FreeformDocument(selected, { x: bounds.left, y: bounds.top, - panx: 0, - pany: 0, + panX: 0, + panY: 0, borderRounding: e.key === "e" ? -1 : undefined, backgroundColor: selected.length ? "white" : "", scale: zoomBasis, width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, - ink: inkData ? this.marqueeInkSelect(inkData) : undefined, + ink: inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined, title: "a nested collection" }); this.marqueeInkDelete(inkData); SelectionManager.DeselectAll(); if (e.key === "r") { - let summary = Documents.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.GetPrototype()!.CreateLink(newCollection.GetPrototype()!); + let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + Doc.MakeLink(summary.proto!, newCollection.proto!); this.props.addLiveTextDocument(summary); e.preventDefault(); } @@ -182,9 +184,9 @@ export class MarqueeView extends React.Component let bounds = this.Bounds; let selected = this.marqueeSelect(); SelectionManager.DeselectAll(); - let summary = Documents.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + let summary = Docs.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); this.props.addLiveTextDocument(summary); - selected.map(select => summary.GetPrototype()!.CreateLink(select.GetPrototype()!)); + selected.forEach(select => Doc.MakeLink(summary.proto!, select.proto!)); this.cleanupInteractions(true); } @@ -219,19 +221,19 @@ export class MarqueeView extends React.Component let idata = new Map(); ink.forEach((value: StrokeData, key: string, map: any) => !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value)); - this.props.container.props.Document.SetDataOnPrototype(KeyStore.Ink, idata, InkField); + Doc.SetOnPrototype(this.props.container.props.Document, "ink", new InkField(idata)); } } marqueeSelect() { let selRect = this.Bounds; - let selection: Document[] = []; + let selection: Doc[] = []; this.props.activeDocuments().map(doc => { - var z = doc.GetNumber(KeyStore.ZoomBasis, 1); - var x = doc.GetNumber(KeyStore.X, 0); - var y = doc.GetNumber(KeyStore.Y, 0); - var w = doc.Width() / z; - var h = doc.Height() / z; + var z = NumCast(doc.zoomBasis, 1); + var x = NumCast(doc.x); + var y = NumCast(doc.y); + var w = NumCast(doc.width) / z; + var h = NumCast(doc.height) / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 1c0e316e8..9bb90de0d 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -2,15 +2,14 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEdit, faEye, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; -import { KeyStore } from '../../../fields/KeyStore'; -import { ListField } from "../../../fields/ListField"; -import { NumberField } from "../../../fields/NumberField"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import './LinkBox.scss'; import React = require("react"); +import { Doc } from '../../../new_fields/Doc'; +import { Cast, NumCast } from '../../../new_fields/Types'; +import { listSpec } from '../../../new_fields/Schema'; library.add(faEye); @@ -18,9 +17,9 @@ library.add(faEdit); library.add(faTimes); interface Props { - linkDoc: Document; + linkDoc: Doc; linkName: String; - pairedDoc: Document; + pairedDoc: Doc; type: String; showEditor: () => void; } @@ -29,62 +28,52 @@ interface Props { export class LinkBox extends React.Component { @undoBatch - onViewButtonPressed = (e: React.PointerEvent): void => { + onViewButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); let docView = DocumentManager.Instance.getDocumentView(this.props.pairedDoc); if (docView) { docView.props.focus(docView.props.Document); } else { - this.props.pairedDoc.GetAsync(KeyStore.AnnotationOn, (contextDoc: any) => { - if (!contextDoc) { - CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc.MakeDelegate()); - } else if (contextDoc instanceof Document) { - this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => { - contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => { - if (pfield !== cfield) { - contextDoc.SetNumber(KeyStore.CurPage, pfield.Data); - } - let contextView = DocumentManager.Instance.getDocumentView(contextDoc); - if (contextView) { - contextView.props.focus(contextDoc); - } else { - CollectionDockingView.Instance.AddRightSplit(contextDoc); - } - }); - }); + const contextDoc = await Cast(this.props.pairedDoc.annotationOn, Doc); + if (!contextDoc) { + CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(this.props.pairedDoc)); + } else { + const page = NumCast(this.props.pairedDoc.page, undefined); + const curPage = NumCast(contextDoc.curPage, undefined); + if (page !== curPage) { + contextDoc.curPage = page; } - }); + let contextView = DocumentManager.Instance.getDocumentView(contextDoc); + if (contextView) { + contextView.props.focus(contextDoc); + } else { + CollectionDockingView.Instance.AddRightSplit(contextDoc); + } + } } } onEditButtonPressed = (e: React.PointerEvent): void => { - console.log("edit down"); e.stopPropagation(); this.props.showEditor(); } - onDeleteButtonPressed = (e: React.PointerEvent): void => { - console.log("delete down"); + onDeleteButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); - this.props.linkDoc.GetTAsync(KeyStore.LinkedFromDocs, Document, field => { - if (field) { - field.GetTAsync>(KeyStore.LinkedToDocs, ListField, field => { - if (field) { - field.Data.splice(field.Data.indexOf(this.props.linkDoc)); - } - }); + const [linkedFrom, linkedTo] = await Promise.all([Cast(this.props.linkDoc.linkedFrom, Doc), Cast(this.props.linkDoc.linkedTo, Doc)]); + if (linkedFrom) { + const linkedToDocs = Cast(linkedFrom.linkedToDocs, listSpec(Doc)); + if (linkedToDocs) { + linkedToDocs.splice(linkedToDocs.indexOf(this.props.linkDoc)); } - }); - this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => { - if (field) { - field.GetTAsync>(KeyStore.LinkedFromDocs, ListField, field => { - if (field) { - field.Data.splice(field.Data.indexOf(this.props.linkDoc)); - } - }); + } + if (linkedTo) { + const linkedFromDocs = Cast(linkedTo.linkedToDocs, listSpec(Doc)); + if (linkedFromDocs) { + linkedFromDocs.splice(linkedFromDocs.indexOf(this.props.linkDoc)); } - }); + } } render() { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 79e5a156d..a5f495477 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -91,7 +91,7 @@ export namespace Doc { return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined; } export async function SetOnPrototype(doc: Doc, key: string, value: Field) { - const proto = await Cast(doc.proto, Doc); + const proto = doc.proto; if (proto) { proto[key] = value; } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index cdb34cedf..49e6bf61e 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -27,5 +27,10 @@ const strokeDataSchema = createSimpleSchema({ export class InkField extends ObjectField { @serializable(map(object(strokeDataSchema))) - readonly inkData: Map = new Map; + readonly inkData: Map; + + constructor(data?: Map) { + super(); + this.inkData = data || new Map; + } } diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 079c7b76d..649dfdc3e 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -67,6 +67,10 @@ export function StrCast(field: FieldResult, defaultVal: Opt = "") { return Cast(field, "string", defaultVal); } +export function BoolCast(field: FieldResult, defaultVal: Opt = undefined) { + return Cast(field, "boolean", defaultVal); +} + type WithoutList = T extends List ? R[] : T; export function FieldValue>(field: Opt | Promise>, defaultValue: U): WithoutList; -- cgit v1.2.3-70-g09d2 From 513e9042ea815e964462e824d85fbd229381250f Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 01:19:52 -0400 Subject: A bunch more stuff --- src/client/DocServer.ts | 6 +- .../northstar/core/brusher/IBaseBrushable.ts | 4 +- src/client/northstar/core/filter/FilterModel.ts | 17 ++- .../northstar/core/filter/IBaseFilterConsumer.ts | 4 +- src/client/northstar/dash-fields/HistogramField.ts | 3 +- src/client/util/TooltipTextMenu.tsx | 4 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/Main.tsx | 152 ++++++++++----------- .../views/collections/CollectionDockingView.tsx | 8 +- src/client/views/collections/CollectionPDFView.tsx | 10 +- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 9 +- .../CollectionFreeFormLinkView.tsx | 20 +-- .../CollectionFreeFormLinksView.tsx | 63 +++++---- .../CollectionFreeFormRemoteCursors.tsx | 1 - src/client/views/nodes/IconBox.tsx | 12 +- 16 files changed, 165 insertions(+), 154 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 02fd28a86..3f17baec6 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, Types } from "./../server/Message"; +import { MessageStore, Types, Message } from "./../server/Message"; import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -13,6 +13,10 @@ export namespace DocServer { return window.location.origin + extension; } + export function DeleteDatabase() { + Utils.Emit(_socket, MessageStore.DeleteAll, {}); + } + export async function GetRefField(id: string): Promise> { let cached = _cache[id]; if (cached === undefined) { diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts index c46db4d22..87f4ba413 100644 --- a/src/client/northstar/core/brusher/IBaseBrushable.ts +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -1,9 +1,9 @@ import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from '../../../../fields/Document'; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseBrushable extends IEquatable { - BrusherModels: Array; + BrusherModels: Array; BrushColors: Array; Position: PIXIPoint; Size: PIXIPoint; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index e2ba3f652..6ab96b33d 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -2,10 +2,9 @@ import { ValueComparison } from "./ValueComparision"; import { Utils } from "../../utils/Utils"; import { IBaseFilterProvider } from "./IBaseFilterProvider"; import { FilterOperand } from "./FilterOperand"; -import { KeyStore } from "../../../../fields/KeyStore"; -import { FieldWaiting } from "../../../../fields/Field"; -import { Document } from "../../../../fields/Document"; import { HistogramField } from "../../dash-fields/HistogramField"; +import { Cast, FieldValue } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export class FilterModel { public ValueComparisons: ValueComparison[]; @@ -52,12 +51,12 @@ export class FilterModel { let children = new Array(); let linkedGraphNodes = baseOperation.Links; linkedGraphNodes.map(linkVm => { - let filterDoc = linkVm.Get(KeyStore.LinkedFromDocs); - if (filterDoc && filterDoc !== FieldWaiting && filterDoc instanceof Document) { - let filterHistogram = filterDoc.GetT(KeyStore.Data, HistogramField); - if (filterHistogram && filterHistogram !== FieldWaiting) { - if (!visitedFilterProviders.has(filterHistogram.Data)) { - let child = FilterModel.GetFilterModelsRecursive(filterHistogram.Data, visitedFilterProviders, filterModels, false); + let filterDoc = FieldValue(Cast(linkVm.linkedFrom, Doc)); + if (filterDoc) { + let filterHistogram = Cast(filterDoc.data, HistogramField); + if (filterHistogram) { + if (!visitedFilterProviders.has(filterHistogram.HistoOp)) { + let child = FilterModel.GetFilterModelsRecursive(filterHistogram.HistoOp, visitedFilterProviders, filterModels, false); if (child !== "") { // if (linkVm.IsInverted) { // child = "! " + child; diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts index 59d7adf4c..e7549d113 100644 --- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts +++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts @@ -1,10 +1,10 @@ import { FilterOperand } from '../filter/FilterOperand'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from "../../../../fields/Document"; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseFilterConsumer extends IEquatable { FilterOperand: FilterOperand; - Links: Document[]; + Links: Doc[]; } export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer { diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index baeaca1dd..118f4cf7f 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -7,8 +7,9 @@ import { ObjectField } from "../../../new_fields/Doc"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; + function serialize(field: HistogramField) { - return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit + return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; } function deserialize(jp: any) { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4f0eb7d63..1b6647003 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -35,8 +35,8 @@ export class TooltipTextMenu { private fontStylesToName: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); //dropdown doms - private fontSizeDom: Node; - private fontStyleDom: Node; + private fontSizeDom?: Node; + private fontStyleDom?: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 0f05da22c..616299146 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,8 +1,8 @@ import { observer } from "mobx-react"; import { observable } from "mobx"; import { InkingControl } from "./InkingControl"; -import { InkTool } from "../../fields/InkField"; import React = require("react"); +import { InkTool } from "../../new_fields/InkField"; interface StrokeProps { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index c6b3f06d8..1e3d4e259 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -8,17 +8,12 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Measure from 'react-measure'; import * as request from 'request'; -import { Document } from '../../fields/Document'; -import { Field, FieldWaiting, Opt, FIELD_WAITING } from '../../fields/Field'; -import { KeyStore } from '../../fields/KeyStore'; -import { ListField } from '../../fields/ListField'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { RouteStore } from '../../server/RouteStore'; -import { ServerUtils } from '../../server/ServerUtil'; -import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; -import { Documents } from '../documents/Documents'; +import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; +import { Docs } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway'; @@ -26,7 +21,6 @@ import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; -import { Server } from '../Server'; import { SetupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; @@ -39,6 +33,10 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; +import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { DocServer } from '../DocServer'; +import { listSpec } from '../../new_fields/Schema'; @observer @@ -48,11 +46,13 @@ export class Main extends React.Component { @observable public pwidth: number = 0; @observable public pheight: number = 0; - @computed private get mainContainer(): Document | undefined | FIELD_WAITING { - return CurrentUserUtils.UserDocument.GetT(KeyStore.ActiveWorkspace, Document); + @computed private get mainContainer(): Opt { + return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc)); } - private set mainContainer(doc: Document | undefined | FIELD_WAITING) { - doc && CurrentUserUtils.UserDocument.Set(KeyStore.ActiveWorkspace, doc); + private set mainContainer(doc: Opt) { + if (doc) { + CurrentUserUtils.UserDocument.activeWorkspace = doc; + } } constructor(props: Readonly<{}>) { @@ -100,8 +100,8 @@ export class Main extends React.Component { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; - Server.GetField(CurrentUserUtils.MainDocId, action((field: Opt) => { - if (field instanceof Document) { + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt) => { + if (field instanceof Doc) { this.openWorkspace(field, true); } })); @@ -113,9 +113,9 @@ export class Main extends React.Component { window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler window.addEventListener("keydown", (e) => { - if (e.key == "Escape") { + if (e.key === "Escape") { DragManager.AbortDrag(); - SelectionManager.DeselectAll() + SelectionManager.DeselectAll(); } }, false); // drag event handler // click interactions for the context menu @@ -126,54 +126,55 @@ export class Main extends React.Component { }), true); } - initAuthenticationRouters = () => { + initAuthenticationRouters = async () => { // Load the user's active workspace, or create a new one if initial session after signup if (!CurrentUserUtils.MainDocId) { - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { - if (doc) { - CurrentUserUtils.MainDocId = doc.Id; - this.openWorkspace(doc); - } else { - this.createNewWorkspace(); - } - }); + const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); + if (doc) { + CurrentUserUtils.MainDocId = doc[Id]; + this.openWorkspace(doc); + } else { + this.createNewWorkspace(); + } } else { - Server.GetField(CurrentUserUtils.MainDocId).then(field => - field instanceof Document ? this.openWorkspace(field) : + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(field => + field instanceof Doc ? this.openWorkspace(field) : this.createNewWorkspace(CurrentUserUtils.MainDocId)); } } @action - createNewWorkspace = (id?: string): void => { - CurrentUserUtils.UserDocument.GetTAsync>(KeyStore.Workspaces, ListField).then(action((list: Opt>) => { - if (list) { - let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; - let mainDoc = Documents.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.Data.length + 1}` }, id); - list.Data.push(mainDoc); - CurrentUserUtils.MainDocId = mainDoc.Id; - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => { - this.openWorkspace(mainDoc); - let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }); - mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); - }, 0); - } - })); + createNewWorkspace = async (id?: string) => { + const list = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + if (list) { + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; + let mainDoc = Docs.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.length + 1}` }, id); + list.push(mainDoc); + CurrentUserUtils.MainDocId = mainDoc[Id]; + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + setTimeout(() => { + this.openWorkspace(mainDoc); + let pendingDocument = Docs.SchemaDocument([], { title: "New Mobile Uploads" }); + mainDoc.optionalRightCollection = pendingDocument; + }, 0); + } } @action - openWorkspace = (doc: Document, fromHistory = false): void => { + openWorkspace = async (doc: Doc, fromHistory = false) => { this.mainContainer = doc; - fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id); - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => - // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) - setTimeout(() => - col && col.GetTAsync>(KeyStore.Data, ListField, (f: Opt>) => - f && f.Data.length > 0 && CollectionDockingView.Instance.AddRightSplit(col)) - , 100) - ); + fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc.Id); + const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); + // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) + setTimeout(async () => { + if (col) { + const l = Cast(col.data, listSpec(Doc)); + if (l && l.length > 0) { + CollectionDockingView.Instance.AddRightSplit(col); + } + } + }, 100); } @computed @@ -196,7 +197,7 @@ export class Main extends React.Component { PanelHeight={pheightFunc} isTopMost={true} selectOnLoad={false} - focus={emptyDocFunction} + focus={emptyFunction} parentActive={returnTrue} whenActiveChanged={emptyFunction} ContainingCollectionView={undefined} />} @@ -214,17 +215,17 @@ export class Main extends React.Component { let audiourl = "http://techslides.com/demos/samples/sample.mp3"; let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" })); - let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); - let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); - let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, title: "video node" })); - let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); - let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); + let addTextNode = action(() => Docs.TextDocument({ width: 200, height: 200, title: "a text note" })); + let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); + let addSchemaNode = action(() => Docs.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); + let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); + let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); + let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); + let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); + let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); + let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); - let btns: [React.RefObject, IconName, string, () => Document][] = [ + let btns: [React.RefObject, IconName, string, () => Doc][] = [ [React.createRef(), "font", "Add Textbox", addTextNode], [React.createRef(), "image", "Add Image", addImageNode], [React.createRef(), "file-pdf", "Add PDF", addPDFNode], @@ -260,9 +261,8 @@ export class Main extends React.Component { let logoutRef = React.createRef(); let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ - , + ,
@@ -271,7 +271,7 @@ export class Main extends React.Component {
,
-
+
]; } @@ -279,10 +279,10 @@ export class Main extends React.Component { get workspaceMenu() { let areWorkspacesShown = () => this._workspacesShown; let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let workspaces = CurrentUserUtils.UserDocument.GetT>(KeyStore.Workspaces, ListField); - return (!workspaces || workspaces === FieldWaiting || this.mainContainer === FieldWaiting) ? (null) : + let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + return (!workspaces || !this.mainContainer) ? (null) : ; } @@ -303,17 +303,17 @@ export class Main extends React.Component { } // --------------- Northstar hooks ------------- / - private _northstarSchemas: Document[] = []; + private _northstarSchemas: Doc[] = []; @action SetNorthstarCatalog(ctlog: Catalog) { CurrentUserUtils.NorthstarDBCatalog = ctlog; if (ctlog && ctlog.schemas) { ctlog.schemas.map(schema => { - let schemaDocuments: Document[] = []; + let schemaDocuments: Doc[] = []; let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Document) { + promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + if (field instanceof Doc) { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); @@ -321,12 +321,12 @@ export class Main extends React.Component { new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); - schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); + schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); } }))); return promises; }, [] as Promise[])).finally(() => - this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); + this._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); }); } } @@ -338,7 +338,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos(); + await Docs.initProtos(); await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); })(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 69401ceeb..2ff409b9b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -6,13 +6,11 @@ import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import { Utils, returnTrue, emptyFunction, returnOne, returnZero } from "../../../Utils"; -import { Server } from "../../Server"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; -import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; @@ -206,7 +204,7 @@ export class CollectionDockingView extends React.Component) => + DocServer.GetRefField(docid).then(action(async (sourceDoc: Opt) => (sourceDoc instanceof Doc) && DragLinksAsDocuments(tab, x, y, sourceDoc))); } else if ((className === "lm_title" || className === "lm_tab lm_active") && !e.shiftKey) { @@ -216,7 +214,7 @@ export class CollectionDockingView extends React.Component) => { + DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), x, y, { @@ -301,7 +299,7 @@ export class CollectionDockingView extends React.Component { return FieldView.LayoutString(CollectionPDFView, fieldKey); } - private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } - private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; + private get curPage() { return NumCast(this.props.Document.curPage, -1); } + private get numPages() { return NumCast(this.props.Document.numPages); } + @action onPageBack = () => this.curPage > 1 ? (this.props.Document.curPage = this.curPage - 1) : -1; + @action onPageForward = () => this.curPage < this.numPages ? (this.props.Document.curPage = this.curPage + 1) : -1; private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2e1175f28..874170f3d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; -import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'; import "react-table/react-table.css"; import { emptyFunction, returnFalse, returnZero } from "../../../Utils"; import { SetupDrag } from "../../util/DragManager"; @@ -283,7 +283,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu // is displayed (unlikely) it won't show up until something else changes. //TODO Types - untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); + untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)))); this.columns.forEach(key => keys[key] = true); return Array.from(Object.keys(keys)).map(item => diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 779dc8fc3..d314e3fc0 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,6 +1,5 @@ import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); @@ -8,6 +7,7 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; +import { NumCast } from "../../../new_fields/Types"; @observer @@ -44,8 +44,9 @@ export class CollectionVideoView extends React.Component { if (ele) { this._player = ele.getElementsByTagName("video")[0]; console.log(this._player); - if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { - this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); + const curPage = NumCast(this.props.Document.curPage, -1); + if (curPage >= 0) { + this._currentTimecode = curPage; } } } @@ -69,7 +70,7 @@ export class CollectionVideoView extends React.Component { (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { this._currentTimecode = this._player.currentTime; - this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this._currentTimecode)); + this.props.Document.curPage = Math.round(this._currentTimecode); } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 20c5a84bf..d4987fc18 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,15 +1,15 @@ import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { KeyStore } from "../../../../fields/KeyStore"; import { Utils } from "../../../../Utils"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); +import { StrCast, NumCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export interface CollectionFreeFormLinkViewProps { - A: Document; - B: Document; - LinkDocs: Document[]; + A: Doc; + B: Doc; + LinkDocs: Doc[]; } @observer @@ -17,16 +17,16 @@ export class CollectionFreeFormLinkView extends React.Component { this.props.LinkDocs.map(l => - console.log("Link:" + l.Title)); + console.log("Link:" + StrCast(l.title))); } render() { let l = this.props.LinkDocs; let a = this.props.A; let b = this.props.B; - let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Width() / 2); - let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Height() / 2); - let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Width() / 2); - let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Height() / 2); + let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.width) / 2); + let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.height) / 2); + let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.width) / 2); + let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / 2); return ( { _brushReactionDisposer?: IReactionDisposer; componentDidMount() { - this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)), + this._brushReactionDisposer = reaction(() => Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).map(doc => NumCast(doc.x)), () => { - let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc.GetText(KeyStore.BackgroundLayout, "").indexOf("istogram") !== -1); + let views = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => StrCast(doc.backgroundLayout, "").indexOf("istogram") !== -1); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { let srcDoc = views[j]; let dstDoc = views[i]; - let x1 = srcDoc.GetNumber(KeyStore.X, 0); - let x1w = srcDoc.GetNumber(KeyStore.Width, -1); - let x2 = dstDoc.GetNumber(KeyStore.X, 0); - let x2w = dstDoc.GetNumber(KeyStore.Width, -1); + let x1 = NumCast(srcDoc.x); + let x1w = NumCast(srcDoc.width, -1); + let x2 = NumCast(dstDoc.x); + let x2w = NumCast(dstDoc.width, -1); if (x1w < 0 || x2w < 0 || i === j) { continue; } let dstTarg = dstDoc; let srcTarg = srcDoc; - let findBrush = (field: ListField) => field.Data.findIndex(brush => { - let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + let findBrush = (field: List) => field.findIndex(brush => { + let bdocs = brush ? Cast(brush.brushingDocs, listSpec(Doc), []) : []; return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); - let brushAction = (field: ListField) => { + let brushAction = (field: List) => { let found = findBrush(field); if (found !== -1) { console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); - field.Data.splice(found, 1); + field.splice(found, 1); } }; if (Math.abs(x1 + x1w - x2) < 20) { - let linkDoc: Document = new Document(); - linkDoc.SetText(KeyStore.Title, "Histogram Brush"); - linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title); - linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField); + let linkDoc: Doc = new Doc(); + linkDoc.title = "Histogram Brush"; + linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title); + linkDoc.brushingDocs = new List([dstTarg, srcTarg]); - brushAction = (field: ListField) => { + brushAction = (field: List) => { if (findBrush(field) === -1) { console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); - (findBrush(field) === -1) && field.Data.push(linkDoc); + (findBrush(field) === -1) && field.push(linkDoc); } }; } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc)); + if (dstBrushDocs === undefined) { + dstTarg.brushingDocs = dstBrushDocs = new List(); + } + let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc)); + if (srcBrushDocs === undefined) { + srcTarg.brushingDocs = srcBrushDocs = new List(); + } + brushAction(dstBrushDocs); + brushAction(srcBrushDocs); } } @@ -70,9 +79,9 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -82,12 +91,12 @@ export class CollectionFreeFormLinksView extends React.Component { let srcViews = this.documentAnchors(connection.a); let targetViews = this.documentAnchors(connection.b); - let possiblePairs: { a: Document, b: Document, }[] = []; + let possiblePairs: { a: Doc, b: Doc, }[] = []; srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); possiblePairs.map(possiblePair => drawnPairs.reduce((found, drawnPair) => { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); - if (match && !drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { + if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { drawnPair.l.push(connection.l); } return match || found; @@ -96,7 +105,7 @@ export class CollectionFreeFormLinksView extends React.Component ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index cf0a6de00..036745eca 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,5 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../../fields/KeyStore"; import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 9c90c0a0e..f7cceb3d4 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -4,12 +4,12 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } fr import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from '../../../fields/Document'; -import { IconField } from "../../../fields/IconFIeld"; -import { KeyStore } from "../../../fields/KeyStore"; import { SelectionManager } from "../../util/SelectionManager"; import { FieldView, FieldViewProps } from './FieldView'; import "./IconBox.scss"; +import { Cast } from "../../../new_fields/Types"; +import { Doc } from "../../../new_fields/Doc"; +import { IconField } from "../../../new_fields/IconField"; library.add(faCaretUp); @@ -22,8 +22,8 @@ library.add(faFilm); export class IconBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(IconBox); } - @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } - @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

Error loading layout data

" as string); } + @computed get maximized() { return Cast(this.props.Document.maximizedDoc, Doc); } + @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.layout : "

Error loading layout data

"; } @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } public static DocumentIcon(layout: string) { @@ -33,7 +33,7 @@ export class IconBox extends React.Component { layout.indexOf("Video") !== -1 ? faFilm : layout.indexOf("Collection") !== -1 ? faObjectGroup : faCaretUp; - return + return ; } render() { -- cgit v1.2.3-70-g09d2 From 7a820b3b175ea52712927e75ce16e32f0ed3a131 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 19:51:58 -0400 Subject: Compiling --- src/client/util/DragManager.ts | 8 +++---- src/client/views/MainOverlayTextBox.tsx | 17 +++++++------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 17 ++++++-------- src/fields/RichTextField.ts | 26 ---------------------- src/new_fields/RichTextField.ts | 12 ++++++++++ src/new_fields/Types.ts | 14 ++++++------ 7 files changed, 39 insertions(+), 57 deletions(-) delete mode 100644 src/fields/RichTextField.ts create mode 100644 src/new_fields/RichTextField.ts (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0174b2f54..e65f2b9ed 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -158,13 +158,13 @@ export namespace DragManager { } export class LinkDragData { - constructor(linkSourceDoc: Document, blacklist: Document[] = []) { + constructor(linkSourceDoc: Doc, blacklist: Doc[] = []) { this.linkSourceDocument = linkSourceDoc; this.blacklist = blacklist; } - droppedDocuments: Document[] = []; - linkSourceDocument: Document; - blacklist: Document[]; + droppedDocuments: Doc[] = []; + linkSourceDocument: Doc; + blacklist: Doc[]; [id: string]: any; } diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index be8d67925..a7ced36bf 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -2,16 +2,15 @@ import { action, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; -import { Document } from '../../fields/Document'; -import { Key } from '../../fields/Key'; -import { KeyStore } from '../../fields/KeyStore'; -import { emptyDocFunction, emptyFunction, returnTrue, returnZero } from '../../Utils'; +import { emptyFunction, returnTrue, returnZero } from '../../Utils'; import '../northstar/model/ModelExtensions'; import '../northstar/utils/Extensions'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import "./MainOverlayTextBox.scss"; import { FormattedTextBox } from './nodes/FormattedTextBox'; +import { Doc } from '../../new_fields/Doc'; +import { NumCast } from '../../new_fields/Types'; interface MainOverlayTextBoxProps { } @@ -19,11 +18,11 @@ interface MainOverlayTextBoxProps { @observer export class MainOverlayTextBox extends React.Component { public static Instance: MainOverlayTextBox; - @observable public TextDoc?: Document = undefined; + @observable public TextDoc?: Doc = undefined; public TextScroll: number = 0; @observable _textRect: any; @observable _textXf: () => Transform = () => Transform.Identity(); - private _textFieldKey: Key = KeyStore.Data; + private _textFieldKey: string = "data"; private _textColor: string | null = null; private _textTargetDiv: HTMLDivElement | undefined; private _textProxyDiv: React.RefObject; @@ -35,7 +34,7 @@ export class MainOverlayTextBox extends React.Component } @action - SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: () => Transform) { + SetTextDoc(textDoc?: Doc, textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform) { if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } @@ -94,10 +93,10 @@ export class MainOverlayTextBox extends React.Component let s = 1 / this._textXf().Scale; return
+ style={{ width: `${NumCast(this.TextDoc.width)}px`, height: `${NumCast(this.TextDoc.height)}px` }}> + ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} />
; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 80900c450..047fbad18 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -97,7 +97,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!NumCast(d.height)) { let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); - d.height = nw && nh ? nh / nw * d.Width() : 300; + d.height = nw && nh ? nh / nw * NumCast(d.Width) : 300; } this.bringToFront(d); }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index c65b1ac89..7a85c9dd3 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -20,7 +20,8 @@ import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { Opt, Doc } from "../../../new_fields/Doc"; import { observer } from "mobx-react"; import { InkingControl } from "../InkingControl"; -import { StrCast } from "../../../new_fields/Types"; +import { StrCast, Cast } from "../../../new_fields/Types"; +import { RichTextField } from "../../../new_fields/RichTextField"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -77,11 +78,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe const state = this._editorView.state.apply(tx); this._editorView.updateState(state); this._applyingChange = true; - this.props.Document.SetDataOnPrototype( - this.props.fieldKey, - JSON.stringify(state.toJSON()), - RichTextField - ); + Doc.SetOnPrototype(this.props.Document, this.props.fieldKey, new RichTextField(JSON.stringify(state.toJSON()))); Doc.SetOnPrototype(this.props.Document, "documentText", state.doc.textBetween(0, state.doc.content.size, "\n\n")); this._applyingChange = false; // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); @@ -127,8 +124,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._reactionDisposer = reaction( () => { - const field = this.props.Document ? this.props.Document.GetT(this.props.fieldKey, RichTextField) : undefined; - return field && field !== FieldWaiting ? field.Data : undefined; + const field = this.props.Document ? Cast(this.props.Document[this.props.fieldKey], RichTextField) : undefined; + return field ? field.Data : undefined; }, field => field && this._editorView && !this._applyingChange && this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))) @@ -136,8 +133,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this.setupEditor(config, this.props.Document); } - private setupEditor(config: any, doc?: Document) { - let field = doc ? doc.GetT(this.props.fieldKey, RichTextField) : undefined; + private setupEditor(config: any, doc?: Doc) { + let field = doc ? Cast(doc[this.props.fieldKey], RichTextField) : undefined; if (this._ref.current) { this._editorView = new EditorView(this._ref.current, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts deleted file mode 100644 index f53f48ca6..000000000 --- a/src/fields/RichTextField.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { BasicField } from "./BasicField"; -import { Types } from "../server/Message"; -import { FieldId } from "./Field"; - -export class RichTextField extends BasicField { - constructor(data: string = "", id?: FieldId, save: boolean = true) { - super(data, save, id); - } - - ToScriptString(): string { - return `new RichTextField(${this.Data})`; - } - - Copy() { - return new RichTextField(this.Data); - } - - ToJson() { - return { - type: Types.RichText, - data: this.Data, - id: this.Id - }; - } - -} \ No newline at end of file diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts new file mode 100644 index 000000000..156e4efd9 --- /dev/null +++ b/src/new_fields/RichTextField.ts @@ -0,0 +1,12 @@ +import { ObjectField } from "./Doc"; +import { serializable } from "serializr"; + +export class RichTextField extends ObjectField { + @serializable(true) + readonly Data: string; + + constructor(data: string) { + super(); + this.Data = data; + } +} \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 4808d6e46..7fa18673f 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -38,10 +38,10 @@ export interface Interface { } export function Cast | ListSpec>(field: FieldResult, ctor: T): FieldResult>; -export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: WithoutList>): WithoutList>; -export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal?: ToType): FieldResult> | undefined { +export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: WithoutList> | null): WithoutList>; +export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal?: ToType | null): FieldResult> | undefined { if (field instanceof Promise) { - return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal; + return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal; } if (field !== undefined && !(field instanceof Promise)) { if (typeof ctor === "string") { @@ -56,18 +56,18 @@ export function Cast | ListSpec>(field: Fi return field as ToType; } } - return defaultVal; + return defaultVal === null ? undefined : defaultVal; } -export function NumCast(field: FieldResult, defaultVal: Opt = 0) { +export function NumCast(field: FieldResult, defaultVal: number | null = 0) { return Cast(field, "number", defaultVal); } -export function StrCast(field: FieldResult, defaultVal: Opt = "") { +export function StrCast(field: FieldResult, defaultVal: string | null = "") { return Cast(field, "string", defaultVal); } -export function BoolCast(field: FieldResult, defaultVal: Opt = undefined) { +export function BoolCast(field: FieldResult, defaultVal: boolean | null = null) { return Cast(field, "boolean", defaultVal); } -- cgit v1.2.3-70-g09d2 From d4a77dd055685dd81a762ef40e0c3b7606586e9c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 21:40:17 -0400 Subject: Split more files up --- src/client/DocServer.ts | 3 +- src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 3 +- src/client/util/Scripting.ts | 1 + src/client/views/Main.tsx | 3 +- .../views/collections/CollectionBaseView.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 3 +- .../CollectionFreeFormLinksView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/LinkMenu.tsx | 3 +- src/new_fields/Doc.ts | 37 +++------------------- src/new_fields/HtmlField.ts | 2 +- src/new_fields/IconField.ts | 2 +- src/new_fields/InkField.ts | 2 +- src/new_fields/List.ts | 3 +- src/new_fields/ObjectField.ts | 17 ++++++++++ src/new_fields/Proxy.ts | 4 ++- src/new_fields/RefField.ts | 18 +++++++++++ src/new_fields/RichTextField.ts | 2 +- src/new_fields/Schema.ts | 8 ++--- src/new_fields/Types.ts | 2 +- src/new_fields/URLField.ts | 2 +- src/new_fields/util.ts | 4 ++- .../authentication/controllers/WorkspacesMenu.tsx | 3 +- src/server/database.ts | 2 ++ 30 files changed, 88 insertions(+), 60 deletions(-) create mode 100644 src/new_fields/ObjectField.ts create mode 100644 src/new_fields/RefField.ts (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 3f17baec6..c7cbfce37 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,8 +1,9 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, Types, Message } from "./../server/Message"; -import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; +import { Opt, FieldWaiting } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; +import { RefField, HandleUpdate } from '../new_fields/RefField'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 118f4cf7f..730289536 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,7 +3,7 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField } from "../../../new_fields/Doc"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 4a65b14cf..a9c68ccba 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -20,7 +20,8 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { NumCast, Cast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/RefField"; @observer diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index dbec82340..e45f61c11 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -11,6 +11,7 @@ import { Docs } from "../documents/Documents"; import { Doc, Field } from '../../new_fields/Doc'; import { ImageField, PdfField, VideoField, AudioField } from '../../new_fields/URLField'; import { List } from '../../new_fields/List'; +import { RichTextField } from '../../new_fields/RichTextField'; export interface ScriptSucccess { success: true; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 1e3d4e259..4a68d1c68 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -33,10 +33,11 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; -import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { DocServer } from '../DocServer'; import { listSpec } from '../../new_fields/Schema'; +import { Id } from '../../new_fields/RefField'; @observer diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4807dc40a..b2fba1415 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -4,9 +4,10 @@ import * as React from 'react'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { Doc, FieldResult, Opt, Id } from '../../../new_fields/Doc'; +import { Doc, FieldResult, Opt } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; +import { Id } from '../../../new_fields/RefField'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2ff409b9b..1574562c6 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -13,11 +13,12 @@ import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; -import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { listSpec } from "../../../new_fields/Schema"; +import { Id, FieldId } from "../../../new_fields/RefField"; @observer export class CollectionDockingView extends React.Component { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 874170f3d..58d20819b 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -19,10 +19,11 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { Opt, Field, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Field, Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; +import { Id } from "../../../new_fields/RefField"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 558a8728f..4d090b680 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,12 +10,13 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, ObjectField, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; +import { ObjectField } from "../../../new_fields/ObjectField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c9d8d83c8..7ec9a8549 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,7 +10,8 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; import { Cast, StrCast, BoolCast } from '../../../new_fields/Types'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; +import { Id } from '../../../new_fields/RefField'; export interface TreeViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index ce9995630..f693d55e8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -7,10 +7,11 @@ import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { listSpec } from "../../../../new_fields/Schema"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 047fbad18..18107e98a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -19,10 +19,11 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index aabc1633e..c304b6a35 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -15,7 +15,7 @@ import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Field, Opt, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Doc } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FieldValue, Cast, PromiseValue } from "../../../new_fields/Types"; @@ -24,6 +24,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { MarqueeView } from "../collections/collectionFreeForm/MarqueeView"; import { DocServer } from "../../DocServer"; +import { Id } from "../../../new_fields/RefField"; const linkSchema = createSchema({ title: "string", diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index c00c47fc4..dc36c5914 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -16,6 +16,7 @@ import { Opt, Doc, FieldResult } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ImageField, VideoField, AudioField } from "../../../new_fields/URLField"; import { IconField } from "../../../new_fields/IconField"; +import { RichTextField } from "../../../new_fields/RichTextField"; // diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 3ecc8555d..e21adebbc 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -5,9 +5,10 @@ import { LinkBox } from "./LinkBox"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; +import { Id } from "../../../new_fields/RefField"; interface Props { docView: DocumentView; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index fb7b6e360..4ef2a465f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -8,38 +8,8 @@ import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types"; import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; import { List } from "./List"; - -export type FieldId = string; -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); -export abstract class RefField { - @serializable(alias("id", primitive())) - private __id: FieldId; - readonly [Id]: FieldId; - - constructor(id?: FieldId) { - this.__id = id || Utils.GenerateGuid(); - this[Id] = this.__id; - } - - protected [HandleUpdate]?(diff: any): void; -} - -export const Update = Symbol("Update"); -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; - private [Parent]?: Doc; - readonly [Id] = ""; -} - -export namespace ObjectField { - export function MakeCopy(field: ObjectField) { - //TODO Types - return field; - } -} +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId, Id } from "./RefField"; export function IsField(field: any): field is Field { return (typeof field === "string") @@ -53,6 +23,7 @@ export type Opt = T | undefined; export type FieldWaiting = T extends undefined ? never : Promise; export type FieldResult = Opt | FieldWaiting>; +export const Update = Symbol("Update"); export const Self = Symbol("Self"); @Deserializable("doc").withFields(["id"]) @@ -161,7 +132,7 @@ export namespace Doc { copy[key] = field; } } - }) + }); return copy; } diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index 76fdb1f62..808a3499b 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("html") export class HtmlField extends ObjectField { diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index 32f3aa4d5..46f111f8e 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("icon") export class IconField extends ObjectField { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 49e6bf61e..42223c494 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; export enum InkTool { None, diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index f01ac210a..428f661c9 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,8 +1,9 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, ObjectField, Update, OnUpdate, Self } from "./Doc"; +import { Field, Update, Self } from "./Doc"; import { setter, getter } from "./util"; import { serializable, alias, list } from "serializr"; import { observable } from "mobx"; +import { ObjectField, OnUpdate } from "./ObjectField"; @Deserializable("list") class ListImpl extends ObjectField { diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts new file mode 100644 index 000000000..9cac2c528 --- /dev/null +++ b/src/new_fields/ObjectField.ts @@ -0,0 +1,17 @@ +import { Doc } from "./Doc"; + +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +const Id = Symbol("Object Id"); +export class ObjectField { + protected [OnUpdate]?: (diff?: any) => void; + private [Parent]?: Doc; + readonly [Id] = ""; +} + +export namespace ObjectField { + export function MakeCopy(field: ObjectField) { + //TODO Types + return field; + } +} diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index 2aa78731e..56e41cc0f 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -1,8 +1,10 @@ import { Deserializable } from "../client/util/SerializationHelper"; -import { RefField, Id, ObjectField, FieldWaiting } from "./Doc"; +import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; +import { RefField, Id } from "./RefField"; +import { ObjectField } from "./ObjectField"; @Deserializable("proxy") export class ProxyField extends ObjectField { diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts new file mode 100644 index 000000000..202c65f21 --- /dev/null +++ b/src/new_fields/RefField.ts @@ -0,0 +1,18 @@ +import { serializable, primitive, alias } from "serializr"; +import { Utils } from "../Utils"; + +export type FieldId = string; +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export abstract class RefField { + @serializable(alias("id", primitive())) + private __id: FieldId; + readonly [Id]: FieldId; + + constructor(id?: FieldId) { + this.__id = id || Utils.GenerateGuid(); + this[Id] = this.__id; + } + + protected [HandleUpdate]?(diff: any): void; +} diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index 156e4efd9..0fa3cf73c 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,4 +1,4 @@ -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; export class RichTextField extends ObjectField { diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 5081521c7..7444878fe 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -21,15 +21,15 @@ export function makeInterface(...schemas: T): (doc?: Doc) } } const proto = new Proxy({}, { - get(target: any, prop) { - const field = target.doc[prop]; + get(target: any, prop, receiver) { + const field = receiver.doc[prop]; if (prop in schema) { return Cast(field, (schema as any)[prop]); } return field; }, - set(target: any, prop, value) { - target.doc[prop] = value; + set(target: any, prop, value, receiver) { + receiver.doc[prop] = value; return true; } }); diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 7fa18673f..3f8eabd45 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -1,4 +1,4 @@ -import { Field, Opt, FieldWaiting, FieldResult, RefField } from "./Doc"; +import { Field, Opt, FieldResult } from "./Doc"; import { List } from "./List"; export type ToType | ListSpec> = diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index 1da245e73..95c679df7 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; function url() { return custom( diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 2d9721b2e..011e8c8d9 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,8 +1,10 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc"; +import { Update, Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; +import { RefField, Id } from "./RefField"; +import { ObjectField, Parent, OnUpdate } from "./ObjectField"; export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 29327e5ad..91756315d 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -3,8 +3,9 @@ import { observable, action, configure, reaction, computed, ObservableMap, runIn import { observer } from "mobx-react"; import './WorkspacesMenu.css'; import { EditableView } from '../../../client/views/EditableView'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; import { StrCast } from '../../../new_fields/Types'; +import { Id } from '../../../new_fields/RefField'; export interface WorkspaceMenuProps { active: Doc | undefined; diff --git a/src/server/database.ts b/src/server/database.ts index a61b4d823..6b3b6797f 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,11 +60,13 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocument"); this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocuments"); this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); -- cgit v1.2.3-70-g09d2 From 506af03831bf3cc002f93ad8708eafb909c0a194 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 22:27:26 -0400 Subject: Various fixes --- src/client/DocServer.ts | 24 ++++++++++++++++++---- src/client/documents/Documents.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/collections/CollectionPDFView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 1 + .../views/collections/CollectionVideoView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/new_fields/util.ts | 5 +++-- src/server/database.ts | 21 +++++++++++++------ src/server/index.ts | 10 +++++---- 14 files changed, 55 insertions(+), 26 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c7cbfce37..07997f072 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -55,12 +55,28 @@ export namespace DocServer { map[id] = cached; } } - const prom = Utils.EmitCallback(_socket, MessageStore.GetFields, requestedIds); - requestedIds.map((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); + const prom = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds).then(fields => { + for (const key in fields) { + const field = fields[key]; + if (field) { + fields[key] = SerializationHelper.Deserialize(field); + } + } + return fields; + }); + requestedIds.forEach((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); const fields = await prom; - requestedIds.map((id, index) => map[id] = fields[index]); + requestedIds.forEach((id, index) => { + const field = fields[index]; + if (field) { + _cache[id] = field; + } else { + delete _cache[id]; + } + map[id] = field; + }); const otherFields = await Promise.all(promises); - waitingIds.map((id, index) => map[id] = otherFields[index]); + waitingIds.forEach((id, index) => map[id] = otherFields[index]); return map; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c30fb21d5..2a9687bda 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -138,7 +138,7 @@ export namespace Docs { return webProto; } function CreateCollectionPrototype(): Doc { - let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("DataKey"), + let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("data"), { panX: 0, panY: 0, scale: 1, width: 500, height: 500 }); return collProto; } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a9c68ccba..19d108676 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -26,7 +26,7 @@ import { Id } from "../../../new_fields/RefField"; @observer export class HistogramBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(HistogramBox, fieldStr); } private _dropXRef = React.createRef(); private _dropYRef = React.createRef(); private _dropXDisposer?: DragManager.DragDropDisposer; diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index e73b7b4a6..99438b4e8 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -13,7 +13,7 @@ import { NumCast } from "../../../new_fields/Types"; @observer export class CollectionPDFView extends React.Component { - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionPDFView, fieldKey); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 4d090b680..2c2d74302 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -53,6 +53,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @action protected async setCursorPosition(position: [number, number]) { + return; let ind; let doc = this.props.Document; let id = CurrentUserUtils.id; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index d314e3fc0..d45be228a 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -18,7 +18,7 @@ export class CollectionVideoView extends React.Component { @observable _currentTimecode: number = 0; @observable _isPlaying: boolean = false; - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e7bf1e121..b72065bca 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { trace } from 'mobx'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 18107e98a..dfacca204 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} - + {/* */} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index dc36c5914..df76f7cea 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -45,8 +45,8 @@ export interface FieldViewProps { @observer export class FieldView extends React.Component { - public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { - return `<${fieldType.name} {...props} fieldKey={${fieldStr}} />`; + public static LayoutString(fieldType: { name: string }, fieldStr: string = "data") { + return `<${fieldType.name} {...props} fieldKey={"${fieldStr}"} />`; } @computed diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a85c9dd3..96512718f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -55,7 +55,7 @@ const RichTextDocument = makeInterface(richTextSchema); @observer export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) { - public static LayoutString(fieldStr: string = "DataKey") { + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(FormattedTextBox, fieldStr); } private _ref: React.RefObject; diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index ae39ebe2d..876a3c173 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -14,7 +14,7 @@ import { Doc, IsField } from "../../../new_fields/Doc"; export class KeyValueBox extends React.Component { private _mainCont = React.createRef(); - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 011e8c8d9..b2299f34a 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -5,8 +5,9 @@ import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; import { RefField, Id } from "./RefField"; import { ObjectField, Parent, OnUpdate } from "./ObjectField"; +import { action } from "mobx"; -export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { +export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { target[prop] = value; return true; @@ -46,7 +47,7 @@ export function setter(target: any, prop: string | symbol | number, value: any, undo: () => receiver[prop] = curValue }); return true; -} +}); export function getter(target: any, prop: string | symbol | number, receiver: any): any { if (typeof prop === "symbol") { diff --git a/src/server/database.ts b/src/server/database.ts index 6b3b6797f..4775c0eeb 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,19 +60,28 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocument"); - this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => - fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); + this.db && this.db.collection(collectionName).findOne({ _id: id }, (err, result) => { + if (result) { + result.id = result._id; + delete result._id; + fn(result); + } else { + fn(undefined); + } + }); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocuments"); - this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { + this.db && this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } - fn(docs.map(doc => ({ id: doc._id, type: doc.type, data: doc.data }))); + fn(docs.map(doc => { + doc.id = doc._id; + delete doc._id; + return doc; + })); }); } diff --git a/src/server/index.ts b/src/server/index.ts index 10158eb96..6801b3132 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -234,16 +234,18 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); - Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); - Utils.AddServerHandler(socket, MessageStore.GetRefFields, GetRefFields); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); }); -function deleteFields() { - return Database.Instance.deleteAll(); +async function deleteFields() { + await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); } async function deleteAll() { await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); await Database.Instance.deleteAll('sessions'); await Database.Instance.deleteAll('users'); } -- cgit v1.2.3-70-g09d2 From a2751d16babb38cde2b86b1cb8fc5d74c15762d7 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 28 Apr 2019 00:23:18 -0400 Subject: Decent amount of stuff is working --- src/client/views/Main.tsx | 2 +- src/client/views/collections/CollectionBaseView.tsx | 2 +- src/client/views/collections/CollectionPDFView.tsx | 3 ++- src/client/views/collections/CollectionVideoView.tsx | 3 ++- src/client/views/collections/CollectionView.tsx | 3 ++- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 3 ++- src/client/views/nodes/PDFBox.tsx | 2 +- src/new_fields/RichTextField.ts | 2 ++ src/new_fields/Types.ts | 2 +- 12 files changed, 18 insertions(+), 11 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 4a68d1c68..98c5a5306 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -165,7 +165,7 @@ export class Main extends React.Component { @action openWorkspace = async (doc: Doc, fromHistory = false) => { this.mainContainer = doc; - fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc.Id); + fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc[Id]); const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(async () => { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index b2fba1415..ed761d3f3 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -95,7 +95,7 @@ export class CollectionBaseView extends React.Component { //TODO This won't create the field if it doesn't already exist const value = Cast(props.Document[props.fieldKey], listSpec(Doc)); if (value !== undefined) { - if (allowDuplicates || !value.some(v => v.Id === doc.Id)) { + if (allowDuplicates || !value.some(v => v[Id] === doc[Id])) { value.push(doc); } } else { diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 99438b4e8..5a1af354a 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -8,6 +8,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; import { emptyFunction } from "../../../Utils"; import { NumCast } from "../../../new_fields/Types"; +import { Id } from "../../../new_fields/RefField"; @observer @@ -33,7 +34,7 @@ export class CollectionPDFView extends React.Component { } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "PDFOptions", event: emptyFunction }); } } diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index d45be228a..7232ecea2 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -8,6 +8,7 @@ import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormV import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; import { NumCast } from "../../../new_fields/Types"; +import { Id } from "../../../new_fields/RefField"; @observer @@ -107,7 +108,7 @@ export class CollectionVideoView extends React.Component { } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "VideoOptions", event: emptyFunction }); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b72065bca..c2049a09a 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -10,6 +10,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_ import { observer } from 'mobx-react'; import { undoBatch } from '../../util/UndoManager'; import { trace } from 'mobx'; +import { Id } from '../../../new_fields/RefField'; @observer export class CollectionView extends React.Component { @@ -31,7 +32,7 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } // bcz: ? Why do we need to compare Id's? onContextMenu = (e: React.MouseEvent): void => { - if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform) }); ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema) }); ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree) }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dfacca204..dcded7648 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -257,7 +257,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { moveDocument: this.props.moveDocument, ScreenToLocalTransform: this.getTransform, isTopMost: false, - selectOnLoad: document.Id === this._selectOnLoaded, + selectOnLoad: document[Id] === this._selectOnLoaded, PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions PanelHeight: () => Cast(document.height, "number", 0), ContentScaling: returnOne, diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 376af0b36..8766eb7ea 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -20,6 +20,7 @@ const schema = createSchema({ zIndex: "number" }); +//TODO Types: The import order is wrong, so positionSchema is undefined type FreeformDocument = makeInterface<[typeof schema, typeof positionSchema]>; const FreeformDocument = makeInterface(schema, positionSchema); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c304b6a35..3814eeb9c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -139,7 +139,7 @@ export class DocumentView extends DocComponent(Docu } onClick = (e: React.MouseEvent): void => { - if (CurrentUserUtils.MainDocId !== this.props.Document.Id && + if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { SelectionManager.SelectDoc(this, e.ctrlKey); @@ -247,7 +247,7 @@ export class DocumentView extends DocComponent(Docu 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: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document.Id)) }); + ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])) }); ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]) }); //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 96512718f..c4c720ca9 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -22,6 +22,7 @@ import { observer } from "mobx-react"; import { InkingControl } from "../InkingControl"; import { StrCast, Cast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; +import { Id } from "../../../new_fields/RefField"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -108,7 +109,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }; if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id, + this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc[Id], () => { if (this._editorView) { this._editorView.destroy(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 7fbfed1c0..9f0849492 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -447,7 +447,7 @@ export class PDFBox extends DocComponent(PdfDocumen let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField); let xf = FieldValue(this.Document.nativeHeight, 0) / renderHeight; return
- + {({ measureRef }) =>
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index 0fa3cf73c..f2033d5a7 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,6 +1,8 @@ import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; +import { Deserializable } from "../client/util/SerializationHelper"; +@Deserializable("RichTextField") export class RichTextField extends ObjectField { @serializable(true) readonly Data: string; diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 3f8eabd45..e179c2602 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -76,7 +76,7 @@ type WithoutList = T extends List ? R[] : T; export function FieldValue>(field: FieldResult, defaultValue: U): WithoutList; export function FieldValue(field: FieldResult): Opt; export function FieldValue(field: FieldResult, defaultValue?: T): Opt { - return field instanceof Promise ? defaultValue : field; + return (field instanceof Promise || field === undefined) ? defaultValue : field; } export interface PromiseLike { -- cgit v1.2.3-70-g09d2 From 877b104a61d2ab072e3b6a006168ec03e2c46365 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 30 Apr 2019 00:11:27 -0400 Subject: Mostly fixed lists --- src/client/util/UndoManager.ts | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/debug/Test.tsx | 8 +- src/new_fields/Doc.ts | 10 +- src/new_fields/List.ts | 192 +++++++++++++++++---- src/new_fields/util.ts | 8 + 6 files changed, 179 insertions(+), 44 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index f7c3e5a7b..0b5280c4a 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -141,10 +141,10 @@ export namespace UndoManager { }); //TODO Make this return the return value - export function RunInBatch(fn: () => void, batchName: string) { + export function RunInBatch(fn: () => T, batchName: string) { let batch = StartBatch(batchName); try { - runInAction(fn); + return runInAction(fn); } finally { batch.end(); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dcded7648..d796bd8d5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -272,6 +272,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { get views() { let curPage = FieldValue(this.Document.curPage, -1); let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { + if (!FieldValue(doc)) return prev; var page = Cast(doc.page, "number", -1); if (page === curPage || page === -1) { let minim = Cast(doc.isMinimized, "boolean"); diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 7415d4b28..04ef00722 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -61,14 +61,12 @@ class Test extends React.Component { assert(test2.testDoc === undefined); test2.url = 35; assert(test2.url === 35); - const l = new List(); + const l = new List(); //TODO push, and other array functions don't go through the proxy - l.push(1); + l.push(doc2); //TODO currently length, and any other string fields will get serialized - l.length = 3; - l[2] = 5; + doc.list = l; console.log(l.slice()); - console.log(SerializationHelper.Serialize(l)); } render() { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index d15b6309d..6ddb0df89 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -3,7 +3,7 @@ import { serializable, primitive, map, alias, list } from "serializr"; import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; import { Utils } from "../Utils"; import { DocServer } from "../client/DocServer"; -import { setter, getter, getField, updateFunction } from "./util"; +import { setter, getter, getField, updateFunction, deleteProperty } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types"; import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; @@ -34,7 +34,7 @@ export class Doc extends RefField { set: setter, get: getter, ownKeys: target => Object.keys(target.__fields), - deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + deleteProperty: deleteProperty, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); if (!id || forceSave) { @@ -151,8 +151,8 @@ export namespace Doc { } export function MakeLink(source: Doc, target: Doc): Doc { - let linkDoc = new Doc; - UndoManager.RunInBatch(() => { + return UndoManager.RunInBatch(() => { + let linkDoc = new Doc; linkDoc.title = "New Link"; linkDoc.linkDescription = ""; linkDoc.linkTags = "Default"; @@ -171,8 +171,8 @@ export namespace Doc { source.linkedToDocs = linkedTo = new List(); } linkedTo.push(linkDoc); + return linkDoc; }, "make link"); - return linkDoc; } export function MakeDelegate(doc: Doc): Doc; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index e4a80f7a1..ec1bf44a9 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,21 +1,173 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self } from "./Doc"; -import { setter, getter } from "./util"; +import { setter, getter, deleteProperty } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda, reaction } from "mobx"; import { ObjectField, OnUpdate } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ProxyField } from "./Proxy"; const listHandlers: any = { - push(...items: any[]) { - // console.log("push"); - // console.log(...items); - return this[Self].__fields.push(...items); + /// Mutator methods + copyWithin() { + throw new Error("copyWithin not supported yet"); + }, + fill(value: any, start?: number, end?: number) { + if (value instanceof RefField) { + throw new Error("fill with RefFields not supported yet"); + } + const res = this[Self].__fields.fill(value, start, end); + this[Update](); + return res; }, pop(): any { - return this[Self].__fields.pop(); + const field = toRealField(this[Self].__fields.pop()); + this[Update](); + return field; + }, + push(...items: any[]) { + items = items.map(toObjectField); + const res = this[Self].__fields.push(...items); + this[Update](); + return res; + }, + reverse() { + const res = this[Self].__fields.reverse(); + this[Update](); + return res; + }, + shift() { + const res = toRealField(this[Self].__fields.shift()); + this[Update](); + return res; + }, + sort(cmpFunc: any) { + const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined); + this[Update](); + return res; + }, + splice(start: number, deleteCount: number, ...items: any[]) { + items = items.map(toObjectField); + const res = this[Self].__fields.splice(start, deleteCount, ...items); + this[Update](); + return res.map(toRealField); + }, + unshift(...items: any[]) { + items = items.map(toObjectField); + const res = this[Self].__fields.unshift(...items); + this[Update](); + return res; + + }, + /// Accessor methods + concat(...items: any[]) { + return this[Self].__fields.map(toRealField).concat(...items); + }, + includes(valueToFind: any, fromIndex: number) { + const fields = this[Self].__fields; + if (valueToFind instanceof RefField) { + return fields.map(toRealField).includes(valueToFind, fromIndex); + } else { + return fields.includes(valueToFind, fromIndex); + } + }, + indexOf(valueToFind: any, fromIndex: number) { + const fields = this[Self].__fields; + if (valueToFind instanceof RefField) { + return fields.map(toRealField).indexOf(valueToFind, fromIndex); + } else { + return fields.indexOf(valueToFind, fromIndex); + } + }, + join(separator: any) { + return this[Self].__fields.map(toRealField).join(separator); + }, + lastIndexOf(valueToFind: any, fromIndex: number) { + const fields = this[Self].__fields; + if (valueToFind instanceof RefField) { + return fields.map(toRealField).lastIndexOf(valueToFind, fromIndex); + } else { + return fields.lastIndexOf(valueToFind, fromIndex); + } + }, + slice(begin: number, end: number) { + return this[Self].__fields.slice(begin, end).map(toRealField); + }, + + /// Iteration methods + entries() { + return this[Self].__fields.map(toRealField).entries(); + }, + every(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).every(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + filter(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).filter(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + find(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).find(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + findIndex(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).findIndex(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + forEach(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).forEach(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + map(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).map(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + reduce(callback: any, initialValue: any) { + return this[Self].__fields.map(toRealField).reduce(callback, initialValue); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); + }, + reduceRight(callback: any, initialValue: any) { + return this[Self].__fields.map(toRealField).reduceRight(callback, initialValue); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); + }, + some(callback: any, thisArg: any) { + return this[Self].__fields.map(toRealField).some(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + values() { + return this[Self].__fields.map(toRealField).values(); + }, + [Symbol.iterator]() { + return this[Self].__fields.map(toRealField).values(); } }; +function toObjectField(field: Field) { + return field instanceof RefField ? new ProxyField(field) : field; +} + +function toRealField(field: Field) { + return field instanceof ProxyField ? field.value() : field; +} + function listGetter(target: any, prop: string | number | symbol, receiver: any): any { if (listHandlers.hasOwnProperty(prop)) { return listHandlers[prop]; @@ -38,36 +190,15 @@ interface ListIndexUpdate { type ListUpdate = ListSpliceUpdate | ListIndexUpdate; -const ObserveDisposer = Symbol("Observe Disposer"); - -function listObserver(this: ListImpl, change: IArrayChange | IArraySplice) { - if (change.type === "splice") { - this[Update]({ - index: change.index, - removedCount: change.removedCount, - added: change.added, - type: change.type - }); - } else { - //This should already be handled by the getter for the Proxy - // this[Update]({ - // index: change.index, - // newValue: change.newValue, - // type: change.type - // }); - } -} - @Deserializable("list") class ListImpl extends ObjectField { constructor(fields: T[] = []) { super(); this.___fields = fields; - this[ObserveDisposer] = observe(this.__fields as IObservableArray, listObserver.bind(this)); const list = new Proxy(this, { set: setter, - get: getter, - deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + get: listGetter, + deleteProperty: deleteProperty, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); return list; @@ -82,8 +213,6 @@ class ListImpl extends ObjectField { private set __fields(value) { this.___fields = value; - this[ObserveDisposer](); - this[ObserveDisposer] = observe(this.__fields as IObservableArray, listObserver.bind(this)); } // @serializable(alias("fields", list(autoObject()))) @@ -97,7 +226,6 @@ class ListImpl extends ObjectField { update && update(); } - private [ObserveDisposer]: Lambda; private [Self] = this; } export type List = ListImpl & T[]; diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 511820115..128817ab8 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -78,6 +78,14 @@ export function getField(target: any, prop: string | number, ignoreProto: boolea return field; } +export function deleteProperty(target: any, prop: string | number | symbol) { + if (typeof prop === "symbol") { + delete target[prop]; + return true; + } + throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); +} + export function updateFunction(target: any, prop: any, value: any) { return (diff?: any) => { if (!diff) diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; -- cgit v1.2.3-70-g09d2 From 654ad2b11a3dc98c2e802c535b0cd615e50a486c Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 30 Apr 2019 09:36:00 -0400 Subject: fixed marquee select doc placement --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 644a8784c..df1e7a90e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -143,8 +143,8 @@ export class MarqueeView extends React.Component let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); - d.x = NumCast(d.X) - bounds.left - bounds.width / 2; - d.y = NumCast(d.Y) - bounds.top - bounds.height / 2; + d.x = NumCast(d.x) - bounds.left - bounds.width / 2; + d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.page = -1; return d; }); -- cgit v1.2.3-70-g09d2 From e013b7b146f91b0ffbc26e3770f5f90f417da60b Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 30 Apr 2019 12:09:54 -0400 Subject: fixed inking --- src/client/views/InkingCanvas.tsx | 18 +++++++++++------- src/client/views/InkingStroke.scss | 3 +++ src/client/views/InkingStroke.tsx | 8 ++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 ++++++++++------- src/new_fields/Doc.ts | 6 +++++- 5 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 src/client/views/InkingStroke.scss (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 1e26893c5..1c0d13545 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -139,21 +139,25 @@ export class InkingCanvas extends React.Component { let curPage = NumCast(this.props.Document.curPage, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { if (strokeData.page === -1 || strokeData.page === curPage) { - paths.push(); + color={strokeData.color} + width={strokeData.width} + tool={strokeData.tool} + deleteCallback={this.removeLine} />); } return paths; }, [] as JSX.Element[]); - return [ - {paths.filter(path => path.props.tool === InkTool.Highlighter)} + {paths.filter(path => path.props.tool !== InkTool.Highlighter)} , - - {paths.filter(path => path.props.tool !== InkTool.Highlighter)} + {paths.filter(path => path.props.tool === InkTool.Highlighter)} ]; } diff --git a/src/client/views/InkingStroke.scss b/src/client/views/InkingStroke.scss new file mode 100644 index 000000000..cdbfdcff3 --- /dev/null +++ b/src/client/views/InkingStroke.scss @@ -0,0 +1,3 @@ +.inkingStroke-marker { + mix-blend-mode: multiply +} \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 616299146..37b1f5899 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,14 +1,16 @@ import { observer } from "mobx-react"; -import { observable } from "mobx"; +import { observable, trace } from "mobx"; import { InkingControl } from "./InkingControl"; import React = require("react"); import { InkTool } from "../../new_fields/InkField"; +import "./InkingStroke.scss"; interface StrokeProps { offsetX: number; offsetY: number; id: string; + count: number; line: Array<{ x: number, y: number }>; color: string; width: string; @@ -48,10 +50,12 @@ export class InkingStroke extends React.Component { render() { let pathStyle = this.createStyle(); let pathData = this.parseData(this.props.line); + let pathlength = this.props.count; // bcz: this is needed to force reactions to the line data changes + let marker = this.props.tool === InkTool.Highlighter ? "-marker" : ""; let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none"; return ( - ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d796bd8d5..2689f48cd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from "mobx"; +import { action, computed, trace } from "mobx"; import { observer } from "mobx-react"; import { emptyFunction, returnFalse, returnOne } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; @@ -19,7 +19,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; @@ -243,11 +243,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { focusDocument = (doc: Doc) => { this.setPan( - Cast(doc.x, "number", 0) + Cast(doc.width, "number", 0) / 2, - Cast(doc.y, "number", 0) + Cast(doc.height, "number", 0) / 2); + NumCast(doc.x) + NumCast(doc.width) / 2, + NumCast(doc.y) + NumCast(doc.height) / 2); this.props.focus(this.props.Document); } + getDocumentViewProps(document: Doc): DocumentViewProps { return { Document: document, @@ -258,8 +259,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ScreenToLocalTransform: this.getTransform, isTopMost: false, selectOnLoad: document[Id] === this._selectOnLoaded, - PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions - PanelHeight: () => Cast(document.height, "number", 0), + PanelWidth: document[WidthSym], + PanelHeight: document[HeightSym], ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, @@ -268,8 +269,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - @computed + @computed.struct get views() { + trace(); let curPage = FieldValue(this.Document.curPage, -1); let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { if (!FieldValue(doc)) return prev; @@ -295,6 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private childViews = () => [...this.views, ]; render() { + trace(); const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; return (
= Opt | FieldWaiting { return NumCast(this.__fields.width); } // bcz: is this the right way to access width/height? it didn't work with : this.width + public [HeightSym] = () => { return NumCast(this.__fields.height); } } export namespace Doc { -- cgit v1.2.3-70-g09d2 From 37062ef8b33efebd9fafcd2c076d5cb49f5a288f Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 30 Apr 2019 13:43:15 -0400 Subject: from commit --- src/client/documents/Documents.ts | 12 ++++-------- src/client/views/DocumentDecorations.tsx | 3 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 ++------ 3 files changed, 7 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index aa5277910..ff21dd5b0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,11 +32,7 @@ import { IconField } from "../../new_fields/IconField"; import { listSpec } from "../../new_fields/Schema"; import { DocServer } from "../DocServer"; import { StrokeData, InkField } from "../../new_fields/InkField"; -import { KeyStore } from "../../fields/KeyStore"; -// export class stringArray implements List { -// public Values: string[] = []; -// } export interface DocumentOptions { x?: number; y?: number; @@ -60,7 +56,7 @@ export interface DocumentOptions { curPage?: number; documentText?: string; borderRounding?: number; - //schemaColumns?: stringArray; + schemaColumns?: List; // [key: string]: Opt; } const delegateKeys = ["x", "y", "width", "height", "panX", "panY"]; @@ -243,13 +239,13 @@ export namespace Docs { if (!makePrototype) { return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, new List(documents)); } - return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns],*/...options, viewType: CollectionViewType.Freeform }); + return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Freeform }); } export function SchemaDocument(documents: Array, options: DocumentOptions) { - return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns], */...options, viewType: CollectionViewType.Schema }); + return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Schema }); } export function TreeDocument(documents: Array, options: DocumentOptions) { - return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns], */...options, viewType: CollectionViewType.Tree }); + return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Tree }); } export function DockDocument(config: string, options: DocumentOptions) { return CreateInstance(collProto, config, { ...options, viewType: CollectionViewType.Docking }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 556117c54..8632286ab 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -18,7 +18,6 @@ import { Doc, FieldResult } from "../../new_fields/Doc"; import { listSpec } from "../../new_fields/Schema"; import { Docs } from "../documents/Documents"; import { List } from "../../new_fields/List"; -import { KeyStore } from "../../fields/KeyStore"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -40,7 +39,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @observable private _minimizedY = 0; @observable private _title: string = ""; @observable private _edtingTitle = false; - @observable private _fieldKey = KeyStore.Title; + @observable private _fieldKey = "title"; @observable private _hidden = false; @observable private _opacity = 1; @observable private _iconifying = false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f99800e21..8d10666b7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -22,9 +22,7 @@ import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Sc import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; -import { List } from "../../../../new_fields/List"; import { Id } from "../../../../new_fields/RefField"; -import { KeyStore } from "../../../../fields/KeyStore"; export const panZoomSchema = createSchema({ panX: "number", @@ -272,7 +270,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed.struct get views() { - trace(); let curPage = FieldValue(this.Document.curPage, -1); let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { if (!FieldValue(doc)) return prev; @@ -298,7 +295,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private childViews = () => [...this.views, ]; render() { - trace(); const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; return (
{ @computed get overlayView() { let overlayLayout = Cast(this.props.Document.overlayLayout, "string", ""); return !overlayLayout ? (null) : - (); } render() { @@ -346,7 +342,7 @@ class CollectionFreeFormBackgroundView extends React.Component); } render() { -- cgit v1.2.3-70-g09d2 From 7261d69c9e9dcdbcc413eff062eb01de2032f9ef Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 30 Apr 2019 15:21:20 -0400 Subject: fixed link lines --- src/client/views/DocumentDecorations.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 4 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 +++++-------------- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 ++ src/client/views/nodes/DocumentView.tsx | 9 +++++---- 6 files changed, 16 insertions(+), 24 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8632286ab..1dc7c8394 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -268,7 +268,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> minDocs.map(minDoc => { minDoc.x = NumCast(minDocs[0].x); minDoc.y = NumCast(minDocs[0].y); - minDoc.linkTags = new List(minDocs); + minDoc.linkTags = new List(minDocs.filter(d => d != minDoc)); if (this._iconifying && selectedDocs[0].props.removeDocument) { selectedDocs[0].props.removeDocument(minDoc); (minDoc.maximizedDoc as Doc).minimizedDoc = undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index e5dcf8c29..4a75fccff 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -85,10 +85,10 @@ export class CollectionFreeFormLinksView extends React.Component - child.Id === collid).map(view => + child[Id] === collid).map(view => DocumentManager.Instance.getDocumentViews(view).map(view => equalViews.push(view))); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8d10666b7..e54553d2b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -97,7 +97,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!NumCast(d.height)) { let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); - d.height = nw && nh ? nh / nw * NumCast(d.Width) : 300; + d.height = nw && nh ? nh / nw * NumCast(d.width) : 300; } this.bringToFront(d); }); @@ -108,12 +108,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return false; } - @action - cleanupInteractions = () => { - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - } - @action onPointerDown = (e: React.PointerEvent): void => { let childSelected = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), [] as Doc[]).filter(doc => doc).reduce((childSelected, doc) => { @@ -125,7 +119,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { (e.button === 0 && e.altKey)) && (childSelected || this.props.active()))) || (!CollectionFreeFormView.RIGHT_BTN_DRAG && ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && (childSelected || this.props.active())))) { - this.cleanupInteractions(); + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); document.addEventListener("pointerup", this.onPointerUp); this._lastX = e.pageX; @@ -134,7 +129,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } onPointerUp = (e: PointerEvent): void => { - this.cleanupInteractions(); + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); } @action @@ -300,11 +296,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
- {/* - - {this.props.Document.Title} - - */} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1d3850a72..85a12defa 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -109,9 +109,7 @@ export class MarqueeView extends React.Component onClick = (e: React.MouseEvent): void => { if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - if (this.props.isSelected()) { - PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress); - } + PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress); // let the DocumentView stopPropagation of this event when it selects this document } else { // why do we get a click event when the cursor have moved a big distance? // let's cut it off here so no one else has to deal with it. diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index bd084bfe0..c8f0bca91 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -114,6 +114,8 @@ export class CollectionFreeFormDocumentView extends DocComponent d); + docs.push(this.props.Document); minimizedDocSet.map(async minimizedDoc => { if (minimizedDoc instanceof Document) { this.props.addDocument && this.props.addDocument(minimizedDoc, false); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ac3dcde42..eab068355 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -308,8 +308,8 @@ export class DocumentView extends DocComponent(Docu isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); - @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } - @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } + @computed get nativeWidth() { return this.Document.nativeWidth || 0; } + @computed get nativeHeight() { return this.Document.nativeHeight || 0; } @computed get contents() { return (); } render() { @@ -322,8 +322,9 @@ export class DocumentView extends DocComponent(Docu ref={this._mainCont} style={{ borderRadius: "inherit", - background: FieldValue(this.Document.backgroundColor) || "", - width: nativeWidth, height: nativeHeight, + background: this.Document.backgroundColor || "", + width: nativeWidth, + height: nativeHeight, transform: `scale(${scaling}, ${scaling})` }} onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} -- cgit v1.2.3-70-g09d2 From ca4a0a6454e69f0eeabdfb6ec78f8ecd60e18b76 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 1 May 2019 02:03:40 -0400 Subject: Undo with lists is working better --- src/client/views/DocumentDecorations.tsx | 8 ++++---- .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 4 ++-- src/new_fields/Doc.ts | 9 ++++++--- src/new_fields/List.ts | 2 +- src/new_fields/util.ts | 16 +++++++++++++--- 5 files changed, 26 insertions(+), 13 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3ed8ba3b2..2a6d72dbc 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -57,8 +57,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> reaction(() => SelectionManager.SelectedDocuments().slice(), (docs) => docs.length === 0 && (this._edtingTitle = false)); } - @action titleChanged = (event: any) => { this._title = event.target.value; } - @action titleBlur = () => { this._edtingTitle = false; } + @action titleChanged = (event: any) => { this._title = event.target.value; }; + @action titleBlur = () => { this._edtingTitle = false; }; @action titleEntered = (e: any) => { var key = e.keyCode || e.which; // enter pressed @@ -238,7 +238,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc.y = NumCast(doc.y) - 24; iconDoc.maximizedDoc = doc; doc.minimizedDoc = iconDoc; - console.log("Layout " + iconDoc.layout) + console.log("Layout " + iconDoc.layout); docView.props.addDocument && docView.props.addDocument(iconDoc, false); return iconDoc; } @@ -274,7 +274,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> minDocs.map(minDoc => { minDoc.x = NumCast(minDocs[0].x); minDoc.y = NumCast(minDocs[0].y); - minDoc.linkTags = new List(minDocs.filter(d => d != minDoc)); + minDoc.linkTags = new List(minDocs.filter(d => d !== minDoc)); if (this._iconifying && selectedDocs[0].props.removeDocument) { selectedDocs[0].props.removeDocument(minDoc); (minDoc.maximizedDoc as Doc).minimizedDoc = undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 4a75fccff..b34e0856e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -60,11 +60,11 @@ export class CollectionFreeFormLinksView extends React.Component(); } let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc)); if (srcBrushDocs === undefined) { - srcTarg.brushingDocs = srcBrushDocs = new List(); + srcTarg.brushingDocs = srcBrushDocs = new List(); } brushAction(dstBrushDocs); brushAction(srcBrushDocs); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 113380ce8..b2979af11 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -25,6 +25,7 @@ export type FieldResult = Opt | FieldWaiting { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); + this[SelfProxy] = doc; if (!id || forceSave) { DocServer.CreateField(SerializationHelper.Serialize(doc)); } @@ -68,7 +70,7 @@ export class Doc extends RefField { const field = value[key]; if (!(field instanceof ObjectField)) continue; field[Parent] = this[Self]; - field[OnUpdate] = updateFunction(this[Self], key, field); + field[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); } } @@ -81,8 +83,9 @@ export class Doc extends RefField { } private [Self] = this; - public [WidthSym] = () => { return NumCast(this.__fields.width); } // bcz: is this the right way to access width/height? it didn't work with : this.width - public [HeightSym] = () => { return NumCast(this.__fields.height); } + private [SelfProxy]: any; + public [WidthSym] = () => NumCast(this.__fields.width); // bcz: is this the right way to access width/height? it didn't work with : this.width + public [HeightSym] = () => NumCast(this.__fields.height); } export namespace Doc { diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 5852e2c30..ff10a3f73 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -218,7 +218,7 @@ class ListImpl extends ObjectField { } [Copy]() { - let copiedData = this.__fields.map(f => f instanceof ObjectField ? f[Copy]() : f); + let copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f); let deepCopy = new ListImpl(copiedData as any); return deepCopy; } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 128817ab8..bbd8157f6 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -31,7 +31,7 @@ export const setter = action(function (target: any, prop: string | symbol | numb throw new Error("Can't put the same object in multiple documents at the same time"); } value[Parent] = target; - value[OnUpdate] = updateFunction(target, prop, value); + value[OnUpdate] = updateFunction(target, prop, value, receiver); } if (curValue instanceof ObjectField) { delete curValue[Parent]; @@ -86,9 +86,19 @@ export function deleteProperty(target: any, prop: string | number | symbol) { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); } -export function updateFunction(target: any, prop: any, value: any) { +export function updateFunction(target: any, prop: any, value: any, receiver: any) { + let current = ObjectField.MakeCopy(value); return (diff?: any) => { - if (!diff) diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + if (true || !diff) { + diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + const oldValue = current; + const newValue = ObjectField.MakeCopy(value); + current = newValue; + UndoManager.AddEvent({ + redo() { receiver[prop] = newValue; }, + undo() { receiver[prop] = oldValue; } + }); + } target[Update](diff); }; } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 105ba2402ad0da59d3d0750fa045a0f47eb73848 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 1 May 2019 10:51:17 -0400 Subject: cleaned up videos a bit. --- .../views/collections/CollectionVideoView.tsx | 90 ++++++++-------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 5 +- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/VideoBox.tsx | 37 ++++----- 5 files changed, 55 insertions(+), 82 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 7232ecea2..9dee217cb 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,17 +7,16 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; -import { NumCast } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/RefField"; +import { VideoBox } from "../nodes/VideoBox"; @observer export class CollectionVideoView extends React.Component { - private _intervalTimer: any = undefined; - private _player: HTMLVideoElement | undefined = undefined; + private _videoBox: VideoBox | undefined = undefined; + @observable _playTimer?: NodeJS.Timeout = undefined; @observable _currentTimecode: number = 0; - @observable _isPlaying: boolean = false; public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionVideoView, fieldKey); @@ -30,7 +29,7 @@ export class CollectionVideoView extends React.Component { {" " + Math.round((this._currentTimecode - Math.trunc(this._currentTimecode)) * 100)}
,
- {this._isPlaying ? "\"" : ">"} + {this._playTimer ? "\"" : ">"}
,
F @@ -38,61 +37,37 @@ export class CollectionVideoView extends React.Component { ]); } - _ele: HTMLDivElement | null = null; @action - mainCont = (ele: HTMLDivElement | null) => { - this._ele = ele; - if (ele) { - this._player = ele.getElementsByTagName("video")[0]; - console.log(this._player); - const curPage = NumCast(this.props.Document.curPage, -1); - if (curPage >= 0) { - this._currentTimecode = curPage; - } + updateTimecode = () => { + if (this._videoBox && this._videoBox.player) { + this._currentTimecode = this._videoBox.player.currentTime; + this.props.Document.curPage = Math.round(this._currentTimecode); } } - componentDidMount() { - this._intervalTimer = setInterval(this.updateTimecode, 1000); - } + componentDidMount() { this.updateTimecode(); } - componentWillUnmount() { - clearInterval(this._intervalTimer); - } - - @action - updateTimecode = () => { - this._player = this._player ? this._player : this._ele ? this._ele.getElementsByTagName("video")[0] : undefined; - if (this._player) { - let timecode = (this._player as any).hasOwnProperty("AHackBecauseSomethingResetsTheVideoToZero") ? - (this._player as any).AHackBecauseSomethingResetsTheVideoToZero : -1; - if (timecode !== -1 && Object) { - this._player.currentTime = timecode; - (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; - } else { - this._currentTimecode = this._player.currentTime; - this.props.Document.curPage = Math.round(this._currentTimecode); - } - } - } + componentWillUnmount() { if (this._playTimer) clearInterval(this._playTimer); } @action onPlayDown = () => { - if (this._player) { - if (this._player.paused) { - this._player.play(); - this._isPlaying = true; + if (this._videoBox && this._videoBox.player) { + if (this._videoBox.player.paused) { + this._videoBox.player.play(); + if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 1000); } else { - this._player.pause(); - this._isPlaying = false; + this._videoBox.player.pause(); + if (this._playTimer) clearInterval(this._playTimer); + this._playTimer = undefined; + } } } @action onFullDown = (e: React.PointerEvent) => { - if (this._player) { - this._player.requestFullscreen(); + if (this._videoBox && this._videoBox.player) { + this._videoBox.player.requestFullscreen(); e.stopPropagation(); e.preventDefault(); } @@ -100,11 +75,13 @@ export class CollectionVideoView extends React.Component { @action onResetDown = () => { - if (this._player) { - this._player.pause(); - this._player.currentTime = 0; + if (this._videoBox && this._videoBox.player) { + this._videoBox.player.pause(); + this._videoBox.player.currentTime = 0; + if (this._playTimer) clearInterval(this._playTimer); + this._playTimer = undefined; + this.updateTimecode(); } - } onContextMenu = (e: React.MouseEvent): void => { @@ -113,20 +90,19 @@ export class CollectionVideoView extends React.Component { } } + setVideoBox = (player: VideoBox) => { this._videoBox = player; } + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; - return ( - <> - - {this.props.isSelected() ? this.uIButtons : (null)} - - ); + return (<> + + {this.props.isSelected() ? this.uIButtons : (null)} + ); } render() { - trace(); return ( - + {this.subView} ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4b759b948..54b721f7b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -71,7 +71,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { public getActiveDocuments = () => { const curPage = FieldValue(this.Document.curPage, -1); return FieldValue(this.children, [] as Doc[]).filter(doc => { - var page = Cast(doc.page, "number", -1); + var page = NumCast(doc.page, -1); return page === curPage || page === -1; }); } @@ -274,7 +274,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let curPage = FieldValue(this.Document.curPage, -1); let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { if (!FieldValue(doc)) return prev; - var page = Cast(doc.page, "number", -1); + var page = NumCast(doc.page, -1); if (page === curPage || page === -1) { let minim = Cast(doc.isMinimized, "boolean"); if (minim === undefined || !minim) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cda9f9473..f58dc4a02 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -18,12 +18,11 @@ import "./DocumentView.scss"; import React = require("react"); import { Opt, Doc } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; -import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; -import { FieldValue, Cast, PromiseValue, StrCast } from "../../../new_fields/Types"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { FieldValue, StrCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { MarqueeView } from "../collections/collectionFreeForm/MarqueeView"; import { DocServer } from "../../DocServer"; import { Id } from "../../../new_fields/RefField"; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index c04b91c21..63009f2db 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -41,6 +41,7 @@ export interface FieldViewProps { focus: (doc: Doc) => void; PanelWidth: () => number; PanelHeight: () => number; + setVideoBox?: (player: VideoBox) => void; } @observer diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 184a89dbc..422508f90 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -2,15 +2,16 @@ import React = require("react"); import { observer } from "mobx-react"; import { FieldView, FieldViewProps } from './FieldView'; import "./VideoBox.scss"; -import { action, computed } from "mobx"; +import { action, computed, trace } from "mobx"; import { DocComponent } from "../DocComponent"; import { positionSchema } from "./DocumentView"; import { makeInterface } from "../../../new_fields/Schema"; import { pageSchema } from "./ImageBox"; -import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { Cast, FieldValue, NumCast, ToConstructor, ListSpec } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; import Measure from "react-measure"; import "./VideoBox.scss"; +import { Field, FieldResult, Opt } from "../../../new_fields/Doc"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); @@ -18,24 +19,20 @@ const VideoDocument = makeInterface(positionSchema, pageSchema); @observer export class VideoBox extends DocComponent(VideoDocument) { - private _videoRef = React.createRef(); + private _videoRef: HTMLVideoElement | null = null; + private _loaded: boolean = false; + private get initialTimecode() { return FieldValue(this.Document.curPage, -1); } public static LayoutString() { return FieldView.LayoutString(VideoBox); } - constructor(props: FieldViewProps) { - super(props); + public get player(): HTMLVideoElement | undefined { + if (this._videoRef) { + return this._videoRef; + } } - - @computed private get curPage() { return FieldValue(this.Document.curPage, -1); } - - - _loaded: boolean = false; - @action setScaling = (r: any) => { if (this._loaded) { // bcz: the nativeHeight should really be set when the document is imported. - // also, the native dimensions could be different for different pages of the PDF - // so this design is flawed. var nativeWidth = FieldValue(this.Document.nativeWidth, 0); var nativeHeight = FieldValue(this.Document.nativeHeight, 0); var newNativeHeight = nativeWidth * r.entry.height / r.entry.width; @@ -48,26 +45,26 @@ export class VideoBox extends DocComponent(VideoD } } - get player(): HTMLVideoElement | undefined { - return this._videoRef.current ? this._videoRef.current.getElementsByTagName("video")[0] : undefined; + componentDidMount() { + if (this.props.setVideoBox) this.props.setVideoBox(this); } @action setVideoRef = (vref: HTMLVideoElement | null) => { - if (this.curPage >= 0 && vref) { - vref.currentTime = this.curPage; - (vref as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage; + this._videoRef = vref; + if (this.initialTimecode >= 0 && vref) { + vref.currentTime = this.initialTimecode; } } videoContent(path: string) { return ; + ; } render() { - let field = FieldValue(Cast(this.Document[this.props.fieldKey], VideoField)); + let field = Cast(this.Document[this.props.fieldKey], VideoField); if (!field) { return
Loading
; } -- cgit v1.2.3-70-g09d2 From 407c104f0ad0957d71f73c14f5b835fab387ecd2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 2 May 2019 00:50:08 -0400 Subject: fixed up templates a bit. starting on summarization --- src/client/views/Templates.tsx | 3 ++ .../collections/collectionFreeForm/MarqueeView.tsx | 5 +++- src/client/views/nodes/DocumentContentsView.tsx | 25 +++++++++++++++-- src/client/views/nodes/DocumentView.tsx | 32 ++++------------------ 4 files changed, 36 insertions(+), 29 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 25d89772e..e17dd2354 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -53,6 +53,9 @@ export namespace Templates { export const Title = new Template("Title", TemplatePosition.InnerTop, `
{layout}
{props.Document.title}
` ); + export const Summary = new Template("Title", TemplatePosition.InnerTop, + `
{layout}
{props.Document.doc1.title}
` + ); export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption]; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 85a12defa..c58e7780c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -13,6 +13,8 @@ import { Utils } from "../../../../Utils"; import { Doc } from "../../../../new_fields/Doc"; import { NumCast, Cast } from "../../../../new_fields/Types"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; +import { Templates } from "../../Templates"; +import { List } from "../../../../new_fields/List"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -178,7 +180,8 @@ export class MarqueeView extends React.Component // SelectionManager.DeselectAll(); if (e.key === "r") { let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - Doc.MakeLink(summary.proto!, newCollection.proto!); + summary.doc1 = newCollection.proto!; + summary.templates = new List([Templates.Summary.Layout]); this.props.addLiveTextDocument(summary); e.preventDefault(); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 794442469..24e8a36ae 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -20,7 +20,8 @@ import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); import { FieldViewProps } from "./FieldView"; import { Without, OmitKeys } from "../../../Utils"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, StrCast } from "../../../new_fields/Types"; +import { List } from "../../../new_fields/List"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; @@ -40,11 +41,31 @@ export class DocumentContentsView extends React.Component obj.active = this.props.parentActive).omit }; } + @computed get templates(): List { + let field = this.props.Document.templates; + if (field && field instanceof List) { + return field; + } + return new List(); + } + set templates(templates: List) { this.props.Document.templates = templates; } + get finalLayout() { + const baseLayout = this.layout; + let base = baseLayout; + let layout = baseLayout; + + this.templates.forEach(template => { + layout = template.replace("{layout}", base); + base = layout; + }); + return layout; + } + render() { return { console.log(test); }} />; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ae2d3af13..e83f3fcba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -243,42 +243,22 @@ export class DocumentView extends DocComponent(Docu } } - updateLayout = async () => { - const baseLayout = await StrCast(this.props.Document.baseLayout); - if (baseLayout) { - let base = baseLayout; - let layout = baseLayout; - - this.templates.forEach(template => { - layout = template.replace("{layout}", base); - base = layout; - }); - - this.props.Document.layout = layout; - } - } @action addTemplate = (template: Template) => { - let templates = this.templates; - templates.push(template.Layout); - this.templates = new List(templates.map(t => t)); - this.updateLayout(); + this.templates.push(template.Layout); + this.templates = this.templates; } @action removeTemplate = (template: Template) => { - let templates = this.templates; - for (let i = 0; i < templates.length; i++) { - let temp = templates[i]; - if (temp === template.Layout) { - templates.splice(i, 1); + for (let i = 0; i < this.templates.length; i++) { + if (this.templates[i] === template.Layout) { + this.templates.splice(i, 1); break; } } - templates = new List(templates.splice(0, templates.length)); - this.templates = templates; - this.updateLayout(); + this.templates = this.templates; } @action -- cgit v1.2.3-70-g09d2 From a78282cdf7fbb99386484640e1fb89d4b9b0cbee Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 2 May 2019 16:19:07 -0400 Subject: fixed some things with trees and summaries. --- src/client/views/Main.tsx | 3 +-- src/client/views/Templates.tsx | 12 +++++++++++- src/client/views/collections/CollectionTreeView.tsx | 10 +++++++--- .../views/collections/collectionFreeForm/MarqueeView.tsx | 4 +++- src/client/views/nodes/DocumentContentsView.tsx | 3 ++- src/client/views/nodes/FieldView.tsx | 11 ++++------- src/client/views/nodes/ImageBox.scss | 2 ++ src/new_fields/List.ts | 6 +++--- src/server/authentication/models/current_user_utils.ts | 2 ++ 9 files changed, 35 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index a07a2d5b1..97eb73d7f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -144,8 +144,7 @@ export class Main extends React.Component { createNewWorkspace = async (id?: string) => { const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { - let libraryDoc = Docs.TreeDocument([CurrentUserUtils.UserDocument], { x: 0, y: 400, title: `Library: ${CurrentUserUtils.email} ${list.length + 1}` }); - libraryDoc.excludeFromLibrary = true; + let libraryDoc = await (CurrentUserUtils.UserDocument.library as Doc); let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(libraryDoc, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; let mainDoc = Docs.DockDocument([libraryDoc, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index e17dd2354..668ae5312 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -54,7 +54,17 @@ export namespace Templates { `
{layout}
{props.Document.title}
` ); export const Summary = new Template("Title", TemplatePosition.InnerTop, - `
{layout}
{props.Document.doc1.title}
` + `
+
+ {layout} +
+
+ +
+
+ +
+
` ); export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption]; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 48b226615..2cef1462b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,7 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable } from "mobx"; +import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; import { EditableView } from "../EditableView"; @@ -145,8 +145,11 @@ class TreeView extends React.Component {
; } public static GetChildElements(docs: Doc[], remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => !child.excludeFromLibrary).map(child => - ); + return docs.filter(child => !child.excludeFromLibrary).filter(doc => FieldValue(doc)).map(child => { + console.log("child = " + child[Id]); + return + } + ); } } @@ -168,6 +171,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } render() { + trace(); const children = this.children; let dropAction = StrCast(this.props.Document.dropAction, "alias") as dropActionType; if (!children) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c58e7780c..82027a6f2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -180,7 +180,9 @@ export class MarqueeView extends React.Component // SelectionManager.DeselectAll(); if (e.key === "r") { let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.doc1 = newCollection.proto!; + summary.doc1 = selected[0]; + if (selected.length > 1) + summary.doc2 = selected[1]; summary.templates = new List([Templates.Summary.Layout]); this.props.addLiveTextDocument(summary); e.preventDefault(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 24e8a36ae..ddfe79a5c 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -15,6 +15,7 @@ import { IconBox } from "./IconBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { VideoBox } from "./VideoBox"; +import { FieldView } from "./FieldView"; import { WebBox } from "./WebBox"; import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); @@ -63,7 +64,7 @@ export class DocumentContentsView extends React.Component { } render() { const field = this.field; - if (!field) { + if (field === undefined) { return

{''}

; } - if (typeof field === "string") { - return

{field}

; - } + // if (typeof field === "string") { + // return

{field}

; + // } else if (field instanceof RichTextField) { return ; } @@ -108,9 +108,6 @@ export class FieldView extends React.Component { // else if (field instanceof HtmlField) { // return // } - else if (typeof field === "number") { - return

{field}

; - } else if (!(field instanceof Promise)) { return

{JSON.stringify(field)}

; } diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 9fe211df0..2316a050e 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -10,6 +10,8 @@ } .imageBox-cont-interactive { pointer-events: all; + width:100%; + height:auto; } .imageBox-dot { diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 1c4b96c81..db7932cec 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -2,7 +2,7 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self, FieldResult } from "./Doc"; import { setter, getter, deleteProperty } from "./util"; import { serializable, alias, list } from "serializr"; -import { observable } from "mobx"; +import { observable, action } from "mobx"; import { ObjectField, OnUpdate, Copy } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; @@ -25,12 +25,12 @@ const listHandlers: any = { this[Update](); return field; }, - push(...items: any[]) { + push: action(function (this: any, ...items: any[]) { items = items.map(toObjectField); const res = this[Self].__fields.push(...items); this[Update](); return res; - }, + }), reverse() { const res = this[Self].__fields.reverse(); this[Update](); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9db470ca0..93c2afb1d 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -26,6 +26,8 @@ export class CurrentUserUtils { doc.title = this.email; doc.data = new List(); doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); + doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); + (doc.library as Doc).excludeFromLibrary = true; return doc; } -- cgit v1.2.3-70-g09d2 From 26b0374d87ef1b14d947d5882f73e67b8607436e Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 3 May 2019 10:58:12 -0400 Subject: changes to icon box and decorations. --- src/client/views/DocumentDecorations.tsx | 19 ++++++------- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 8 ++++-- src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/IconBox.scss | 12 +++++++- src/client/views/nodes/IconBox.tsx | 32 +++++++++++++++++++--- 6 files changed, 56 insertions(+), 19 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d07adcb71..9771c6580 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -48,14 +48,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @observable private _fieldKey = "title"; @observable private _hidden = false; @observable private _opacity = 1; - @observable private _iconifying = false; + @observable private _removeIcon = false; @observable public Interacting = false; constructor(props: Readonly<{}>) { super(props); DocumentDecorations.Instance = this; this.keyinput = React.createRef(); - reaction(() => SelectionManager.SelectedDocuments().slice(), (docs) => docs.length === 0 && (this._edtingTitle = false)); + reaction(() => SelectionManager.SelectedDocuments().slice(), docs => this._edtingTitle = false); } @action titleChanged = (event: any) => { this._title = event.target.value; }; @@ -197,6 +197,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0) { this._downX = e.pageX; this._downY = e.pageY; + this._removeIcon = false; let selDoc = SelectionManager.SelectedDocuments()[0]; let selDocPos = selDoc.props.ScreenToLocalTransform().scale(selDoc.props.ContentScaling()).inverse().transformPoint(0, 0); this._minimizedX = selDocPos[0] + 12; @@ -222,18 +223,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> Promise.all(selectedDocs.map(selDoc => this.getIconDoc(selDoc))).then(minDocSet => this.moveIconDocs(SelectionManager.SelectedDocuments()) ); - this._iconifying = snapped; + this._removeIcon = snapped; } } - @action createIcon = (docView: DocumentView, layoutString: string): Doc => { let doc = docView.props.Document; let iconDoc = Docs.IconDocument(layoutString); iconDoc.title = "ICON" + StrCast(doc.title); + iconDoc.labelField = this._fieldKey; iconDoc.isMinimized = false; - iconDoc.nativeWidth = Number(MINIMIZED_ICON_SIZE); - iconDoc.nativeHeight = Number(MINIMIZED_ICON_SIZE); iconDoc.width = Number(MINIMIZED_ICON_SIZE); iconDoc.height = Number(MINIMIZED_ICON_SIZE); iconDoc.x = NumCast(doc.x); @@ -275,15 +274,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> minDocs.map(minDoc => { minDoc.x = NumCast(minDocs[0].x); minDoc.y = NumCast(minDocs[0].y); - minDoc.linkTags = new List(minDocs.filter(d => d !== minDoc)); - if (this._iconifying && selectedDocs[0].props.removeDocument) { + minDoc.linkedIconTags = new List(minDocs.filter(d => d !== minDoc)); + if (this._removeIcon && selectedDocs[0].props.removeDocument) { selectedDocs[0].props.removeDocument(minDoc); (minDoc.maximizedDoc as Doc).minimizedDoc = undefined; } }); runInAction(() => this._minimizedX = this._minimizedY = 0); - if (!this._iconifying) selectedDocs[0].props.toggleMinimized(); - this._iconifying = false; + selectedDocs[0].props.toggleMinimized(); + this._removeIcon = false; }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 54b721f7b..17c25c9db 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -225,7 +225,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onDragOver = (): void => { } - bringToFront(doc: Doc) { + bringToFront = (doc: Doc) => { const docs = (this.children || []); docs.slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; @@ -266,6 +266,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { focus: this.focusDocument, parentActive: this.props.active, whenActiveChanged: this.props.active, + bringToFront: this.bringToFront, }; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 09f9c8516..53298fbdd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -112,10 +112,11 @@ export class CollectionFreeFormDocumentView extends DocComponent => { SelectionManager.DeselectAll(); let isMinimized: boolean | undefined; - let minimizedDocSet = Cast(this.props.Document.linkTags, listSpec(Doc)); - if (!minimizedDocSet) return; + let minimizedDocSet = Cast(this.props.Document.linkedIconTags, listSpec(Doc), []); let docs = minimizedDocSet.map(d => d); - docs.push(this.props.Document); + let minimDoc = Cast(this.props.Document.minimizedDoc, Doc); + if (minimDoc instanceof Doc) docs.push(minimDoc); + else docs.push(this.props.Document); docs.map(async minimizedDoc => { this.props.addDocument && this.props.addDocument(minimizedDoc, false); let maximizedDoc = await Cast(minimizedDoc.maximizedDoc, Doc); @@ -125,6 +126,7 @@ export class CollectionFreeFormDocumentView extends DocComponent boolean; whenActiveChanged: (isActive: boolean) => void; toggleMinimized: () => void; + bringToFront: (doc: Doc) => void; } const schema = createSchema({ diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss index ce0ee2e09..85bbdeb59 100644 --- a/src/client/views/nodes/IconBox.scss +++ b/src/client/views/nodes/IconBox.scss @@ -4,9 +4,19 @@ position: absolute; left:0; top:0; + height: 100%; + width: max-content; + // overflow: hidden; + pointer-events: all; svg { - width: 100% !important; + width: $MINIMIZED_ICON_SIZE !important; height: 100%; background: white; } + .iconBox-label { + position: inherit; + width:max-content; + font-size: 14px; + margin-top: 3px; + } } \ No newline at end of file diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 7a0c49735..08301ae0d 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -2,14 +2,17 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed } from "mobx"; +import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { SelectionManager } from "../../util/SelectionManager"; import { FieldView, FieldViewProps } from './FieldView'; import "./IconBox.scss"; -import { Cast } from "../../../new_fields/Types"; -import { Doc } from "../../../new_fields/Doc"; +import { Cast, StrCast, BoolCast } from "../../../new_fields/Types"; +import { Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { IconField } from "../../../new_fields/IconField"; +import { ContextMenu } from "../ContextMenu"; +import Measure from "react-measure"; +import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; library.add(faCaretUp); @@ -36,10 +39,31 @@ export class IconBox extends React.Component { return ; } + setLabelField = (e: React.MouseEvent): void => { + this.props.Document.hideLabel = !BoolCast(this.props.Document.hideLabel); + } + + specificContextMenu = (e: React.MouseEvent): void => { + ContextMenu.Instance.addItem({ + description: BoolCast(this.props.Document.hideLabel) ? "show label" : "hide label", + event: this.setLabelField + }); + } + @observable _panelWidth: number = 0; + @observable _panelHeight: number = 0; render() { + let labelField = StrCast(this.props.Document.labelField); + let hideLabel = BoolCast(this.props.Document.hideLabel); + let maxDoc = Cast(this.props.Document.maximizedDoc, Doc) as Doc; + let label = !hideLabel && maxDoc && labelField ? maxDoc[labelField] : ""; return ( -
+
{this.minimizedIcon} + runInAction(() => { if (r.entry.width || BoolCast(this.props.Document.hideLabel)) this.props.Document.nativeWidth = this.props.Document.width = (r.entry.width + Number(MINIMIZED_ICON_SIZE)); })}> + {({ measureRef }) => + {label} + } +
); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9b33ac1cb790e88558edb3e4626f5a7b759ea3db Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 3 May 2019 14:46:31 -0400 Subject: added make button option. summarize to text notes that can be frozen to resize. --- src/client/views/DocumentDecorations.tsx | 1 + .../collections/collectionFreeForm/MarqueeView.tsx | 20 +++++++++++++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +++++++++------- src/client/views/nodes/DocumentView.tsx | 10 +++++++++- src/client/views/nodes/FormattedTextBox.tsx | 20 ++++++++++++++------ 5 files changed, 48 insertions(+), 19 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2299f4c32..693d6ec55 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -255,6 +255,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action createIcon = (selected: DocumentView[], layoutString: string): Doc => { let doc = selected[0].props.Document; let iconDoc = Docs.IconDocument(layoutString); + iconDoc.isButton = true; iconDoc.title = selected.length > 1 ? "ICONset" : "ICON" + StrCast(doc.title); iconDoc.labelField = this._fieldKey; iconDoc[this._fieldKey] = selected.length > 1 ? "collection" : undefined; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 82027a6f2..8c81f6990 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -154,7 +154,8 @@ export class MarqueeView extends React.Component e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { - this.props.removeDocument(d); + if (e.key !== "r") + this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.page = -1; @@ -180,12 +181,21 @@ export class MarqueeView extends React.Component // SelectionManager.DeselectAll(); if (e.key === "r") { let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.doc1 = selected[0]; - if (selected.length > 1) - summary.doc2 = selected[1]; - summary.templates = new List([Templates.Summary.Layout]); + summary.maximizedDocs = new List(selected); + // summary.doc1 = selected[0]; + // if (selected.length > 1) + // summary.doc2 = selected[1]; + // summary.templates = new List([Templates.Summary.Layout]); this.props.addLiveTextDocument(summary); e.preventDefault(); + let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); + selected.map(maximizedDoc => { + let maxx = NumCast(maximizedDoc.x, undefined); + let maxy = NumCast(maximizedDoc.y, undefined); + let maxw = NumCast(maximizedDoc.width, undefined); + let maxh = NumCast(maximizedDoc.height, undefined); + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) + }); } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 741af82fd..2ba0458f5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -138,8 +138,8 @@ export class CollectionFreeFormDocumentView extends DocComponent d instanceof Doc).map(maxDoc => this.props.addDocument!(maxDoc, false)); - this.toggleIcon(); + if (await BoolCast(this.props.Document.isButton, false)) { + let maximizedDocs = await Cast(this.props.Document.maximizedDocs, listSpec(Doc)); + if (maximizedDocs) { // bcz: need a better way to associate behaviors with click events on widget-documents + if (ctrlKey) + this.props.addDocument && maximizedDocs.filter(d => d instanceof Doc).map(maxDoc => this.props.addDocument!(maxDoc, false)); + this.toggleIcon(); + } } } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 892850a69..c08e322c0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -16,7 +16,7 @@ import { Template, Templates } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Opt, Doc } from "../../../new_fields/Doc"; +import { Opt, Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { FieldValue, StrCast, BoolCast } from "../../../new_fields/Types"; @@ -200,6 +200,13 @@ export class DocumentView extends DocComponent(Docu let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); CollectionDockingView.Instance.AddRightSplit(kvp); } + makeButton = (e: React.MouseEvent): void => { + this.props.Document.isButton = !BoolCast(this.props.Document.isButton, false); + if (this.props.Document.isButton && !this.props.Document.nativeWidth) { + this.props.Document.nativeWidth = this.props.Document[WidthSym](); + this.props.Document.nativeHeight = this.props.Document[HeightSym](); + } + } fullScreenClicked = (e: React.MouseEvent): void => { const doc = Doc.MakeDelegate(FieldValue(this.Document.proto)); if (doc) { @@ -263,6 +270,7 @@ export class DocumentView extends DocComponent(Docu e.preventDefault(); ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); + ContextMenu.Instance.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton }); 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) }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 1d362bdaa..eeb60cb3d 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -17,10 +17,10 @@ import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Opt, Doc } from "../../../new_fields/Doc"; +import { Opt, Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { observer } from "mobx-react"; import { InkingControl } from "../InkingControl"; -import { StrCast, Cast, NumCast } from "../../../new_fields/Types"; +import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; import { Id } from "../../../new_fields/RefField"; const { buildMenuItems } = require("prosemirror-example-setup"); @@ -128,7 +128,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ); } else { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform)); + () => this.props.isSelected() && !BoolCast(this.props.Document.isButton, false) && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform)); } @@ -203,15 +203,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE - textCapability = (e: React.MouseEvent): void => { }; + textCapability = (e: React.MouseEvent): void => { + if (NumCast(this.props.Document.nativeWidth)) { + this.props.Document.nativeWidth = undefined; + this.props.Document.nativeHeight = undefined; + } else { + this.props.Document.nativeWidth = this.props.Document[WidthSym](); + this.props.Document.nativeHeight = this.props.Document[HeightSym](); + } + } specificContextMenu = (e: React.MouseEvent): void => { if (!this._gotDown) { e.preventDefault(); return; } ContextMenu.Instance.addItem({ - description: "Text Capability", + description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.textCapability }); @@ -302,7 +310,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe // tfs: do we need this event handler onWheel={this.onPointerWheel} > -
+
); } -- cgit v1.2.3-70-g09d2