diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 43 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 2 | ||||
-rw-r--r-- | src/debug/Test.tsx | 13 | ||||
-rw-r--r-- | src/new_fields/Doc.ts | 13 | ||||
-rw-r--r-- | src/new_fields/List.ts | 5 | ||||
-rw-r--r-- | src/new_fields/Schema.ts | 20 | ||||
-rw-r--r-- | src/new_fields/Types.ts | 27 |
8 files changed, 74 insertions, 55 deletions
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<T>(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<FieldViewProps, ImageDocument>(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<number>, + fields: listSpec("number"), url: "number", testDoc: ImageField }); @@ -30,13 +28,6 @@ const schema2 = createSchema({ const Test2Doc = makeStrictInterface(schema2); type Test2Doc = makeStrictInterface<typeof schema2>; -const schema3 = createSchema({ - test: "boolean", -}); - -const Test3Doc = makeStrictInterface(schema3); -type Test3Doc = makeStrictInterface<typeof schema3>; - 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<T extends Field>(doc: Doc, key: string, ctor: FieldCtor<T>, ignoreProto: boolean = false): Promise<T | undefined> { + export function GetTAsync<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): Promise<T | undefined> { 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<T extends Field>(doc: Doc, key: string, ctor: FieldCtor<T>, ignoreProto: boolean = false): T | null | undefined { + export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, 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<Doc>): Opt<Doc> { 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<T extends Field> extends ObjectField { - constructor() { + constructor(fields: T[] = []) { super(); + this.__fields = fields; const list = new Proxy<this>(this, { set: setter, get: getter, @@ -21,7 +22,7 @@ class ListImpl<T extends Field> 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<T extends Interface[]> = { 1: ToInterface<Head<T>> & AllToInterface<Tail<T>>, @@ -10,10 +12,10 @@ export const emptySchema = createSchema({}); export const Document = makeInterface(emptySchema); export type Document = makeInterface<[typeof emptySchema]>; -export type makeInterface<T extends Interface[], U extends Doc = Doc> = Partial<AllToInterface<T>> & U; +export type makeInterface<T extends Interface[]> = Partial<AllToInterface<T>> & Doc; // export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>; // export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>; -export function makeInterface<T extends Interface[], U extends Doc>(...schemas: T): (doc: U) => makeInterface<T, U> { +export function makeInterface<T extends Interface[]>(...schemas: T): (doc: Doc) => makeInterface<T> { let schema: Interface = {}; for (const s of schemas) { for (const key in s) { @@ -33,7 +35,10 @@ export function makeInterface<T extends Interface[], U extends Doc>(...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<T extends Interface>(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<T extends Interface>(schema: T): T & { prototype: T schema.prototype = Doc; return schema as any; } + +export function listSpec<U extends ToConstructor<Field>>(type: U): ListSpec<ToType<U>> { + 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<T> = +export type ToType<T extends ToConstructor<Field> | ListSpec<Field>> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends ListSpec<infer U> ? List<U> : // T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never; + T extends { new(...args: any[]): List<Field> } ? never : T extends { new(...args: any[]): infer R } ? R : never; -export type ToConstructor<T> = +export type ToConstructor<T extends Field> = T extends string ? "string" : T extends number ? "number" : - T extends boolean ? "boolean" : new (...args: any[]) => T; + T extends boolean ? "boolean" : + T extends List<infer U> ? ListSpec<U> : + new (...args: any[]) => T; -export type ToInterface<T> = { +export type ToInterface<T extends Interface> = { [P in keyof T]: ToType<T[P]>; }; -// type ListSpec<T extends Field[]> = { List: FieldCtor<Head<T>> | ListSpec<Tail<T>> }; -export type ListSpec<T> = { List: FieldCtor<T> }; +// type ListSpec<T extends Field[]> = { List: ToContructor<Head<T>> | ListSpec<Tail<T>> }; +export type ListSpec<T extends Field> = { List: ToConstructor<T> }; // type ListType<U extends Field[]> = { 0: List<ListType<Tail<U>>>, 1: ToType<Head<U>> }[HasTail<U> extends true ? 0 : 1]; @@ -34,11 +37,9 @@ export interface Interface { // [key: string]: ToConstructor<Field> | ListSpec<Field[]>; } -export type FieldCtor<T extends Field> = T extends List<infer R> ? ListSpec<R> : ToConstructor<T>; - -export function Cast<T extends FieldCtor<Field>>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult<ToType<T>>; -export function Cast<T extends FieldCtor<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType<T>): ToType<T>; -export function Cast<T extends FieldCtor<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType<T>): FieldResult<ToType<T>> | undefined { +export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult<ToType<T>>; +export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType<T>): ToType<T>; +export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType<T>): FieldResult<ToType<T>> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) : defaultVal; } @@ -58,7 +59,9 @@ export function Cast<T extends FieldCtor<Field>>(field: Field | FieldWaiting | u return defaultVal; } -export function FieldValue<T extends Field, U extends T>(field: Opt<T> | Promise<Opt<T>>, defaultValue: U): T; +type WithoutList<T extends Field> = T extends List<infer R> ? R[] : T; + +export function FieldValue<T extends Field, U extends WithoutList<T>>(field: Opt<T> | Promise<Opt<T>>, defaultValue: U): WithoutList<T>; export function FieldValue<T extends Field>(field: Opt<T> | Promise<Opt<T>>): Opt<T>; export function FieldValue<T extends Field>(field: Opt<T> | Promise<Opt<T>>, defaultValue?: T): Opt<T> { return field instanceof Promise ? defaultValue : field; |