aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/DocumentManager.ts44
-rw-r--r--src/client/util/DragManager.ts76
-rw-r--r--src/client/util/Scripting.ts34
-rw-r--r--src/client/util/SelectionManager.ts6
-rw-r--r--src/client/util/SerializationHelper.ts130
-rw-r--r--src/client/util/TooltipTextMenu.tsx8
-rw-r--r--src/client/util/UndoManager.ts7
7 files changed, 211 insertions, 94 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 56669fb79..69964e2c9 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,9 +1,8 @@
import { computed, observable } from 'mobx';
-import { Document } from "../../fields/Document";
-import { FieldWaiting } from '../../fields/Field';
-import { KeyStore } from '../../fields/KeyStore';
-import { ListField } from '../../fields/ListField';
import { DocumentView } from '../views/nodes/DocumentView';
+import { Doc } from '../../new_fields/Doc';
+import { FieldValue, Cast } from '../../new_fields/Types';
+import { listSpec } from '../../new_fields/Schema';
export class DocumentManager {
@@ -25,26 +24,21 @@ export class DocumentManager {
// this.DocumentViews = new Array<DocumentView>();
}
- public getDocumentView(toFind: Document): DocumentView | null {
+ public getDocumentView(toFind: Doc): DocumentView | null {
- let toReturn: DocumentView | null;
- toReturn = null;
+ let toReturn: DocumentView | null = null;
//gets document view that is in a freeform canvas collection
DocumentManager.Instance.DocumentViews.map(view => {
- let doc = view.props.Document;
-
- if (doc === toFind) {
+ if (view.props.Document === toFind) {
toReturn = view;
return;
}
});
if (!toReturn) {
DocumentManager.Instance.DocumentViews.map(view => {
- let doc = view.props.Document;
-
- let docSrc = doc.GetT(KeyStore.Prototype, Document);
- if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) {
+ let doc = view.props.Document.proto;
+ if (doc && Object.is(doc, toFind)) {
toReturn = view;
}
});
@@ -52,7 +46,7 @@ export class DocumentManager {
return toReturn;
}
- public getDocumentViews(toFind: Document): DocumentView[] {
+ public getDocumentViews(toFind: Doc): DocumentView[] {
let toReturn: DocumentView[] = [];
@@ -64,8 +58,8 @@ export class DocumentManager {
if (doc === toFind) {
toReturn.push(view);
} else {
- let docSrc = doc.GetT(KeyStore.Prototype, Document);
- if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) {
+ let docSrc = FieldValue(doc.proto);
+ if (docSrc && Object.is(docSrc, toFind)) {
toReturn.push(view);
}
}
@@ -77,20 +71,20 @@ export class DocumentManager {
@computed
public get LinkedDocumentViews() {
return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => {
- let linksList = dv.props.Document.GetT(KeyStore.LinkedToDocs, ListField);
- if (linksList && linksList !== FieldWaiting && linksList.Data.length) {
- pairs.push(...linksList.Data.reduce((pairs, link) => {
- if (link instanceof Document) {
- let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document);
- if (linkToDoc && linkToDoc !== FieldWaiting) {
+ let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc));
+ if (linksList && linksList.length) {
+ pairs.push(...linksList.reduce((pairs, link) => {
+ if (link) {
+ let linkToDoc = FieldValue(Cast(link.linkedTo, Doc));
+ if (linkToDoc) {
DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 =>
pairs.push({ a: dv, b: docView1, l: link }));
}
}
return pairs;
- }, [] as { a: DocumentView, b: DocumentView, l: Document }[]));
+ }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]));
}
return pairs;
- }, [] as { a: DocumentView, b: DocumentView, l: Document }[]);
+ }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]);
}
} \ No newline at end of file
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 136852e12..a3dbe6e43 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,14 +1,14 @@
import { action } from "mobx";
-import { Document } from "../../fields/Document";
-import { FieldWaiting } from "../../fields/Field";
-import { KeyStore } from "../../fields/KeyStore";
import { emptyFunction } from "../../Utils";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
-import { DocumentDecorations } from "../views/DocumentDecorations";
import * as globalCssVariables from "../views/globalCssVariables.scss";
import { MainOverlayTextBox } from "../views/MainOverlayTextBox";
+import { Doc } from "../../new_fields/Doc";
+import { Cast } from "../../new_fields/Types";
+import { listSpec } from "../../new_fields/Schema";
-export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) {
+export type dropActionType = "alias" | "copy" | undefined;
+export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Doc, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType) {
let onRowMove = action((e: PointerEvent): void => {
e.stopPropagation();
e.preventDefault();
@@ -16,7 +16,7 @@ export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc:
document.removeEventListener("pointermove", onRowMove);
document.removeEventListener('pointerup', onRowUp);
var dragData = new DragManager.DocumentDragData([docFunc()]);
- dragData.copyOnDrop = copyOnDrop;
+ dragData.dropAction = dropAction;
dragData.moveDocument = moveFunc;
DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y);
});
@@ -40,19 +40,19 @@ export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc:
return onItemDown;
}
-export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Document) {
- let srcTarg = sourceDoc.GetPrototype();
+export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) {
+ let srcTarg = sourceDoc.proto;
let draggedDocs = srcTarg ?
- srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc =>
- (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : [];
+ Cast(srcTarg.linkedToDocs, listSpec(Doc), []).map(linkDoc =>
+ Cast(linkDoc.linkedTo, Doc) as Doc) : [];
let draggedFromDocs = srcTarg ?
- srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc =>
- (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : [];
+ Cast(srcTarg.linkedFromDocs, listSpec(Doc), []).map(linkDoc =>
+ Cast(linkDoc.linkedFrom, Doc) as Doc) : [];
draggedDocs.push(...draggedFromDocs);
if (draggedDocs.length) {
- let moddrag = [] as Document[];
+ let moddrag: Doc[] = [];
for (const draggedDoc of draggedDocs) {
- let doc = await draggedDoc.GetTAsync(KeyStore.AnnotationOn, Document);
+ let doc = await Cast(draggedDoc.annotationOn, Doc);
if (doc) moddrag.push(doc);
}
let dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
@@ -134,37 +134,42 @@ export namespace DragManager {
};
}
- export type MoveFunction = (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
+ export type MoveFunction = (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
export class DocumentDragData {
- constructor(dragDoc: Document[]) {
+ constructor(dragDoc: Doc[]) {
this.draggedDocuments = dragDoc;
this.droppedDocuments = dragDoc;
this.xOffset = 0;
this.yOffset = 0;
}
- draggedDocuments: Document[];
- droppedDocuments: Document[];
+ draggedDocuments: Doc[];
+ droppedDocuments: Doc[];
xOffset: number;
yOffset: number;
- aliasOnDrop?: boolean;
- copyOnDrop?: boolean;
+ dropAction: dropActionType;
+ userDropAction: dropActionType;
moveDocument?: MoveFunction;
[id: string]: any;
}
export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) {
StartDrag(eles, dragData, downX, downY, options,
- (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : dragData.draggedDocuments));
+ (dropData: { [id: string]: any }) =>
+ (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ?
+ dragData.draggedDocuments.map(d => Doc.MakeAlias(d)) :
+ dragData.userDropAction == "copy" || (!dragData.userDropAction && dragData.dropAction == "copy") ?
+ dragData.draggedDocuments.map(d => Doc.MakeCopy(d, true)) :
+ dragData.draggedDocuments));
}
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;
}
@@ -188,7 +193,7 @@ export namespace DragManager {
let xs: number[] = [];
let ys: number[] = [];
- const docs: Document[] =
+ const docs: Doc[] =
dragData instanceof DocumentDragData ? dragData.draggedDocuments : [];
let dragElements = eles.map(ele => {
const w = ele.offsetWidth,
@@ -252,7 +257,7 @@ export namespace DragManager {
e.stopPropagation();
e.preventDefault();
if (dragData instanceof DocumentDragData) {
- dragData.aliasOnDrop = e.ctrlKey || e.altKey;
+ dragData.userDropAction = e.ctrlKey || e.altKey ? "alias" : undefined;
}
if (e.shiftKey) {
AbortDrag();
@@ -301,15 +306,20 @@ export namespace DragManager {
function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) {
let removed = dragEles.map(dragEle => {
- let parent = dragEle.parentElement;
- if (parent) parent.removeChild(dragEle);
- return [dragEle, parent];
+ // let parent = dragEle.parentElement;
+ // if (parent) parent.removeChild(dragEle);
+ let ret = [dragEle, dragEle.style.width, dragEle.style.height];
+ dragEle.style.width = "0";
+ dragEle.style.height = "0";
+ return ret;
});
const target = document.elementFromPoint(e.x, e.y);
removed.map(r => {
- let dragEle = r[0];
- let parent = r[1];
- if (parent && dragEle) parent.appendChild(dragEle);
+ let dragEle = r[0] as HTMLElement;
+ dragEle.style.width = r[1] as string;
+ dragEle.style.height = r[2] as string;
+ // let parent = r[1];
+ // if (parent && dragEle) parent.appendChild(dragEle);
});
if (target) {
if (finishDrag) finishDrag(dragData);
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index c67cc067a..e45f61c11 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,13 +1,5 @@
// import * as ts from "typescript"
let ts = (window as any).ts;
-import { Opt, Field } from "../../fields/Field";
-import { Document } from "../../fields/Document";
-import { NumberField } from "../../fields/NumberField";
-import { ImageField } from "../../fields/ImageField";
-import { TextField } from "../../fields/TextField";
-import { RichTextField } from "../../fields/RichTextField";
-import { KeyStore } from "../../fields/KeyStore";
-import { ListField } from "../../fields/ListField";
// // @ts-ignore
// import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts'
// // @ts-ignore
@@ -15,8 +7,11 @@ import { ListField } from "../../fields/ListField";
// @ts-ignore
import * as typescriptlib from '!!raw-loader!./type_decls.d';
-import { Documents } from "../documents/Documents";
-import { Key } from "../../fields/Key";
+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;
@@ -50,9 +45,9 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an
return { compiled: false, errors: diagnostics };
}
- let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key];
- let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)];
- let params: any[] = [KeyStore, Documents, ...fieldTypes];
+ let fieldTypes = [Doc, ImageField, PdfField, VideoField, AudioField, List, RichTextField];
+ let paramNames = ["Docs", ...fieldTypes.map(fn => fn.name)];
+ let params: any[] = [Docs, ...fieldTypes];
let compiledFunction = new Function(...paramNames, `return ${script}`);
let { capturedVariables = {} } = options;
let run = (args: { [name: string]: any } = {}): ScriptResult => {
@@ -171,17 +166,4 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics);
return Run(outputText, paramNames, diagnostics, script, options);
-}
-
-export function OrLiteralType(returnType: string): string {
- return `${returnType} | string | number`;
-}
-
-export function ToField(data: any): Opt<Field> {
- if (typeof data === "string") {
- return new TextField(data);
- } else if (typeof data === "number") {
- return new NumberField(data);
- }
- return undefined;
} \ No newline at end of file
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index da66bf3fc..fe5acf4b4 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,5 +1,5 @@
-import { action, observable } from "mobx";
-import { Document } from "../../fields/Document";
+import { observable, action } from "mobx";
+import { Doc } from "../../new_fields/Doc";
import { MainOverlayTextBox } from "../views/MainOverlayTextBox";
import { DocumentView } from "../views/nodes/DocumentView";
@@ -49,7 +49,7 @@ export namespace SelectionManager {
return manager.SelectedDocuments.indexOf(doc) !== -1;
}
- export function DeselectAll(except?: Document): void {
+ export function DeselectAll(except?: Doc): void {
let found: DocumentView | undefined = undefined;
if (except) {
for (const view of manager.SelectedDocuments) {
diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts
new file mode 100644
index 000000000..7ded85e43
--- /dev/null
+++ b/src/client/util/SerializationHelper.ts
@@ -0,0 +1,130 @@
+import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema, primitive, SKIP } from "serializr";
+import { Field } from "../../new_fields/Doc";
+
+export namespace SerializationHelper {
+ let serializing: number = 0;
+ export function IsSerializing() {
+ return serializing > 0;
+ }
+
+ export function Serialize(obj: Field): any {
+ if (obj === undefined || obj === null) {
+ return undefined;
+ }
+
+ if (typeof obj !== 'object') {
+ return obj;
+ }
+
+ serializing += 1;
+ if (!(obj.constructor.name in reverseMap)) {
+ throw Error(`type '${obj.constructor.name}' not registered. Make sure you register it using a @Deserializable decorator`);
+ }
+
+ const json = serialize(obj);
+ json.__type = reverseMap[obj.constructor.name];
+ serializing -= 1;
+ return json;
+ }
+
+ export function Deserialize(obj: any): any {
+ if (obj === undefined || obj === null) {
+ return undefined;
+ }
+
+ if (typeof obj !== 'object') {
+ return obj;
+ }
+
+ serializing += 1;
+ if (!obj.__type) {
+ throw Error("No property 'type' found in JSON.");
+ }
+
+ if (!(obj.__type in serializationTypes)) {
+ throw Error(`type '${obj.__type}' not registered. Make sure you register it using a @Deserializable decorator`);
+ }
+
+ const value = deserialize(serializationTypes[obj.__type], obj);
+ serializing -= 1;
+ return value;
+ }
+}
+
+let serializationTypes: { [name: string]: any } = {};
+let reverseMap: { [ctor: string]: string } = {};
+
+export interface DeserializableOpts {
+ (constructor: { new(...args: any[]): any }): void;
+ withFields(fields: string[]): Function;
+}
+
+export function Deserializable(name: string): DeserializableOpts;
+export function Deserializable(constructor: { new(...args: any[]): any }): void;
+export function Deserializable(constructor: { new(...args: any[]): any } | string): DeserializableOpts | void {
+ function addToMap(name: string, ctor: { new(...args: any[]): any }) {
+ const schema = getDefaultModelSchema(ctor) as any;
+ if (schema.targetClass !== ctor) {
+ const newSchema = { ...schema, factory: () => new ctor() };
+ setDefaultModelSchema(ctor, newSchema);
+ }
+ if (!(name in serializationTypes)) {
+ serializationTypes[name] = ctor;
+ reverseMap[ctor.name] = name;
+ } else {
+ throw new Error(`Name ${name} has already been registered as deserializable`);
+ }
+ }
+ if (typeof constructor === "string") {
+ return Object.assign((ctor: { new(...args: any[]): any }) => {
+ addToMap(constructor, ctor);
+ }, { withFields: Deserializable.withFields });
+ }
+ addToMap(constructor.name, constructor);
+}
+
+export namespace Deserializable {
+ export function withFields(fields: string[]) {
+ return function (constructor: { new(...fields: any[]): any }) {
+ Deserializable(constructor);
+ let schema = getDefaultModelSchema(constructor);
+ if (schema) {
+ schema.factory = context => {
+ const args = fields.map(key => context.json[key]);
+ return new constructor(...args);
+ };
+ // TODO A modified version of this would let us not reassign fields that we're passing into the constructor later on in deserializing
+ // fields.forEach(field => {
+ // if (field in schema.props) {
+ // let propSchema = schema.props[field];
+ // if (propSchema === false) {
+ // return;
+ // } else if (propSchema === true) {
+ // propSchema = primitive();
+ // }
+ // schema.props[field] = custom(propSchema.serializer,
+ // () => {
+ // return SKIP;
+ // });
+ // }
+ // });
+ } else {
+ schema = {
+ props: {},
+ factory: context => {
+ const args = fields.map(key => context.json[key]);
+ return new constructor(...args);
+ }
+ };
+ setDefaultModelSchema(constructor, schema);
+ }
+ };
+ }
+}
+
+export function autoObject(): PropSchema {
+ return custom(
+ (s) => SerializationHelper.Serialize(s),
+ (s) => SerializationHelper.Deserialize(s)
+ );
+} \ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 14af4bdfd..68a73375e 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -38,9 +38,9 @@ export class TooltipTextMenu {
private listTypeToIcon: Map<NodeType, string>;
private fontSizeIndicator: HTMLSpanElement = document.createElement("span");
//dropdown doms
- private fontSizeDom: Node;
- private fontStyleDom: Node;
- private listTypeBtnDom: Node;
+ private fontSizeDom?: Node;
+ private fontStyleDom?: Node;
+ private listTypeBtnDom?: Node;
constructor(view: EditorView, editorProps: FieldViewProps) {
this.view = view;
@@ -321,7 +321,7 @@ export class TooltipTextMenu {
this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px";
//UPDATE LIST ITEM DROPDOWN
- this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom);
+ this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!);
//UPDATE FONT STYLE DROPDOWN
let activeStyles = this.activeMarksOnSelection(this.fontStyles);
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 27aed4bac..0b5280c4a 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -1,4 +1,4 @@
-import { observable, action } from "mobx";
+import { observable, action, runInAction } from "mobx";
import 'source-map-support/register';
import { Without } from "../../Utils";
import { string } from "prop-types";
@@ -140,10 +140,11 @@ export namespace UndoManager {
}
});
- export function RunInBatch(fn: () => void, batchName: string) {
+ //TODO Make this return the return value
+ export function RunInBatch<T>(fn: () => T, batchName: string) {
let batch = StartBatch(batchName);
try {
- fn();
+ return runInAction(fn);
} finally {
batch.end();
}