From 54048114bca3a01a6d287112d975edd00a4e398a Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 16 Mar 2019 16:47:06 -0400 Subject: Fixed DocumentContents stuff --- src/debug/Test.tsx | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 7bc70615f..c8de33f41 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,46 +1,29 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; +import JsxParser from 'react-jsx-parser' -class TestInternal extends React.Component { - onContextMenu = (e: React.MouseEvent) => { - console.log("Internal"); - e.stopPropagation(); - } - - onPointerDown = (e: React.MouseEvent) => { - console.log("pointer down") - e.preventDefault(); - } - - render() { - return
Hello world
- } -} - -class TestChild extends React.Component { - onContextMenu = () => { - console.log("Child"); - } - +class Hello extends React.Component<{ firstName: string, lastName: string }> { render() { - return
+ return
Hello {this.props.firstName} {this.props.lastName}
} } -class TestParent extends React.Component { - onContextMenu = () => { - console.log("Parent"); - } - +class Test extends React.Component { render() { - return
+ let jsx = ""; + let bindings = { + props: { + firstName: "First", + lastName: "Last" + } + } + return } } ReactDOM.render((
- +
), document.getElementById('root') ); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 5e086920bf97297a02bcd38faea56454c2220279 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 8 Apr 2019 22:45:22 -0400 Subject: Enabled semi-colon and braces linter rule --- src/Utils.ts | 12 +-- src/client/Server.ts | 35 ++++---- src/client/SocketStub.ts | 24 +++--- src/client/documents/Documents.ts | 38 +++++---- src/client/northstar/core/BaseObject.ts | 4 +- .../northstar/core/attribute/AttributeModel.ts | 6 +- .../core/attribute/AttributeTransformationModel.ts | 17 ++-- .../core/attribute/CalculatedAttributeModel.ts | 2 +- .../northstar/core/brusher/IBaseBrushable.ts | 4 +- src/client/northstar/core/brusher/IBaseBrusher.ts | 2 +- src/client/northstar/core/filter/FilterModel.ts | 2 +- .../northstar/core/filter/IBaseFilterConsumer.ts | 4 +- .../northstar/core/filter/IBaseFilterProvider.ts | 2 +- .../northstar/core/filter/ValueComparision.ts | 16 ++-- src/client/northstar/dash-fields/HistogramField.ts | 2 +- .../dash-nodes/HistogramBinPrimitiveCollection.ts | 12 +-- src/client/northstar/dash-nodes/HistogramBox.tsx | 24 +++--- .../dash-nodes/HistogramBoxPrimitives.tsx | 40 +++++---- .../dash-nodes/HistogramLabelPrimitives.tsx | 15 ++-- src/client/northstar/manager/Gateway.ts | 2 +- src/client/northstar/model/ModelExtensions.ts | 18 ++-- src/client/northstar/model/ModelHelpers.ts | 8 +- .../model/binRanges/AlphabeticVisualBinRange.ts | 4 +- .../model/binRanges/DateTimeVisualBinRange.ts | 4 +- .../model/binRanges/NominalVisualBinRange.ts | 4 +- .../model/binRanges/QuantitativeVisualBinRange.ts | 2 +- .../northstar/model/binRanges/VisualBinRange.ts | 2 +- .../model/binRanges/VisualBinRangeHelper.ts | 14 +-- src/client/northstar/operations/BaseOperation.ts | 9 +- .../northstar/operations/HistogramOperation.ts | 2 +- src/client/northstar/utils/ArrayUtil.ts | 2 +- src/client/northstar/utils/Extensions.ts | 6 +- src/client/northstar/utils/GeometryUtil.ts | 34 ++++---- src/client/northstar/utils/MathUtil.ts | 38 +++++---- src/client/northstar/utils/SizeConverter.ts | 16 ++-- src/client/northstar/utils/StyleContants.ts | 2 +- src/client/northstar/utils/Utils.ts | 8 +- src/client/util/DocumentManager.ts | 12 +-- src/client/util/DragManager.ts | 5 +- src/client/util/RichTextSchema.tsx | 42 ++++----- src/client/util/Scripting.ts | 10 +-- src/client/util/ScrollBox.tsx | 4 +- src/client/util/SelectionManager.ts | 4 +- src/client/util/TooltipTextMenu.tsx | 38 ++++----- src/client/util/Transform.ts | 20 ++--- src/client/util/TypedEvent.ts | 2 +- src/client/util/UndoManager.ts | 24 +++--- src/client/views/ContextMenu.tsx | 14 +-- src/client/views/ContextMenuItem.tsx | 4 +- src/client/views/DocumentDecorations.tsx | 99 +++++++++++----------- src/client/views/EditableView.tsx | 10 +-- src/client/views/InkingCanvas.tsx | 15 ++-- src/client/views/InkingControl.tsx | 12 +-- src/client/views/InkingStroke.tsx | 6 +- src/client/views/Main.tsx | 55 ++++++------ .../views/collections/CollectionBaseView.tsx | 34 +++++--- .../views/collections/CollectionDockingView.tsx | 37 ++++---- src/client/views/collections/CollectionPDFView.tsx | 6 +- .../views/collections/CollectionSchemaView.tsx | 39 ++++----- src/client/views/collections/CollectionSubView.tsx | 41 ++++----- .../views/collections/CollectionTreeView.tsx | 14 +-- .../views/collections/CollectionVideoView.tsx | 6 +- src/client/views/collections/CollectionView.tsx | 20 ++--- .../CollectionFreeFormLinkView.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 18 ++-- .../CollectionFreeFormRemoteCursors.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 33 ++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 15 ++-- .../collectionFreeForm/PreviewCursor.tsx | 5 +- src/client/views/nodes/Annotation.tsx | 22 ++--- src/client/views/nodes/AudioBox.tsx | 12 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 +-- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 35 ++++---- src/client/views/nodes/FieldView.tsx | 29 ++++--- src/client/views/nodes/FormattedTextBox.tsx | 17 ++-- src/client/views/nodes/ImageBox.tsx | 12 +-- src/client/views/nodes/KeyValueBox.tsx | 18 ++-- src/client/views/nodes/KeyValuePair.tsx | 14 +-- src/client/views/nodes/LinkBox.tsx | 17 ++-- src/client/views/nodes/LinkEditor.tsx | 6 +- src/client/views/nodes/LinkMenu.tsx | 10 +-- src/client/views/nodes/PDFBox.tsx | 56 ++++++------ src/client/views/nodes/Sticky.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 10 +-- src/client/views/nodes/WebBox.tsx | 6 +- src/debug/Test.tsx | 8 +- src/debug/Viewer.tsx | 48 +++++------ src/fields/AudioField.ts | 2 +- src/fields/BasicField.ts | 6 +- src/fields/Document.ts | 25 +++--- src/fields/DocumentReference.ts | 2 +- src/fields/Field.ts | 2 +- src/fields/HtmlField.ts | 2 +- src/fields/ImageField.ts | 2 +- src/fields/InkField.ts | 2 +- src/fields/Key.ts | 6 +- src/fields/KeyStore.ts | 3 +- src/fields/ListField.ts | 31 ++++--- src/fields/NumberField.ts | 4 +- src/fields/PDFField.ts | 4 +- src/fields/RichTextField.ts | 2 +- src/fields/TextField.ts | 4 +- src/fields/TupleField.ts | 6 +- src/fields/VideoField.ts | 2 +- src/fields/WebField.ts | 2 +- src/mobile/ImageUpload.tsx | 14 +-- src/server/Client.ts | 4 +- src/server/authentication/config/passport.ts | 6 +- .../authentication/controllers/WorkspacesMenu.tsx | 2 +- .../authentication/controllers/user_controller.ts | 20 ++--- .../authentication/models/current_user_utils.ts | 8 +- src/server/authentication/models/user_model.ts | 2 +- src/server/database.ts | 34 ++++---- src/server/index.ts | 76 ++++++++--------- test/test.ts | 6 +- tslint.json | 16 ++-- 117 files changed, 901 insertions(+), 826 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 8bd7f2f5c..b0e66787e 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -6,16 +6,16 @@ import { Message, Types } from './server/Message'; export class Utils { public static GenerateGuid(): string { - return v4() + return v4(); } public static GenerateDeterministicGuid(seed: string): string { - return v5(seed, v5.URL) + return v5(seed, v5.URL); } public static GetScreenTransform(ele: HTMLElement): { scale: number, translateX: number, translateY: number } { if (!ele) { - return { scale: 1, translateX: 1, translateY: 1 } + return { scale: 1, translateX: 1, translateY: 1 }; } const rect = ele.getBoundingClientRect(); const scale = ele.offsetWidth === 0 && rect.width === 0 ? 1 : rect.width / ele.offsetWidth; @@ -55,8 +55,8 @@ export class Utils { return (args: any) => { this.log(prefix, messageName, args, true); func(args); - } - }; + }; + } public static Emit(socket: Socket | SocketIOClient.Socket, message: Message, args: T) { this.log("Emit", message.Name, args, false); @@ -81,7 +81,7 @@ export class Utils { public static AddServerHandlerCallback(socket: Socket, message: Message, handler: (args: [T, (res: any) => any]) => any) { socket.on(message.Message, (arg: T, fn: (res: any) => any) => { this.log('S receiving', message.Name, arg, true); - handler([arg, this.loggingCallback('S sending', fn, message.Name)]) + handler([arg, this.loggingCallback('S sending', fn, message.Name)]); }); } } diff --git a/src/client/Server.ts b/src/client/Server.ts index 45c7144ca..857101a33 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -1,7 +1,7 @@ -import { Key } from "../fields/Key" +import { Key } from "../fields/Key"; import { ObservableMap, action, reaction } from "mobx"; -import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field" -import { Document } from "../fields/Document" +import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field"; +import { Document } from "../fields/Document"; import { SocketStub, FieldMap } from "./SocketStub"; import * as OpenSocket from 'socket.io-client'; import { Utils } from "./../Utils"; @@ -10,7 +10,7 @@ import { MessageStore, Types } from "./../server/Message"; export class Server { public static ClientFieldsCached: ObservableMap = new ObservableMap(); static Socket: SocketIOClient.Socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); - static GUID: string = Utils.GenerateGuid() + static GUID: string = Utils.GenerateGuid(); // Retrieves the cached value of the field and sends a request to the server for the real value (if it's not cached). @@ -25,15 +25,16 @@ export class Server { this.ClientFieldsCached.set(fieldid, FieldWaiting); SocketStub.SEND_FIELD_REQUEST(fieldid, action((field: Field | undefined) => { let cached = this.ClientFieldsCached.get(fieldid); - if (cached !== FieldWaiting) + if (cached !== FieldWaiting) { cb(cached); + } else { if (field) { this.ClientFieldsCached.set(fieldid, field); } else { - this.ClientFieldsCached.delete(fieldid) + this.ClientFieldsCached.delete(fieldid); } - cb(field) + cb(field); } })); } else if (cached !== FieldWaiting) { @@ -42,12 +43,12 @@ export class Server { reaction(() => this.ClientFieldsCached.get(fieldid), (field, reaction) => { if (field !== FieldWaiting) { - reaction.dispose() - cb(field) + reaction.dispose(); + cb(field); } - }) + }); } - } + }; if (callback) { fn(callback); } else { @@ -79,15 +80,15 @@ export class Server { let field = fields[id]; if (field) { if (!(this.ClientFieldsCached.get(field.Id) instanceof Field)) { - this.ClientFieldsCached.set(field.Id, field) + this.ClientFieldsCached.set(field.Id, field); } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache") + throw new Error("we shouldn't be trying to replace things that are already in the cache"); } } else { if (this.ClientFieldsCached.get(id) === FieldWaiting) { this.ClientFieldsCached.delete(id); } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache") + throw new Error("we shouldn't be trying to replace things that are already in the cache"); } } } @@ -99,9 +100,9 @@ export class Server { let realField = field as Field; existingFields[realField.Id] = realField; } - cb({ ...fields, ...existingFields }) + cb({ ...fields, ...existingFields }); } - }, { fireImmediately: true }) + }, { fireImmediately: true }); })); }; if (callback) { @@ -139,7 +140,7 @@ export class Server { public static UpdateField(field: Field) { if (!this.ClientFieldsCached.has(field.Id)) { - this.ClientFieldsCached.set(field.Id, field) + this.ClientFieldsCached.set(field.Id, field); } SocketStub.SEND_SET_FIELD(field); } diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index c3cd8bee6..257973e3d 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -1,7 +1,7 @@ -import { Key } from "../fields/Key" -import { Field, FieldId, Opt } from "../fields/Field" +import { Key } from "../fields/Key"; +import { Field, FieldId, Opt } from "../fields/Field"; import { ObservableMap } from "mobx"; -import { Document } from "../fields/Document" +import { Document } from "../fields/Document"; import { MessageStore, DocumentTransfer } from "../server/Message"; import { Utils } from "../Utils"; import { Server } from "./Server"; @@ -37,7 +37,7 @@ export class SocketStub { // document.fields.forEach((f, key) => (this.FieldStore.get(document.Id) as Document)._proxies.set(key.Id, (f as Field).Id)); console.log("sending " + document.Title); - Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())) + Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())); } public static SEND_FIELD_REQUEST(fieldid: FieldId): Promise>; @@ -50,12 +50,12 @@ export class SocketStub { } else { cb(undefined); } - }) - } + }); + }; if (callback) { fn(callback); } else { - return new Promise(fn) + return new Promise(fn); } } @@ -65,7 +65,7 @@ export class SocketStub { for (let field of fields) { fieldMap[field._id] = ServerUtils.FromJson(field); } - callback(fieldMap) + callback(fieldMap); }); } @@ -78,8 +78,9 @@ export class SocketStub { // server updates its document to hold a proxy mapping from key => fieldId var document = this.FieldStore.get(doc.Id) as Document; - if (document) + if (document) { document._proxies.set(key.Id, value.Id); + } // server adds the field to its repository of fields this.FieldStore.set(value.Id, value); @@ -93,8 +94,9 @@ export class SocketStub { // Server removes the field id from the document's list of field proxies var document = this.FieldStore.get(doc.Id) as Document; - if (document) + if (document) { document._proxies.delete(key.Id); + } } public static SEND_SET_FIELD(field: Field) { @@ -103,6 +105,6 @@ export class SocketStub { // ...SOCKET(SET_FIELD, field id, serialized field value) // Server updates the value of the field in its fieldstore - Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()) + Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()); } } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 613b94abd..72e6e57ab 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -64,7 +64,7 @@ export namespace Documents { const webProtoId = "webProto"; const collProtoId = "collectionProto"; const kvpProtoId = "kvpProto"; - const videoProtoId = "videoProto" + const videoProtoId = "videoProto"; const audioProtoId = "audioProto"; export function initProtos(): Promise { @@ -102,7 +102,7 @@ export namespace Documents { if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } if (options.panx !== undefined) { doc.SetNumber(KeyStore.PanX, options.panx); } if (options.pany !== undefined) { doc.SetNumber(KeyStore.PanY, options.pany); } - return doc + return doc; } function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document { @@ -110,10 +110,12 @@ export namespace Documents { } function SetInstanceOptions(doc: Document, options: DocumentOptions, value: [T, { new(): U }] | Document, id?: string) { var deleg = doc.MakeDelegate(id); - if (value instanceof Document) - deleg.Set(KeyStore.Data, value) - else + if (value instanceof Document) { + deleg.Set(KeyStore.Data, value); + } + else { deleg.SetData(KeyStore.Data, value[0], value[1]); + } return assignOptions(deleg, options); } @@ -134,7 +136,7 @@ export namespace Documents { function CreateTextPrototype(): Document { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); - return textProto + return textProto; } function CreatePdfPrototype(): Document { let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("AnnotationsKey"), @@ -168,7 +170,7 @@ export namespace Documents { } function CreateAudioPrototype(): Document { let audioProto = setupPrototypeOptions(audioProtoId, "AUDIO_PROTO", AudioBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }) + { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); return audioProto; } @@ -205,22 +207,22 @@ export namespace Documents { return assignToDelegate(SetInstanceOptions(webProto, options, [html, HtmlField]).MakeDelegate(), options); } export function KVPDocument(document: Document, options: DocumentOptions = {}, id?: string) { - return assignToDelegate(SetInstanceOptions(kvpProto, options, document, id), options) + return assignToDelegate(SetInstanceOptions(kvpProto, options, document, id), options); } export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string, makePrototype: boolean = true) { if (!makePrototype) { - return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id) + return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id); } - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options); } export function SchemaDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options); } export function TreeDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Tree }, [documents, ListField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Tree }, [documents, ListField], id), options); } export function DockDocument(config: string, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options); } export function CaptionDocument(doc: Document) { @@ -240,13 +242,13 @@ export namespace Documents {
` + FormattedTextBox.LayoutString("CaptionKey") + `
- ` }; + `; } export function FixedCaption(fieldName: string = "Caption") { return `
` + FormattedTextBox.LayoutString(fieldName + "Key") + `
-
` }; + `; } function OuterCaption() { return (` @@ -258,7 +260,7 @@ export namespace Documents { - `) + `); } function InnerCaption() { return (` @@ -270,7 +272,7 @@ export namespace Documents { - `) + `); } /* @@ -293,6 +295,6 @@ export namespace Documents { - `) + `); } } \ No newline at end of file diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts index f1761e643..ed3818071 100644 --- a/src/client/northstar/core/BaseObject.ts +++ b/src/client/northstar/core/BaseObject.ts @@ -1,5 +1,5 @@ -import { IEquatable } from '../utils/IEquatable' -import { IDisposable } from '../utils/IDisposable' +import { IEquatable } from '../utils/IEquatable'; +import { IDisposable } from '../utils/IDisposable'; export class BaseObject implements IEquatable, IDisposable { diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts index 230bfecc8..c89b1617c 100644 --- a/src/client/northstar/core/attribute/AttributeModel.ts +++ b/src/client/northstar/core/attribute/AttributeModel.ts @@ -1,5 +1,5 @@ -import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea' -import { BaseObject } from '../BaseObject' +import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea'; +import { BaseObject } from '../BaseObject'; import { observable } from "mobx"; export abstract class AttributeModel extends BaseObject { @@ -93,7 +93,7 @@ export class BackendAttributeModel extends AttributeModel { } public get DisplayName(): string { - return this._displayName.ReplaceAll("_", " ");; + return this._displayName.ReplaceAll("_", " "); } public get CodeName(): string { diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts index f50b78d51..66485183b 100644 --- a/src/client/northstar/core/attribute/AttributeTransformationModel.ts +++ b/src/client/northstar/core/attribute/AttributeTransformationModel.ts @@ -1,4 +1,4 @@ -; + import { computed, observable } from "mobx"; import { AggregateFunction } from "../../model/idea/idea"; import { AttributeModel } from "./AttributeModel"; @@ -20,16 +20,21 @@ export class AttributeTransformationModel implements IEquatable { if (this.AggregateFunction === AggregateFunction.Count) { return "count"; } - if (this.AggregateFunction === AggregateFunction.Avg) + if (this.AggregateFunction === AggregateFunction.Avg) { displayName = "avg(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Max) + } + else if (this.AggregateFunction === AggregateFunction.Max) { displayName = "max(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Min) + } + else if (this.AggregateFunction === AggregateFunction.Min) { displayName = "min(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Sum) + } + else if (this.AggregateFunction === AggregateFunction.Sum) { displayName = "sum(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.SumE) + } + else if (this.AggregateFunction === AggregateFunction.SumE) { displayName = "sumE(" + displayName + ")"; + } return displayName; } diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts index 0b8e0d12c..a197c1305 100644 --- a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts +++ b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts @@ -1,5 +1,5 @@ import { BackendAttributeModel, AttributeModel, CodeAttributeModel } from "./AttributeModel"; -import { DataType, VisualizationHint } from '../../model/idea/idea' +import { DataType, VisualizationHint } from '../../model/idea/idea'; export class CalculatedAttributeManager { public static AllCalculatedAttributes: Array = new Array(); diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts index 99a36636f..c46db4d22 100644 --- a/src/client/northstar/core/brusher/IBaseBrushable.ts +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -1,6 +1,6 @@ -import { PIXIPoint } from '../../utils/MathUtil' +import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from '../../../../fields/Document' +import { Document } from '../../../../fields/Document'; export interface IBaseBrushable extends IEquatable { BrusherModels: Array; diff --git a/src/client/northstar/core/brusher/IBaseBrusher.ts b/src/client/northstar/core/brusher/IBaseBrusher.ts index d7ae65464..d2de6ed62 100644 --- a/src/client/northstar/core/brusher/IBaseBrusher.ts +++ b/src/client/northstar/core/brusher/IBaseBrusher.ts @@ -1,4 +1,4 @@ -import { PIXIPoint } from '../../utils/MathUtil' +import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index 20fca77f5..e2ba3f652 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -15,7 +15,7 @@ export class FilterModel { public Equals(other: FilterModel): boolean { if (!Utils.EqualityHelper(this, other)) return false; - if (!this.isSame(this.ValueComparisons, (other as FilterModel).ValueComparisons)) return false; + if (!this.isSame(this.ValueComparisons, (other).ValueComparisons)) return false; return true; } diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts index 93f66a154..59d7adf4c 100644 --- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts +++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts @@ -1,5 +1,5 @@ -import { FilterOperand } from '../filter/FilterOperand' -import { IEquatable } from '../../utils/IEquatable' +import { FilterOperand } from '../filter/FilterOperand'; +import { IEquatable } from '../../utils/IEquatable'; import { Document } from "../../../../fields/Document"; export interface IBaseFilterConsumer extends IEquatable { diff --git a/src/client/northstar/core/filter/IBaseFilterProvider.ts b/src/client/northstar/core/filter/IBaseFilterProvider.ts index d082bfe12..fc3301b11 100644 --- a/src/client/northstar/core/filter/IBaseFilterProvider.ts +++ b/src/client/northstar/core/filter/IBaseFilterProvider.ts @@ -1,4 +1,4 @@ -import { FilterModel } from '../filter/FilterModel' +import { FilterModel } from '../filter/FilterModel'; export interface IBaseFilterProvider { FilterModels: Array; diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts index 1a3e461f5..80b1242a9 100644 --- a/src/client/northstar/core/filter/ValueComparision.ts +++ b/src/client/northstar/core/filter/ValueComparision.ts @@ -1,5 +1,5 @@ -import { Predicate } from '../../model/idea/idea' -import { Utils } from '../../utils/Utils' +import { Predicate } from '../../model/idea/idea'; +import { Utils } from '../../utils/Utils'; import { AttributeModel } from '../attribute/AttributeModel'; export class ValueComparison { @@ -15,15 +15,19 @@ export class ValueComparison { } public Equals(other: Object): boolean { - if (!Utils.EqualityHelper(this, other)) + if (!Utils.EqualityHelper(this, other)) { return false; - if (this.Predicate !== (other as ValueComparison).Predicate) + } + if (this.Predicate !== (other as ValueComparison).Predicate) { return false; + } let isComplex = (typeof this.Value === "object"); - if (!isComplex && this.Value !== (other as ValueComparison).Value) + if (!isComplex && this.Value !== (other as ValueComparison).Value) { return false; - if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) + } + if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) { return false; + } return true; } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index fa2a9c008..6abde4677 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -41,7 +41,7 @@ export class HistogramField extends BasicField { data: this.toString(), _id: this.Id - } + }; } @action diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts index cdae90c8b..6291ec1fc 100644 --- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts +++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; import { ChartType } from '../../northstar/model/binRanges/VisualBinRange'; import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea"; @@ -29,7 +29,7 @@ export class HistogramBinPrimitiveCollection { private _histoBox: HistogramBox; private get histoOp() { return this._histoBox.HistoOp; } private get histoResult() { return this.histoOp.Result as HistogramResult; } - private get sizeConverter() { return this._histoBox.SizeConverter!; } + private get sizeConverter() { return this._histoBox.SizeConverter; } public BinPrimitives: Array = new Array(); public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY; @@ -99,13 +99,14 @@ export class HistogramBinPrimitiveCollection { private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number { let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!); - if (unNormalizedValue === undefined) + if (unNormalizedValue === undefined) { return brushFactorSum; + } var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ? unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]); - let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult)) + let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult)); // bcz: are these calls needed? let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin); @@ -145,8 +146,9 @@ export class HistogramBinPrimitiveCollection { let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!)); let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!)); - if (xFrom !== undefined && yFrom !== undefined && xTo !== undefined && yTo !== undefined) + if (xFrom !== undefined && yFrom !== undefined && xTo !== undefined && yTo !== undefined) { this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue); + } } return 0; } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index ec9413649..7df59ef07 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { action, computed, observable, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; @@ -25,7 +25,7 @@ import { StyleConstants } from "../utils/StyleContants"; @observer export class HistogramBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr); } private _dropXRef = React.createRef(); private _dropYRef = React.createRef(); private _dropXDisposer?: DragManager.DragDropDisposer; @@ -92,15 +92,15 @@ export class HistogramBox extends React.Component { } reaction(() => CurrentUserUtils.NorthstarDBCatalog, (catalog?: Catalog) => this.activateHistogramOperation(catalog), { fireImmediately: true }); reaction(() => [this.VisualBinRanges && this.VisualBinRanges.slice()], () => this.SizeConverter.SetVisualBinRanges(this.VisualBinRanges)); - reaction(() => [this.PanelHeight, this.PanelWidth], () => this.SizeConverter.SetIsSmall(this.PanelWidth < 40 && this.PanelHeight < 40)) + reaction(() => [this.PanelHeight, this.PanelWidth], () => this.SizeConverter.SetIsSmall(this.PanelWidth < 40 && this.PanelHeight < 40)); reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined, (binRanges: BinRange[] | undefined) => { if (binRanges) { this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map((br, ind) => - VisualBinRangeHelper.GetVisualBinRange(this.HistoOp.Schema!.distinctAttributeParameters, br, this.HistogramResult!, ind ? this.HistoOp.Y : this.HistoOp.X, this.ChartType))); + VisualBinRangeHelper.GetVisualBinRange(this.HistoOp.Schema!.distinctAttributeParameters, br, this.HistogramResult, ind ? this.HistoOp.Y : this.HistoOp.X, this.ChartType))); - let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp.Schema!.distinctAttributeParameters, this.HistoOp.V, this.HistogramResult!, ModelHelpers.AllBrushIndex(this.HistogramResult!)); - this.ValueRange = Object.values(this.HistogramResult!.bins!).reduce((prev, cur) => { + let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp.Schema!.distinctAttributeParameters, this.HistoOp.V, this.HistogramResult, ModelHelpers.AllBrushIndex(this.HistogramResult)); + this.ValueRange = Object.values(this.HistogramResult.bins!).reduce((prev, cur) => { let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult; return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev; }, [Number.MAX_VALUE, Number.MIN_VALUE]); @@ -109,10 +109,12 @@ export class HistogramBox extends React.Component { } componentWillUnmount() { - if (this._dropXDisposer) + if (this._dropXDisposer) { this._dropXDisposer(); - if (this._dropYDisposer) + } + if (this._dropYDisposer) { this._dropYDisposer(); + } } activateHistogramOperation(catalog?: Catalog) { @@ -128,7 +130,7 @@ export class HistogramBox extends React.Component { this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { brush.SetNumber(KeyStore.BackgroundColor, StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]); let brushed = brush.GetList(KeyStore.BrushingDocs, [] as Document[]); - return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] } + return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] }; })); }, { fireImmediately: true }); reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true }); @@ -146,7 +148,7 @@ export class HistogramBox extends React.Component { let roff = this.SizeConverter.RightOffset; let boff = this.SizeConverter.BottomOffset; return ( - runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}> + runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}> {({ measureRef }) =>
@@ -168,7 +170,7 @@ export class HistogramBox extends React.Component {
} - ) + ); } } diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index a78703247..4c5bdb14b 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; @@ -28,17 +28,18 @@ export class HistogramBoxPrimitives extends React.Component this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); } @computed get barPrimitives() { let histoResult = this.props.HistoBox.HistogramResult; - if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) + if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) { return (null); + } let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult); return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => { - let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox); + let drawPrims = new HistogramBinPrimitiveCollection(histoResult.bins![key], this.props.HistoBox); let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex, - ModelHelpers.GetBinFilterModel(histoResult!.bins![key], allBrushIndex, histoResult!, this.histoOp.X, this.histoOp.Y)); + ModelHelpers.GetBinFilterModel(histoResult.bins![key], allBrushIndex, histoResult, this.histoOp.X, this.histoOp.Y)); drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp => prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle)))); return prims; - }, [] as JSX.Element[]) + }, [] as JSX.Element[]); } componentDidMount() { @@ -47,8 +48,9 @@ export class HistogramBoxPrimitives extends React.Component bp.BrushIndex === allBrushIndex); - if (!rawAllBrushPrim) - return () => { } + if (!rawAllBrushPrim) { + return () => { }; + } let allBrushPrim = rawAllBrushPrim; return () => runInAction(() => { if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) { @@ -59,23 +61,25 @@ export class HistogramBoxPrimitives extends React.Component {labels.reduce((prims, binLabel, i) => { let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis); prims.push(this.drawLine(r.xFrom, r.yFrom, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); - if (i === labels.length - 1) + if (i === labels.length - 1) { prims.push(this.drawLine(axis === 0 ? r.xTo : r.xFrom, axis === 0 ? r.yFrom : r.yTo, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); + } return prims; }, [] as JSX.Element[])} - + ; } drawLine(xFrom: number, yFrom: number, width: number, height: number) { @@ -89,9 +93,9 @@ export class HistogramBoxPrimitives extends React.Component + let trans1Xpercent = `${xFrom / this.renderDimension * 100}%`; + let trans1Ypercent = `${yFrom / this.renderDimension * 100}%`; + return ; } drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) { if (r.height < 0) { @@ -102,11 +106,11 @@ export class HistogramBoxPrimitives extends React.Component { if (e.button === 0) tapHandler() }} + return ( { if (e.button === 0) tapHandler(); }} x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />); } render() { @@ -118,6 +122,6 @@ export class HistogramBoxPrimitives extends React.Component -
+ ; } } \ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx index dd62e9146..5785fe838 100644 --- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { action, computed, reaction } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; @@ -13,7 +13,7 @@ import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives"; export class HistogramLabelPrimitives extends React.Component { componentDidMount() { reaction(() => [this.props.HistoBox.PanelWidth, this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length], - (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0] as number, fields[1] as number, this.props.HistoBox), { fireImmediately: true }); + (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0], fields[1], this.props.HistoBox), { fireImmediately: true }); } @action @@ -32,8 +32,9 @@ export class HistogramLabelPrimitives extends React.ComponentFontStyles.AxisLabel.fontSize + 5))); sc.MaxLabelSizes[axis].coords[axis] + 5); @@ -52,8 +53,8 @@ export class HistogramLabelPrimitives extends React.Component @@ -61,7 +62,7 @@ export class HistogramLabelPrimitives extends React.Component - ) + ); } return prims; }, [] as JSX.Element[]); @@ -73,7 +74,7 @@ export class HistogramLabelPrimitives extends React.Component {xaxislines} {yaxislines} - + ; } } \ No newline at end of file diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index ba6fe2ad5..1c8d3fd73 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -1,4 +1,4 @@ -import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea" +import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea"; import { computed, observable, action } from "mobx"; export class Gateway { diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts index e4bf77ed8..29f80d2d1 100644 --- a/src/client/northstar/model/ModelExtensions.ts +++ b/src/client/northstar/model/ModelExtensions.ts @@ -1,7 +1,7 @@ -import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea' -import { Utils } from '../utils/Utils' +import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea'; +import { Utils } from '../utils/Utils'; -import { FilterModel } from '../core/filter/FilterModel' +import { FilterModel } from '../core/filter/FilterModel'; (SingleDimensionAggregateParameters as any).prototype.Equals = function (other: Object) { if (!Utils.EqualityHelper(this, other)) return false; @@ -9,13 +9,13 @@ import { FilterModel } from '../core/filter/FilterModel' (other as SingleDimensionAggregateParameters).attributeParameters!)) return false; if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters)) return false; return true; -} +}; { (AttributeParameters as any).prototype.Equals = function (other: AttributeParameters) { - return (this).constructor.name === (other).constructor.name && + return (this).constructor.name === (other).constructor.name && this.rawName === other.rawName; - } + }; } { @@ -23,7 +23,7 @@ import { FilterModel } from '../core/filter/FilterModel' if (!Utils.EqualityHelper(this, other)) return false; if ((this as Solution).solutionId !== (other as Solution).solutionId) return false; return true; - } + }; } { @@ -35,7 +35,7 @@ import { FilterModel } from '../core/filter/FilterModel' if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false; return true; - } + }; } { @@ -44,5 +44,5 @@ import { FilterModel } from '../core/filter/FilterModel' if ((this as Brush).brushEnum !== (other as Brush).brushEnum) return false; if ((this as Brush).brushIndex !== (other as Brush).brushIndex) return false; return true; - } + }; } \ No newline at end of file diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index 1a58e6180..ac807b41f 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -64,7 +64,7 @@ export class ModelHelpers { if (aggParams) { aggregateParameters.push(aggParams); - var margin = new MarginAggregateParameters() + var margin = new MarginAggregateParameters(); margin.aggregateFunction = agg.AggregateFunction; margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel); margin.distinctAttributeParameters = distinctAttributeParameters; @@ -106,7 +106,7 @@ export class ModelHelpers { { rawName: am.CodeName, visualizationHints: am.VisualizationHints, - id: (am as BackendAttributeModel).Id + id: (am).Id }); } else if (am instanceof CodeAttributeModel) { @@ -114,11 +114,11 @@ export class ModelHelpers { { rawName: am.CodeName, visualizationHints: am.VisualizationHints, - code: (am as CodeAttributeModel).Code + code: (am).Code }); } else { - throw new Exception() + throw new Exception(); } } diff --git a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts index 995bf4e0b..120b034f2 100644 --- a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts @@ -1,5 +1,5 @@ -import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class AlphabeticVisualBinRange extends VisualBinRange { public DataBinRange: AlphabeticBinRange; diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts index f5872aa4c..776e643cd 100644 --- a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts @@ -1,5 +1,5 @@ -import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class DateTimeVisualBinRange extends VisualBinRange { public DataBinRange: DateTimeBinRange; diff --git a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts index 407ff3ea6..42509d797 100644 --- a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts @@ -1,5 +1,5 @@ -import { NominalBinRange, BinLabel } from '../../model/idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { NominalBinRange, BinLabel } from '../../model/idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class NominalVisualBinRange extends VisualBinRange { public DataBinRange: NominalBinRange; diff --git a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts index 80886416b..c579c8e5f 100644 --- a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts @@ -1,4 +1,4 @@ -import { QuantitativeBinRange } from '../idea/idea' +import { QuantitativeBinRange } from '../idea/idea'; import { VisualBinRange } from './VisualBinRange'; import { format } from "d3-format"; diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts index a0766e494..449a22e91 100644 --- a/src/client/northstar/model/binRanges/VisualBinRange.ts +++ b/src/client/northstar/model/binRanges/VisualBinRange.ts @@ -1,4 +1,4 @@ -import { BinLabel } from '../../model/idea/idea' +import { BinLabel } from '../../model/idea/idea'; export abstract class VisualBinRange { diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts index 63ee61909..9671e55f8 100644 --- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts +++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts @@ -16,18 +16,18 @@ export class VisualBinRangeHelper { public static GetNonAggregateVisualBinRange(dataBinRange: BinRange): VisualBinRange { if (dataBinRange instanceof NominalBinRange) { - return new NominalVisualBinRange(dataBinRange as NominalBinRange); + return new NominalVisualBinRange(dataBinRange); } else if (dataBinRange instanceof QuantitativeBinRange) { - return new QuantitativeVisualBinRange(dataBinRange as QuantitativeBinRange); + return new QuantitativeVisualBinRange(dataBinRange); } else if (dataBinRange instanceof AlphabeticBinRange) { - return new AlphabeticVisualBinRange(dataBinRange as AlphabeticBinRange); + return new AlphabeticVisualBinRange(dataBinRange); } else if (dataBinRange instanceof DateTimeBinRange) { - return new DateTimeVisualBinRange(dataBinRange as DateTimeBinRange); + return new DateTimeVisualBinRange(dataBinRange); } - throw new Exception() + throw new Exception(); } public static GetVisualBinRange(distinctAttributeParameters: AttributeParameters | undefined, dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange { @@ -51,13 +51,13 @@ export class VisualBinRangeHelper { } } } - }; + } let visualBinRange = QuantitativeVisualBinRange.Initialize(minValue, maxValue, 10, false); if (chartType === ChartType.HorizontalBar || chartType === ChartType.VerticalBar) { visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue), - Math.max(0, (visualBinRange as QuantitativeVisualBinRange).DataBinRange.maxValue!), + Math.max(0, (visualBinRange).DataBinRange.maxValue!), SETTINGS_X_BINS, false); } else if (chartType === ChartType.SinglePoint) { diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts index a14337763..c6d5f0a15 100644 --- a/src/client/northstar/operations/BaseOperation.ts +++ b/src/client/northstar/operations/BaseOperation.ts @@ -1,4 +1,4 @@ -import { FilterModel } from '../core/filter/FilterModel' +import { FilterModel } from '../core/filter/FilterModel'; import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea'; import { action, computed, observable } from "mobx"; import { Gateway } from '../manager/Gateway'; @@ -62,8 +62,9 @@ export abstract class BaseOperation { } let operationParameters = this.CreateOperationParameters(); - if (this.Result) - this.Result.progress = 0; // bcz: used to set Result to undefined, but that causes the display to blink + if (this.Result) { + this.Result.progress = 0; + } // bcz: used to set Result to undefined, but that causes the display to blink this.Error = ""; let salt = Math.random().toString(); this.RequestSalt = salt; @@ -97,7 +98,7 @@ export abstract class BaseOperation { pollPromise.Start(async () => { let result = await Gateway.Instance.GetResult(resultParameters.toJSON()); if (result instanceof ErrorResult) { - throw new Error((result as ErrorResult).message); + throw new Error((result).message); } if (this.RequestSalt === pollPromise.RequestSalt) { if (result && (!this.Result || this.Result.progress !== result.progress)) { diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index a3ddc1c98..760106023 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -62,7 +62,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @computed public get FilterString(): string { let filterModels: FilterModel[] = []; - return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true) + return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); } @computed diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts index a52ca6d96..12b8d8e77 100644 --- a/src/client/northstar/utils/ArrayUtil.ts +++ b/src/client/northstar/utils/ArrayUtil.ts @@ -50,7 +50,7 @@ export class ArrayUtil { if (filtered.length > 0) { return filtered[0]; } - throw new Exception() + throw new Exception(); } public static FirstOrDefault(arr: T[], predicate: (x: any) => boolean): T | undefined { diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts index 7c2b7fc9d..df14d4da0 100644 --- a/src/client/northstar/utils/Extensions.ts +++ b/src/client/northstar/utils/Extensions.ts @@ -6,7 +6,7 @@ interface String { String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string { var target = this; return target.split(toReplace).join(replacement); -} +}; String.prototype.Truncate = function (length: number, replacement: string): String { var target = this; @@ -14,7 +14,7 @@ String.prototype.Truncate = function (length: number, replacement: string): Stri target = target.slice(0, Math.max(0, length - replacement.length)) + replacement; } return target; -} +}; interface Math { log10(val: number): number; @@ -22,7 +22,7 @@ interface Math { Math.log10 = function (val: number): number { return Math.log(val) / Math.LN10; -} +}; declare interface ObjectConstructor { assign(...objects: Object[]): Object; diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts index 6d8acea20..d5220c479 100644 --- a/src/client/northstar/utils/GeometryUtil.ts +++ b/src/client/northstar/utils/GeometryUtil.ts @@ -8,15 +8,19 @@ export class GeometryUtil { let minY: number = Number.MAX_VALUE; let maxX: number = Number.MIN_VALUE; let maxY: number = Number.MIN_VALUE; - for (var i = 0; i < points.length; i++) { - if (points[i].x < minX) - minX = points[i].x; - if (points[i].y < minY) - minY = points[i].y; - if (points[i].x > maxX) - maxX = points[i].x; - if (points[i].y > maxY) - maxY = points[i].y; + for (const point of points) { + if (point.x < minX) { + minX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y > maxY) { + maxY = point.y; + } } return new PIXIRectangle(minX * scale - padding, minY * scale - padding, (maxX - minX) * scale + padding * 2, (maxY - minY) * scale + padding * 2); } @@ -35,7 +39,7 @@ export class GeometryUtil { nx = (cos * (x - cx)) + (sin * (y - cy)) + cx, ny = (cos * (y - cy)) - (sin * (x - cx)) + cy; return new PIXIPoint(nx, ny); - } + }; return points.map(p => rotate(center.x, center.y, p.x, p.y, angle)); } @@ -54,9 +58,9 @@ export class GeometryUtil { return []; } - for (let v = 0; v < points.length; v++) { - x = points[v].x; - y = points[v].y; + for (const point of points) { + x = point.x; + y = point.y; sum_x += x; sum_y += y; sum_xx += x * x; @@ -68,8 +72,8 @@ export class GeometryUtil { let b = (sum_y / count) - (m * sum_x) / count; let result: PIXIPoint[] = new Array(); - for (let v = 0; v < points.length; v++) { - x = points[v].x; + for (const point of points) { + x = point.x; y = x * m + b; result.push(new PIXIPoint(x, y)); } diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts index 7aa255096..4b44f40c3 100644 --- a/src/client/northstar/utils/MathUtil.ts +++ b/src/client/northstar/utils/MathUtil.ts @@ -16,11 +16,11 @@ export class PIXIRectangle { public x: number; public y: number; public width: number; - public height: number - public get left() { return this.x } + public height: number; + public get left() { return this.x; } public get right() { return this.x + this.width; } - public get top() { return this.y } - public get bottom() { return this.top + this.height } + public get top() { return this.y; } + public get bottom() { return this.top + this.height; } public static get EMPTY() { return new PIXIRectangle(0, 0, -1, -1); } constructor(x: number, y: number, width: number, height: number) { this.x = x; @@ -127,14 +127,18 @@ export class MathUtil { } public static PointInPIXIRectangle(p: PIXIPoint, rect: PIXIRectangle): boolean { - if (p.x < rect.left - this.EPSILON) + if (p.x < rect.left - this.EPSILON) { return false; - if (p.x > rect.right + this.EPSILON) + } + if (p.x > rect.right + this.EPSILON) { return false; - if (p.y < rect.top - this.EPSILON) + } + if (p.y < rect.top - this.EPSILON) { return false; - if (p.y > rect.bottom + this.EPSILON) + } + if (p.y > rect.bottom + this.EPSILON) { return false; + } return true; } @@ -145,23 +149,27 @@ export class MathUtil { var r3 = new PIXIPoint(rect.right, rect.bottom); var r4 = new PIXIPoint(rect.left, rect.bottom); var ret = new Array(); - var dist = this.Dist(lineFrom, lineTo) + var dist = this.Dist(lineFrom, lineTo); var inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } return ret; } @@ -178,7 +186,7 @@ export class MathUtil { } public static Dot(p1: PIXIPoint, p2: PIXIPoint): number { - return p1.x * p2.x + p1.y * p2.y + return p1.x * p2.x + p1.y * p2.y; } public static Normalize(p1: PIXIPoint) { @@ -193,7 +201,7 @@ export class MathUtil { public static DistSquared(p1: PIXIPoint, p2: PIXIPoint): number { const a = p1.x - p2.x; const b = p1.y - p2.y; - return (a * a + b * b) + return (a * a + b * b); } public static RectIntersectsRect(r1: PIXIRectangle, r2: PIXIRectangle): boolean { diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts index b5c4a16ab..a52890ed9 100644 --- a/src/client/northstar/utils/SizeConverter.ts +++ b/src/client/northstar/utils/SizeConverter.ts @@ -32,8 +32,8 @@ export class SizeConverter { this.Initialized++; var xLabels = visualBinRanges[0].GetLabels(); var yLabels = visualBinRanges[1].GetLabels(); - var xLabelStrings = xLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length }); - var yLabelStrings = yLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length }); + var xLabelStrings = xLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; }); + var yLabelStrings = yLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; }); var metricsX = { width: 75 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number, //xLabelStrings[0]!.slice(0, 20)) // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS)); @@ -62,19 +62,20 @@ export class SizeConverter { public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) { var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult; - if (value && value.hasResult) + if (value && value.hasResult) { return [this.DataToScreenCoord(value.result!, axis) - 5, this.DataToScreenCoord(value.result!, axis) + 5]; + } return [undefined, undefined]; } public DataToScreenXAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) { var value = visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![index]); - return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))] + return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))]; } public DataToScreenYAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) { var value = visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![index]); - return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))] + return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))]; } public DataToScreenX(x: number): number { @@ -85,8 +86,9 @@ export class SizeConverter { return flip ? (this.RenderDimension) - retY : retY; } public DataToScreenCoord(v: number, axis: number) { - if (axis === 0) + if (axis === 0) { return this.DataToScreenX(v); + } return this.DataToScreenY(v); } public DataToScreenRange(minVal: number, maxVal: number, axis: number) { @@ -94,6 +96,6 @@ export class SizeConverter { let xTo = this.DataToScreenX(axis === 0 ? maxVal : this.DataMaxs[0]); let yFrom = this.DataToScreenY(axis === 1 ? minVal : this.DataMins[1]); let yTo = this.DataToScreenY(axis === 1 ? maxVal : this.DataMaxs[1]); - return { xFrom, yFrom, xTo, yTo } + return { xFrom, yFrom, xTo, yTo }; } } \ No newline at end of file diff --git a/src/client/northstar/utils/StyleContants.ts b/src/client/northstar/utils/StyleContants.ts index ac8617e3b..e9b6e0297 100644 --- a/src/client/northstar/utils/StyleContants.ts +++ b/src/client/northstar/utils/StyleContants.ts @@ -11,7 +11,7 @@ export class StyleConstants { static OPERATOR_MENU_LARGE: number = 35; static OPERATOR_MENU_SMALL: number = 25; - static BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd] + static BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd]; static GAP: number = 3; static BACKGROUND_COLOR: number = 0xF3F3F3; diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts index c96b4cbd9..d071dec62 100644 --- a/src/client/northstar/utils/Utils.ts +++ b/src/client/northstar/utils/Utils.ts @@ -1,7 +1,7 @@ -import { IBaseBrushable } from '../core/brusher/IBaseBrushable' -import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer' -import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider' -import { AggregateFunction } from '../model/idea/idea' +import { IBaseBrushable } from '../core/brusher/IBaseBrushable'; +import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer'; +import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider'; +import { AggregateFunction } from '../model/idea/idea'; export class Utils { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index fb489edb6..f38b8ca75 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,7 +1,7 @@ -import React = require('react') +import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, computed } from 'mobx'; -import { Document } from "../../fields/Document" +import { Document } from "../../fields/Document"; import { DocumentView } from '../views/nodes/DocumentView'; import { KeyStore } from '../../fields/KeyStore'; import { FieldWaiting } from '../../fields/Field'; @@ -50,7 +50,7 @@ export class DocumentManager { if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn = view; } - }) + }); return (toReturn); } @@ -71,7 +71,7 @@ export class DocumentManager { toReturn.push(view); } } - }) + }); return (toReturn); } @@ -86,8 +86,8 @@ export class DocumentManager { let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document); if (linkToDoc && linkToDoc !== FieldWaiting) { DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - pairs.push({ a: dv, b: docView1, l: link }) - }) + pairs.push({ a: dv, b: docView1, l: link }); + }); } } return pairs; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f95b2c29d..4849ae9f7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -103,7 +103,7 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset.canDrop + delete element.dataset.canDrop; }; } @@ -216,8 +216,9 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - if (dragData instanceof DocumentDragData) + if (dragData instanceof DocumentDragData) { dragData.aliasOnDrop = e.ctrlKey || e.altKey; + } if (e.shiftKey) { abortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2a3c1da6e..92944bec0 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,13 +1,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model" -import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands' -import { redo, undo } from 'prosemirror-history' -import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list' +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; +import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands'; +import { redo, undo } from 'prosemirror-history'; +import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list'; import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; // :: Object @@ -24,7 +24,7 @@ export const nodes: { [index: string]: NodeSpec } = { content: "inline*", group: "block", parseDOM: [{ tag: "p" }], - toDOM() { return pDOM } + toDOM() { return pDOM; } }, // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. @@ -33,14 +33,14 @@ export const nodes: { [index: string]: NodeSpec } = { group: "block", defining: true, parseDOM: [{ tag: "blockquote" }], - toDOM() { return blockquoteDOM } + toDOM() { return blockquoteDOM; } }, // :: NodeSpec A horizontal rule (`
`). horizontal_rule: { group: "block", parseDOM: [{ tag: "hr" }], - toDOM() { return hrDOM } + toDOM() { return hrDOM; } }, // :: NodeSpec A heading textblock, with a `level` attribute that @@ -57,7 +57,7 @@ export const nodes: { [index: string]: NodeSpec } = { { tag: "h4", attrs: { level: 4 } }, { tag: "h5", attrs: { level: 5 } }, { tag: "h6", attrs: { level: 6 } }], - toDOM(node: any) { return ["h" + node.attrs.level, 0] } + toDOM(node: any) { return ["h" + node.attrs.level, 0]; } }, // :: NodeSpec A code listing. Disallows marks or non-text inline @@ -70,7 +70,7 @@ export const nodes: { [index: string]: NodeSpec } = { code: true, defining: true, parseDOM: [{ tag: "pre", preserveWhitespace: "full" }], - toDOM() { return preDOM } + toDOM() { return preDOM; } }, // :: NodeSpec The text node. @@ -96,10 +96,10 @@ export const nodes: { [index: string]: NodeSpec } = { src: dom.getAttribute("src"), title: dom.getAttribute("title"), alt: dom.getAttribute("alt") - } + }; } }], - toDOM(node: any) { return ["img", node.attrs] } + toDOM(node: any) { return ["img", node.attrs]; } }, // :: NodeSpec A hard line break, represented in the DOM as `
`. @@ -108,7 +108,7 @@ export const nodes: { [index: string]: NodeSpec } = { group: "inline", selectable: false, parseDOM: [{ tag: "br" }], - toDOM() { return brDOM } + toDOM() { return brDOM; } }, ordered_list: { @@ -136,7 +136,7 @@ export const nodes: { [index: string]: NodeSpec } = { ...listItem, content: 'paragraph block*' } -} +}; const emDOM: DOMOutputSpecArray = ["em", 0]; const strongDOM: DOMOutputSpecArray = ["strong", 0]; @@ -156,17 +156,17 @@ export const marks: { [index: string]: MarkSpec } = { inclusive: false, parseDOM: [{ tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } + return { href: dom.getAttribute("href"), title: dom.getAttribute("title") }; } }], - toDOM(node: any) { return ["a", node.attrs, 0] } + toDOM(node: any) { return ["a", node.attrs, 0]; } }, // :: MarkSpec An emphasis mark. Rendered as an `` element. // Has parse rules that also match `` and `font-style: italic`. em: { parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], - toDOM() { return emDOM } + toDOM() { return emDOM; } }, // :: MarkSpec A strong mark. Rendered as ``, parse rules @@ -175,7 +175,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [{ tag: "strong" }, { tag: "b" }, { style: "font-weight" }], - toDOM() { return strongDOM } + toDOM() { return strongDOM; } }, underline: { @@ -221,9 +221,9 @@ export const marks: { [index: string]: MarkSpec } = { // :: MarkSpec Code font mark. Represented as a `` element. code: { parseDOM: [{ tag: "code" }], - toDOM() { return codeDOM } + toDOM() { return codeDOM; } } -} +}; // :: Schema // This schema rougly corresponds to the document schema used by @@ -233,4 +233,4 @@ export const marks: { [index: string]: MarkSpec } = { // // To reuse elements from this schema, extend or read from its // `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). -export const schema = new Schema({ nodes, marks }) \ No newline at end of file +export const schema = new Schema({ nodes, marks }); \ No newline at end of file diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index bf9b8266f..468484928 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -14,7 +14,7 @@ import { ListField } from "../../fields/ListField"; // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' // @ts-ignore -import * as typescriptlib from '!!raw-loader!./type_decls.d' +import * as typescriptlib from '!!raw-loader!./type_decls.d'; import { Documents } from "../documents/Documents"; import { Key } from "../../fields/Key"; @@ -50,7 +50,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an 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 params: any[] = [KeyStore, Documents, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let run = (args: { [name: string]: any } = {}): ScriptResult => { let argsArray: any[] = []; @@ -67,7 +67,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an } catch (error) { return { success: false, error }; } - } + }; return { compiled: true, run }; } @@ -90,14 +90,14 @@ class ScriptingCompilerHost { } // getDefaultLibFileName(options: ts.CompilerOptions): string { getDefaultLibFileName(options: any): string { - return 'node_modules/typescript/lib/lib.d.ts' // No idea what this means... + return 'node_modules/typescript/lib/lib.d.ts'; // No idea what this means... } writeFile(fileName: string, content: string) { const file = this.files.find(file => file.fileName === fileName); if (file) { file.content = content; } else { - this.files.push({ fileName, content }) + this.files.push({ fileName, content }); } } getCurrentDirectory(): string { diff --git a/src/client/util/ScrollBox.tsx b/src/client/util/ScrollBox.tsx index b6b088170..a209874a3 100644 --- a/src/client/util/ScrollBox.tsx +++ b/src/client/util/ScrollBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); export class ScrollBox extends React.Component { onWheel = (e: React.WheelEvent) => { @@ -16,6 +16,6 @@ export class ScrollBox extends React.Component { }} onWheel={this.onWheel}> {this.props.children} - ) + ); } } \ No newline at end of file diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1bb15c86a..5ddaafc72 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -23,7 +23,7 @@ export namespace SelectionManager { @action DeselectAll(): void { - manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)) + manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)); manager.SelectedDocuments = []; } } @@ -46,7 +46,7 @@ export namespace SelectionManager { } } - manager.DeselectAll() + manager.DeselectAll(); if (found) manager.SelectDoc(found, false); Main.Instance.SetTextDoc(undefined, undefined); } diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 913472aa0..bd5753093 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -5,12 +5,12 @@ import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType } from "prosemirror-model" -import React = require("react") +import { Schema, NodeType } from "prosemirror-model"; +import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); -import { library } from '@fortawesome/fontawesome-svg-core' -import { wrapInList, bulletList } from 'prosemirror-schema-list' +import { library } from '@fortawesome/fontawesome-svg-core'; +import { wrapInList, bulletList } from 'prosemirror-schema-list'; import { faListUl } from '@fortawesome/free-solid-svg-icons'; @@ -39,7 +39,7 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, //this doesn't work currently - look into notion of active block { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, - ] + ]; items.forEach(({ dom }) => this.tooltip.appendChild(dom)); //pointer down handler to activate button effects @@ -52,8 +52,8 @@ export class TooltipTextMenu { //uncomment this if we want the bullet button to disappear if current selection is bulleted // dom.style.display = active ? "" : "none" } - }) - }) + }); + }); this.update(view, undefined); } @@ -99,32 +99,32 @@ export class TooltipTextMenu { return { command: setBlockType(schema.nodes.heading, { level }), dom: this.icon("H" + level, "heading") - } + }; } //updates the tooltip menu when the selection changes update(view: EditorView, lastState: EditorState | undefined) { - let state = view.state + let state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) return + lastState.selection.eq(state.selection)) return; // Hide the tooltip if the selection is empty if (state.selection.empty) { - this.tooltip.style.display = "none" - return + this.tooltip.style.display = "none"; + return; } // Otherwise, reposition it and update its content - this.tooltip.style.display = "" - let { from, to } = state.selection - let start = view.coordsAtPos(from), end = view.coordsAtPos(to) + this.tooltip.style.display = ""; + let { from, to } = state.selection; + let start = view.coordsAtPos(from), end = view.coordsAtPos(to); // The box in which the tooltip is positioned, to use as base - let box = this.tooltip.offsetParent!.getBoundingClientRect() + let box = this.tooltip.offsetParent!.getBoundingClientRect(); // Find a center-ish x position from the selection endpoints (when // crossing lines, end may be more to the left) - let left = Math.max((start.left + end.left) / 2, start.left + 3) - this.tooltip.style.left = (left - box.left) + "px" + let left = Math.max((start.left + end.left) / 2, start.left + 3); + this.tooltip.style.left = (left - box.left) + "px"; let width = Math.abs(start.left - end.left) / 2; let mid = Math.min(start.left, end.left) + width; @@ -133,5 +133,5 @@ export class TooltipTextMenu { this.tooltip.style.bottom = (box.bottom - start.top) + "px"; } - destroy() { this.tooltip.remove() } + destroy() { this.tooltip.remove(); } } \ No newline at end of file diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index ed4282874..e9170ec36 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -62,19 +62,19 @@ export class Transform { return this; } - translated = (x: number, y: number): Transform => this.copy().translate(x, y) + translated = (x: number, y: number): Transform => this.copy().translate(x, y); - preTranslated = (x: number, y: number): Transform => this.copy().preTranslate(x, y) + preTranslated = (x: number, y: number): Transform => this.copy().preTranslate(x, y); - scaled = (scale: number): Transform => this.copy().scale(scale) + scaled = (scale: number): Transform => this.copy().scale(scale); - scaledAbout = (scale: number, x: number, y: number): Transform => this.copy().scaleAbout(scale, x, y) + scaledAbout = (scale: number, x: number, y: number): Transform => this.copy().scaleAbout(scale, x, y); - preScaled = (scale: number): Transform => this.copy().preScale(scale) + preScaled = (scale: number): Transform => this.copy().preScale(scale); - transformed = (transform: Transform): Transform => this.copy().transform(transform) + transformed = (transform: Transform): Transform => this.copy().transform(transform); - preTransformed = (transform: Transform): Transform => this.copy().preTransform(transform) + preTransformed = (transform: Transform): Transform => this.copy().preTransform(transform); transformPoint = (x: number, y: number): [number, number] => { x *= this._scale; @@ -84,7 +84,7 @@ export class Transform { return [x, y]; } - transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale] + transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale]; transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } { [x, y] = this.transformPoint(x, y); @@ -92,8 +92,8 @@ export class Transform { return { x, y, width, height }; } - inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) + inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale); - copy = () => new Transform(this._translateX, this._translateY, this._scale) + copy = () => new Transform(this._translateX, this._translateY, this._scale); } \ No newline at end of file diff --git a/src/client/util/TypedEvent.ts b/src/client/util/TypedEvent.ts index 1b251da25..532ba78eb 100644 --- a/src/client/util/TypedEvent.ts +++ b/src/client/util/TypedEvent.ts @@ -36,5 +36,5 @@ export class TypedEvent { this.listenersOncer = []; } - pipe = (te: TypedEvent): Disposable => this.on((e) => te.emit(e)) + pipe = (te: TypedEvent): Disposable => this.on((e) => te.emit(e)); } \ No newline at end of file diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index b4ea4acae..27aed4bac 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -1,5 +1,5 @@ import { observable, action } from "mobx"; -import 'source-map-support/register' +import 'source-map-support/register'; import { Without } from "../../Utils"; import { string } from "prop-types"; @@ -31,9 +31,9 @@ function propertyDecorator(target: any, key: string | symbol) { batch.end(); } } - }) + }); } - }) + }); } export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor): any; @@ -43,11 +43,11 @@ export function undoBatch(target: any, key?: string | symbol, descriptor?: Typed return function () { let batch = UndoManager.StartBatch(""); try { - return target.apply(undefined, arguments) + return target.apply(undefined, arguments); } finally { batch.end(); } - } + }; } if (!descriptor) { propertyDecorator(target, key); @@ -58,11 +58,11 @@ export function undoBatch(target: any, key?: string | symbol, descriptor?: Typed descriptor.value = function (...args: any[]) { let batch = UndoManager.StartBatch(getBatchName(target, key)); try { - return oldFunction.apply(this, args) + return oldFunction.apply(this, args); } finally { batch.end(); } - } + }; return descriptor; } @@ -117,8 +117,8 @@ export namespace UndoManager { EndBatch(cancel); } - end = () => { this.dispose(false); } - cancel = () => { this.dispose(true); } + end = () => { this.dispose(false); }; + cancel = () => { this.dispose(true); }; } export function StartBatch(batchName: string): Batch { @@ -138,7 +138,7 @@ export namespace UndoManager { redoStack.length = 0; currentBatch = undefined; } - }) + }); export function RunInBatch(fn: () => void, batchName: string) { let batch = StartBatch(batchName); @@ -166,7 +166,7 @@ export namespace UndoManager { undoing = false; redoStack.push(commands); - }) + }); export const Redo = action(() => { if (redoStack.length === 0) { @@ -185,6 +185,6 @@ export namespace UndoManager { undoing = false; undoStack.push(commands); - }) + }); } \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index cfa8ea7b7..615a928ad 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -2,11 +2,11 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; import { observer } from "mobx-react"; -import "./ContextMenu.scss" +import "./ContextMenu.scss"; @observer export class ContextMenu extends React.Component { - static Instance: ContextMenu + static Instance: ContextMenu; @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault() }]; @observable private _pageX: number = 0; @@ -22,15 +22,15 @@ export class ContextMenu extends React.Component { constructor(props: Readonly<{}>) { super(props); - this.ref = React.createRef() + this.ref = React.createRef(); ContextMenu.Instance = this; } @action clearItems() { - this._items = [] - this._display = "none" + this._items = []; + this._display = "none"; } @action @@ -56,7 +56,7 @@ export class ContextMenu extends React.Component { this._searchString = ""; - this._display = "flex" + this._display = "flex"; } intersects = (x: number, y: number): boolean => { @@ -86,7 +86,7 @@ export class ContextMenu extends React.Component { {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). map(prop => )} - ) + ); } @action diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 4801c1555..70813f0dd 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -11,7 +11,7 @@ export interface SubmenuProps { } export interface ContextMenuItemProps { - type: ContextMenuProps | SubmenuProps + type: ContextMenuProps | SubmenuProps; } export class ContextMenuItem extends React.Component { @@ -20,6 +20,6 @@ export class ContextMenuItem extends React.Component {
{this.props.description}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 285d145a2..b29fb6a2b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -21,8 +21,8 @@ export const Flyout = higflyout.default; @observer export class DocumentDecorations extends React.Component<{}, { value: string }> { - static Instance: DocumentDecorations - private _resizer = "" + static Instance: DocumentDecorations; + private _resizer = ""; private _isPointerDown = false; private keyinput: React.RefObject; private _documents: DocumentView[] = SelectionManager.SelectedDocuments(); @@ -40,8 +40,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> constructor(props: Readonly<{}>) { - super(props) - DocumentDecorations.Instance = this + super(props); + DocumentDecorations.Instance = this; this.handleChange = this.handleChange.bind(this); this.keyinput = React.createRef(); } @@ -49,7 +49,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action handleChange = (event: any) => { this._title = event.target.value; - }; + } @action enterPressed = (e: any) => { @@ -59,14 +59,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> var text = e.target.value; if (text[0] === '#') { let command = text.slice(1, text.length); - this._fieldKey = new Key(command) + this._fieldKey = new Key(command); // if (command === "Title" || command === "title") { // this._fieldKey = KeyStore.Title; // } // else if (command === "Width" || command === "width") { // this._fieldKey = KeyStore.Width; // } - this._title = "changed" + this._title = "changed"; // TODO: Change field with switch statement } else { @@ -89,7 +89,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) - } + }; }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); } @@ -104,7 +104,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onBackgroundMove); document.removeEventListener("pointerup", this.onBackgroundUp); document.addEventListener("pointerup", this.onBackgroundUp); - this._lastDrag = [e.clientX, e.clientY] + this._lastDrag = [e.clientX, e.clientY]; e.stopPropagation(); e.preventDefault(); } @@ -127,7 +127,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragComplete: action(() => this._dragging = false), }, hideSource: true - }) + }); e.stopPropagation(); } @@ -199,53 +199,53 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onLinkerButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); - document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.addEventListener("pointermove", this.onLinkerButtonMoved); - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointerup", this.onLinkerButtonUp); document.addEventListener("pointerup", this.onLinkerButtonUp); } onLinkerButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkerButtonMoved) - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp); e.stopPropagation(); } onLinkerButtonMoved = (e: PointerEvent): void => { if (this._linkerButton.current !== null) { - document.removeEventListener("pointermove", this.onLinkerButtonMoved) - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp); let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, hideSource: false - }) + }); } e.stopPropagation(); } onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); - document.removeEventListener("pointermove", this.onLinkButtonMoved) + document.removeEventListener("pointermove", this.onLinkButtonMoved); document.addEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp) + document.removeEventListener("pointerup", this.onLinkButtonUp); document.addEventListener("pointerup", this.onLinkButtonUp); } onLinkButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkButtonMoved) - document.removeEventListener("pointerup", this.onLinkButtonUp) + document.removeEventListener("pointermove", this.onLinkButtonMoved); + document.removeEventListener("pointerup", this.onLinkButtonUp); e.stopPropagation(); } onLinkButtonMoved = async (e: PointerEvent) => { if (this._linkButton.current !== null) { - document.removeEventListener("pointermove", this.onLinkButtonMoved) + document.removeEventListener("pointermove", this.onLinkButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp); let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document; - let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); let draggedDocs = (srcTarg && srcTarg !== FieldWaiting) ? srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; @@ -265,7 +265,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragComplete: action(() => { }), }, hideSource: false - }) + }); } } e.stopPropagation(); @@ -285,38 +285,38 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> case "": break; case "documentDecorations-topLeftResizer": - dX = -1 - dY = -1 - dW = -(e.movementX) - dH = -(e.movementY) + dX = -1; + dY = -1; + dW = -(e.movementX); + dH = -(e.movementY); break; case "documentDecorations-topRightResizer": - dW = e.movementX - dY = -1 - dH = -(e.movementY) + dW = e.movementX; + dY = -1; + dH = -(e.movementY); break; case "documentDecorations-topResizer": - dY = -1 - dH = -(e.movementY) + dY = -1; + dH = -(e.movementY); break; case "documentDecorations-bottomLeftResizer": - dX = -1 - dW = -(e.movementX) - dH = e.movementY + dX = -1; + dW = -(e.movementX); + dH = e.movementY; break; case "documentDecorations-bottomRightResizer": - dW = e.movementX - dH = e.movementY + dW = e.movementX; + dH = e.movementY; break; case "documentDecorations-bottomResizer": - dH = e.movementY + dH = e.movementY; break; case "documentDecorations-leftResizer": - dX = -1 - dW = -(e.movementX) + dX = -1; + dW = -(e.movementX); break; case "documentDecorations-rightResizer": - dW = e.movementX + dW = e.movementX; break; } @@ -338,14 +338,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = doc.GetNumber(KeyStore.NativeHeight, 0); if (nativeWidth > 0 && nativeHeight > 0) { - if (Math.abs(dW) > Math.abs(dH)) + if (Math.abs(dW) > Math.abs(dH)) { actualdH = nativeHeight / nativeWidth * actualdW; + } else actualdW = nativeWidth / nativeHeight * actualdH; } doc.SetNumber(KeyStore.Width, actualdW); doc.SetNumber(KeyStore.Height, actualdH); } - }) + }); } onPointerUp = (e: PointerEvent): void => { @@ -362,10 +363,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (this._title === "changed" && this._documents.length > 0) { let field = this._documents[0].props.Document.Get(this._fieldKey); if (field instanceof TextField) { - return (field as TextField).GetValue(); + return (field).GetValue(); } else if (field instanceof NumberField) { - return (field as NumberField).GetValue().toString(); + return (field).GetValue().toString(); } } return this._title; @@ -388,7 +389,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return (null); } if (isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { - console.log("DocumentDecorations: Bounds Error") + console.log("DocumentDecorations: Bounds Error"); return (null); } @@ -414,7 +415,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> top: bounds.y - this._resizeBorderWidth / 2, pointerEvents: this._dragging ? "none" : "all", zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0, - }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} > + }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); }} >
∞
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 982aacdea..2f17c6c51 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,7 +1,7 @@ -import React = require('react') +import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, trace } from 'mobx'; -import "./EditableView.scss" +import "./EditableView.scss"; export interface EditableProps { /** @@ -22,7 +22,7 @@ export interface EditableProps { * The contents to render when not editing */ contents: any; - height: number + height: number; display?: string; } @@ -55,14 +55,14 @@ export class EditableView extends React.Component { render() { if (this.editing) { return this.editing = false)} - style={{ display: this.props.display }}> + style={{ display: this.props.display }}>; } else { return (
this.editing = true)} > {this.props.contents}
- ) + ); } } } \ No newline at end of file diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 4ecc44119..47ee8eb85 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -82,7 +82,7 @@ export class InkingCanvas extends React.Component { }); this.inkData = data; } - }; + } @action onPointerUp = (e: PointerEvent): void => { @@ -109,7 +109,7 @@ export class InkingCanvas extends React.Component { @action onPointerMove = (e: PointerEvent): void => { - e.stopPropagation() + e.stopPropagation(); e.preventDefault(); if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { let data = this.inkData; // add points to new line as it is being drawn @@ -120,7 +120,7 @@ export class InkingCanvas extends React.Component { } this.inkData = data; } - }; + } relativeCoordinatesForEvent = (ex: number, ey: number): { x: number, y: number } => { let [x, y] = this.props.getScreenTransform().transformPoint(ex, ey); @@ -137,14 +137,15 @@ export class InkingCanvas extends React.Component { @computed get drawnPaths() { - let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1) + let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page === -1 || strokeData.page === curPage) + if (strokeData.page === -1 || strokeData.page === curPage) { paths.push() + tool={strokeData.tool} deleteCallback={this.removeLine} />); + } return paths; }, [] as JSX.Element[]); return [ { {this.props.children()} {this.drawnPaths} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 64ee66ec7..9a68f0671 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,10 +1,10 @@ import { observable, action, computed } from "mobx"; -import { CirclePicker, ColorResult } from 'react-color' +import { CirclePicker, ColorResult } from 'react-color'; import React = require("react"); import { InkTool } from "../../fields/InkField"; import { observer } from "mobx-react"; -import "./InkingControl.scss" +import "./InkingControl.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons'; @@ -25,7 +25,7 @@ export class InkingControl extends React.Component { constructor(props: Readonly<{}>) { super(props); - InkingControl.Instance = this + InkingControl.Instance = this; } @action @@ -66,9 +66,9 @@ export class InkingControl extends React.Component { selected = (tool: InkTool) => { if (this._selectedTool === tool) { - return { color: "#61aaa3" } + return { color: "#61aaa3" }; } - return {} + return {}; } @action @@ -111,6 +111,6 @@ export class InkingControl extends React.Component { onChange={(e: React.ChangeEvent) => this.switchWidth(e.target.value)} /> - ) + ); } } \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 12b15a3f0..0f05da22c 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -30,7 +30,7 @@ export class InkingStroke extends React.Component { } parseData = (line: Array<{ x: number, y: number }>): string => { - return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L ") + return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L "); } createStyle() { @@ -41,7 +41,7 @@ export class InkingStroke extends React.Component { fill: "none", stroke: this._strokeColor, strokeWidth: this._strokeWidth + "px", - } + }; } } @@ -53,6 +53,6 @@ export class InkingStroke extends React.Component { return ( - ) + ); } } \ No newline at end of file diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 6376fd694..fd2e23c91 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -16,7 +16,7 @@ import { WorkspacesMenu } from '../../server/authentication/controllers/Workspac import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { Utils, returnTrue, emptyFunction } from '../../Utils'; -import * as rp from 'request-promise' +import * as rp from 'request-promise'; import { RouteStore } from '../../server/RouteStore'; import { ServerUtils } from '../../server/ServerUtil'; import { Documents } from '../documents/Documents'; @@ -74,7 +74,7 @@ export class Main extends React.Component { if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; } - }; + } CurrentUserUtils.loadCurrentUser(); @@ -119,8 +119,8 @@ export class Main extends React.Component { initEventListeners = () => { // window.addEventListener("pointermove", (e) => this.reportLocation(e)) - window.addEventListener("drop", (e) => e.preventDefault(), false) // drop event handler - window.addEventListener("dragover", (e) => e.preventDefault(), false) // drag event handler + window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler + window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", action(function (e: PointerEvent) { if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { @@ -139,15 +139,15 @@ export class Main extends React.Component { } else { this.createNewWorkspace(); } - }) + }); } else { Server.GetField(CurrentUserUtils.MainDocId).then(field => { if (field instanceof Document) { - this.openWorkspace(field) + this.openWorkspace(field); } else { this.createNewWorkspace(CurrentUserUtils.MainDocId); } - }) + }); } } @@ -163,7 +163,7 @@ export class Main extends React.Component { // 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" }) + let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }); mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); }, 0); } @@ -182,7 +182,7 @@ export class Main extends React.Component { if (f && f.Data.length > 0) { CollectionDockingView.Instance.AddRightSplit(col); } - }) + }); } }, 100); }); @@ -191,7 +191,7 @@ export class Main extends React.Component { @observable workspacesShown: boolean = false; - areWorkspacesShown = () => this.workspacesShown + areWorkspacesShown = () => this.workspacesShown; @action toggleWorkspaces = () => { this.workspacesShown = !this.workspacesShown; @@ -199,7 +199,7 @@ export class Main extends React.Component { pwidthFunc = () => this.pwidth; pheightFunc = () => this.pheight; - focusDocument = (doc: Document) => { } + focusDocument = (doc: Document) => { }; noScaling = () => 1; @observable _textDoc?: Document = undefined; @@ -208,8 +208,9 @@ export class Main extends React.Component { SetTextDoc(textDoc?: Document, div?: HTMLDivElement) { this._textDoc = undefined; this._textDoc = textDoc; - if (div) + if (div) { this._textRect = div.getBoundingClientRect(); + } } @computed @@ -221,7 +222,7 @@ export class Main extends React.Component { let h: number = this._textRect.height; return
{ }} /> - + ; } else return (null); } @@ -241,19 +242,19 @@ export class Main extends React.Component { focus={this.focusDocument} parentActive={returnTrue} onActiveChanged={emptyFunction} - ContainingCollectionView={undefined} /> + ContainingCollectionView={undefined} />; } /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */ @computed get nodesMenu() { let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; - let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf" + let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf"; let weburl = "https://cs.brown.edu/courses/cs166/"; 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 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 })); @@ -261,7 +262,7 @@ export class Main extends React.Component { let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a schema collection" })); let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 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 addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); let btns: [React.RefObject, IconName, string, () => Document][] = [ [React.createRef(), "font", "Add Textbox", addTextNode], @@ -273,7 +274,7 @@ export class Main extends React.Component { [React.createRef(), "object-group", "Add Collection", addColNode], [React.createRef(), "tree", "Add Tree", addTreeNode], [React.createRef(), "table", "Add Schema", addSchemaNode], - ] + ]; return < div id="add-nodes-menu" > @@ -289,7 +290,7 @@ export class Main extends React.Component {
)} - + ; } /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @@ -298,7 +299,7 @@ export class Main extends React.Component { let workspacesRef = React.createRef(); let logoutRef = React.createRef(); - let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})) + let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ ,
@@ -310,7 +311,7 @@ export class Main extends React.Component {
,
- ] + ]; } render() { @@ -318,7 +319,7 @@ export class Main extends React.Component { let workspaces = this.userDocument.GetT>(KeyStore.Workspaces, ListField); if (workspaces && workspaces !== FieldWaiting) { workspaceMenu = + isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} />; } return ( <> @@ -359,7 +360,7 @@ export class Main extends React.Component { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); - let histoOp = new HistogramOperation(schema!.displayName!, + let histoOp = new HistogramOperation(schema.displayName!, new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); @@ -368,7 +369,7 @@ export class Main extends React.Component { })); }); return schemaDoc; - }) + }); } } async initializeNorthstar(): Promise { @@ -386,7 +387,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos() - await CurrentUserUtils.loadCurrentUser() + await Documents.initProtos(); + await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); -})() +})(); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 7a5ab6e3c..32462a4c1 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -66,17 +66,20 @@ export class CollectionBaseView extends React.Component { createsCycle(documentToAdd: Document, containerDocument: Document): boolean { let data = documentToAdd.GetList(KeyStore.Data, []); for (const doc of data) { - if (this.createsCycle(doc, containerDocument)) + if (this.createsCycle(doc, containerDocument)) { return true; + } } let annots = documentToAdd.GetList(KeyStore.Annotations, []); for (const annot of annots) { - if (this.createsCycle(annot, containerDocument)) + if (this.createsCycle(annot, containerDocument)) { return true; + } } for (let containerProto: FieldValue = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { - if (containerProto.Id === documentToAdd.Id) + if (containerProto.Id === documentToAdd.Id) { return true; + } } return false; } @@ -91,20 +94,23 @@ export class CollectionBaseView extends React.Component { } if (props.Document.Get(props.fieldKey) instanceof Field) { //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); if (!this.createsCycle(doc, props.Document)) { - if (!value.some(v => v.Id === doc.Id) || allowDuplicates) + if (!value.some(v => v.Id === doc.Id) || allowDuplicates) { value.push(doc); + } } - else + else { return false; + } } else { let proto = props.Document.GetPrototype(); if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) { props.Document.SetOnPrototype(props.fieldKey, new ListField([doc])); } - else + else { return false; + } } return true; } @@ -113,7 +119,7 @@ export class CollectionBaseView extends React.Component { removeDocument(doc: Document): boolean { const props = this.props; //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); let index = -1; for (let i = 0; i < value.length; i++) { if (value[i].Id === doc.Id) { @@ -125,16 +131,16 @@ export class CollectionBaseView extends React.Component { if (annotationOn === props.Document) { doc.Set(KeyStore.AnnotationOn, undefined, true); } - }) + }); if (index !== -1) { - value.splice(index, 1) + value.splice(index, 1); // SelectionManager.DeselectAll() - ContextMenu.Instance.clearItems() + ContextMenu.Instance.clearItems(); return true; } - return false + return false; } @action.bound @@ -155,12 +161,12 @@ export class CollectionBaseView extends React.Component { moveDocument: this.moveDocument, active: this.active, onActiveChanged: this.onActiveChanged, - } + }; return (
{this.props.children(this.collectionViewType, props)}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c3757a377..ea6d3a247 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -32,7 +32,7 @@ export class CollectionDockingView extends React.Component) => { - if (f instanceof Document) - DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), e.pageX, e.pageY, + if (f instanceof Document) { + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, hideSource: false - }) + }); + } })); } if (className === "lm_drag_handle" || className === "lm_close" || className === "lm_maximise" || className === "lm_minimise" || className === "lm_close_tab") { @@ -220,7 +222,7 @@ export class CollectionDockingView extends React.Component { var json = JSON.stringify(this._goldenLayout.toConfig()); - this.props.Document.SetText(KeyStore.Data, json) + this.props.Document.SetText(KeyStore.Data, json); } itemDropped = () => { @@ -236,7 +238,7 @@ export class CollectionDockingView extends React.Component { Server.GetField(this.props.documentId, action((f: Opt) => this._document = f as Document)); } - private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth) - private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight) - private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth) + private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); + private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); + private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()) + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()); } render() { - if (!this._document) + if (!this._document) { return (null); + } var content =
{ onActiveChanged={emptyFunction} focus={(doc: Document) => { }} ContainingCollectionView={undefined} /> -
+ ; return { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}> {({ measureRef }) =>
{content}
} -
+ ; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 32f50afc0..97bac745c 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -2,7 +2,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import "./CollectionPDFView.scss" +import "./CollectionPDFView.scss"; import React = require("react"); import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -44,7 +44,7 @@ export class CollectionPDFView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -52,6 +52,6 @@ export class CollectionPDFView extends React.Component { {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9b780f29b..52933818f 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -41,7 +41,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl if (field instanceof Key) { this.key = field; } - })) + })); } render() { @@ -49,7 +49,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl return (
this.key && this.props.toggle(this.key)} /> {this.key.Name} -
) + ); } return (null); } @@ -85,10 +85,10 @@ export class CollectionSchemaView extends CollectionSubView { focus: emptyFunction, active: returnFalse, onActiveChanged: emptyFunction, - } + }; let contents = ( - ) + ); let reference = React.createRef(); let onItemDown = setupDrag(reference, () => props.Document, this.props.moveDocument); let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => { @@ -106,7 +106,7 @@ export class CollectionSchemaView extends CollectionSubView { } } return false; - } + }; return (
applyToDoc(doc, run)); } - }) + }); }}>
- ) + ); } private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { @@ -156,7 +156,7 @@ export class CollectionSchemaView extends CollectionSubView { that._selectedIndex = rowInfo.index; if (handleOriginal) { - handleOriginal() + handleOriginal(); } }), style: { @@ -182,7 +182,7 @@ export class CollectionSchemaView extends CollectionSubView { this.columns.splice(index, 1); } - }) + }); } //toggles preview side-panel of schema @@ -197,7 +197,7 @@ export class CollectionSchemaView extends CollectionSubView { @computed get findAllDocumentKeys(): { [id: string]: boolean } { const docs = this.props.Document.GetList(this.props.fieldKey, []); - let keys: { [id: string]: boolean } = {} + let keys: { [id: string]: boolean } = {}; if (this._optionsActivated > -1) { // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be @@ -206,7 +206,7 @@ export class CollectionSchemaView extends CollectionSubView { // is displayed (unlikely) it won't show up until something else changes. untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); } - this.columns.forEach(key => keys[key.Id] = true) + this.columns.forEach(key => keys[key.Id] = true); return keys; } @@ -248,10 +248,10 @@ export class CollectionSchemaView extends CollectionSubView { getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) - getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - focusDocument = (doc: Document) => { } + focusDocument = (doc: Document) => { }; onPointerDown = (e: React.PointerEvent): void => { if (this.props.isSelected()) { @@ -273,8 +273,9 @@ export class CollectionSchemaView extends CollectionSubView { this.newKeyName = e.currentTarget.value; } onWheel = (e: React.WheelEvent): void => { - if (this.props.active()) + if (this.props.active()) { e.stopPropagation(); + } } @observable _optionsActivated: number = 0; @@ -322,9 +323,9 @@ export class CollectionSchemaView extends CollectionSubView { } - ) + ); let dividerDragger = this.splitPercentage === 0 ? (null) : -
+
; //options button and menu let optionsMenu = !this.props.active() ? (null) : (
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 59b89e119..bd385c27e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -14,7 +14,7 @@ import { NumberField } from "../../../fields/NumberField"; import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; -import * as rp from 'request-promise' +import * as rp from 'request-promise'; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Document, allowDuplicates?: boolean) => boolean; @@ -58,8 +58,8 @@ export class CollectionSubView extends React.Component { let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); cursors.push(entry); } - })) - }) + })); + }); } } @@ -77,17 +77,17 @@ export class CollectionSubView extends React.Component { added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } else if (de.data.moveDocument) { const move = de.data.moveDocument; - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false); } else { - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } e.stopPropagation(); return added; } if (de.data instanceof DragManager.LinkDragData) { let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; - if (sourceDoc) runInAction(() => { - let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + if (sourceDoc) { runInAction(() => { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); if (srcTarg && srcTarg !== FieldWaiting) { let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); linkDocs.map(linkDoc => { @@ -97,9 +97,10 @@ export class CollectionSubView extends React.Component { de.data.droppedDocuments.push(dropdoc); this.props.addDocument(dropdoc, false); } - }) + }); } - }) + }); + } return true; } return false; @@ -133,7 +134,7 @@ export class CollectionSubView extends React.Component { alias.SetNumber(KeyStore.Height, options.height || options.width || 300); this.props.addDocument(alias, false); } - }) + }); return undefined; } ctor = Documents.WebDocument; @@ -151,8 +152,8 @@ export class CollectionSubView extends React.Component { if (text && text.startsWith(" { let prom = new Promise(res => e.dataTransfer.items[i].getAsString(res)).then(action((s: string) => { str = s; - return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)) + return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)); })).then(res => { let type = res.headers["content-type"]; if (type) { - let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }) + let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }); if (doc) { this.props.addDocument(doc, false); } @@ -186,13 +187,13 @@ export class CollectionSubView extends React.Component { promises.push(prom); // this.props.addDocument(Documents.WebDocument(s, { ...options, width: 300, height: 300 }), false) } - let type = item.type + let type = item.type; if (item.kind === "file") { let file = item.getAsFile(); - let formData = new FormData() + let formData = new FormData(); if (file) { - formData.append('file', file) + formData.append('file', file); } let prom = fetch(upload, { @@ -201,15 +202,15 @@ export class CollectionSubView extends React.Component { }).then(async (res: Response) => { const json = await res.json(); json.map((file: any) => { - let path = window.location.origin + file + let path = window.location.origin + file; runInAction(() => { - let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }) + let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }); let docs = this.props.Document.GetT(KeyStore.Data, ListField); if (docs !== FieldWaiting) { if (!docs) { docs = new ListField(); - this.props.Document.Set(KeyStore.Data, docs) + this.props.Document.Set(KeyStore.Data, docs); } if (doc) { docs.Data.push(doc); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2bdf0baa6..659cff9fe 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -12,7 +12,7 @@ import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; import { CollectionView } from "./CollectionView"; import { CollectionSubView } from "./CollectionSubView"; -import React = require("react") +import React = require("react"); import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; import { props } from 'bluebird'; @@ -58,7 +58,7 @@ class TreeView extends React.Component { return true; } //TODO This should check if it was removed - this.remove(document) + this.remove(document); return addDoc(document); } @@ -69,7 +69,7 @@ class TreeView extends React.Component { case BulletType.Collapsed: bullet = "caret-right"; break; case BulletType.Collapsible: bullet = "caret-down"; break; } - return
{bullet ? : ""}
+ return
{bullet ? : ""}
; } /** @@ -93,7 +93,7 @@ class TreeView extends React.Component {
{editableView(this.props.document.Title)}
-
) +
); } render() { @@ -105,7 +105,7 @@ class TreeView extends React.Component { bulletType = BulletType.Collapsible; childElements =
    {children.Data.map(value => )} -
+ ; } else bulletType = BulletType.Collapsed; } @@ -115,7 +115,7 @@ class TreeView extends React.Component { {this.renderTitle()} {childElements ? childElements : (null)} - + ; } } @@ -136,7 +136,7 @@ export class CollectionTreeView extends CollectionSubView { let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => ) - ) + ); return (
e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}> diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 1acc76c85..b02983a2e 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -4,7 +4,7 @@ import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); -import "./CollectionVideoView.scss" +import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -111,7 +111,7 @@ export class CollectionVideoView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -119,6 +119,6 @@ export class CollectionVideoView extends React.Component { return ( {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b31dcc888..8abd0a02d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,4 +1,4 @@ -import * as React from 'react' +import * as React from 'react'; import { FieldViewProps, FieldView } from '../nodes/FieldView'; import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @@ -13,26 +13,26 @@ import { undoBatch } from '../../util/UndoManager'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (type) { - case CollectionViewType.Schema: return () - case CollectionViewType.Docking: return () - case CollectionViewType.Tree: return () + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); case CollectionViewType.Freeform: default: - return () + return (); } return (null); } onContextMenu = (e: React.MouseEvent): void => { if (!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.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)) }); } } @@ -41,6 +41,6 @@ export class CollectionView extends React.Component { {this.SubView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3dfd74ec8..081b3eb6c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -32,6 +32,6 @@ export class CollectionFreeFormLinkView extends React.Component - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index c288e7abf..cf058090d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -17,7 +17,7 @@ export class CollectionFreeFormLinksView extends React.Component DocumentManager.Instance.getAllDocumentViews(this.HackToAvoidReactionFiringUnnecessarily!). map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)), @@ -31,13 +31,14 @@ export class CollectionFreeFormLinksView extends React.Component) => field.Data.findIndex(brush => { let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; - return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false) + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); let brushAction = (field: ListField) => { let found = findBrush(field); @@ -64,13 +65,13 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -86,15 +87,16 @@ export class CollectionFreeFormLinksView extends React.Component { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) + if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { drawnPair.l.push(connection.l); + } } return match || found; }, false)) { drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); } - }) - return drawnPairs + }); + return drawnPairs; }, [] as { a: Document, b: Document, l: Document[] }[]); return connections.map(c => ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 17656e4ae..fc832264d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -57,7 +57,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component { if (el) this.crosshairs = el }} + ref={(el) => { if (el) this.crosshairs = el; }} width={20} height={20} style={{ @@ -93,7 +93,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component ); } - }) + }); } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1c3899b24..e694bc7a7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -49,7 +49,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (dv) { SelectionManager.SelectDoc(dv, true); } - }) + }); } public getActiveDocuments = () => { @@ -70,8 +70,8 @@ export class CollectionFreeFormView extends CollectionSubView { private outerElement?: HTMLDivElement; - @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } - @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); } + @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @@ -109,7 +109,7 @@ export class CollectionFreeFormView extends CollectionSubView { d.SetNumber(KeyStore.Height, 300); } this.bringToFront(d); - }) + }); } } return true; @@ -133,8 +133,9 @@ export class CollectionFreeFormView extends CollectionSubView { document.addEventListener("pointerup", this.onPointerUp); this._lastX = this.DownX = e.pageX; this._lastY = this.DownY = e.pageY; - if (this.props.isSelected()) + if (this.props.isSelected()) { e.stopPropagation(); + } } } @@ -182,12 +183,13 @@ export class CollectionFreeFormView extends CollectionSubView { let transform = this.getTransform(); let deltaScale = (1 - (e.deltaY / coefficient)); - if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) + if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling; + } let [x, y] = transform.transformPoint(e.clientX, e.clientY); - let localTransform = this.getLocalTransform() - localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y); // console.log(localTransform) this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); @@ -209,7 +211,7 @@ export class CollectionFreeFormView extends CollectionSubView { onDrop = (e: React.DragEvent): void => { var pt = this.getTransform().transformPoint(e.pageX, e.pageY); super.onDrop(e, { x: pt[0], y: pt[1] }); - }; + } onDragOver = (): void => { } @@ -228,7 +230,7 @@ export class CollectionFreeFormView extends CollectionSubView { } return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); }).map((doc, index) => { - doc.SetNumber(KeyStore.ZIndex, index + 1) + doc.SetNumber(KeyStore.ZIndex, index + 1); }); } @@ -268,7 +270,7 @@ export class CollectionFreeFormView extends CollectionSubView { focus: this.focusDocument, parentActive: this.props.active, onActiveChanged: this.props.active, - } + }; } @computed @@ -276,10 +278,11 @@ export class CollectionFreeFormView extends CollectionSubView { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page === curPage || page === -1) + if (page === curPage || page === -1) { prev.push(); + } return prev; - }, [] as JSX.Element[]) + }, [] as JSX.Element[]); } @computed @@ -295,8 +298,8 @@ export class CollectionFreeFormView extends CollectionSubView { layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={() => false} select={() => { }} />); } - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) - getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()); + getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH); getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 704db1d4a..1e6faafb3 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -37,7 +37,7 @@ export class MarqueeView extends React.Component @action cleanupInteractions = (all: boolean = false) => { if (all) { - document.removeEventListener("pointermove", this.onPointerMove, true) + document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); } else { this._used = true; @@ -52,7 +52,7 @@ export class MarqueeView extends React.Component this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; - document.addEventListener("pointermove", this.onPointerMove, true) + document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } @@ -94,7 +94,7 @@ export class MarqueeView extends React.Component let top = this._downY < this._lastY ? this._downY : this._lastY; let topLeft = this.props.getTransform().transformPoint(left, top); let size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) } + return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } @action @@ -180,9 +180,10 @@ export class MarqueeView extends React.Component var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.GetNumber(KeyStore.Width, 0); var h = doc.GetNumber(KeyStore.Height, 0); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) - selection.push(doc) - }) + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); return selection; } @@ -190,7 +191,7 @@ export class MarqueeView extends React.Component get marqueeDiv() { let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return
+ return
; } render() { diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx index 599461f85..8eabb020a 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx @@ -90,7 +90,7 @@ export class PreviewCursor extends React.Component { {this.props.children}
- ) + ); } } @@ -109,8 +109,9 @@ export class PreviewCursorPrompt extends React.Component { render() { let p = this.props.getPoint(); - if (this.props.getVisible() && this._promptRef.current) + if (this.props.getVisible() && this._promptRef.current) { this._promptRef.current.focus(); + } return
I diff --git a/src/client/views/nodes/Annotation.tsx b/src/client/views/nodes/Annotation.tsx index e4f17940c..3e4ed6bf1 100644 --- a/src/client/views/nodes/Annotation.tsx +++ b/src/client/views/nodes/Annotation.tsx @@ -1,8 +1,8 @@ import "./ImageBox.scss"; -import React = require("react") -import { observer } from "mobx-react" +import React = require("react"); +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; -import 'react-pdf/dist/Page/AnnotationLayer.css' +import 'react-pdf/dist/Page/AnnotationLayer.css'; interface IProps { Span: HTMLSpanElement; @@ -29,13 +29,13 @@ export class Annotation extends React.Component { */ onColorChange = (e: React.PointerEvent) => { if (e.currentTarget.innerHTML === "r") { - this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)"; } else if (e.currentTarget.innerHTML === "b") { - this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)" + this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)"; } else if (e.currentTarget.innerHTML === "y") { - this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)"; } else if (e.currentTarget.innerHTML === "g") { - this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)" + this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)"; } } @@ -54,11 +54,11 @@ export class Annotation extends React.Component { this.props.Highlights.splice(index, 1); } } - }) + }); //removing from CurrAnno and Annotation array this.props.Annotations.splice(index, 1); - this.props.CurrAnno.pop() + this.props.CurrAnno.pop(); //removing span from div if (this.props.Span.parentElement) { @@ -70,11 +70,11 @@ export class Annotation extends React.Component { if (item === e) { item.remove(); } - }) + }); e.remove(); } } - }) + }); } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1bd934c25..1493ff25b 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,18 +1,18 @@ -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { ContextMenu } from "../../views/ContextMenu"; import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; import { AudioField } from "../../../fields/AudioField"; -import "./AudioBox.scss" +import "./AudioBox.scss"; import { NumberField } from "../../../fields/NumberField"; @observer export class AudioBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(AudioBox) } + public static LayoutString() { return FieldView.LayoutString(AudioBox); } constructor(props: FieldViewProps) { super(props); @@ -28,7 +28,7 @@ export class AudioBox extends React.Component { render() { - let field = this.props.Document.Get(this.props.fieldKey) + let field = this.props.Document.Get(this.props.fieldKey); let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3"; @@ -39,6 +39,6 @@ export class AudioBox extends React.Component { Not supported.
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index dcf82ccd4..77f41105f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -35,24 +35,24 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1 + contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; getTransform = (): Transform => this.props.ScreenToLocalTransform() @@ -66,7 +66,7 @@ export class CollectionFreeFormDocumentView extends React.Component + />; } panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 34cc326aa..5836da396 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -26,7 +26,7 @@ import { FieldViewProps } from "./FieldView"; import { Without } from "../../../Utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? -type BindingProps = Without +type BindingProps = Without; export interface JsxBindings { props: BindingProps; [keyName: string]: BindingProps | Field; @@ -92,7 +92,7 @@ export class DocumentContentsView extends React.Component { console.log(test) }} - /> + onError={(test: any) => { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ab9cd2d53..9670ca6b2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -100,8 +100,9 @@ export class DocumentView extends React.Component { if (e.shiftKey && e.buttons === 2) { if (this.props.isTopMost) { this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey); - } else + } else { CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e); + } e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { @@ -112,7 +113,7 @@ export class DocumentView extends React.Component { document.addEventListener("pointerup", this.onPointerUp); } } - }; + } private dropDisposer?: DragManager.DragDropDisposer; @@ -179,7 +180,7 @@ export class DocumentView extends React.Component { } e.stopPropagation(); e.preventDefault(); - }; + } onPointerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -190,22 +191,22 @@ export class DocumentView extends React.Component { ) { SelectionManager.SelectDoc(this, e.ctrlKey); } - }; + } stopPropogation = (e: React.SyntheticEvent) => { e.stopPropagation(); - }; + } deleteClicked = (): void => { if (this.props.removeDocument) { this.props.removeDocument(this.props.Document); } - }; + } fieldsClicked = (e: React.MouseEvent): void => { if (this.props.addDocument) { this.props.addDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); } - }; + } fullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.OpenFullScreen(this.props.Document); ContextMenu.Instance.clearItems(); @@ -214,7 +215,7 @@ export class DocumentView extends React.Component { event: this.closeFullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } closeFullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.CloseFullScreen(); @@ -224,7 +225,7 @@ export class DocumentView extends React.Component { event: this.fullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } @action public minimize = (): void => { @@ -234,7 +235,7 @@ export class DocumentView extends React.Component { BooleanField ); SelectionManager.DeselectAll(); - }; + } @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -276,7 +277,7 @@ export class DocumentView extends React.Component { ); e.stopPropagation(); } - }; + } onDrop = (e: React.DragEvent) => { if (e.isDefaultPrevented()) { @@ -290,7 +291,7 @@ export class DocumentView extends React.Component { e.stopPropagation(); e.preventDefault(); } - }; + } @action onContextMenu = (e: React.MouseEvent): void => { @@ -352,14 +353,14 @@ export class DocumentView extends React.Component { }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); SelectionManager.SelectDoc(this, e.ctrlKey); - }; + } isMinimized = () => { let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField); if (field && field !== FieldWaiting) { return field.Data; } - }; + } @action expand = () => { @@ -368,13 +369,13 @@ export class DocumentView extends React.Component { false as boolean, BooleanField ); - }; + } - isSelected = () => SelectionManager.IsSelected(this) + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); - }; + } render() { if (!this.props.Document) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d9422ae9b..07c5b332c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { computed } from "mobx"; import { Field, FieldWaiting, FieldValue } from "../../../fields/Field"; @@ -7,7 +7,7 @@ import { TextField } from "../../../fields/TextField"; import { NumberField } from "../../../fields/NumberField"; import { RichTextField } from "../../../fields/RichTextField"; import { ImageField } from "../../../fields/ImageField"; -import { VideoField } from "../../../fields/VideoField" +import { VideoField } from "../../../fields/VideoField"; import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; @@ -57,22 +57,22 @@ export class FieldView extends React.Component { render() { const field = this.field; if (!field) { - return

{''}

+ return

{''}

; } if (field instanceof TextField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field instanceof RichTextField) { - return + return ; } else if (field instanceof ImageField) { - return + return ; } else if (field instanceof VideoField) { - return + return ; } else if (field instanceof AudioField) { - return + return ; } else if (field instanceof Document) { return ( @@ -92,25 +92,26 @@ export class FieldView extends React.Component { ContainingCollectionView={undefined} parentActive={this.props.active} onActiveChanged={this.props.onActiveChanged} /> - ) + ); } else if (field instanceof ListField) { return (
{(field as ListField).Data.map(f => f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")} -
) +
); } // bcz: this belongs here, but it doesn't render well so taking it out for now // else if (field instanceof HtmlField) { // return // } else if (field instanceof NumberField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field !== FieldWaiting) { - return

{JSON.stringify(field.GetValue())}

+ return

{JSON.stringify(field.GetValue())}

; } - else - return

{"Waiting for server..."}

+ else { + return

{"Waiting for server..."}

; + } } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a94be12b..beca6cdc6 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -61,7 +61,7 @@ export class FormattedTextBox extends React.Component { ); // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); } - }; + } get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.Document; } get FieldKey() { return this.props.fieldKey === KeyStore.Archives ? KeyStore.Data : this.props.fieldKey; } @@ -81,12 +81,13 @@ export class FormattedTextBox extends React.Component { if (this.props.fieldKey === KeyStore.Archives) { this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id, () => { - if (this._editorView) - this._editorView!.destroy(); + if (this._editorView) { + this._editorView.destroy(); + } this.setupEditor(config); } - ) + ); } this._reactionDisposer = reaction( @@ -153,7 +154,7 @@ export class FormattedTextBox extends React.Component { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } - }; + } onPointerUp = (e: React.PointerEvent): void => { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); @@ -162,7 +163,7 @@ export class FormattedTextBox extends React.Component { e.preventDefault(); Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); } - }; + } onFocused = (e: React.FocusEvent): void => { if (this.props.fieldKey !== KeyStore.Archives) { @@ -191,11 +192,11 @@ export class FormattedTextBox extends React.Component { // ] // }) // e.stopPropagation() - }; + } onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - }; + } tooltipMenuPlugin() { return new Plugin({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c5f29f7b0..6b0a3a799 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -9,13 +9,13 @@ import { KeyStore } from '../../../fields/KeyStore'; import { ContextMenu } from "../../views/ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; -import React = require("react") +import React = require("react"); import { Utils } from '../../../Utils'; @observer export class ImageBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(ImageBox) } + public static LayoutString() { return FieldView.LayoutString(ImageBox); } private _ref: React.RefObject; private _imgRef: React.RefObject; private _downX: number = 0; @@ -39,7 +39,7 @@ export class ImageBox extends React.Component { onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w) + this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); } componentDidMount() { @@ -86,7 +86,7 @@ export class ImageBox extends React.Component { onMoveNextRequest={action(() => this._photoIndex = (this._photoIndex + 1) % images.length )} - />) + />); } } @@ -96,7 +96,7 @@ export class ImageBox extends React.Component { let url = field.Data.href; ContextMenu.Instance.addItem({ description: "Copy path", event: () => { - Utils.CopyText(url) + Utils.CopyText(url); } }); } @@ -111,6 +111,6 @@ export class ImageBox extends React.Component {
Image not found {this.lightbox(path)} -
) +
); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8a7f32e6d..bcac113f0 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -7,7 +7,7 @@ import { KeyStore } from '../../../fields/KeyStore'; import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; -import React = require("react") +import React = require("react"); import { CompileScript, ToField } from "../../util/Scripting"; import { Key } from '../../../fields/Key'; import { observable, action } from "mobx"; @@ -15,7 +15,7 @@ import { observable, action } from "mobx"; @observer export class KeyValueBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @@ -36,7 +36,7 @@ export class KeyValueBox extends React.Component { if (this._keyInput && this._valueInput) { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return + return; } let realDoc = doc; @@ -55,8 +55,8 @@ export class KeyValueBox extends React.Component { realDoc.Set(new Key(this._keyInput), dataField); } } - this._keyInput = "" - this._valueInput = "" + this._keyInput = ""; + this._valueInput = ""; } } } @@ -73,7 +73,7 @@ export class KeyValueBox extends React.Component { createTable = () => { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return Loading... + return Loading...; } let realDoc = doc; @@ -84,13 +84,13 @@ export class KeyValueBox extends React.Component { if (!(key in ids)) { ids[key] = key; } - }) + }); } let rows: JSX.Element[] = []; let i = 0; for (let key in ids) { - rows.push() + rows.push(); } return rows; } @@ -125,6 +125,6 @@ export class KeyValueBox extends React.Component { {this.newKeyValue()} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index c6a0a7296..a1050dc6e 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,14 +1,14 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import "./KeyValueBox.scss"; import "./KeyValuePair.scss"; -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { Opt, Field } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; import { Document } from '../../../fields/Document'; import { Key } from '../../../fields/Key'; -import { Server } from "../../Server" +import { Server } from "../../Server"; import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; @@ -25,7 +25,7 @@ export interface KeyValuePairProps { export class KeyValuePair extends React.Component { @observable - private key: Opt + private key: Opt; constructor(props: KeyValuePairProps) { super(props); @@ -41,7 +41,7 @@ export class KeyValuePair extends React.Component { render() { if (!this.key) { - return error + return error; } let props: FieldViewProps = { @@ -55,7 +55,7 @@ export class KeyValuePair extends React.Component { onActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, - } + }; let contents = ( ); @@ -101,6 +101,6 @@ export class KeyValuePair extends React.Component { return false; }}> - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 4791d6029..b016a3d48 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkBox.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkBox.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -30,7 +30,7 @@ interface Props { linkName: String; pairedDoc: Document; type: String; - showEditor: () => void + showEditor: () => void; } @observer @@ -49,15 +49,16 @@ export class LinkBox extends React.Component { } 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) + 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); } - }) + }); }); } }); @@ -80,7 +81,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => { @@ -89,7 +90,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); } @@ -117,6 +118,6 @@ export class LinkBox extends React.Component { - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index 3f7b4bf2d..bde50fed8 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkEditor.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkEditor.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -43,7 +43,7 @@ export class LinkEditor extends React.Component {
SAVE
- ) + ); } @action diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 6c2d24630..ac09da305 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -13,7 +13,7 @@ import React = require("react"); interface Props { docView: DocumentView; - changeFlyout: () => void + changeFlyout: () => void; } @observer @@ -25,9 +25,9 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = link.GetT(key, Document); if (doc && doc !== FieldWaiting) { - return this._editingLink = link)} type={type} /> + return this._editingLink = link)} type={type} />; } - }) + }); } render() { @@ -43,11 +43,11 @@ export class LinkMenu extends React.Component { {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Source: ")} - ) + ); } else { return ( this._editingLink = undefined)}> - ) + ); } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 774d9be3e..81ceb37f6 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -17,7 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import "./PDFBox.scss"; import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here -import React = require("react") +import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx @@ -55,7 +55,7 @@ import { SelectionManager } from "../../util/SelectionManager"; export class PDFBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(PDFBox); } - private _mainDiv = React.createRef() + private _mainDiv = React.createRef(); private _pdf = React.createRef(); @observable private _renderAsSvg = true; @@ -72,7 +72,7 @@ export class PDFBox extends React.Component { private _currTool: any; //keeps track of current tool button reference private _drawToolOn: boolean = false; //boolean that keeps track of the drawing tool - private _drawTool = React.createRef()//drawing tool button reference + private _drawTool = React.createRef();//drawing tool button reference private _colorTool = React.createRef(); //color button reference private _currColor: string = "black"; //current color that user selected (for ink/pen) @@ -85,7 +85,7 @@ export class PDFBox extends React.Component { @observable private _perPageInfo: Object[] = []; //stores pageInfo @observable private _pageInfo: any = { area: [], divs: [], anno: [] }; //divs is array of objects linked to anno - @observable private _currAnno: any = [] + @observable private _currAnno: any = []; @observable private _interactive: boolean = false; @observable private _loaded: boolean = false; @@ -168,24 +168,24 @@ export class PDFBox extends React.Component { let obj: Object = { parentDivs: [], spans: [] }; //@ts-ignore if (range.commonAncestorContainer.className === 'react-pdf__Page__textContent') { //multiline highlighting case - obj = this.highlightNodes(range.commonAncestorContainer.childNodes) + obj = this.highlightNodes(range.commonAncestorContainer.childNodes); } else { //single line highlighting case - let parentDiv = range.commonAncestorContainer.parentElement + let parentDiv = range.commonAncestorContainer.parentElement; if (parentDiv) { if (parentDiv.className === 'react-pdf__Page__textContent') { //when highlight is overwritten - obj = this.highlightNodes(parentDiv.childNodes) + obj = this.highlightNodes(parentDiv.childNodes); } else { parentDiv.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - obj.parentDivs.push(parentDiv) + obj.parentDivs.push(parentDiv); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - obj.spans.push(child) + obj.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); } } } @@ -196,21 +196,21 @@ export class PDFBox extends React.Component { } highlightNodes = (nodes: NodeListOf) => { - let temp = { parentDivs: [], spans: [] } + let temp = { parentDivs: [], spans: [] }; nodes.forEach((div) => { div.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - temp.parentDivs.push(div) + temp.parentDivs.push(div); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - temp.spans.push(child) + temp.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); - }) + }); return temp; } @@ -228,8 +228,8 @@ export class PDFBox extends React.Component { index = this._pageInfo.divs.indexOf(obj); } } - }) - }) + }); + }); if (this._pageInfo.anno.length >= index + 1) { if (this._currAnno.length === 0) { @@ -239,13 +239,13 @@ export class PDFBox extends React.Component { if (this._currAnno.length === 0) { //if there are no current annotation let div = span.offsetParent; //@ts-ignore - let divX = div.style.left + let divX = div.style.left; //@ts-ignore - let divY = div.style.top + let divY = div.style.top; //slicing "px" from the end divX = divX.slice(0, divX.length - 2); //gets X of the DIV element (parent of Span) divY = divY.slice(0, divY.length - 2); //gets Y of the DIV element (parent of Span) - let annotation = + let annotation = ; this._pageInfo.anno.push(annotation); this._currAnno.push(annotation); } @@ -263,7 +263,7 @@ export class PDFBox extends React.Component { this.makeEditableAndHighlight(color); } } catch (ex) { - this.makeEditableAndHighlight(color) + this.makeEditableAndHighlight(color); } } } @@ -305,7 +305,7 @@ export class PDFBox extends React.Component { } if (this._mainDiv.current) { - let sticky = + let sticky = ; this._pageInfo.area.push(sticky); } this._toolOn = false; @@ -404,19 +404,19 @@ export class PDFBox extends React.Component { if (e instanceof HTMLCanvasElement) { this._pdfCanvas = e; - this._pdfContext = e.getContext("2d") + this._pdfContext = e.getContext("2d"); } - }) + }); } - }) + }); } // bcz: the number of pages should really be set when the document is imported. this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages); if (this._perPageInfo.length === 0) { //Makes sure it only runs once - this._perPageInfo = [...Array(page._transport.numPages)] + this._perPageInfo = [...Array(page._transport.numPages)]; } this._loaded = true; } diff --git a/src/client/views/nodes/Sticky.tsx b/src/client/views/nodes/Sticky.tsx index 4a4d69e90..11719831b 100644 --- a/src/client/views/nodes/Sticky.tsx +++ b/src/client/views/nodes/Sticky.tsx @@ -39,7 +39,7 @@ export class Sticky extends React.Component { document.addEventListener("pointermove", this.drawMove); document.addEventListener("pointerup", this.drawUp); } - }; + } //when user drags drawMove = (e: PointerEvent): void => { @@ -49,7 +49,7 @@ export class Sticky extends React.Component { //connects the point this.ctx.lineTo(x, y); this.ctx.stroke(); - }; + } /** * when user lifts the mouse, the drawing ends @@ -58,7 +58,7 @@ export class Sticky extends React.Component { this.ctx.closePath(); console.log(this.ctx); document.removeEventListener("pointermove", this.drawMove); - }; + } render() { return ( diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index a08b320e8..314af64c9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { FieldWaiting, Opt } from '../../../fields/Field'; import { VideoField } from '../../../fields/VideoField'; @@ -13,8 +13,8 @@ import { number } from "prop-types"; export class VideoBox extends React.Component { private _reactionDisposer: Opt; - private _videoRef = React.createRef() - public static LayoutString() { return FieldView.LayoutString(VideoBox) } + private _videoRef = React.createRef(); + public static LayoutString() { return FieldView.LayoutString(VideoBox); } constructor(props: FieldViewProps) { super(props); @@ -58,7 +58,7 @@ export class VideoBox extends React.Component { render() { let field = this.props.Document.GetT(this.props.fieldKey, VideoField); if (!field || field === FieldWaiting) { - return
Loading
+ return
Loading
; } let path = field.Data.href; trace(); @@ -73,6 +73,6 @@ export class VideoBox extends React.Component { } - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c1d389001..90ce72c41 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,9 +1,9 @@ import "./WebBox.scss"; -import React = require("react") +import React = require("react"); import { WebField } from '../../../fields/WebField'; import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { computed } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; @@ -33,6 +33,6 @@ export class WebBox extends React.Component { return (
{content} -
) + ); } } \ No newline at end of file diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index c8de33f41..11f2b0c4e 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import JsxParser from 'react-jsx-parser' +import JsxParser from 'react-jsx-parser'; class Hello extends React.Component<{ firstName: string, lastName: string }> { render() { - return
Hello {this.props.firstName} {this.props.lastName}
+ return
Hello {this.props.firstName} {this.props.lastName}
; } } @@ -16,8 +16,8 @@ class Test extends React.Component { firstName: "First", lastName: "Last" } - } - return + }; + return ; } } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index f13cccd24..857da1ebb 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -40,22 +40,22 @@ class ListViewer extends React.Component<{ field: ListField }>{
{this.props.field.Data.map(field => )}
- ) + ); } else { - content = <>[...] ({this.props.field.Id}) + content = <>[...] ({this.props.field.Id}); } return (
{content}
- ) + ); } } @observer class DocumentViewer extends React.Component<{ field: Document }> { - private keyMap: ObservableMap = new ObservableMap + private keyMap: ObservableMap = new ObservableMap; private disposer?: Lambda; @@ -67,12 +67,12 @@ class DocumentViewer extends React.Component<{ field: Document }> { if (field && field instanceof Key) { this.keyMap.set(id, field); } - }) + }); } }); - } - this.disposer = this.props.field._proxies.observe(f) - f() + }; + this.disposer = this.props.field._proxies.observe(f); + f(); } componentWillUnmount() { @@ -89,8 +89,8 @@ class DocumentViewer extends React.Component<{ field: Document }> { ({key ? key.Name : kv[0]}): - ) - }) + ); + }); return (
Document ({this.props.field.Id}) @@ -98,7 +98,7 @@ class DocumentViewer extends React.Component<{ field: Document }> { {fields}
- ) + ); } } @@ -111,15 +111,15 @@ class DebugViewer extends React.Component<{ fieldId: string }> { private error?: string; constructor(props: { fieldId: string }) { - super(props) - this.update() + super(props); + this.update(); } update() { Server.GetField(this.props.fieldId, action((field: Opt) => { this.field = field; if (!field) { - this.error = `Field with id ${this.props.fieldId} not found` + this.error = `Field with id ${this.props.fieldId} not found`; } })); @@ -130,20 +130,20 @@ class DebugViewer extends React.Component<{ fieldId: string }> { if (this.field) { // content = this.field.ToJson(); if (this.field instanceof ListField) { - content = () + content = (); } else if (this.field instanceof Document) { - content = () + content = (); } else if (this.field instanceof BasicField) { - content = () + content = (); } else if (this.field instanceof Key) { - content = () + content = (); } else { - content = (Unrecognized field type) + content = (Unrecognized field type); } } else if (this.error) { - content = Field {this.props.fieldId} not found + content = Field {this.props.fieldId} not found ; } else { - content = Field loading: {this.props.fieldId} + content = Field loading: {this.props.fieldId}; } return content; } @@ -165,8 +165,8 @@ class Viewer extends React.Component { @action onKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter") { - this.ids.push(this.idToAdd) - this.idToAdd = "" + this.ids.push(this.idToAdd); + this.idToAdd = ""; } } @@ -180,7 +180,7 @@ class Viewer extends React.Component { {this.ids.map(id => )} - ) + ); } } diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts index 252a5b74e..996d2556d 100644 --- a/src/fields/AudioField.ts +++ b/src/fields/AudioField.ts @@ -25,7 +25,7 @@ export class AudioField extends BasicField { type: Types.Audio, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/BasicField.ts b/src/fields/BasicField.ts index 3083a1937..17b1fc4e8 100644 --- a/src/fields/BasicField.ts +++ b/src/fields/BasicField.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { observable, computed, action } from "mobx"; import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; @@ -9,7 +9,7 @@ export abstract class BasicField extends Field { this.data = data; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -36,7 +36,7 @@ export abstract class BasicField extends Field { UndoManager.AddEvent({ undo: () => this.Data = oldValue, redo: () => this.Data = value - }) + }); Server.UpdateField(this); } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 4fa478f32..4584660fb 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -37,21 +37,24 @@ export class Document extends Field { } } - public Width = () => this.GetNumber(KeyStore.Width, 0) + public Width = () => this.GetNumber(KeyStore.Width, 0); public Height = () => this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? (this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0)) * this.GetNumber(KeyStore.Width, 0) : 0); - public Scale = () => this.GetNumber(KeyStore.Scale, 1) + public Scale = () => this.GetNumber(KeyStore.Scale, 1); @computed public get Title(): string { let title = this.Get(KeyStore.Title, true); - if (title) - if (title !== FieldWaiting && title instanceof TextField) + if (title) { + if (title !== FieldWaiting && title instanceof TextField) { return title.Data; + } else return "-waiting-"; + } let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle) + if (parTitle) { if (parTitle !== FieldWaiting) return parTitle.Data + ".alias"; else return "-waiting-.alias"; + } return "-untitled-"; } @@ -398,11 +401,13 @@ export class Document extends Field { } } else - if (field instanceof Document) // ... TODO bcz: should we copy documents or reference them - copy.Set(key!, field) - else if (field) - copy.Set(key!, field.Copy()) - }) + if (field instanceof Document) { // ... TODO bcz: should we copy documents or reference them + copy.Set(key!, field); + } + else if (field) { + copy.Set(key!, field.Copy()); + } + }); } }); return copy; diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 9d3c209b4..6c0c1ef82 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -52,6 +52,6 @@ export class DocumentReference extends Field { type: Types.DocumentReference, data: this.document.Id, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/Field.ts b/src/fields/Field.ts index 0d0e56f77..d9db23b9e 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -65,5 +65,5 @@ export abstract class Field { abstract Copy(): Field; - abstract ToJson(): { _id: string, type: Types, data: any } + abstract ToJson(): { _id: string, type: Types, data: any }; } \ No newline at end of file diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts index 7cbdf7e58..65665cf7a 100644 --- a/src/fields/HtmlField.ts +++ b/src/fields/HtmlField.ts @@ -20,6 +20,6 @@ export class HtmlField extends BasicField { type: Types.Html, data: this.Data, _id: this.Id, - } + }; } } \ No newline at end of file diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index ef616b2ad..dd843026f 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -24,6 +24,6 @@ export class ImageField extends BasicField { type: Types.Image, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index 2a4ed18e7..ab706ee30 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -36,7 +36,7 @@ export class InkField extends BasicField { type: Types.Ink, data: this.Data, _id: this.Id, - } + }; } UpdateFromServer(data: any) { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 00d78d516..c7f806b88 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { Utils } from "../Utils"; import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -16,7 +16,7 @@ export class Key extends Field { this.name = name; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -45,6 +45,6 @@ export class Key extends Field { type: Types.Key, data: this.name, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index e24e9c8ec..425408273 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -56,8 +56,9 @@ export namespace KeyStore { ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { - if (key.Id === keyid) + if (key.Id === keyid) { return key; + } } return undefined; } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 815a3df73..b6eab5f86 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -7,7 +7,7 @@ import { Field, FieldId } from "./Field"; import { FieldMap } from "../client/SocketStub"; export class ListField extends BasicField { - private _proxies: string[] = [] + private _proxies: string[] = []; constructor(data: T[] = [], id?: FieldId, save: boolean = true) { super(data, save, id); this.updateProxies(); @@ -22,23 +22,24 @@ export class ListField extends BasicField { private observeDisposer: Lambda | undefined; private observeList(): void { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.observeDisposer = observe(this.Data as IObservableArray, (change: IArrayChange | IArraySplice) => { - this.updateProxies() + this.updateProxies(); if (change.type === "splice") { UndoManager.AddEvent({ undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed), redo: () => this.Data.splice(change.index, change.removedCount, ...change.added) - }) + }); } else { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); } - if (!this._processingServerUpdate) + if (!this._processingServerUpdate) { Server.UpdateField(this); + } }); } @@ -78,19 +79,23 @@ export class ListField extends BasicField { var proxies = this._proxies.map(p => p); var added = this.data.length < this._proxies.length; var deleted = this.data.length > this._proxies.length; - for (let i = 0; i < dataids.length && added; i++) + for (let i = 0; i < dataids.length && added; i++) { added = proxies.indexOf(dataids[i]) !== -1; - for (let i = 0; i < this._proxies.length && deleted; i++) + } + for (let i = 0; i < this._proxies.length && deleted; i++) { deleted = dataids.indexOf(proxies[i]) !== -1; + } this._processingServerUpdate = true; for (let i = 0; i < proxies.length && added; i++) { - if (dataids.indexOf(proxies[i]) === -1) + if (dataids.indexOf(proxies[i]) === -1) { this.Data.splice(i, 0, fields[proxies[i]] as T); + } } for (let i = dataids.length - 1; i >= 0 && deleted; i--) { - if (proxies.indexOf(dataids[i]) === -1) + if (proxies.indexOf(dataids[i]) === -1) { this.Data.splice(i, 1); + } } if (!added && !deleted) {// otherwise, just rebuild the whole list this.setData(proxies.map(id => fields[id] as T)); @@ -98,7 +103,7 @@ export class ListField extends BasicField { this._processingServerUpdate = false; } callback(this); - })) + })); } ToScriptString(): string { @@ -114,12 +119,12 @@ export class ListField extends BasicField { type: Types.List, data: this._proxies || [], _id: this.Id - } + }; } static FromJson(id: string, ids: string[]): ListField { let list = new ListField([], id, false); list._proxies = ids; - return list + return list; } } \ No newline at end of file diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index e0c8648de..45b920e31 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { Types } from "../server/Message"; import { FieldId } from "./Field"; @@ -20,6 +20,6 @@ export class NumberField extends BasicField { _id: this.Id, type: Types.Number, data: this.Data - } + }; } } \ No newline at end of file diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index 436c1cf2b..65e179894 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -1,6 +1,6 @@ import { BasicField } from "./BasicField"; import { Field, FieldId } from "./Field"; -import { observable } from "mobx" +import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -27,7 +27,7 @@ export class PDFField extends BasicField { type: Types.PDF, data: this.Data.href, _id: this.Id - } + }; } @observable diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 5efb43314..6f7b3074a 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -20,7 +20,7 @@ export class RichTextField extends BasicField { type: Types.RichText, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index 71d8ea310..69d26f42f 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { FieldId } from "./Field"; import { Types } from "../server/Message"; @@ -20,6 +20,6 @@ export class TextField extends BasicField { type: Types.Text, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts index e2162c751..ad0f6f350 100644 --- a/src/fields/TupleField.ts +++ b/src/fields/TupleField.ts @@ -21,7 +21,7 @@ export class TupleField extends BasicField<[T, U]> { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); Server.UpdateField(this); } else { throw new Error("Why are you messing with the length of a tuple, huh?"); @@ -31,7 +31,7 @@ export class TupleField extends BasicField<[T, U]> { protected setData(value: [T, U]) { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.data = observable(value) as (T | U)[] as [T, U]; this.observeTuple(); @@ -54,6 +54,6 @@ export class TupleField extends BasicField<[T, U]> { type: Types.Tuple, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts index 992cc1641..d7cd7e968 100644 --- a/src/fields/VideoField.ts +++ b/src/fields/VideoField.ts @@ -24,7 +24,7 @@ export class VideoField extends BasicField { type: Types.Video, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 0cbcc6d33..6023e9e6b 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -24,7 +24,7 @@ export class WebField extends BasicField { type: Types.Web, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index c3684a0eb..ec89a1194 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -22,7 +22,7 @@ import { Opt } from '../fields/Field'; // } const onFileLoad = async (file: any) => { - let imgPrev = document.getElementById("img_preview") + let imgPrev = document.getElementById("img_preview"); if (imgPrev) { let files: File[] = file.target.files; if (files.length !== 0) { @@ -30,15 +30,15 @@ const onFileLoad = async (file: any) => { let formData = new FormData(); formData.append("file", files[0]); - const upload = window.location.origin + "/upload" + const upload = window.location.origin + "/upload"; const res = await fetch(upload, { method: 'POST', body: formData }); const json = await res.json(); json.map(async (file: any) => { - let path = window.location.origin + file - var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }) + let path = window.location.origin + file; + var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }); const res = await rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)); if (!res) { @@ -47,12 +47,12 @@ const onFileLoad = async (file: any) => { const field = await Server.GetField(res); let pending: Opt; if (field instanceof Document) { - pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document) + pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document); } if (pending) { pending.GetOrCreateAsync(KeyStore.Data, ListField, list => { list.Data.push(doc); - }) + }); } }); @@ -61,7 +61,7 @@ const onFileLoad = async (file: any) => { //imgPrev.setAttribute("src", window.location.origin + files[0].name) } } -} +}; ReactDOM.render((
diff --git a/src/server/Client.ts b/src/server/Client.ts index 6b8841658..02402a5a0 100644 --- a/src/server/Client.ts +++ b/src/server/Client.ts @@ -2,14 +2,14 @@ import { computed } from "mobx"; export class Client { constructor(guid: string) { - this.guid = guid + this.guid = guid; } private guid: string; @computed public get GUID(): string { - return this.guid + return this.guid; } } \ No newline at end of file diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts index b6fe15655..d42741410 100644 --- a/src/server/authentication/config/passport.ts +++ b/src/server/authentication/config/passport.ts @@ -1,4 +1,4 @@ -import * as passport from 'passport' +import * as passport from 'passport'; import * as passportLocal from 'passport-local'; import * as mongodb from 'mongodb'; import * as _ from "lodash"; @@ -22,7 +22,7 @@ passport.deserializeUser((id, done) => { passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { if (error) return done(error); - if (!user) return done(undefined, false, { message: "Invalid email or password" }) // invalid email + if (!user) return done(undefined, false, { message: "Invalid email or password" }); // invalid email user.comparePassword(password, (error: Error, isMatch: boolean) => { if (error) return done(error); if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password @@ -37,7 +37,7 @@ export let isAuthenticated = (req: Request, res: Response, next: NextFunction) = return next(); } return res.redirect(RouteStore.login); -} +}; export let isAuthorized = (req: Request, res: Response, next: NextFunction) => { const provider = req.path.split("/").slice(-1)[0]; diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 835432c8e..b08c1aebe 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import './WorkspacesMenu.css' +import './WorkspacesMenu.css'; import { Document } from '../../../fields/Document'; import { EditableView } from '../../../client/views/EditableView'; import { KeyStore } from '../../../fields/KeyStore'; diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index 2bbb334b5..1dacdf3fa 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -109,12 +109,12 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => { } passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => { - if (err) { next(err); return } + if (err) { next(err); return; } if (!user) { return res.redirect(RouteStore.signup); } req.logIn(user, (err) => { - if (err) { next(err); return } + if (err) { next(err); return; } res.redirect(RouteStore.home); }); })(req, res, next); @@ -132,14 +132,14 @@ export let getLogout = (req: Request, res: Response) => { sess.destroy((err) => { if (err) { console.log(err); } }); } res.redirect(RouteStore.login); -} +}; export let getForgot = function (req: Request, res: Response) { res.render("forgot.pug", { title: "Recover Password", user: req.user, }); -} +}; export let postForgot = function (req: Request, res: Response, next: NextFunction) { const email = req.body.email; @@ -152,14 +152,14 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio return; } done(null, buffer.toString('hex')); - }) + }); }, function (token: string, done: any) { User.findOne({ email }, function (err, user: DashUserModel) { if (!user) { // NO ACCOUNT WITH SUBMITTED EMAIL res.redirect(RouteStore.forgot); - return + return; } user.passwordResetToken = token; user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR @@ -193,8 +193,8 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio ], function (err) { if (err) return next(err); res.redirect(RouteStore.forgot); - }) -} + }); +}; export let getReset = function (req: Request, res: Response) { User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { @@ -206,7 +206,7 @@ export let getReset = function (req: Request, res: Response) { user: req.user, }); }); -} +}; export let postReset = function (req: Request, res: Response) { async.waterfall([ @@ -263,4 +263,4 @@ export let postReset = function (req: Request, res: Response) { ], function (err) { res.redirect(RouteStore.login); }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 0ac85b446..13eddafbf 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -70,7 +70,7 @@ export class CurrentUserUtils { let doc = new Document(id); doc.Set(KeyStore.Workspaces, new ListField()); - doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })) + doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); return doc; } @@ -81,7 +81,7 @@ export class CurrentUserUtils { CurrentUserUtils.curr_id = obj.id as string; CurrentUserUtils.curr_email = obj.email as string; } else { - throw new Error("There should be a user! Why does Dash think there isn't one?") + throw new Error("There should be a user! Why does Dash think there isn't one?"); } }); let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { @@ -92,9 +92,9 @@ export class CurrentUserUtils { } else { this.user_document = this.createUserDocument(id); } - }) + }); } else { - throw new Error("There should be a user id! Why does Dash think there isn't one?") + throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); return Promise.all([userPromise, userDocPromise]); diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 81580aad5..1c6926517 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -2,7 +2,7 @@ import * as bcrypt from "bcrypt-nodejs"; //@ts-ignore import * as mongoose from "mongoose"; -var url = 'mongodb://localhost:27017/Dash' +var url = 'mongodb://localhost:27017/Dash'; mongoose.connect(url, { useNewUrlParser: true }); diff --git a/src/server/database.ts b/src/server/database.ts index 415acc09a..0bc806253 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,15 +1,15 @@ import * as mongodb from 'mongodb'; export class Database { - public static Instance = new Database() + public static Instance = new Database(); private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; private db?: mongodb.Db; constructor() { this.MongoClient.connect(this.url, (err, client) => { - this.db = client.db() - }) + this.db = client.db(); + }); } private currentWrites: { [_id: string]: Promise } = {}; @@ -30,19 +30,19 @@ export class Database { // console.log(JSON.stringify(res.result)); // } if (this.currentWrites[id] === promise) { - delete this.currentWrites[id] + delete this.currentWrites[id]; } if (resolve) { resolve(); } callback(); }); - } + }; if (prom) { const newProm: Promise = prom.then(() => run(newProm)); this.currentWrites[id] = newProm; } else { - const newProm: Promise = new Promise(res => run(newProm, res)) + const newProm: Promise = new Promise(res => run(newProm, res)); this.currentWrites[id] = newProm; } } @@ -61,7 +61,7 @@ export class Database { let collection = this.db.collection(collectionName); collection.deleteMany({}, res); } - }) + }); } public insert(kvpairs: any) { @@ -70,7 +70,7 @@ export class Database { collection.insertOne(kvpairs, (err: any, res: any) => { if (err) { // console.log(err) - return + return; } }); } @@ -81,30 +81,30 @@ export class Database { if (this.db) { let collection = this.db.collection('documents'); collection.findOne({ _id: id }, (err: any, res: any) => { - result = res + result = res; if (!result) { - fn(undefined) + fn(undefined); } - fn(result) - }) - }; + fn(result); + }); + } } public getDocuments(ids: string[], fn: (res: any) => void) { if (this.db) { let collection = this.db.collection('documents'); - let cursor = collection.find({ _id: { "$in": ids } }) + let cursor = collection.find({ _id: { "$in": ids } }); cursor.toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } fn(docs); - }) - }; + }); + } } public print() { - console.log("db says hi!") + console.log("db says hi!"); } } diff --git a/src/server/index.ts b/src/server/index.ts index f60e6e293..b9c7448b4 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,10 +1,10 @@ -import * as express from 'express' -const app = express() -import * as webpack from 'webpack' +import * as express from 'express'; +const app = express(); +import * as webpack from 'webpack'; import * as wdm from 'webpack-dev-middleware'; import * as whm from 'webpack-hot-middleware'; -import * as path from 'path' -import * as formidable from 'formidable' +import * as path from 'path'; +import * as formidable from 'formidable'; import * as passport from 'passport'; import { MessageStore, Transferable } from "./Message"; import { Client } from './Client'; @@ -13,7 +13,7 @@ import { Utils } from '../Utils'; import { ObservableMap } from 'mobx'; import { FieldId, Field } from '../fields/Field'; import { Database } from './database'; -import * as io from 'socket.io' +import * as io from 'socket.io'; import { getLogin, postLogin, getSignup, postSignup, getLogout, postReset, getForgot, postForgot, getReset } from './authentication/controllers/user_controller'; const config = require('../../webpack.config'); const compiler = webpack(config); @@ -31,19 +31,19 @@ const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); import { DashUserModel } from './authentication/models/user_model'; import * as fs from 'fs'; -import * as request from 'request' +import * as request from 'request'; import { RouteStore } from './RouteStore'; -import { exec } from 'child_process' +import { exec } from 'child_process'; const download = (url: string, dest: fs.PathLike) => { request.get(url).pipe(fs.createWriteStream(dest)); -} +}; const mongoUrl = 'mongodb://localhost:27017/Dash'; -mongoose.connect(mongoUrl) +mongoose.connect(mongoUrl); mongoose.connection.on('connected', function () { console.log("connected"); -}) +}); // SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE // ORDER OF IMPORTS MATTERS @@ -73,7 +73,7 @@ app.use((req, res, next) => { app.get("/hello", (req, res) => { res.send("

Hello

"); -}) +}); enum Method { GET, @@ -98,7 +98,7 @@ function addSecureRoute(method: Method, const dashUser: DashUserModel = req.user; if (!dashUser) return onRejection(res); handler(dashUser, res, req); - } + }; subscribers.forEach(route => { switch (method) { case Method.GET: @@ -116,7 +116,7 @@ function addSecureRoute(method: Method, let FieldStore: ObservableMap = new ObservableMap(); app.use(express.static(__dirname + RouteStore.public)); -app.use(RouteStore.images, express.static(__dirname + RouteStore.public)) +app.use(RouteStore.images, express.static(__dirname + RouteStore.public)); app.get("/pull", (req, res) => { exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => { @@ -125,7 +125,7 @@ app.get("/pull", (req, res) => { return; } res.redirect("/"); - }) + }); }); // GETTERS @@ -178,13 +178,13 @@ addSecureRoute( addSecureRoute( Method.POST, (user, res, req) => { - let form = new formidable.IncomingForm() - form.uploadDir = __dirname + "/public/files/" - form.keepExtensions = true + let form = new formidable.IncomingForm(); + form.uploadDir = __dirname + "/public/files/"; + form.keepExtensions = true; // let path = req.body.path; - console.log("upload") + console.log("upload"); form.parse(req, (err, fields, files) => { - console.log("parsing") + console.log("parsing"); let names: any[] = []; for (const name in files) { let file = files[name]; @@ -211,8 +211,8 @@ app.post(RouteStore.login, postLogin); app.get(RouteStore.logout, getLogout); // FORGOT PASSWORD EMAIL HANDLING -app.get(RouteStore.forgot, getForgot) -app.post(RouteStore.forgot, postForgot) +app.get(RouteStore.forgot, getForgot); +app.post(RouteStore.forgot, postForgot); // RESET PASSWORD EMAIL HANDLING app.get(RouteStore.reset, getReset); @@ -232,32 +232,32 @@ app.get(RouteStore.deleteAll, (req, res) => { app.use(wdm(compiler, { publicPath: config.output.publicPath -})) +})); -app.use(whm(compiler)) +app.use(whm(compiler)); // start the Express server app.listen(port, () => { console.log(`server started at http://localhost:${port}`); -}) +}); const server = io(); interface Map { [key: string]: Client; } -let clients: Map = {} +let clients: Map = {}; server.on("connection", function (socket: Socket) { - console.log("a user has connected") + console.log("a user has connected"); - Utils.Emit(socket, MessageStore.Foo, "handshooken") + Utils.Emit(socket, MessageStore.Foo, "handshooken"); - Utils.AddServerHandler(socket, MessageStore.Bar, barReceived) - Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)) - Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField) - Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields) - Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields) -}) + Utils.AddServerHandler(socket, MessageStore.Bar, barReceived); + Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)); + Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); + Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); +}); function deleteFields() { return Database.Instance.deleteAll(); @@ -276,12 +276,12 @@ function barReceived(guid: String) { function getField([id, callback]: [string, (result: any) => void]) { Database.Instance.getDocument(id, (result: any) => { if (result) { - callback(result) + callback(result); } else { - callback(undefined) + callback(undefined); } - }) + }); } function getFields([ids, callback]: [string[], (result: any) => void]) { @@ -291,7 +291,7 @@ function getFields([ids, callback]: [string[], (result: any) => void]) { function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue._id, newValue, () => { socket.broadcast.emit(MessageStore.SetField.Message, newValue); - }) + }); } server.listen(serverPort); diff --git a/test/test.ts b/test/test.ts index db24cae5f..16cace026 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,6 +1,6 @@ import { NumberField } from "../src/fields/NumberField"; import { expect } from 'chai'; -import 'mocha' +import 'mocha'; import { Key } from "../src/fields/Key"; import { Document } from "../src/fields/Document"; import { autorun, reaction } from "mobx"; @@ -17,7 +17,7 @@ describe('Number Controller', () => { it('Should update', () => { const numController = new NumberField(15); let ran = false; - reaction(() => numController.Data, (data) => { ran = true; }) + reaction(() => numController.Data, (data) => { ran = true; }); expect(ran).to.equal(false); numController.Data = 5; expect(ran).to.equal(true); @@ -42,7 +42,7 @@ describe("Document", () => { let key = new Key("Test"); let key2 = new Key("Test2"); let ran = false; - reaction(() => doc.Get(key), (field) => { ran = true }); + reaction(() => doc.Get(key), (field) => { ran = true; }); expect(ran).to.equal(false); doc.Set(key2, new NumberField(4)); diff --git a/tslint.json b/tslint.json index 54876916e..aa4dee4e5 100644 --- a/tslint.json +++ b/tslint.json @@ -27,14 +27,14 @@ "arrow-return-shorthand": true, // "object-literal-shorthand": true, // "object-literal-sort-keys": true, - // "semicolon": [ - // true, - // "always" - // ], - // "curly": [ - // true, - // "ignore-same-line" - // ], + "semicolon": [ + true, + "always" + ], + "curly": [ + true, + "ignore-same-line" + ], // "quotemark": [ // true, // "double", -- cgit v1.2.3-70-g09d2 From 79d8b5c812db5c28f477ace8db0ee4d9e18a84b7 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 17 Apr 2019 06:16:50 -0400 Subject: Started implementing new documents --- package.json | 1 + src/debug/Test.tsx | 39 ++++++----- src/fields/NewDoc.ts | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 18 deletions(-) create mode 100644 src/fields/NewDoc.ts (limited to 'src/debug/Test.tsx') diff --git a/package.json b/package.json index 2463afa74..1eb546a80 100644 --- a/package.json +++ b/package.json @@ -163,6 +163,7 @@ "react-table": "^6.9.2", "request": "^2.88.0", "request-promise": "^4.2.4", + "serializr": "^1.5.1", "socket.io": "^2.2.0", "socket.io-client": "^2.2.0", "typescript-collections": "^1.3.2", diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 11f2b0c4e..ca093e5b2 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,29 +1,32 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import JsxParser from 'react-jsx-parser'; +import { serialize, deserialize, map } from 'serializr'; +import { URLField, Doc } from '../fields/NewDoc'; -class Hello extends React.Component<{ firstName: string, lastName: string }> { - render() { - return
Hello {this.props.firstName} {this.props.lastName}
; +class Test extends React.Component { + onClick = () => { + const url = new URLField(new URL("http://google.com")); + const doc = new Doc("a"); + const doc2 = new Doc("b"); + doc.hello = 5; + doc.fields = "test"; + doc.test = "hello doc"; + doc.url = url; + doc.testDoc = doc2; + + console.log(doc.hello); + console.log(doc.fields); + console.log(doc.test); + console.log(doc.url); + console.log(doc.testDoc); } -} -class Test extends React.Component { render() { - let jsx = ""; - let bindings = { - props: { - firstName: "First", - lastName: "Last" - } - }; - return ; + return ; } } -ReactDOM.render(( -
- -
), +ReactDOM.render( + , document.getElementById('root') ); \ No newline at end of file diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts new file mode 100644 index 000000000..d0e518306 --- /dev/null +++ b/src/fields/NewDoc.ts @@ -0,0 +1,190 @@ +import { observable, action } from "mobx"; +import { Server } from "../client/Server"; +import { UndoManager } from "../client/util/UndoManager"; +import { serialize, deserialize, serializable, primitive } from "serializr"; + +const Type = Symbol("type"); + +const Id = Symbol("id"); +export abstract class RefField { + readonly [Id]: string; + + constructor(id: string) { + this[Id] = id; + } +} + +const Update = Symbol("Update"); +const Parent = Symbol("Parent"); +export class ObjectField { + protected [Update]?: (diff?: any) => void; + private [Parent]?: Doc; +} + +function url() { + return { + serializer: function (value: URL) { + return value.href; + }, + deserializer: function (jsonValue: string, done: (err: any, val: any) => void) { + done(undefined, new URL(jsonValue)); + } + }; +} +export class URLField extends ObjectField { + @serializable(url()) + url: URL; + + constructor(url: URL) { + super(); + this.url = url; + } +} + +export class ProxyField extends ObjectField { + constructor(); + constructor(value: T); + constructor(value?: T) { + super(); + if (value) { + this.cache = value; + this.fieldId = value[Id]; + } + } + + @serializable(primitive()) + readonly fieldId: string = ""; + + // This getter/setter and nested object thing is + // because mobx doesn't play well with observable proxies + @observable.ref + private _cache: { readonly field: T | undefined } = { field: undefined }; + private get cache(): T | undefined { + return this._cache.field; + } + private set cache(field: T | undefined) { + this._cache = { field }; + } + + private failed = false; + private promise?: Promise; + + value(callback?: ((field: T | undefined) => void)): T | undefined | null { + if (this.cache) { + callback && callback(this.cache); + return this.cache; + } + if (this.failed) { + return undefined; + } + if (!this.promise) { + // this.promise = Server.GetField(this.fieldId).then(action((field: any) => { + // this.promise = undefined; + // this.cache = field; + // if (field === undefined) this.failed = true; + // return field; + // })); + this.promise = new Promise(r => r()); + } + callback && this.promise.then(callback); + return null; + } +} + +export type Field = number | string | boolean | ObjectField | RefField; + +const Self = Symbol("Self"); +export class Doc extends RefField { + + private static setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + const curValue = target.__fields[prop]; + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { + // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically + // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way + return true; + } + if (value instanceof RefField) { + value = new ProxyField(value); + } + if (value instanceof ObjectField) { + if (value[Parent] && value[Parent] !== target) { + throw new Error("Can't put the same object in multiple documents at the same time"); + } + value[Parent] = target; + value[Update] = (diff?: any) => { + if (!diff) diff = serialize(value); + target[Update]({ [prop]: diff }); + }; + } + if (curValue instanceof ObjectField) { + delete curValue[Parent]; + delete curValue[Update]; + } + target.__fields[prop] = value; + target[Update]({ [prop]: typeof value === "object" ? serialize(value) : value }); + UndoManager.AddEvent({ + redo: () => receiver[prop] = value, + undo: () => receiver[prop] = curValue + }); + return true; + } + + private static getter(target: any, prop: string | symbol | number, receiver: any): any { + if (typeof prop !== "string") { + return undefined; + } + return Doc.getField(target, prop, receiver); + } + + private static getField(target: any, prop: string, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { + if (typeof prop === "symbol") { + return target.__fields[prop]; + } + const field = target.__fields[prop]; + if (field instanceof ProxyField) { + return field.value(callback); + } + if (field === undefined && !ignoreProto) { + const proto = Doc.getField(target, "prototype", true); + if (proto instanceof Doc) { + let field = proto[prop]; + callback && callback(field === null ? undefined : field); + return field; + } + } + callback && callback(field); + return field; + + } + + static GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { + const self = doc[Self]; + return new Promise(res => Doc.getField(self, key, ignoreProto, res)); + } + + constructor(id: string) { + super(id); + const doc = new Proxy(this, { + set: Doc.setter, + get: Doc.getter, + deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + return doc; + } + + [key: string]: Field | null | undefined; + + @observable + private __fields: { [key: string]: Field | null | undefined } = {}; + + private [Update] = (diff?: any) => { + console.log(JSON.stringify(diff || this)); + } + + private [Self] = this; +} + +export namespace Doc { + export const Prototype = Symbol("Prototype"); +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6afdd5e5136394c9dc739b5de390aa1b55c6360f Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 17 Apr 2019 13:51:40 -0400 Subject: Serialization is mostly working --- src/client/util/SerializationHelper.ts | 72 ++++++++++++++++++++++++++++++++++ src/debug/Test.tsx | 10 ++--- src/fields/NewDoc.ts | 45 ++++++++++++++------- 3 files changed, 107 insertions(+), 20 deletions(-) create mode 100644 src/client/util/SerializationHelper.ts (limited to 'src/debug/Test.tsx') diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts new file mode 100644 index 000000000..656101c95 --- /dev/null +++ b/src/client/util/SerializationHelper.ts @@ -0,0 +1,72 @@ +import { PropSchema, serialize, deserialize, custom } from "serializr"; +import { Field } from "../../fields/NewDoc"; + +export class SerializationHelper { + + public static Serialize(obj: Field): any { + if (!obj) { + return null; + } + + if (typeof obj !== 'object') { + return obj; + } + + 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]; + return json; + } + + public static Deserialize(obj: any): any { + if (!obj) { + return null; + } + + if (typeof obj !== 'object') { + return obj; + } + + 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`); + } + + return deserialize(serializationTypes[obj.__type], obj); + } +} + +let serializationTypes: { [name: string]: any } = {}; +let reverseMap: { [ctor: string]: string } = {}; + +export function Deserializable(name: string): Function; +export function Deserializable(constructor: Function): void; +export function Deserializable(constructor: Function | string): Function | void { + function addToMap(name: string, ctor: Function) { + if (!(name in serializationTypes)) { + serializationTypes[name] = constructor; + reverseMap[ctor.name] = name; + } else { + throw new Error(`Name ${name} has already been registered as deserializable`); + } + } + if (typeof constructor === "string") { + return (ctor: Function) => { + addToMap(constructor, ctor); + }; + } + addToMap(constructor.name, constructor); +} + +export function autoObject(): PropSchema { + return custom( + (s) => SerializationHelper.Serialize(s), + (s) => SerializationHelper.Deserialize(s) + ); +} \ No newline at end of file diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index ca093e5b2..7e7b3a964 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { serialize, deserialize, map } from 'serializr'; import { URLField, Doc } from '../fields/NewDoc'; +import { SerializationHelper } from '../client/util/SerializationHelper'; class Test extends React.Component { onClick = () => { @@ -14,11 +15,10 @@ class Test extends React.Component { doc.url = url; doc.testDoc = doc2; - console.log(doc.hello); - console.log(doc.fields); - console.log(doc.test); - console.log(doc.url); - console.log(doc.testDoc); + console.log("doc", doc); + const cereal = Doc.Serialize(doc); + console.log("cereal", cereal); + console.log("doc again", SerializationHelper.Deserialize(cereal)); } render() { diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts index d0e518306..05dd14bc3 100644 --- a/src/fields/NewDoc.ts +++ b/src/fields/NewDoc.ts @@ -1,16 +1,15 @@ import { observable, action } from "mobx"; import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; -import { serialize, deserialize, serializable, primitive } from "serializr"; +import { serialize, deserialize, serializable, primitive, map, alias } from "serializr"; +import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; -const Type = Symbol("type"); - -const Id = Symbol("id"); export abstract class RefField { - readonly [Id]: string; + @serializable(alias("id", primitive())) + readonly __id: string; constructor(id: string) { - this[Id] = id; + this.__id = id; } } @@ -31,6 +30,8 @@ function url() { } }; } + +@Deserializable export class URLField extends ObjectField { @serializable(url()) url: URL; @@ -41,6 +42,7 @@ export class URLField extends ObjectField { } } +@Deserializable export class ProxyField extends ObjectField { constructor(); constructor(value: T); @@ -48,7 +50,7 @@ export class ProxyField extends ObjectField { super(); if (value) { this.cache = value; - this.fieldId = value[Id]; + this.fieldId = value.__id; } } @@ -94,11 +96,17 @@ export class ProxyField extends ObjectField { export type Field = number | string | boolean | ObjectField | RefField; const Self = Symbol("Self"); + +@Deserializable export class Doc extends RefField { private static setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + if (prop === "__id" || prop === "__fields") { + target[prop] = value; + return true; + } const curValue = target.__fields[prop]; - if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value.__id)) { // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way return true; @@ -130,16 +138,16 @@ export class Doc extends RefField { } private static getter(target: any, prop: string | symbol | number, receiver: any): any { - if (typeof prop !== "string") { - return undefined; + if (typeof prop === "symbol") { + return target[prop]; + } + if (prop === "__id" || prop === "__fields") { + return target[prop]; } return Doc.getField(target, prop, receiver); } - private static getField(target: any, prop: string, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { - if (typeof prop === "symbol") { - return target.__fields[prop]; - } + private static getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { const field = target.__fields[prop]; if (field instanceof ProxyField) { return field.value(callback); @@ -162,6 +170,10 @@ export class Doc extends RefField { return new Promise(res => Doc.getField(self, key, ignoreProto, res)); } + static Serialize(doc: Doc) { + return SerializationHelper.Serialize(doc[Self]); + } + constructor(id: string) { super(id); const doc = new Proxy(this, { @@ -175,6 +187,7 @@ export class Doc extends RefField { [key: string]: Field | null | undefined; + @serializable(alias("fields", map(autoObject()))) @observable private __fields: { [key: string]: Field | null | undefined } = {}; @@ -187,4 +200,6 @@ export class Doc extends RefField { export namespace Doc { export const Prototype = Symbol("Prototype"); -} \ No newline at end of file +} + +export const GetAsync = Doc.GetAsync; \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9712a046868ee51a565a425d3216a2bb297c4eee Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 17 Apr 2019 19:45:59 -0400 Subject: Got saving to database working --- src/client/DocServer.ts | 72 +++++++++++++++++++++++++++++++++ src/client/util/SerializationHelper.ts | 73 +++++++++++++++++++++++++++++----- src/debug/Test.tsx | 6 +-- src/fields/NewDoc.ts | 52 ++++++++++++++++-------- src/server/Message.ts | 12 ++++++ src/server/database.ts | 16 ++++---- src/server/index.ts | 19 ++++++++- 7 files changed, 212 insertions(+), 38 deletions(-) create mode 100644 src/client/DocServer.ts (limited to 'src/debug/Test.tsx') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts new file mode 100644 index 000000000..9a3e122e8 --- /dev/null +++ b/src/client/DocServer.ts @@ -0,0 +1,72 @@ +import * as OpenSocket from 'socket.io-client'; +import { MessageStore, Types } from "./../server/Message"; +import { Opt, FieldWaiting, RefField, HandleUpdate } from '../fields/NewDoc'; +import { Utils } from '../Utils'; +import { SerializationHelper } from './util/SerializationHelper'; + +export namespace DocServer { + const _cache: { [id: string]: RefField | Promise> } = {}; + const _socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); + const GUID: string = Utils.GenerateGuid(); + + export async function GetRefField(id: string): Promise> { + let cached = _cache[id]; + if (cached === undefined) { + const prom = Utils.EmitCallback(_socket, MessageStore.GetRefField, id).then(fieldJson => { + const field = fieldJson === undefined ? fieldJson : SerializationHelper.Deserialize(fieldJson); + if (field) { + _cache[id] = field; + } else { + delete _cache[id]; + } + return field; + }); + _cache[id] = prom; + return prom; + } else if (cached instanceof Promise) { + return cached; + } else { + return cached; + } + } + + export function UpdateField(id: string, diff: any) { + Utils.Emit(_socket, MessageStore.UpdateField, { id, diff }); + } + + export function CreateField(initialState: any) { + if (!("id" in initialState)) { + throw new Error("Can't create a field on the server without an id"); + } + Utils.Emit(_socket, MessageStore.CreateField, initialState); + } + + function respondToUpdate(diff: any) { + const id = diff.id; + if (id === undefined) { + return; + } + const field = _cache[id]; + const update = (f: Opt) => { + if (f === undefined) { + return; + } + const handler = f[HandleUpdate]; + if (handler) { + handler(diff); + } + }; + if (field instanceof Promise) { + field.then(update); + } else { + update(field); + } + } + + function connected(message: string) { + _socket.emit(MessageStore.Bar.Message, GUID); + } + + Utils.AddServerHandler(_socket, MessageStore.Foo, connected); + Utils.AddServerHandler(_socket, MessageStore.UpdateField, respondToUpdate); +} \ No newline at end of file diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index 656101c95..7273c3fe4 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -1,9 +1,13 @@ -import { PropSchema, serialize, deserialize, custom } from "serializr"; +import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema, primitive, SKIP } from "serializr"; import { Field } from "../../fields/NewDoc"; -export class SerializationHelper { +export namespace SerializationHelper { + let serializing: number = 0; + export function IsSerializing() { + return serializing > 0; + } - public static Serialize(obj: Field): any { + export function Serialize(obj: Field): any { if (!obj) { return null; } @@ -12,16 +16,18 @@ export class SerializationHelper { 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; } - public static Deserialize(obj: any): any { + export function Deserialize(obj: any): any { if (!obj) { return null; } @@ -30,6 +36,7 @@ export class SerializationHelper { return obj; } + serializing += 1; if (!obj.__type) { throw Error("No property 'type' found in JSON."); } @@ -38,32 +45,78 @@ export class SerializationHelper { throw Error(`type '${obj.__type}' not registered. Make sure you register it using a @Deserializable decorator`); } - return deserialize(serializationTypes[obj.__type], obj); + const value = deserialize(serializationTypes[obj.__type], obj); + serializing -= 1; + return value; } } let serializationTypes: { [name: string]: any } = {}; let reverseMap: { [ctor: string]: string } = {}; -export function Deserializable(name: string): Function; +export interface DeserializableOpts { + (constructor: Function): void; + withFields(fields: string[]): Function; +} + +export function Deserializable(name: string): DeserializableOpts; export function Deserializable(constructor: Function): void; -export function Deserializable(constructor: Function | string): Function | void { +export function Deserializable(constructor: Function | string): DeserializableOpts | void { function addToMap(name: string, ctor: Function) { if (!(name in serializationTypes)) { - serializationTypes[name] = constructor; + serializationTypes[name] = ctor; reverseMap[ctor.name] = name; } else { throw new Error(`Name ${name} has already been registered as deserializable`); } } if (typeof constructor === "string") { - return (ctor: Function) => { + return Object.assign((ctor: Function) => { 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), diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 7e7b3a964..660115453 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -7,8 +7,8 @@ import { SerializationHelper } from '../client/util/SerializationHelper'; class Test extends React.Component { onClick = () => { const url = new URLField(new URL("http://google.com")); - const doc = new Doc("a"); - const doc2 = new Doc("b"); + const doc = new Doc(); + const doc2 = new Doc(); doc.hello = 5; doc.fields = "test"; doc.test = "hello doc"; @@ -16,7 +16,7 @@ class Test extends React.Component { doc.testDoc = doc2; console.log("doc", doc); - const cereal = Doc.Serialize(doc); + const cereal = SerializationHelper.Serialize(doc); console.log("cereal", cereal); console.log("doc again", SerializationHelper.Deserialize(cereal)); } diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts index 05dd14bc3..46f2e20e9 100644 --- a/src/fields/NewDoc.ts +++ b/src/fields/NewDoc.ts @@ -1,16 +1,24 @@ import { observable, action } from "mobx"; import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; -import { serialize, deserialize, serializable, primitive, map, alias } from "serializr"; +import { serializable, primitive, map, alias } from "serializr"; import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; +import { Utils } from "../Utils"; +import { DocServer } from "../client/DocServer"; +export const HandleUpdate = Symbol("HandleUpdate"); +const Id = Symbol("Id"); export abstract class RefField { @serializable(alias("id", primitive())) - readonly __id: string; + private __id: string; + readonly [Id]: string; - constructor(id: string) { - this.__id = id; + constructor(id?: string) { + this.__id = id || Utils.GenerateGuid(); + this[Id] = this.__id; } + + protected [HandleUpdate]?(diff: any): void; } const Update = Symbol("Update"); @@ -31,10 +39,10 @@ function url() { }; } -@Deserializable +@Deserializable("url") export class URLField extends ObjectField { @serializable(url()) - url: URL; + readonly url: URL; constructor(url: URL) { super(); @@ -42,7 +50,7 @@ export class URLField extends ObjectField { } } -@Deserializable +@Deserializable("proxy") export class ProxyField extends ObjectField { constructor(); constructor(value: T); @@ -50,7 +58,7 @@ export class ProxyField extends ObjectField { super(); if (value) { this.cache = value; - this.fieldId = value.__id; + this.fieldId = value[Id]; } } @@ -94,19 +102,26 @@ export class ProxyField extends ObjectField { } export type Field = number | string | boolean | ObjectField | RefField; +export type Opt = T | undefined; +export type FieldWaiting = null; +export const FieldWaiting: FieldWaiting = null; const Self = Symbol("Self"); -@Deserializable +@Deserializable("doc").withFields(["id"]) export class Doc extends RefField { private static setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { - if (prop === "__id" || prop === "__fields") { + if (SerializationHelper.IsSerializing()) { + target[prop] = value; + return true; + } + if (typeof prop === "symbol") { target[prop] = value; return true; } const curValue = target.__fields[prop]; - if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value.__id)) { + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way return true; @@ -120,7 +135,7 @@ export class Doc extends RefField { } value[Parent] = target; value[Update] = (diff?: any) => { - if (!diff) diff = serialize(value); + if (!diff) diff = SerializationHelper.Serialize(value); target[Update]({ [prop]: diff }); }; } @@ -129,7 +144,7 @@ export class Doc extends RefField { delete curValue[Update]; } target.__fields[prop] = value; - target[Update]({ [prop]: typeof value === "object" ? serialize(value) : value }); + target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue @@ -141,7 +156,7 @@ export class Doc extends RefField { if (typeof prop === "symbol") { return target[prop]; } - if (prop === "__id" || prop === "__fields") { + if (SerializationHelper.IsSerializing()) { return target[prop]; } return Doc.getField(target, prop, receiver); @@ -174,7 +189,7 @@ export class Doc extends RefField { return SerializationHelper.Serialize(doc[Self]); } - constructor(id: string) { + constructor(id?: string, forceSave?: boolean) { super(id); const doc = new Proxy(this, { set: Doc.setter, @@ -182,6 +197,9 @@ export class Doc extends RefField { deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); + if (!id || forceSave) { + DocServer.CreateField(SerializationHelper.Serialize(doc)); + } return doc; } @@ -191,8 +209,8 @@ export class Doc extends RefField { @observable private __fields: { [key: string]: Field | null | undefined } = {}; - private [Update] = (diff?: any) => { - console.log(JSON.stringify(diff || this)); + private [Update] = (diff: any) => { + DocServer.UpdateField(this[Id], diff); } private [Self] = this; diff --git a/src/server/Message.ts b/src/server/Message.ts index bbe4ffcad..843a923d1 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -24,6 +24,14 @@ export interface Transferable { readonly data?: any; } +export interface Reference { + readonly id: string; +} + +export interface Diff extends Reference { + readonly diff: any; +} + export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); @@ -32,4 +40,8 @@ export namespace MessageStore { export const GetFields = new Message("Get Fields"); // send string[] of 'id' get Transferable[] back export const GetDocument = new Message("Get Document"); export const DeleteAll = new Message("Delete All"); + + export const GetRefField = new Message("Get Ref Field"); + export const UpdateField = new Message("Update Ref Field"); + export const CreateField = new Message("Create Ref Field"); } diff --git a/src/server/database.ts b/src/server/database.ts index 5457e4dd5..a61b4d823 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -13,14 +13,14 @@ export class Database { this.MongoClient.connect(this.url, (err, client) => this.db = client.db()); } - public update(id: string, value: any, callback: () => void) { + public update(id: string, value: any, callback: () => void, upsert = true, collectionName = Database.DocumentsCollection) { if (this.db) { - let collection = this.db.collection('documents'); + let collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; let newProm: Promise; const run = (): Promise => { return new Promise(resolve => { - collection.updateOne({ _id: id }, { $set: value }, { upsert: true } + collection.updateOne({ _id: id }, { $set: value }, { upsert } , (err, res) => { if (err) { console.log(err.message); @@ -51,10 +51,12 @@ export class Database { this.db && this.db.collection(collectionName).deleteMany({}, res)); } - public insert(kvpairs: any, collectionName = Database.DocumentsCollection) { - this.db && this.db.collection(collectionName).insertOne(kvpairs, (err, res) => - err // && console.log(err) - ); + public insert(value: any, collectionName = Database.DocumentsCollection) { + if ("id" in value) { + value._id = value.id; + delete value.id; + } + this.db && this.db.collection(collectionName).insertOne(value); } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { diff --git a/src/server/index.ts b/src/server/index.ts index 70a7d266c..d6d5f0e55 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -22,7 +22,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo import { DashUserModel } from './authentication/models/user_model'; import { Client } from './Client'; import { Database } from './database'; -import { MessageStore, Transferable } from "./Message"; +import { MessageStore, Transferable, Diff } from "./Message"; import { RouteStore } from './RouteStore'; const app = express(); const config = require('../../webpack.config'); @@ -232,6 +232,10 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); + + Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); + Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); + Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); }); function deleteFields() { @@ -262,5 +266,18 @@ function setField(socket: Socket, newValue: Transferable) { socket.broadcast.emit(MessageStore.SetField.Message, newValue)); } +function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { + Database.Instance.getDocument(id, callback, "newDocuments"); +} + +function UpdateField(socket: Socket, diff: Diff) { + Database.Instance.update(diff.id, diff.diff, + () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); +} + +function CreateField(newValue: any) { + Database.Instance.insert(newValue, "newDocuments"); +} + server.listen(serverPort); console.log(`listening on port ${serverPort}`); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 8eebfed7906e1e2088d528e3af36af21094c38a9 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 18 Apr 2019 19:17:48 -0400 Subject: Implemented document schemas --- src/debug/Test.tsx | 50 ++++++++++++++++++++++++++--- src/fields/NewDoc.ts | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 129 insertions(+), 11 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 660115453..b46eb4477 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,9 +1,35 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { serialize, deserialize, map } from 'serializr'; -import { URLField, Doc } from '../fields/NewDoc'; +import { URLField, Doc, createSchema, makeInterface, makeStrictInterface } from '../fields/NewDoc'; import { SerializationHelper } from '../client/util/SerializationHelper'; +const schema1 = createSchema({ + hello: "number", + test: "string", + fields: "boolean", + url: URLField, + testDoc: Doc +}); + +const TestDoc = makeInterface(schema1); +type TestDoc = makeInterface; + +const schema2 = createSchema({ + hello: URLField, + test: "boolean", + fields: "string", + url: "number", + testDoc: URLField +}); + +const Test2Doc = makeStrictInterface(schema2); +type Test2Doc = makeStrictInterface; + +const assert = (bool: boolean) => { + if (!bool) throw new Error(); +}; + class Test extends React.Component { onClick = () => { const url = new URLField(new URL("http://google.com")); @@ -15,10 +41,24 @@ class Test extends React.Component { doc.url = url; doc.testDoc = doc2; - console.log("doc", doc); - const cereal = SerializationHelper.Serialize(doc); - console.log("cereal", cereal); - console.log("doc again", SerializationHelper.Deserialize(cereal)); + + const test1: TestDoc = TestDoc(doc); + const test2: Test2Doc = Test2Doc(doc); + assert(test1.hello === 5); + assert(test1.fields === undefined); + assert(test1.test === "hello doc"); + assert(test1.url === url); + assert(test1.testDoc === doc2); + test1.myField = 20; + assert(test1.myField === 20); + + assert(test2.hello === undefined); + assert(test2.fields === "test"); + assert(test2.test === undefined); + assert(test2.url === undefined); + assert(test2.testDoc === undefined); + test2.url = 35; + assert(test2.url === 35); } render() { diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts index 46f2e20e9..150b8dae8 100644 --- a/src/fields/NewDoc.ts +++ b/src/fields/NewDoc.ts @@ -1,5 +1,4 @@ import { observable, action } from "mobx"; -import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; import { serializable, primitive, map, alias } from "serializr"; import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; @@ -185,10 +184,6 @@ export class Doc extends RefField { return new Promise(res => Doc.getField(self, key, ignoreProto, res)); } - static Serialize(doc: Doc) { - return SerializationHelper.Serialize(doc[Self]); - } - constructor(id?: string, forceSave?: boolean) { super(id); const doc = new Proxy(this, { @@ -220,4 +215,87 @@ export namespace Doc { export const Prototype = Symbol("Prototype"); } -export const GetAsync = Doc.GetAsync; \ No newline at end of file +export const GetAsync = Doc.GetAsync; + +interface IDoc { + [key: string]: Field | null | undefined; +} + +interface ImageDocument extends IDoc { + data: URLField; + test: number; +} + +export type ToType = + T extends "string" ? string : + T extends "number" ? number : + T extends "boolean" ? boolean : + T extends { new(...args: any[]): infer R } ? R : undefined; + +export type ToInterface = { + [P in keyof T]: ToType; +}; + +interface Interface { + [key: string]: { new(...args: any[]): (ObjectField | RefField) } | "number" | "boolean" | "string"; +} + +type FieldCtor = { new(): T } | "number" | "string" | "boolean"; + +function Cast(field: Field | undefined, ctor: FieldCtor): T | undefined { + if (field !== undefined) { + if (typeof ctor === "string") { + if (typeof field === ctor) { + return field as T; + } + } else if (field instanceof ctor) { + return field; + } + } + return undefined; +} + +export type makeInterface = Partial> & Doc; +export function makeInterface(schema: T): (doc: Doc) => makeInterface { + return function (doc: any) { + return new Proxy(doc, { + get(target, prop) { + const field = target[prop]; + if (prop in schema) { + return Cast(field, (schema as any)[prop]); + } + return field; + } + }); + }; +} + +export type makeStrictInterface = Partial>; +export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { + const proto = {}; + for (const key in schema) { + const type = schema[key]; + Object.defineProperty(proto, key, { + get() { + return Cast(this.__doc[key], type); + }, + set(value) { + value = Cast(value, type); + if (value !== undefined) { + this.__doc[key] = value; + return; + } + throw new TypeError("Expected type " + type); + } + }); + } + return function (doc: any) { + const obj = Object.create(proto); + obj.__doc = doc; + return obj; + }; +} + +export function createSchema(schema: T): T { + return schema; +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From be5d2d30bdd98dfc32c28a84ad606eb2b4599932 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 19 Apr 2019 02:40:46 -0400 Subject: Kind of got list typing working for schemas --- src/client/views/nodes/ImageBox.tsx | 10 ++++----- src/debug/Test.tsx | 13 ++++++++--- src/fields/NewDoc.ts | 43 +++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 17 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index fe0b07bc0..71b431b84 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -38,7 +38,7 @@ export class ImageBox extends React.Component { onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - if (this._photoIndex == 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); + if (this._photoIndex === 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); } @@ -53,7 +53,7 @@ export class ImageBox extends React.Component { onDrop = (e: React.DragEvent) => { e.stopPropagation(); e.preventDefault(); - console.log("IMPLEMENT ME PLEASE") + console.log("IMPLEMENT ME PLEASE"); } @@ -145,9 +145,9 @@ export class ImageBox extends React.Component { let left = (nativeWidth - paths.length * dist) / 2; return paths.map((p, i) =>
-
{ e.stopPropagation(); this.onDotDown(i); }} /> +
{ e.stopPropagation(); this.onDotDown(i); }} />
- ) + ); } render() { @@ -159,7 +159,7 @@ export class ImageBox extends React.Component { let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1); return (
- Image not found + Image not found {paths.length > 1 ? this.dots(paths) : (null)} {this.lightbox(paths)}
); diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index b46eb4477..033615be6 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { serialize, deserialize, map } from 'serializr'; -import { URLField, Doc, createSchema, makeInterface, makeStrictInterface } from '../fields/NewDoc'; +import { URLField, Doc, createSchema, makeInterface, makeStrictInterface, List, ListSpec } from '../fields/NewDoc'; import { SerializationHelper } from '../client/util/SerializationHelper'; const schema1 = createSchema({ @@ -18,7 +18,7 @@ type TestDoc = makeInterface; const schema2 = createSchema({ hello: URLField, test: "boolean", - fields: "string", + fields: { List: "number" } as ListSpec, url: "number", testDoc: URLField }); @@ -26,6 +26,13 @@ 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(); }; @@ -53,7 +60,7 @@ class Test extends React.Component { assert(test1.myField === 20); assert(test2.hello === undefined); - assert(test2.fields === "test"); + // assert(test2.fields === "test"); assert(test2.test === undefined); assert(test2.url === undefined); assert(test2.testDoc === undefined); diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts index 150b8dae8..7be0d5146 100644 --- a/src/fields/NewDoc.ts +++ b/src/fields/NewDoc.ts @@ -107,6 +107,10 @@ export const FieldWaiting: FieldWaiting = null; const Self = Symbol("Self"); +export class List extends ObjectField { + [index: number]: T; +} + @Deserializable("doc").withFields(["id"]) export class Doc extends RefField { @@ -230,26 +234,47 @@ export type ToType = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : - T extends { new(...args: any[]): infer R } ? R : undefined; + T extends ListSpec ? List : + T extends { new(...args: any[]): infer R } ? R : never; + +export type ToConstructor = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : { new(...args: any[]): T }; export type ToInterface = { [P in keyof T]: ToType; }; +// type ListSpec = { List: FieldCtor> | ListSpec> }; +export type ListSpec = { List: FieldCtor }; + +// type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; + +type Head = T extends [any, ...any[]] ? T[0] : never; +type Tail = + ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; +type HasTail = T extends ([] | [any]) ? false : true; + interface Interface { - [key: string]: { new(...args: any[]): (ObjectField | RefField) } | "number" | "boolean" | "string"; + [key: string]: ToConstructor | ListSpec; + // [key: string]: ToConstructor | ListSpec; } -type FieldCtor = { new(): T } | "number" | "string" | "boolean"; +type FieldCtor = ToConstructor | ListSpec; -function Cast(field: Field | undefined, ctor: FieldCtor): T | undefined { +function Cast(field: Field | undefined, ctor: FieldCtor): ToType | undefined { if (field !== undefined) { if (typeof ctor === "string") { if (typeof field === ctor) { - return field as T; + return field as ToType; + } + } else if (typeof ctor === "object") { + if (field instanceof List) { + return field as ToType; } - } else if (field instanceof ctor) { - return field; + } else if (field instanceof (ctor as any)) { + return field as ToType; } } return undefined; @@ -277,10 +302,10 @@ export function makeStrictInterface(schema: T): (doc: Doc) const type = schema[key]; Object.defineProperty(proto, key, { get() { - return Cast(this.__doc[key], type); + return Cast(this.__doc[key], type as any); }, set(value) { - value = Cast(value, type); + value = Cast(value, type as any); if (value !== undefined) { this.__doc[key] = value; return; -- cgit v1.2.3-70-g09d2 From ecae4ae106be3e07471208cb93ec0965548d2d12 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 19 Apr 2019 05:40:10 -0400 Subject: Added decent amount of list support --- src/debug/Test.tsx | 8 +++ src/fields/NewDoc.ts | 190 ++++++++++++++++++++++++++++----------------------- 2 files changed, 111 insertions(+), 87 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 033615be6..6a677f80f 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -66,6 +66,14 @@ class Test extends React.Component { assert(test2.testDoc === undefined); test2.url = 35; assert(test2.url === 35); + const l = new List(); + //TODO push, and other array functions don't go through the proxy + l.push(1); + //TODO currently length, and any other string fields will get serialized + l.length = 3; + l[2] = 5; + console.log(l.slice()); + console.log(SerializationHelper.Serialize(l)); } render() { diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts index 7be0d5146..c22df4b70 100644 --- a/src/fields/NewDoc.ts +++ b/src/fields/NewDoc.ts @@ -1,6 +1,6 @@ import { observable, action } from "mobx"; import { UndoManager } from "../client/util/UndoManager"; -import { serializable, primitive, map, alias } from "serializr"; +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"; @@ -21,9 +21,10 @@ export abstract class RefField { } const Update = Symbol("Update"); +const OnUpdate = Symbol("OnUpdate"); const Parent = Symbol("Parent"); export class ObjectField { - protected [Update]?: (diff?: any) => void; + protected [OnUpdate]?: (diff?: any) => void; private [Parent]?: Doc; } @@ -107,92 +108,112 @@ export const FieldWaiting: FieldWaiting = null; const Self = Symbol("Self"); -export class List extends ObjectField { - [index: number]: T; +function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + if (SerializationHelper.IsSerializing()) { + target[prop] = value; + return true; + } + if (typeof prop === "symbol") { + target[prop] = value; + return true; + } + const curValue = target.__fields[prop]; + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { + // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically + // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way + return true; + } + if (value instanceof RefField) { + value = new ProxyField(value); + } + if (value instanceof ObjectField) { + if (value[Parent] && value[Parent] !== target) { + throw new Error("Can't put the same object in multiple documents at the same time"); + } + value[Parent] = target; + value[OnUpdate] = (diff?: any) => { + if (!diff) diff = SerializationHelper.Serialize(value); + target[Update]({ [prop]: diff }); + }; + } + if (curValue instanceof ObjectField) { + delete curValue[Parent]; + delete curValue[OnUpdate]; + } + target.__fields[prop] = value; + target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); + UndoManager.AddEvent({ + redo: () => receiver[prop] = value, + undo: () => receiver[prop] = curValue + }); + return true; } -@Deserializable("doc").withFields(["id"]) -export class Doc extends RefField { - - private static setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { - if (SerializationHelper.IsSerializing()) { - target[prop] = value; - return true; - } - if (typeof prop === "symbol") { - target[prop] = value; - return true; - } - const curValue = target.__fields[prop]; - if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { - // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically - // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way - return true; - } - if (value instanceof RefField) { - value = new ProxyField(value); - } - if (value instanceof ObjectField) { - if (value[Parent] && value[Parent] !== target) { - throw new Error("Can't put the same object in multiple documents at the same time"); - } - value[Parent] = target; - value[Update] = (diff?: any) => { - if (!diff) diff = SerializationHelper.Serialize(value); - target[Update]({ [prop]: diff }); - }; - } - if (curValue instanceof ObjectField) { - delete curValue[Parent]; - delete curValue[Update]; - } - target.__fields[prop] = value; - target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); - UndoManager.AddEvent({ - redo: () => receiver[prop] = value, - undo: () => receiver[prop] = curValue - }); - return true; +function getter(target: any, prop: string | symbol | number, receiver: any): any { + if (typeof prop === "symbol") { + return target.__fields[prop] || target[prop]; + } + if (SerializationHelper.IsSerializing()) { + return target[prop]; } + return getField(target, prop, receiver); +} - private static getter(target: any, prop: string | symbol | number, receiver: any): any { - if (typeof prop === "symbol") { - return target[prop]; - } - if (SerializationHelper.IsSerializing()) { - return target[prop]; +function getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { + const field = target.__fields[prop]; + if (field instanceof ProxyField) { + return field.value(callback); + } + if (field === undefined && !ignoreProto) { + const proto = getField(target, "prototype", true); + if (proto instanceof Doc) { + let field = proto[prop]; + callback && callback(field === null ? undefined : field); + return field; } - return Doc.getField(target, prop, receiver); } + callback && callback(field); + return field; - private static getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { - const field = target.__fields[prop]; - if (field instanceof ProxyField) { - return field.value(callback); - } - if (field === undefined && !ignoreProto) { - const proto = Doc.getField(target, "prototype", true); - if (proto instanceof Doc) { - let field = proto[prop]; - callback && callback(field === null ? undefined : field); - return field; - } - } - callback && callback(field); - return field; +} +@Deserializable("list") +class ListImpl extends ObjectField { + constructor() { + super(); + const list = new Proxy(this, { + set: function (a, b, c, d) { return setter(a, b, c, d); }, + get: getter, + deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + return list; } - static GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { - const self = doc[Self]; - return new Promise(res => Doc.getField(self, key, ignoreProto, res)); + [key: number]: T | null | undefined; + + @serializable(alias("fields", list(autoObject()))) + @observable + private __fields: (T | null | undefined)[] = []; + + private [Update] = (diff: any) => { + console.log(diff); + const update = this[OnUpdate]; + update && update(diff); } + private [Self] = this; +} +export type List = ListImpl & T[]; +export const List: { new (): List } = ListImpl as any; + +@Deserializable("doc").withFields(["id"]) +export class Doc extends RefField { constructor(id?: string, forceSave?: boolean) { super(id); const doc = new Proxy(this, { - set: Doc.setter, - get: Doc.getter, + set: setter, + get: getter, deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); @@ -216,20 +237,15 @@ export class Doc extends RefField { } export namespace Doc { + export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { + const self = doc[Self]; + return new Promise(res => getField(self, key, ignoreProto, res)); + } export const Prototype = Symbol("Prototype"); } export const GetAsync = Doc.GetAsync; -interface IDoc { - [key: string]: Field | null | undefined; -} - -interface ImageDocument extends IDoc { - data: URLField; - test: number; -} - export type ToType = T extends "string" ? string : T extends "number" ? number : @@ -261,20 +277,20 @@ interface Interface { // [key: string]: ToConstructor | ListSpec; } -type FieldCtor = ToConstructor | ListSpec; +type FieldCtor = ToConstructor | ListSpec; -function Cast(field: Field | undefined, ctor: FieldCtor): ToType | undefined { +function Cast>(field: Field | undefined, ctor: T): ToType | undefined { if (field !== undefined) { if (typeof ctor === "string") { if (typeof field === ctor) { - return field as ToType; + return field as ToType; } } else if (typeof ctor === "object") { if (field instanceof List) { - return field as ToType; + return field as ToType; } } else if (field instanceof (ctor as any)) { - return field as ToType; + return field as ToType; } } return undefined; -- cgit v1.2.3-70-g09d2 From e678ac7f21e0c44eaa8ad88577093cdb313e21bb Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 19 Apr 2019 23:13:17 -0400 Subject: Deleted more old fields and split new stuff into multiple files --- src/client/DocServer.ts | 2 +- src/client/util/SerializationHelper.ts | 2 +- src/debug/Test.tsx | 8 +- src/fields/HtmlField.ts | 25 --- src/fields/ListField.ts | 196 ------------------ src/fields/NewDoc.ts | 358 --------------------------------- src/fields/TupleField.ts | 59 ------ src/new_fields/Doc.ts | 90 +++++++++ src/new_fields/HtmlField.ts | 14 ++ src/new_fields/List.ts | 35 ++++ src/new_fields/Proxy.ts | 55 +++++ src/new_fields/Schema.ts | 47 +++++ src/new_fields/Types.ts | 58 ++++++ src/new_fields/URLField.ts | 25 +++ src/new_fields/util.ts | 73 +++++++ 15 files changed, 405 insertions(+), 642 deletions(-) delete mode 100644 src/fields/HtmlField.ts delete mode 100644 src/fields/ListField.ts delete mode 100644 src/fields/NewDoc.ts delete mode 100644 src/fields/TupleField.ts create mode 100644 src/new_fields/Doc.ts create mode 100644 src/new_fields/HtmlField.ts create mode 100644 src/new_fields/List.ts create mode 100644 src/new_fields/Proxy.ts create mode 100644 src/new_fields/Schema.ts create mode 100644 src/new_fields/Types.ts create mode 100644 src/new_fields/URLField.ts create mode 100644 src/new_fields/util.ts (limited to 'src/debug/Test.tsx') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 9a3e122e8..615e48af0 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,6 +1,6 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, Types } from "./../server/Message"; -import { Opt, FieldWaiting, RefField, HandleUpdate } from '../fields/NewDoc'; +import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index 7273c3fe4..ac70aba9d 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -1,5 +1,5 @@ import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema, primitive, SKIP } from "serializr"; -import { Field } from "../../fields/NewDoc"; +import { Field } from "../../new_fields/Doc"; export namespace SerializationHelper { let serializing: number = 0; diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 6a677f80f..8b9c9fa0b 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,8 +1,12 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { serialize, deserialize, map } from 'serializr'; -import { URLField, Doc, createSchema, makeInterface, makeStrictInterface, List, ListSpec } from '../fields/NewDoc'; import { SerializationHelper } from '../client/util/SerializationHelper'; +import { createSchema, makeInterface, makeStrictInterface } from '../new_fields/Schema'; +import { URLField } 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", diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts deleted file mode 100644 index a1d880070..000000000 --- a/src/fields/HtmlField.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BasicField } from "./BasicField"; -import { Types } from "../server/Message"; -import { FieldId } from "./Field"; - -export class HtmlField extends BasicField { - constructor(data: string = "", id?: FieldId, save: boolean = true) { - super(data, save, id); - } - - ToScriptString(): string { - return `new HtmlField("${this.Data}")`; - } - - Copy() { - return new HtmlField(this.Data); - } - - ToJson() { - return { - type: Types.Html, - data: this.Data, - id: this.Id, - }; - } -} \ No newline at end of file diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts deleted file mode 100644 index e24099126..000000000 --- a/src/fields/ListField.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { action, IArrayChange, IArraySplice, IObservableArray, observe, observable, Lambda } from "mobx"; -import { Server } from "../client/Server"; -import { UndoManager } from "../client/util/UndoManager"; -import { Types } from "../server/Message"; -import { BasicField } from "./BasicField"; -import { Field, FieldId } from "./Field"; -import { FieldMap } from "../client/SocketStub"; -import { ScriptField } from "./ScriptField"; - -export class ListField extends BasicField { - private _proxies: string[] = []; - private _scriptIds: string[] = []; - private scripts: ScriptField[] = []; - - constructor(data: T[] = [], scripts: ScriptField[] = [], id?: FieldId, save: boolean = true) { - super(data, save, id); - this.scripts = scripts; - this.updateProxies(); - this._scriptIds = this.scripts.map(script => script.Id); - if (save) { - Server.UpdateField(this); - } - this.observeList(); - } - - private _processingServerUpdate: boolean = false; - - private observeDisposer: Lambda | undefined; - private observeList(): void { - if (this.observeDisposer) { - this.observeDisposer(); - } - this.observeDisposer = observe(this.Data as IObservableArray, (change: IArrayChange | IArraySplice) => { - const target = change.object; - this.updateProxies(); - if (change.type === "splice") { - this.runScripts(change.removed, false); - UndoManager.AddEvent({ - undo: () => target.splice(change.index, change.addedCount, ...change.removed), - redo: () => target.splice(change.index, change.removedCount, ...change.added) - }); - this.runScripts(change.added, true); - } else { - this.runScripts([change.oldValue], false); - UndoManager.AddEvent({ - undo: () => target[change.index] = change.oldValue, - redo: () => target[change.index] = change.newValue - }); - this.runScripts([change.newValue], true); - } - if (!this._processingServerUpdate) { - Server.UpdateField(this); - } - }); - } - - private runScripts(fields: T[], added: boolean) { - for (const script of this.scripts) { - this.runScript(fields, script, added); - } - } - - private runScript(fields: T[], script: ScriptField, added: boolean) { - if (!this._processingServerUpdate) { - for (const field of fields) { - script.script.run({ field, added }); - } - } - } - - addScript(script: ScriptField) { - this.scripts.push(script); - this._scriptIds.push(script.Id); - - this.runScript(this.Data, script, true); - UndoManager.AddEvent({ - undo: () => this.removeScript(script), - redo: () => this.addScript(script), - }); - Server.UpdateField(this); - } - - removeScript(script: ScriptField) { - const index = this.scripts.indexOf(script); - if (index === -1) { - return; - } - this.scripts.splice(index, 1); - this._scriptIds.splice(index, 1); - UndoManager.AddEvent({ - undo: () => this.addScript(script), - redo: () => this.removeScript(script), - }); - this.runScript(this.Data, script, false); - Server.UpdateField(this); - } - - protected setData(value: T[]) { - this.runScripts(this.data, false); - - this.data = observable(value); - this.updateProxies(); - this.observeList(); - this.runScripts(this.data, true); - } - - private updateProxies() { - this._proxies = this.Data.map(field => field.Id); - } - - private arraysEqual(a: any[], b: any[]) { - if (a === b) return true; - if (a === null || b === null) return false; - if (a.length !== b.length) return false; - - // If you don't care about the order of the elements inside - // the array, you should sort both arrays here. - // Please note that calling sort on an array will modify that array. - // you might want to clone your array first. - - for (var i = 0; i < a.length; ++i) { - if (a[i] !== b[i]) return false; - } - return true; - } - - init(callback: (field: Field) => any) { - const fieldsPromise = Server.GetFields(this._proxies).then(action((fields: FieldMap) => { - if (!this.arraysEqual(this._proxies, this.data.map(field => field.Id))) { - var dataids = this.data.map(d => d.Id); - var proxies = this._proxies.map(p => p); - var added = this.data.length < this._proxies.length; - var deleted = this.data.length > this._proxies.length; - for (let i = 0; i < dataids.length && added; i++) { - added = proxies.indexOf(dataids[i]) !== -1; - } - for (let i = 0; i < this._proxies.length && deleted; i++) { - deleted = dataids.indexOf(proxies[i]) !== -1; - } - - this._processingServerUpdate = true; - for (let i = 0; i < proxies.length && added; i++) { - if (dataids.indexOf(proxies[i]) === -1) { - this.Data.splice(i, 0, fields[proxies[i]] as T); - } - } - for (let i = dataids.length - 1; i >= 0 && deleted; i--) { - if (proxies.indexOf(dataids[i]) === -1) { - this.Data.splice(i, 1); - } - } - if (!added && !deleted) {// otherwise, just rebuild the whole list - this.setData(proxies.map(id => fields[id] as T)); - } - this._processingServerUpdate = false; - } - })); - - const scriptsPromise = Server.GetFields(this._scriptIds).then((fields: FieldMap) => { - this.scripts = this._scriptIds.map(id => fields[id] as ScriptField); - }); - - Promise.all([fieldsPromise, scriptsPromise]).then(() => callback(this)); - } - - ToScriptString(): string { - return "new ListField([" + this.Data.map(field => field.ToScriptString()).join(", ") + "])"; - } - - Copy(): Field { - return new ListField(this.Data); - } - - - UpdateFromServer(data: { fields: string[], scripts: string[] }) { - this._proxies = data.fields; - this._scriptIds = data.scripts; - } - ToJson() { - return { - type: Types.List, - data: { - fields: this._proxies, - scripts: this._scriptIds, - }, - id: this.Id - }; - } - - static FromJson(id: string, data: { fields: string[], scripts: string[] }): ListField { - let list = new ListField([], [], id, false); - list._proxies = data.fields; - list._scriptIds = data.scripts; - return list; - } -} \ No newline at end of file diff --git a/src/fields/NewDoc.ts b/src/fields/NewDoc.ts deleted file mode 100644 index 70dc1867c..000000000 --- a/src/fields/NewDoc.ts +++ /dev/null @@ -1,358 +0,0 @@ -import { observable, action } from "mobx"; -import { UndoManager } from "../client/util/UndoManager"; -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"; - -export const HandleUpdate = Symbol("HandleUpdate"); -const Id = Symbol("Id"); -export abstract class RefField { - @serializable(alias("id", primitive())) - private __id: string; - readonly [Id]: string; - - constructor(id?: string) { - this.__id = id || Utils.GenerateGuid(); - this[Id] = this.__id; - } - - protected [HandleUpdate]?(diff: any): void; -} - -const Update = Symbol("Update"); -const OnUpdate = Symbol("OnUpdate"); -const Parent = Symbol("Parent"); -export class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; - private [Parent]?: Doc; -} - -function url() { - return { - serializer: function (value: URL) { - return value.href; - }, - deserializer: function (jsonValue: string, done: (err: any, val: any) => void) { - done(undefined, new URL(jsonValue)); - } - }; -} - -@Deserializable("url") -export class URLField extends ObjectField { - @serializable(url()) - readonly url: URL; - - constructor(url: URL) { - super(); - this.url = url; - } -} - -@Deserializable("proxy") -export class ProxyField extends ObjectField { - constructor(); - constructor(value: T); - constructor(value?: T) { - super(); - if (value) { - this.cache = value; - this.fieldId = value[Id]; - } - } - - @serializable(primitive()) - readonly fieldId: string = ""; - - // This getter/setter and nested object thing is - // because mobx doesn't play well with observable proxies - @observable.ref - private _cache: { readonly field: T | undefined } = { field: undefined }; - private get cache(): T | undefined { - return this._cache.field; - } - private set cache(field: T | undefined) { - this._cache = { field }; - } - - private failed = false; - private promise?: Promise; - - value(callback?: ((field: T | undefined) => void)): T | undefined | null { - if (this.cache) { - callback && callback(this.cache); - return this.cache; - } - if (this.failed) { - return undefined; - } - if (!this.promise) { - // this.promise = Server.GetField(this.fieldId).then(action((field: any) => { - // this.promise = undefined; - // this.cache = field; - // if (field === undefined) this.failed = true; - // return field; - // })); - this.promise = new Promise(r => r()); - } - callback && this.promise.then(callback); - return null; - } -} - -export type Field = number | string | boolean | ObjectField | RefField; -export type Opt = T | undefined; -export type FieldWaiting = null; -export const FieldWaiting: FieldWaiting = null; - -const Self = Symbol("Self"); - -function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { - if (SerializationHelper.IsSerializing()) { - target[prop] = value; - return true; - } - if (typeof prop === "symbol") { - target[prop] = value; - return true; - } - const curValue = target.__fields[prop]; - if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { - // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically - // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way - return true; - } - if (value instanceof RefField) { - value = new ProxyField(value); - } - if (value instanceof ObjectField) { - if (value[Parent] && value[Parent] !== target) { - throw new Error("Can't put the same object in multiple documents at the same time"); - } - value[Parent] = target; - value[OnUpdate] = (diff?: any) => { - if (!diff) diff = SerializationHelper.Serialize(value); - target[Update]({ [prop]: diff }); - }; - } - if (curValue instanceof ObjectField) { - delete curValue[Parent]; - delete curValue[OnUpdate]; - } - target.__fields[prop] = value; - target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); - UndoManager.AddEvent({ - redo: () => receiver[prop] = value, - undo: () => receiver[prop] = curValue - }); - return true; -} - -function getter(target: any, prop: string | symbol | number, receiver: any): any { - if (typeof prop === "symbol") { - return target.__fields[prop] || target[prop]; - } - if (SerializationHelper.IsSerializing()) { - return target[prop]; - } - return getField(target, prop, receiver); -} - -function getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { - const field = target.__fields[prop]; - if (field instanceof ProxyField) { - return field.value(callback); - } - if (field === undefined && !ignoreProto) { - const proto = getField(target, "prototype", true); - if (proto instanceof Doc) { - let field = proto[prop]; - callback && callback(field === null ? undefined : field); - return field; - } - } - callback && callback(field); - return field; - -} - -@Deserializable("list") -class ListImpl extends ObjectField { - constructor() { - super(); - const list = new Proxy(this, { - set: function (a, b, c, d) { return setter(a, b, c, d); }, - get: getter, - deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, - defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, - }); - return list; - } - - [key: number]: T | null | undefined; - - @serializable(alias("fields", list(autoObject()))) - @observable - private __fields: (T | null | undefined)[] = []; - - private [Update] = (diff: any) => { - console.log(diff); - const update = this[OnUpdate]; - update && update(diff); - } - - private [Self] = this; -} -export type List = ListImpl & T[]; -export const List: { new (): List } = ListImpl as any; - -@Deserializable("doc").withFields(["id"]) -export class Doc extends RefField { - constructor(id?: string, forceSave?: boolean) { - super(id); - const doc = new Proxy(this, { - set: setter, - get: getter, - deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, - defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, - }); - if (!id || forceSave) { - DocServer.CreateField(SerializationHelper.Serialize(doc)); - } - return doc; - } - - [key: string]: Field | null | undefined; - - @serializable(alias("fields", map(autoObject()))) - @observable - private __fields: { [key: string]: Field | null | undefined } = {}; - - private [Update] = (diff: any) => { - DocServer.UpdateField(this[Id], diff); - } - - private [Self] = this; -} - -export namespace Doc { - export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { - 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 { - const self = doc[Self]; - return new Promise(async res => { - const field = await GetAsync(doc, key, ignoreProto); - return Cast(field, ctor); - }); - } - export function Get(doc: Doc, key: string, ignoreProto: boolean = false): Field | null | undefined { - const self = doc[Self]; - return getField(self, key, ignoreProto); - } - export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): Field | null | undefined { - return Cast(Get(doc, key, ignoreProto), ctor); - } - export const Prototype = Symbol("Prototype"); -} - -export const GetAsync = Doc.GetAsync; - -export type ToType = - T extends "string" ? string : - T extends "number" ? number : - T extends "boolean" ? boolean : - T extends ListSpec ? List : - T extends { new(...args: any[]): infer R } ? R : never; - -export type ToConstructor = - T extends string ? "string" : - T extends number ? "number" : - T extends boolean ? "boolean" : { new(...args: any[]): T }; - -export type ToInterface = { - [P in keyof T]: ToType; -}; - -// type ListSpec = { List: FieldCtor> | ListSpec> }; -export type ListSpec = { List: FieldCtor }; - -// type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; - -type Head = T extends [any, ...any[]] ? T[0] : never; -type Tail = - ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; -type HasTail = T extends ([] | [any]) ? false : true; - -interface Interface { - [key: string]: ToConstructor | ListSpec; - // [key: string]: ToConstructor | ListSpec; -} - -type FieldCtor = ToConstructor | ListSpec; - -function Cast>(field: Field | null | undefined, ctor: T): ToType | null | undefined { - if (field !== undefined && field !== null) { - if (typeof ctor === "string") { - if (typeof field === ctor) { - return field as ToType; - } - } else if (typeof ctor === "object") { - if (field instanceof List) { - return field as ToType; - } - } else if (field instanceof (ctor as any)) { - return field as ToType; - } - } else { - return field; - } - return undefined; -} - -export type makeInterface = Partial> & Doc; -export function makeInterface(schema: T): (doc: Doc) => makeInterface { - return function (doc: any) { - return new Proxy(doc, { - get(target, prop) { - const field = target[prop]; - if (prop in schema) { - return Cast(field, (schema as any)[prop]); - } - return field; - } - }); - }; -} - -export type makeStrictInterface = Partial>; -export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { - const proto = {}; - for (const key in schema) { - const type = schema[key]; - Object.defineProperty(proto, key, { - get() { - return Cast(this.__doc[key], type as any); - }, - set(value) { - value = Cast(value, type as any); - if (value !== undefined) { - this.__doc[key] = value; - return; - } - throw new TypeError("Expected type " + type); - } - }); - } - return function (doc: any) { - const obj = Object.create(proto); - obj.__doc = doc; - return obj; - }; -} - -export function createSchema(schema: T): T { - return schema; -} \ No newline at end of file diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts deleted file mode 100644 index 347f1fa05..000000000 --- a/src/fields/TupleField.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { action, IArrayChange, IArraySplice, IObservableArray, observe, observable, Lambda } from "mobx"; -import { Server } from "../client/Server"; -import { UndoManager } from "../client/util/UndoManager"; -import { Types } from "../server/Message"; -import { BasicField } from "./BasicField"; -import { Field, FieldId } from "./Field"; - -export class TupleField extends BasicField<[T, U]> { - constructor(data: [T, U], id?: FieldId, save: boolean = true) { - super(data, save, id); - if (save) { - Server.UpdateField(this); - } - this.observeTuple(); - } - - private observeDisposer: Lambda | undefined; - private observeTuple(): void { - this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray, (change: IArrayChange | IArraySplice) => { - if (change.type === "update") { - UndoManager.AddEvent({ - undo: () => this.Data[change.index] = change.oldValue, - redo: () => this.Data[change.index] = change.newValue - }); - Server.UpdateField(this); - } else { - throw new Error("Why are you messing with the length of a tuple, huh?"); - } - }); - } - - protected setData(value: [T, U]) { - if (this.observeDisposer) { - this.observeDisposer(); - } - this.data = observable(value) as (T | U)[] as [T, U]; - this.observeTuple(); - } - - UpdateFromServer(values: [T, U]) { - this.setData(values); - } - - ToScriptString(): string { - return `new TupleField([${this.Data[0], this.Data[1]}])`; - } - - Copy(): Field { - return new TupleField(this.Data); - } - - ToJson() { - return { - type: Types.Tuple, - data: this.Data, - id: this.Id - }; - } -} \ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts new file mode 100644 index 000000000..c67170573 --- /dev/null +++ b/src/new_fields/Doc.ts @@ -0,0 +1,90 @@ +import { observable, action } from "mobx"; +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 } from "./util"; +import { Cast, FieldCtor } from "./Types"; + +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export abstract class RefField { + @serializable(alias("id", primitive())) + private __id: string; + readonly [Id]: string; + + constructor(id?: string) { + 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; +} + +export type Field = number | string | boolean | ObjectField | RefField; +export type Opt = T | undefined; +export type FieldWaiting = null; +export const FieldWaiting: FieldWaiting = null; + +export const Self = Symbol("Self"); + +@Deserializable("doc").withFields(["id"]) +export class Doc extends RefField { + constructor(id?: string, forceSave?: boolean) { + super(id); + const doc = new Proxy(this, { + set: setter, + get: getter, + deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + if (!id || forceSave) { + DocServer.CreateField(SerializationHelper.Serialize(doc)); + } + return doc; + } + + [key: string]: Field | null | undefined; + + @serializable(alias("fields", map(autoObject()))) + @observable + private __fields: { [key: string]: Field | null | undefined } = {}; + + private [Update] = (diff: any) => { + DocServer.UpdateField(this[Id], diff); + } + + private [Self] = this; +} + +export namespace Doc { + export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { + 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 { + const self = doc[Self]; + return new Promise(async res => { + const field = await GetAsync(doc, key, ignoreProto); + return Cast(field, ctor); + }); + } + export function Get(doc: Doc, key: string, ignoreProto: boolean = false): Field | null | undefined { + const self = doc[Self]; + return getField(self, key, ignoreProto); + } + export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): Field | null | undefined { + return Cast(Get(doc, key, ignoreProto), ctor); + } + export const Prototype = Symbol("Prototype"); +} + +export const GetAsync = Doc.GetAsync; \ No newline at end of file diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts new file mode 100644 index 000000000..f8e54ade5 --- /dev/null +++ b/src/new_fields/HtmlField.ts @@ -0,0 +1,14 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./Doc"; + +@Deserializable("html") +export class URLField extends ObjectField { + @serializable(primitive()) + readonly html: string; + + constructor(html: string) { + super(); + this.html = html; + } +} diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts new file mode 100644 index 000000000..a1a623f83 --- /dev/null +++ b/src/new_fields/List.ts @@ -0,0 +1,35 @@ +import { Deserializable, autoObject } from "../client/util/SerializationHelper"; +import { Field, ObjectField, Update, OnUpdate, Self } from "./Doc"; +import { setter, getter } from "./util"; +import { serializable, alias, list } from "serializr"; +import { observable } from "mobx"; + +@Deserializable("list") +class ListImpl extends ObjectField { + constructor() { + super(); + const list = new Proxy(this, { + set: function (a, b, c, d) { return setter(a, b, c, d); }, + get: getter, + deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + return list; + } + + [key: number]: T | null | undefined; + + @serializable(alias("fields", list(autoObject()))) + @observable + private __fields: (T | null | undefined)[] = []; + + private [Update] = (diff: any) => { + console.log(diff); + const update = this[OnUpdate]; + update && update(diff); + } + + private [Self] = this; +} +export type List = ListImpl & T[]; +export const List: { new (): List } = ListImpl as any; \ No newline at end of file diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts new file mode 100644 index 000000000..3b4b2e452 --- /dev/null +++ b/src/new_fields/Proxy.ts @@ -0,0 +1,55 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { RefField, Id, ObjectField } from "./Doc"; +import { primitive, serializable } from "serializr"; +import { observable } from "mobx"; + +@Deserializable("proxy") +export class ProxyField extends ObjectField { + constructor(); + constructor(value: T); + constructor(value?: T) { + super(); + if (value) { + this.cache = value; + this.fieldId = value[Id]; + } + } + + @serializable(primitive()) + readonly fieldId: string = ""; + + // This getter/setter and nested object thing is + // because mobx doesn't play well with observable proxies + @observable.ref + private _cache: { readonly field: T | undefined } = { field: undefined }; + private get cache(): T | undefined { + return this._cache.field; + } + private set cache(field: T | undefined) { + this._cache = { field }; + } + + private failed = false; + private promise?: Promise; + + value(callback?: ((field: T | undefined) => void)): T | undefined | null { + if (this.cache) { + callback && callback(this.cache); + return this.cache; + } + if (this.failed) { + return undefined; + } + if (!this.promise) { + // this.promise = Server.GetField(this.fieldId).then(action((field: any) => { + // this.promise = undefined; + // this.cache = field; + // if (field === undefined) this.failed = true; + // return field; + // })); + this.promise = new Promise(r => r()); + } + callback && this.promise.then(callback); + return null; + } +} diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts new file mode 100644 index 000000000..c7d2f0801 --- /dev/null +++ b/src/new_fields/Schema.ts @@ -0,0 +1,47 @@ +import { Interface, ToInterface, Cast } from "./Types"; +import { Doc } from "./Doc"; + +export type makeInterface = Partial> & Doc; +export function makeInterface(schema: T): (doc: Doc) => makeInterface { + return function (doc: any) { + return new Proxy(doc, { + get(target, prop) { + const field = target[prop]; + if (prop in schema) { + return Cast(field, (schema as any)[prop]); + } + return field; + } + }); + }; +} + +export type makeStrictInterface = Partial>; +export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { + const proto = {}; + for (const key in schema) { + const type = schema[key]; + Object.defineProperty(proto, key, { + get() { + return Cast(this.__doc[key], type as any); + }, + set(value) { + value = Cast(value, type as any); + if (value !== undefined) { + this.__doc[key] = value; + return; + } + throw new TypeError("Expected type " + type); + } + }); + } + return function (doc: any) { + const obj = Object.create(proto); + obj.__doc = doc; + return obj; + }; +} + +export function createSchema(schema: T): T { + return schema; +} diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts new file mode 100644 index 000000000..416298a64 --- /dev/null +++ b/src/new_fields/Types.ts @@ -0,0 +1,58 @@ +import { Field, Opt } from "./Doc"; +import { List } from "./List"; + +export type ToType = + T extends "string" ? string : + T extends "number" ? number : + T extends "boolean" ? boolean : + T extends ListSpec ? List : + T extends { new(...args: any[]): infer R } ? R : never; + +export type ToConstructor = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : { new(...args: any[]): T }; + +export type ToInterface = { + [P in keyof T]: ToType; +}; + +// type ListSpec = { List: FieldCtor> | ListSpec> }; +export type ListSpec = { List: FieldCtor }; + +// type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; + +export type Head = T extends [any, ...any[]] ? T[0] : never; +export type Tail = + ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; +export type HasTail = T extends ([] | [any]) ? false : true; + +export interface Interface { + [key: string]: ToConstructor | ListSpec; + // [key: string]: ToConstructor | ListSpec; +} + +export type FieldCtor = ToConstructor | ListSpec; + +export function Cast>(field: Field | null | undefined, ctor: T): ToType | null | undefined { + if (field !== undefined && field !== null) { + if (typeof ctor === "string") { + if (typeof field === ctor) { + return field as ToType; + } + } else if (typeof ctor === "object") { + if (field instanceof List) { + return field as ToType; + } + } else if (field instanceof (ctor as any)) { + return field as ToType; + } + } else { + return field; + } + return undefined; +} + +export function FieldValue(field: Opt | Promise>): Opt { + return field instanceof Promise ? undefined : field; +} diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts new file mode 100644 index 000000000..d27a2b692 --- /dev/null +++ b/src/new_fields/URLField.ts @@ -0,0 +1,25 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable } from "serializr"; +import { ObjectField } from "./Doc"; + +function url() { + return { + serializer: function (value: URL) { + return value.href; + }, + deserializer: function (jsonValue: string, done: (err: any, val: any) => void) { + done(undefined, new URL(jsonValue)); + } + }; +} + +@Deserializable("url") +export class URLField extends ObjectField { + @serializable(url()) + readonly url: URL; + + constructor(url: URL) { + super(); + this.url = url; + } +} \ No newline at end of file diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts new file mode 100644 index 000000000..0f08ecf03 --- /dev/null +++ b/src/new_fields/util.ts @@ -0,0 +1,73 @@ +import { UndoManager } from "../client/util/UndoManager"; +import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc"; +import { SerializationHelper } from "../client/util/SerializationHelper"; +import { ProxyField } from "./Proxy"; + +export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + if (SerializationHelper.IsSerializing()) { + target[prop] = value; + return true; + } + if (typeof prop === "symbol") { + target[prop] = value; + return true; + } + const curValue = target.__fields[prop]; + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { + // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically + // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way + return true; + } + if (value instanceof RefField) { + value = new ProxyField(value); + } + if (value instanceof ObjectField) { + if (value[Parent] && value[Parent] !== target) { + throw new Error("Can't put the same object in multiple documents at the same time"); + } + value[Parent] = target; + value[OnUpdate] = (diff?: any) => { + if (!diff) diff = SerializationHelper.Serialize(value); + target[Update]({ [prop]: diff }); + }; + } + if (curValue instanceof ObjectField) { + delete curValue[Parent]; + delete curValue[OnUpdate]; + } + target.__fields[prop] = value; + target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); + UndoManager.AddEvent({ + redo: () => receiver[prop] = value, + undo: () => receiver[prop] = curValue + }); + return true; +} + +export function getter(target: any, prop: string | symbol | number, receiver: any): any { + if (typeof prop === "symbol") { + return target.__fields[prop] || target[prop]; + } + if (SerializationHelper.IsSerializing()) { + return target[prop]; + } + return getField(target, prop, receiver); +} + +export function getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any { + const field = target.__fields[prop]; + if (field instanceof ProxyField) { + return field.value(callback); + } + if (field === undefined && !ignoreProto) { + const proto = getField(target, "prototype", true); + if (proto instanceof Doc) { + let field = proto[prop]; + callback && callback(field === null ? undefined : field); + return field; + } + } + callback && callback(field); + return field; + +} -- cgit v1.2.3-70-g09d2 From 1eb965a5d9c8aaebf1970bc645edecfb7017b601 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 20 Apr 2019 03:29:35 -0400 Subject: Made the switch in a couple more classes --- src/Utils.ts | 3 -- src/client/views/nodes/DocumentContentsView.tsx | 26 ++------------ src/client/views/nodes/DocumentView.tsx | 16 +++++++-- src/client/views/nodes/FieldView.tsx | 45 ++++++++++--------------- src/client/views/nodes/ImageBox.tsx | 41 +++++++++++++--------- src/debug/Test.tsx | 4 +-- src/new_fields/Doc.ts | 5 +-- src/new_fields/HtmlField.ts | 2 +- src/new_fields/Schema.ts | 24 +++++++++++-- src/new_fields/Types.ts | 19 +++++++---- 10 files changed, 98 insertions(+), 87 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 98f75d3b9..066d653f5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -2,7 +2,6 @@ import v4 = require('uuid/v4'); import v5 = require("uuid/v5"); import { Socket } from 'socket.io'; import { Message } from './server/Message'; -import { Document } from './fields/Document'; export class Utils { @@ -108,6 +107,4 @@ export function returnZero() { return 0; } export function emptyFunction() { } -export function emptyDocFunction(doc: Document) { } - export type Without = Pick>; \ No newline at end of file diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 07599c345..273401111 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,9 +1,5 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { FieldWaiting, Field } from "../../../fields/Field"; -import { Key } from "../../../fields/Key"; -import { KeyStore } from "../../../fields/KeyStore"; -import { ListField } from "../../../fields/ListField"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; @@ -22,46 +18,30 @@ import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); -import { Document } from "../../../fields/Document"; import { FieldViewProps } from "./FieldView"; import { Without, OmitKeys } from "../../../Utils"; +import { Cast } from "../../../new_fields/Types"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; export interface JsxBindings { props: BindingProps; - [keyName: string]: BindingProps | Field; } @observer export class DocumentContentsView extends React.Component boolean, select: (ctrl: boolean) => void, - layoutKey: Key + layoutKey: string }> { - @computed get layout(): string { return this.props.Document.GetText(this.props.layoutKey, "

Error loading layout data

"); } - @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array()); } - @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array()); } - + @computed get layout(): string { return Cast(this.props.Document[this.props.layoutKey], "string", "

Error loading layout data

"); } CreateBindings(): JsxBindings { let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive) }; - - for (const key of this.layoutKeys) { - bindings[key.Name + "Key"] = key; // this maps string values of the form Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data - } - for (const key of this.layoutFields) { - let field = this.props.Document.Get(key); - bindings[key.Name] = field && field !== FieldWaiting ? field.GetValue() : field; - } return bindings; } render() { - let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); - if (!lkeys || lkeys === FieldWaiting) { - return

Error loading layout keys

; - } return ; -const Document = makeInterface(schema); +export const positionSchema = createSchema({ + nativeWidth: "number", + nativeHeight: "number", + width: "number", + height: "number", + x: "number", + y: "number", +}); + +type Document = makeInterface<[typeof schema]>; +const Document = makeInterface([schema]); @observer export class DocumentView extends DocComponent(Document) { @@ -146,7 +155,7 @@ export class DocumentView extends DocComponent(Docu document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - if (!SelectionManager.IsSelected(this) && e.button !== 2) + if (!SelectionManager.IsSelected(this) && e.button !== 2) { if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { if (this.props.Document.Get(KeyStore.MaximizedDoc) instanceof Document) { this.props.Document.GetAsync(KeyStore.MaximizedDoc, maxdoc => { @@ -159,6 +168,7 @@ export class DocumentView extends DocComponent(Docu SelectionManager.SelectDoc(this, e.ctrlKey); } } + } } stopPropagation = (e: React.SyntheticEvent) => { e.stopPropagation(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 93e385821..d8de5afec 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,30 +1,21 @@ import React = require("react"); import { observer } from "mobx-react"; import { computed } from "mobx"; -import { Field, FieldWaiting, FieldValue, Opt } from "../../../fields/Field"; -import { Document } from "../../../fields/Document"; -import { TextField } from "../../../fields/TextField"; -import { NumberField } from "../../../fields/NumberField"; -import { RichTextField } from "../../../fields/RichTextField"; -import { ImageField } from "../../../fields/ImageField"; -import { VideoField } from "../../../fields/VideoField"; -import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; import { WebBox } from "./WebBox"; import { VideoBox } from "./VideoBox"; import { AudioBox } from "./AudioBox"; -import { AudioField } from "../../../fields/AudioField"; -import { ListField } from "../../../fields/ListField"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; -import { KeyStore } from "../../../fields/KeyStore"; -import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils"; +import { returnFalse, emptyFunction, returnOne } from "../../../Utils"; import { CollectionView } from "../collections/CollectionView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { IconField } from "../../../fields/IconFIeld"; import { IconBox } from "./IconBox"; +import { Opt, Doc, Field, FieldValue, FieldWaiting } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; // @@ -33,9 +24,9 @@ import { IconBox } from "./IconBox"; // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // export interface FieldViewProps { - fieldKey: Key; + fieldKey: string; ContainingCollectionView: Opt; - Document: Document; + Document: Doc; isSelected: () => boolean; select: (isCtrlPressed: boolean) => void; isTopMost: boolean; @@ -56,17 +47,17 @@ export class FieldView extends React.Component { } @computed - get field(): FieldValue { - const { Document: doc, fieldKey } = this.props; - return doc.Get(fieldKey); + get field(): FieldValue { + const { Document, fieldKey } = this.props; + return Document[fieldKey]; } render() { const field = this.field; if (!field) { return

{''}

; } - if (field instanceof TextField) { - return

{field.Data}

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

{field}

; } else if (field instanceof RichTextField) { return ; @@ -83,7 +74,7 @@ export class FieldView extends React.Component { else if (field instanceof AudioField) { return ; } - else if (field instanceof Document) { + else if (field instanceof Doc) { return ( { PanelHeight={() => 100} isTopMost={true} //TODO Why is this top most? selectOnLoad={false} - focus={emptyDocFunction} + focus={emptyFunction} isSelected={returnFalse} select={returnFalse} - layoutKey={KeyStore.Layout} + layoutKey={"layout"} ContainingCollectionView={this.props.ContainingCollectionView} parentActive={this.props.active} whenActiveChanged={this.props.whenActiveChanged} /> ); } - else if (field instanceof ListField) { + else if (field instanceof List) { return (
- {(field as ListField).Data.map(f => f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")} + {field.map(f => f instanceof Doc ? f.title : f.toString()).join(", ")}
); } // bcz: this belongs here, but it doesn't render well so taking it out for now // else if (field instanceof HtmlField) { // return // } - else if (field instanceof NumberField) { - return

{field.Data}

; + else if (typeof field === "number") { + return

{field}

; } else if (field !== FieldWaiting) { - return

{JSON.stringify(field.GetValue())}

; + return

{JSON.stringify(field)}

; } else { return

{"Waiting for server..."}

; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index fd5381b77..3b72e9f39 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -3,11 +3,6 @@ import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { Document } from '../../../fields/Document'; -import { FieldWaiting } from '../../../fields/Field'; -import { ImageField } from '../../../fields/ImageField'; -import { KeyStore } from '../../../fields/KeyStore'; -import { ListField } from '../../../fields/ListField'; import { Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; @@ -15,9 +10,23 @@ import { ContextMenu } from "../../views/ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); +import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { DocComponent } from '../DocComponent'; +import { positionSchema } from './DocumentView'; +import { FieldValue, Cast } from '../../../new_fields/Types'; +import { URLField } from '../../../new_fields/URLField'; +import { Doc, FieldWaiting } from '../../../new_fields/Doc'; +import { List } from '../../../new_fields/List'; + +const schema = createSchema({ + curPage: "number" +}); + +type ImageDocument = makeInterface<[typeof schema, typeof positionSchema]>; +const ImageDocument = makeInterface([schema, positionSchema]); @observer -export class ImageBox extends React.Component { +export class ImageBox extends DocComponent(ImageDocument) { public static LayoutString() { return FieldView.LayoutString(ImageBox); } private _imgRef: React.RefObject; @@ -39,8 +48,8 @@ export class ImageBox extends React.Component { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; if (this._photoIndex === 0) { - this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); - this.props.Document.SetNumber(KeyStore.Height, this.props.Document.Width() * h / w); + this.Document.nativeHeight = FieldValue(this.Document.nativeWidth, 0) * h / w; + this.Document.height = FieldValue(this.Document.width, 0) * h / w; } } @@ -126,9 +135,9 @@ export class ImageBox extends React.Component { } specificContextMenu = (e: React.MouseEvent): void => { - let field = this.props.Document.GetT(this.props.fieldKey, ImageField); + let field = Cast(this.Document[this.props.fieldKey], URLField); if (field && field !== FieldWaiting) { - let url = field.Data.href; + let url = field.url.href; ContextMenu.Instance.addItem({ description: "Copy path", event: () => { Utils.CopyText(url); @@ -140,11 +149,11 @@ export class ImageBox extends React.Component { @action onDotDown(index: number) { this._photoIndex = index; - this.props.Document.SetNumber(KeyStore.CurPage, index); + this.Document.curPage = index; } dots(paths: string[]) { - let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1); + let nativeWidth = FieldValue(this.Document.nativeWidth, 1); let dist = Math.min(nativeWidth / paths.length, 40); let left = (nativeWidth - paths.length * dist) / 2; return paths.map((p, i) => @@ -155,12 +164,12 @@ export class ImageBox extends React.Component { } render() { - let field = this.props.Document.Get(this.props.fieldKey); + let field = this.Document[this.props.fieldKey]; let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"]; if (field === FieldWaiting) paths = ["https://image.flaticon.com/icons/svg/66/66163.svg"]; - else if (field instanceof ImageField) paths = [field.Data.href]; - else if (field instanceof ListField) paths = field.Data.filter(val => val as ImageField).map(p => (p as ImageField).Data.href); - let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1); + else if (field instanceof URLField) paths = [field.url.href]; + else if (field instanceof List) paths = field.filter(val => val instanceof URLField).map(p => (p as URLField).url.href); + let nativeWidth = FieldValue(this.Document.nativeWidth, 1); return (
Image not found diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 8b9c9fa0b..81c69ca8e 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -16,8 +16,8 @@ const schema1 = createSchema({ testDoc: Doc }); -const TestDoc = makeInterface(schema1); -type TestDoc = makeInterface; +const TestDoc = makeInterface([schema1]); +type TestDoc = makeInterface<[typeof schema1]>; const schema2 = createSchema({ hello: URLField, diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 23a8c05cc..e0eb44ee9 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -33,6 +33,7 @@ export type Field = number | string | boolean | ObjectField | RefField; export type Opt = T | undefined; export type FieldWaiting = null; export const FieldWaiting: FieldWaiting = null; +export type FieldValue = Opt | FieldWaiting; export const Self = Symbol("Self"); @@ -81,8 +82,8 @@ export namespace Doc { const self = doc[Self]; return getField(self, key, ignoreProto); } - export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): Field | null | undefined { - return Cast(Get(doc, key, ignoreProto), ctor); + export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): T | null | undefined { + return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined; } export function MakeDelegate(doc: Opt): Opt { if (!doc) { diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index f8e54ade5..76fdb1f62 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -3,7 +3,7 @@ import { serializable, primitive } from "serializr"; import { ObjectField } from "./Doc"; @Deserializable("html") -export class URLField extends ObjectField { +export class HtmlField extends ObjectField { @serializable(primitive()) readonly html: string; diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 1607d4c15..1d1f56844 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -1,8 +1,26 @@ -import { Interface, ToInterface, Cast, FieldCtor, ToConstructor } from "./Types"; +import { Interface, ToInterface, Cast, FieldCtor, ToConstructor, HasTail, Head, Tail } from "./Types"; import { Doc } from "./Doc"; -export type makeInterface = Partial> & U; -export function makeInterface(schema: T): (doc: U) => makeInterface { +type All = { + 1: makeInterface, U> & All, U>, + 0: makeInterface, U> +}[HasTail extends true ? 1 : 0]; + +type AllToInterface = { + 1: ToInterface> & AllToInterface>, + 0: ToInterface> +}[HasTail extends true ? 1 : 0]; + +export type makeInterface = Partial> & U; +// export function makeInterface(schemas: T): (doc: U) => All; +// export function makeInterface(schema: T): (doc: U) => makeInterface; +export function makeInterface(schemas: T): (doc: U) => All { + let schema: Interface = {}; + for (const s of schemas) { + for (const key in s) { + schema[key] = s[key]; + } + } return function (doc: any) { return new Proxy(doc, { get(target, prop) { diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index cafb208ce..6ffb3e02f 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -27,14 +27,17 @@ export type Tail = ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; export type HasTail = T extends ([] | [any]) ? false : true; +//TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial export interface Interface { [key: string]: ToConstructor | ListSpec; // [key: string]: ToConstructor | ListSpec; } -export type FieldCtor = ToConstructor | ListSpec; +export type FieldCtor = T extends List ? ListSpec : ToConstructor; -export function Cast>(field: Field | null | undefined, ctor: T): ToType | null | undefined { +export function Cast>(field: Field | null | undefined, ctor: T): ToType | null | undefined; +export function Cast>(field: Field | null | undefined, ctor: T, defaultVal: ToType): ToType; +export function Cast>(field: Field | null | undefined, ctor: T, defaultVal?: ToType): ToType | null | undefined { if (field !== undefined && field !== null) { if (typeof ctor === "string") { if (typeof field === ctor) { @@ -42,17 +45,19 @@ export function Cast>(field: Field | null | undefined } } else if (typeof ctor === "object") { if (field instanceof List) { - return field as ToType; + return field as any; } } else if (field instanceof (ctor as any)) { return field as ToType; } } else { - return field; + return defaultVal; } - return undefined; + return defaultVal; } -export function FieldValue(field: Opt | Promise>): Opt { - return field instanceof Promise ? undefined : field; +export function FieldValue(field: Opt | Promise>, defaultValue: U): T; +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 393d351420b3a0d28f4cd1ea8b674fa5d04bfcde Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 21 Apr 2019 23:40:48 -0400 Subject: More fixes --- .../views/collections/CollectionDockingView.tsx | 6 ++-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 8 ++--- src/client/views/nodes/ImageBox.tsx | 15 +++++----- src/client/views/nodes/VideoBox.tsx | 35 ++++++++++++---------- src/client/views/nodes/WebBox.tsx | 4 +-- src/debug/Test.tsx | 12 ++++---- src/new_fields/Doc.ts | 4 +-- src/new_fields/Schema.ts | 22 +++----------- src/new_fields/Types.ts | 11 +++---- src/new_fields/URLField.ts | 9 ++++-- 12 files changed, 62 insertions(+), 68 deletions(-) (limited to 'src/debug/Test.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 7b204cbdc..86ee7cea9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -16,7 +16,7 @@ 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"; -import { Cast, FieldValue } from "../../../new_fields/Types"; +import { Cast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; @@ -336,8 +336,8 @@ export class DockedFrameRenderer extends React.Component { ScreenToLocalTransform = () => { if (this._mainCont.current && this._mainCont.current.children) { - let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!.children[0].firstChild as HTMLElement); - scale = Utils.GetScreenTransform(this._mainCont.current!).scale; + let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current.children[0].firstChild as HTMLElement); + scale = Utils.GetScreenTransform(this._mainCont.current).scale; return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling()); } return Transform.Identity(); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 27fd25b5c..c6eea5623 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -18,7 +18,7 @@ const schema = createSchema({ }); type FreeformDocument = makeInterface<[typeof schema, typeof positionSchema]>; -const FreeformDocument = makeInterface([schema, positionSchema]); +const FreeformDocument = makeInterface(schema, positionSchema); @observer export class CollectionFreeFormDocumentView extends DocComponent(FreeformDocument) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f1a12e6db..c0afc192e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -56,7 +56,7 @@ export const positionSchema = createSchema({ }); type Document = makeInterface<[typeof schema]>; -const Document = makeInterface([schema]); +const Document = makeInterface(schema); @observer export class DocumentView extends DocComponent(Document) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 845213366..b11a87d75 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -3,19 +3,19 @@ import { observer } from "mobx-react"; import { computed } from "mobx"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; -import { WebBox } from "./WebBox"; import { VideoBox } from "./VideoBox"; import { AudioBox } from "./AudioBox"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; -import { returnFalse, emptyFunction, returnOne } from "../../../Utils"; +import { returnFalse, emptyFunction } from "../../../Utils"; import { CollectionView } from "../collections/CollectionView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { IconField } from "../../../fields/IconFIeld"; import { IconBox } from "./IconBox"; -import { Opt, Doc, Field, FieldValue, FieldWaiting } from "../../../new_fields/Doc"; +import { Opt, Doc, FieldResult } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; +import { ImageField, VideoField, AudioField } from "../../../new_fields/URLField"; // @@ -47,7 +47,7 @@ export class FieldView extends React.Component { } @computed - get field(): FieldValue { + get field(): FieldResult { const { Document, fieldKey } = this.props; return Document[fieldKey]; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3b72e9f39..c11aee56e 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -14,16 +14,15 @@ import { createSchema, makeInterface } from '../../../new_fields/Schema'; import { DocComponent } from '../DocComponent'; import { positionSchema } from './DocumentView'; import { FieldValue, Cast } from '../../../new_fields/Types'; -import { URLField } from '../../../new_fields/URLField'; -import { Doc, FieldWaiting } from '../../../new_fields/Doc'; +import { ImageField } from '../../../new_fields/URLField'; import { List } from '../../../new_fields/List'; -const schema = createSchema({ +export const pageSchema = createSchema({ curPage: "number" }); -type ImageDocument = makeInterface<[typeof schema, typeof positionSchema]>; -const ImageDocument = makeInterface([schema, positionSchema]); +type ImageDocument = makeInterface<[typeof pageSchema, typeof positionSchema]>; +const ImageDocument = makeInterface(pageSchema, positionSchema); @observer export class ImageBox extends DocComponent(ImageDocument) { @@ -135,7 +134,7 @@ export class ImageBox extends DocComponent(ImageD } specificContextMenu = (e: React.MouseEvent): void => { - let field = Cast(this.Document[this.props.fieldKey], URLField); + let field = Cast(this.Document[this.props.fieldKey], ImageField); if (field && field !== FieldWaiting) { let url = field.url.href; ContextMenu.Instance.addItem({ @@ -167,8 +166,8 @@ export class ImageBox extends DocComponent(ImageD let field = this.Document[this.props.fieldKey]; let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"]; if (field === FieldWaiting) paths = ["https://image.flaticon.com/icons/svg/66/66163.svg"]; - else if (field instanceof URLField) paths = [field.url.href]; - else if (field instanceof List) paths = field.filter(val => val instanceof URLField).map(p => (p as URLField).url.href); + else if (field instanceof ImageField) paths = [field.url.href]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); let nativeWidth = FieldValue(this.Document.nativeWidth, 1); return (
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 9d7c2bc56..7b922b620 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,18 +1,22 @@ import React = require("react"); import { observer } from "mobx-react"; -import { FieldWaiting, Opt } from '../../../fields/Field'; -import { VideoField } from '../../../fields/VideoField'; import { FieldView, FieldViewProps } from './FieldView'; import "./VideoBox.scss"; import Measure from "react-measure"; -import { action, trace, observable, IReactionDisposer, computed, reaction } from "mobx"; -import { KeyStore } from "../../../fields/KeyStore"; -import { number } from "prop-types"; +import { action, computed } from "mobx"; +import { DocComponent } from "../DocComponent"; +import { positionSchema } from "./DocumentView"; +import { makeInterface } from "../../../new_fields/Schema"; +import { pageSchema } from "./ImageBox"; +import { Cast, FieldValue } from "../../../new_fields/Types"; +import { VideoField } from "../../../new_fields/URLField"; + +type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; +const VideoDocument = makeInterface(positionSchema, pageSchema); @observer -export class VideoBox extends React.Component { +export class VideoBox extends DocComponent(VideoDocument) { - private _reactionDisposer: Opt; private _videoRef = React.createRef(); public static LayoutString() { return FieldView.LayoutString(VideoBox); } @@ -20,7 +24,7 @@ export class VideoBox extends React.Component { super(props); } - @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } + @computed private get curPage() { return FieldValue(this.Document.curPage, -1); } _loaded: boolean = false; @@ -31,12 +35,12 @@ export class VideoBox extends React.Component { // 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 = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); - var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + var nativeWidth = FieldValue(this.Document.nativeWidth, 0); + var nativeHeight = FieldValue(this.Document.nativeHeight, 0); var newNativeHeight = nativeWidth * r.entry.height / r.entry.width; if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) { - this.props.Document.SetNumber(KeyStore.Height, newNativeHeight / nativeWidth * this.props.Document.GetNumber(KeyStore.Width, 0)); - this.props.Document.SetNumber(KeyStore.NativeHeight, newNativeHeight); + this.Document.height = newNativeHeight / nativeWidth * FieldValue(this.Document.width, 0); + this.Document.nativeHeight = newNativeHeight; } } else { this._loaded = true; @@ -56,12 +60,11 @@ export class VideoBox extends React.Component { } render() { - let field = this.props.Document.GetT(this.props.fieldKey, VideoField); - if (!field || field === FieldWaiting) { + let field = FieldValue(Cast(this.Document[this.props.fieldKey], VideoField)); + if (!field) { return
Loading
; } - let path = field.Data.href; - trace(); + let path = field.url.href; return ( {({ measureRef }) => diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index e3b6e1c05..63778fa50 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -4,7 +4,7 @@ import { FieldViewProps, FieldView } from './FieldView'; import { observer } from "mobx-react"; import { computed } from 'mobx'; import { HtmlField } from "../../../new_fields/HtmlField"; -import { URLField } from "../../../new_fields/URLField"; +import { WebField } from "../../../new_fields/URLField"; @observer export class WebBox extends React.Component { @@ -37,7 +37,7 @@ export class WebBox extends React.Component { let view; if (field instanceof HtmlField) { view = - } else if (field instanceof URLField) { + } else if (field instanceof WebField) { view =