From 9ea0f409cfc2a6c11bb1cf6e00015eb97900507b Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 10 Apr 2019 10:45:59 -0400 Subject: fixed uploading of csv files. --- src/fields/KeyStore.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src/fields') diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 425408273..da2d7268f 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -1,5 +1,4 @@ import { Key } from "./Key"; -import { KeyTransfer } from "../server/Message"; export namespace KeyStore { export const Prototype = new Key("Prototype"); -- cgit v1.2.3-70-g09d2 From 6dd21d8ca48beef6d5054f60d04bb4412b6b33b5 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 11 Apr 2019 17:16:46 -0400 Subject: Fixed another subtle server related bug Added optional capturing to scripts --- src/client/SocketStub.ts | 7 ++- src/client/util/Scripting.ts | 33 ++++++++---- .../views/collections/CollectionBaseView.tsx | 9 +++- src/fields/ScriptField.ts | 63 +++++++++++++++++----- 4 files changed, 85 insertions(+), 27 deletions(-) (limited to 'src/fields') diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 257973e3d..5e2ca6a98 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -62,10 +62,13 @@ export class SocketStub { public static SEND_FIELDS_REQUEST(fieldIds: FieldId[], callback: (fields: FieldMap) => any) { Utils.EmitCallback(Server.Socket, MessageStore.GetFields, fieldIds, (fields: any[]) => { let fieldMap: any = {}; + let proms: Promise[] = []; for (let field of fields) { - fieldMap[field._id] = ServerUtils.FromJson(field); + let f = ServerUtils.FromJson(field); + fieldMap[field._id] = f; + proms.push(new Promise(res => f.init(res))); } - callback(fieldMap); + Promise.all(proms).then(() => callback(fieldMap)); }); } diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 9015f21cf..c67cc067a 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -54,15 +54,20 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; let params: any[] = [KeyStore, Documents, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); + let { capturedVariables = {} } = options; let run = (args: { [name: string]: any } = {}): ScriptResult => { let argsArray: any[] = []; for (let name of customParams) { if (name === "this") { continue; } - argsArray.push(args[name]); + if (name in args) { + argsArray.push(args[name]); + } else { + argsArray.push(capturedVariables[name]); + } } - let thisParam = args.this; + let thisParam = args.this || capturedVariables.this; try { const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); return { success: true, result }; @@ -130,22 +135,30 @@ export interface ScriptOptions { requiredType?: string; addReturn?: boolean; params?: { [name: string]: string }; + capturedVariables?: { [name: string]: Field }; } -export function CompileScript(script: string, { requiredType = "", addReturn = false, params = {} }: ScriptOptions = {}): CompileResult { +export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult { + const { requiredType = "", addReturn = false, params = {}, capturedVariables = {} } = options; let host = new ScriptingCompilerHost; - let paramArray: string[] = []; - if ("this" in params) { - paramArray.push("this"); + let paramNames: string[] = []; + if ("this" in params || "this" in capturedVariables) { + paramNames.push("this"); } for (const key in params) { if (key === "this") continue; - paramArray.push(key); + paramNames.push(key); } - let paramString = paramArray.map(key => { + let paramList = paramNames.map(key => { const val = params[key]; return `${key}: ${val}`; - }).join(", "); + }); + for (const key in capturedVariables) { + if (key === "this") continue; + paramNames.push(key); + paramList.push(`${key}: ${capturedVariables[key].constructor.name}`); + } + let paramString = paramList.join(", "); let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} { ${addReturn ? `return ${script};` : script} })`; @@ -157,7 +170,7 @@ export function CompileScript(script: string, { requiredType = "", addReturn = f let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics); - return Run(outputText, paramArray, diagnostics, script, { requiredType, addReturn, params }); + return Run(outputText, paramNames, diagnostics, script, options); } export function OrLiteralType(returnType: string): string { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4380c8194..ac320eda3 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -8,6 +8,8 @@ import { ListField } from '../../../fields/ListField'; import { NumberField } from '../../../fields/NumberField'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; +import { CompileScript } from '../../util/Scripting'; +import { ScriptField } from '../../../fields/ScriptField'; export enum CollectionViewType { Invalid, @@ -107,15 +109,18 @@ export class CollectionBaseView extends React.Component { const field = new ListField([doc]); // const script = CompileScript(` // if(added) { - // console.log("added " + field.Title); + // console.log("added " + field.Title + " " + doc.Title); // } else { - // console.log("removed " + field.Title); + // console.log("removed " + field.Title + " " + doc.Title); // } // `, { // addReturn: false, // params: { // field: Document.name, // added: "boolean" + // }, + // capturedVariables: { + // doc: this.props.Document // } // }); // if (script.compiled) { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 24c1d9b3a..34c8a7544 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -2,33 +2,34 @@ import { Field, FieldId } from "./Field"; import { Types } from "../server/Message"; import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting"; import { Server } from "../client/Server"; +import { Without } from "../Utils"; + +export interface SerializableOptions extends Without { + capturedIds: { [id: string]: string }; +} export interface ScriptData { script: string; - options: ScriptOptions; + options: SerializableOptions; } export class ScriptField extends Field { - readonly script: CompiledScript; + private _script?: CompiledScript; + get script(): CompiledScript { + return this._script!; + } + private options?: ScriptData; - constructor(script: CompiledScript, id?: FieldId, save: boolean = true) { + constructor(script?: CompiledScript, id?: FieldId, save: boolean = true) { super(id); - this.script = script; + this._script = script; if (save) { Server.UpdateField(this); } } - static FromJson(id: string, data: ScriptData): ScriptField { - const script = CompileScript(data.script, data.options); - if (!script.compiled) { - throw new Error("Can't compile script"); - } - return new ScriptField(script, id, false); - } - ToScriptString() { return "new ScriptField(...)"; } @@ -45,14 +46,50 @@ export class ScriptField extends Field { throw new Error("Script fields currently can't be updated"); } + static FromJson(id: string, data: ScriptData): ScriptField { + let field = new ScriptField(undefined, id, false); + field.options = data; + return field; + } + + init(callback: (res: Field) => any) { + const options = this.options!; + const keys = Object.keys(options.options.capturedIds); + Server.GetFields(keys).then(fields => { + let captured: { [name: string]: Field } = {}; + keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]); + const opts: ScriptOptions = { + addReturn: options.options.addReturn, + params: options.options.params, + requiredType: options.options.requiredType, + capturedVariables: captured + }; + const script = CompileScript(options.script, opts); + if (!script.compiled) { + throw new Error("Can't compile script"); + } + this._script = script; + callback(this); + }); + } + ToJson(): { _id: string, type: Types, data: ScriptData } { const { options, originalScript } = this.script; + let capturedIds: { [id: string]: string } = {}; + for (const capt in options.capturedVariables) { + capturedIds[options.capturedVariables[capt].Id] = capt; + } + const opts: SerializableOptions = { + ...options, + capturedIds + }; + delete (opts as any).capturedVariables; return { _id: this.Id, type: Types.Script, data: { script: originalScript, - options + options: opts, }, }; } -- cgit v1.2.3-70-g09d2 From 5557c3b87df3119a3e53d2edb4bbdb9ae1deafc4 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 12 Apr 2019 18:28:54 -0400 Subject: fixed brushing --- src/client/Server.ts | 3 +++ src/client/northstar/dash-nodes/HistogramBox.tsx | 4 ---- src/client/util/DocumentManager.ts | 7 ++++-- src/client/views/Main.tsx | 16 ++++++++----- .../views/collections/CollectionBaseView.tsx | 11 +++++---- .../CollectionFreeFormLinksView.tsx | 26 +++++++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/fields/Document.ts | 4 ++-- 8 files changed, 42 insertions(+), 30 deletions(-) (limited to 'src/fields') diff --git a/src/client/Server.ts b/src/client/Server.ts index 3bbbebe72..fb5ad1c52 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -123,6 +123,9 @@ export class Server { callback(fieldfromserver); } } + if (!fieldfromserver && callback) { + console.log("Why didn't we get a field?") + } })); } } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 7df59ef07..2084fc346 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -47,10 +47,6 @@ export class HistogramBox extends React.Component { this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap; } - constructor(props: FieldViewProps) { - super(props); - } - @action dropX = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index f38b8ca75..b62287de8 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -28,8 +28,11 @@ export class DocumentManager { } public getAllDocumentViews(collection: Document) { - return this.DocumentViews.filter(dv => - dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document === collection); + return this.DocumentViews.filter(dv => { + console.log((dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document ? + dv.props.ContainingCollectionView.props.Document.Title : "--") + " = " + collection.Title); + return dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document === collection; + }); } public getDocumentView(toFind: Document): DocumentView | null { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index ac00be63c..3cf8f7c26 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -448,11 +448,11 @@ export class Main extends React.Component { @action AddToNorthstarCatalog(ctlog: Catalog) { CurrentUserUtils.NorthstarDBCatalog = CurrentUserUtils.NorthstarDBCatalog ? CurrentUserUtils.NorthstarDBCatalog : ctlog; if (ctlog && ctlog.schemas) { - this._northstarSchemas.push(...ctlog.schemas.map(schema => { - let schemaDoc = Documents.TreeDocument([], { width: 50, height: 100, title: schema.displayName! }); - let schemaDocuments = schemaDoc.GetList(KeyStore.Data, [] as Document[]); + ctlog.schemas.map(schema => { + let promises: Promise[] = []; + let schemaDocuments: Document[] = []; CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { - Server.GetField(attr.displayName! + ".alias", action((field: Opt) => { + let prom = Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { if (field instanceof Document) { schemaDocuments.push(field); } else { @@ -464,9 +464,13 @@ export class Main extends React.Component { schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); } })); + promises.push(prom); }); - return schemaDoc; - })); + Promise.all(promises).finally(() => { + let schemaDoc = Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }); + this._northstarSchemas.push(schemaDoc); + }) + }) } } async initializeNorthstar(): Promise { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 0ace700ce..b5eaab349 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -8,8 +8,6 @@ import { ListField } from '../../../fields/ListField'; import { NumberField } from '../../../fields/NumberField'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; -import { CompileScript } from '../../util/Scripting'; -import { ScriptField } from '../../../fields/ScriptField'; export enum CollectionViewType { Invalid, @@ -37,15 +35,15 @@ export interface CollectionViewProps extends FieldViewProps { @observer export class CollectionBaseView extends React.Component { - get collectionViewType(): CollectionViewType { + get collectionViewType(): CollectionViewType | undefined { let Document = this.props.Document; let viewField = Document.GetT(KeyStore.ViewType, NumberField); if (viewField === FieldWaiting) { - return CollectionViewType.Invalid; + return undefined; } else if (viewField) { return viewField.Data; } else { - return CollectionViewType.Freeform; + return CollectionViewType.Invalid; } } @@ -181,9 +179,10 @@ export class CollectionBaseView extends React.Component { active: this.active, onActiveChanged: this.onActiveChanged, }; + const viewtype = this.collectionViewType; return (
- {this.props.children(this.collectionViewType, props)} + {viewtype !== undefined ? this.props.children(viewtype, props) : (null)}
); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index cf058090d..40d7b25d3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,4 +1,4 @@ -import { computed, reaction } from "mobx"; +import { computed, reaction, trace, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../../fields/Document"; import { FieldWaiting } from "../../../../fields/Field"; @@ -15,18 +15,19 @@ import React = require("react"); @observer export class CollectionFreeFormLinksView extends React.Component { - HackToAvoidReactionFiringUnnecessarily?: Document = undefined; + _brushReactionDisposer?: IReactionDisposer; componentDidMount() { - this.HackToAvoidReactionFiringUnnecessarily = this.props.Document; - reaction(() => - DocumentManager.Instance.getAllDocumentViews(this.HackToAvoidReactionFiringUnnecessarily!). - map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)), + this._brushReactionDisposer = reaction(() => { + // trace(); + return this.props.Document.GetList(this.props.fieldKey, []).map(doc => doc.GetNumber(KeyStore.X, 0)); + }, () => { - let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document); + console.log("title = " + this.props.Document.Title); + let views = this.props.Document.GetList(this.props.fieldKey, []); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { - let srcDoc = views[j].props.Document; - let dstDoc = views[i].props.Document; + let srcDoc = views[j]; + let dstDoc = views[i]; let x1 = srcDoc.GetNumber(KeyStore.X, 0); let x1w = srcDoc.GetNumber(KeyStore.Width, -1); let x2 = dstDoc.GetNumber(KeyStore.X, 0); @@ -53,7 +54,7 @@ export class CollectionFreeFormLinksView extends React.Component) => { + brushAction = (field: ListField) => { if (findBrush(field) === -1) { console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); (findBrush(field) === -1) && field.Data.push(linkDoc); @@ -67,6 +68,11 @@ export class CollectionFreeFormLinksView extends React.Component Date: Sat, 13 Apr 2019 19:39:37 -0400 Subject: cleaning up network data transfer. --- src/Utils.ts | 4 +- src/client/Server.ts | 20 +-- src/client/SocketStub.ts | 58 ++------- src/client/northstar/dash-fields/HistogramField.ts | 5 +- src/fields/AudioField.ts | 4 +- src/fields/BooleanField.ts | 4 +- src/fields/Document.ts | 17 +-- src/fields/DocumentReference.ts | 4 +- src/fields/Field.ts | 4 +- src/fields/HtmlField.ts | 4 +- src/fields/ImageField.ts | 4 +- src/fields/InkField.ts | 4 +- src/fields/Key.ts | 4 +- src/fields/ListField.ts | 4 +- src/fields/NumberField.ts | 4 +- src/fields/PDFField.ts | 4 +- src/fields/RichTextField.ts | 4 +- src/fields/ScriptField.ts | 4 +- src/fields/TextField.ts | 4 +- src/fields/TupleField.ts | 4 +- src/fields/VideoField.ts | 4 +- src/fields/WebField.ts | 4 +- src/server/Message.ts | 137 ++------------------- src/server/ServerUtil.ts | 99 ++++++--------- src/server/database.ts | 64 +++++----- src/server/index.ts | 8 +- 26 files changed, 150 insertions(+), 330 deletions(-) (limited to 'src/fields') diff --git a/src/Utils.ts b/src/Utils.ts index c629bc263..2e672db9a 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,7 +1,7 @@ import v4 = require('uuid/v4'); import v5 = require("uuid/v5"); import { Socket } from 'socket.io'; -import { Message, Types } from './server/Message'; +import { Message, Types, Transferable } from './server/Message'; import { Document } from './fields/Document'; export class Utils { @@ -48,7 +48,7 @@ export class Utils { if (this.logFilter !== undefined && this.logFilter !== message.type) { return; } - let idString = (message._id || message.id || "").padStart(36, ' '); + let idString = (message.id || message.id || "").padStart(36, ' '); prefix = prefix.padEnd(16, ' '); console.log(`${prefix}: ${idString}, ${receiving ? 'receiving' : 'sending'} ${messageName} with data ${JSON.stringify(message)}`); } diff --git a/src/client/Server.ts b/src/client/Server.ts index 3bbbebe72..66e9878d9 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -12,7 +12,6 @@ export class Server { static Socket: SocketIOClient.Socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); 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). // Call this is from within a reaction and test whether the return value is FieldWaiting. public static GetField(fieldid: FieldId): Promise>; @@ -127,13 +126,6 @@ export class Server { } } - public static AddDocument(document: Document) { - SocketStub.SEND_ADD_DOCUMENT(document); - } - public static AddDocumentField(doc: Document, key: Key, value: Field) { - console.log("Add doc field " + doc.Title + " " + key.Name + " fid " + value.Id + " " + value); - SocketStub.SEND_ADD_DOCUMENT_FIELD(doc, key, value); - } public static DeleteDocumentField(doc: Document, key: Key) { SocketStub.SEND_DELETE_DOCUMENT_FIELD(doc, key); } @@ -161,18 +153,18 @@ export class Server { } @action - static updateField(field: { _id: string, data: any, type: Types }) { - if (Server.ClientFieldsCached.has(field._id)) { - var f = Server.ClientFieldsCached.get(field._id); + static updateField(field: { id: string, data: any, type: Types }) { + if (Server.ClientFieldsCached.has(field.id)) { + var f = Server.ClientFieldsCached.get(field.id); if (f) { - // console.log("Applying : " + field._id); + // console.log("Applying : " + field.id); f.UpdateFromServer(field.data); f.init(emptyFunction); } else { - // console.log("Not applying wa : " + field._id); + // console.log("Not applying wa : " + field.id); } } else { - // console.log("Not applying mi : " + field._id); + // console.log("Not applying mi : " + field.id); } } } diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 5e2ca6a98..382a81f66 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -2,7 +2,7 @@ import { Key } from "../fields/Key"; import { Field, FieldId, Opt } from "../fields/Field"; import { ObservableMap } from "mobx"; import { Document } from "../fields/Document"; -import { MessageStore, DocumentTransfer } from "../server/Message"; +import { MessageStore, Transferable } from "../server/Message"; import { Utils } from "../Utils"; import { Server } from "./Server"; import { ServerUtils } from "../server/ServerUtil"; @@ -16,35 +16,12 @@ export interface FieldMap { export class SocketStub { static FieldStore: ObservableMap = new ObservableMap(); - public static SEND_ADD_DOCUMENT(document: Document) { - - // Send a serialized version of the document to the server - // ...SOCKET(ADD_DOCUMENT, serialied document) - - // server stores each document field in its repository of stored fields - // document.fields.forEach((f, key) => this.FieldStore.set((f as Field).Id, f as Field)); - // let strippedDoc = new Document(document.Id); - // document.fields.forEach((f, key) => { - // if (f) { - // // let args: SetFieldArgs = new SetFieldArgs(f.Id, f.GetValue()) - // let args: Transferable = f.ToJson() - // Utils.Emit(Server.Socket, MessageStore.SetField, args) - // } - // }) - - // // server stores stripped down document (w/ only field id proxies) in the field store - // this.FieldStore.set(document.Id, new Document(document.Id)); - // 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())); - } public static SEND_FIELD_REQUEST(fieldid: FieldId): Promise>; public static SEND_FIELD_REQUEST(fieldid: FieldId, callback: (field: Opt) => void): void; public static SEND_FIELD_REQUEST(fieldid: FieldId, callback?: (field: Opt) => void): Promise> | void { let fn = function (cb: (field: Opt) => void) { - Utils.EmitCallback(Server.Socket, MessageStore.GetField, fieldid, (field: any) => { + Utils.EmitCallback(Server.Socket, MessageStore.GetField, fieldid, (field: Transferable) => { if (field) { ServerUtils.FromJson(field).init(cb); } else { @@ -60,36 +37,15 @@ export class SocketStub { } public static SEND_FIELDS_REQUEST(fieldIds: FieldId[], callback: (fields: FieldMap) => any) { - Utils.EmitCallback(Server.Socket, MessageStore.GetFields, fieldIds, (fields: any[]) => { - let fieldMap: any = {}; - let proms: Promise[] = []; - for (let field of fields) { - let f = ServerUtils.FromJson(field); - fieldMap[field._id] = f; - proms.push(new Promise(res => f.init(res))); - } + Utils.EmitCallback(Server.Socket, MessageStore.GetFields, fieldIds, (fields: Transferable[]) => { + let fieldMap: FieldMap = {}; + fields.map(field => fieldMap[field.id] = ServerUtils.FromJson(field)); + let proms = Object.values(fieldMap).map(val => + new Promise(resolve => val!.init(resolve))); Promise.all(proms).then(() => callback(fieldMap)); }); } - public static SEND_ADD_DOCUMENT_FIELD(doc: Document, key: Key, value: Field) { - - // Send a serialized version of the field to the server along with the - // associated info of the document id and key where it is used. - - // ...SOCKET(ADD_DOCUMENT_FIELD, document id, key id, serialized field) - - // server updates its document to hold a proxy mapping from key => fieldId - var document = this.FieldStore.get(doc.Id) as 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); - // Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(doc.ToJson())) - } - public static SEND_DELETE_DOCUMENT_FIELD(doc: Document, key: Key) { // Send a request to delete the field stored under the specified key from the document diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 6abde4677..82de51d56 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -35,12 +35,11 @@ export class HistogramField extends BasicField { } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.HistogramOp, - data: this.toString(), - _id: this.Id + id: this.Id }; } diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts index 996d2556d..87e47a715 100644 --- a/src/fields/AudioField.ts +++ b/src/fields/AudioField.ts @@ -20,11 +20,11 @@ export class AudioField extends BasicField { return new AudioField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Audio, data: this.Data.href, - _id: this.Id + id: this.Id }; } diff --git a/src/fields/BooleanField.ts b/src/fields/BooleanField.ts index d319b4021..d49bfe82b 100644 --- a/src/fields/BooleanField.ts +++ b/src/fields/BooleanField.ts @@ -15,11 +15,11 @@ export class BooleanField extends BasicField { return new BooleanField(this.Data); } - ToJson(): { type: Types; data: boolean; _id: string } { + ToJson() { return { type: Types.Boolean, data: this.Data, - _id: this.Id + id: this.Id }; } } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 628fe684c..7cf784f0e 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -26,6 +26,12 @@ export class Document extends Field { Server.UpdateField(this); } } + static FromJson(data: any, id: string, save: boolean): Document { + let doc = new Document(id, save); + let fields = data as [string, string][]; + fields.forEach(pair => doc._proxies.set(pair[0], pair[1])); + return doc; + } UpdateFromServer(data: [string, string][]) { for (const key in data) { @@ -410,18 +416,15 @@ export class Document extends Field { return copy; } - ToJson(): { type: Types; data: [string, string][]; _id: string } { + ToJson() { let fields: [string, string][] = []; - this._proxies.forEach((field, key) => { - if (field) { - fields.push([key, field]); - } - }); + this._proxies.forEach((field, key) => + field && fields.push([key, field])); return { type: Types.Document, data: fields, - _id: this.Id + id: this.Id }; } } diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 6c0c1ef82..303754177 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -47,11 +47,11 @@ export class DocumentReference extends Field { return ""; } - ToJson(): { type: Types, data: FieldId, _id: string } { + ToJson() { return { type: Types.DocumentReference, data: this.document.Id, - _id: this.Id + id: this.Id }; } } \ No newline at end of file diff --git a/src/fields/Field.ts b/src/fields/Field.ts index d9db23b9e..3b3e95c2b 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -1,6 +1,6 @@ import { Utils } from "../Utils"; -import { Types } from "../server/Message"; +import { Types, Transferable } from "../server/Message"; import { computed } from "mobx"; export function Cast(field: FieldValue, ctor: { new(): T }): Opt { @@ -65,5 +65,5 @@ export abstract class Field { abstract Copy(): Field; - abstract ToJson(): { _id: string, type: Types, data: any }; + abstract ToJson(): Transferable; } \ No newline at end of file diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts index 65665cf7a..a1d880070 100644 --- a/src/fields/HtmlField.ts +++ b/src/fields/HtmlField.ts @@ -15,11 +15,11 @@ export class HtmlField extends BasicField { return new HtmlField(this.Data); } - ToJson(): { _id: string; type: Types; data: string; } { + ToJson() { return { type: Types.Html, data: this.Data, - _id: this.Id, + id: this.Id, }; } } \ No newline at end of file diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index dd843026f..bce20f242 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -19,11 +19,11 @@ export class ImageField extends BasicField { return new ImageField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Image, data: this.Data.href, - _id: this.Id + id: this.Id }; } } \ No newline at end of file diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index ab706ee30..2eacd7d0c 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -31,11 +31,11 @@ export class InkField extends BasicField { return new InkField(this.Data); } - ToJson(): { _id: string; type: Types; data: any; } { + ToJson() { return { type: Types.Ink, data: this.Data, - _id: this.Id, + id: this.Id, }; } diff --git a/src/fields/Key.ts b/src/fields/Key.ts index c7f806b88..57e2dadf0 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -40,11 +40,11 @@ export class Key extends Field { return name; } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Key, data: this.name, - _id: this.Id + id: this.Id }; } } \ No newline at end of file diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 8311e737b..e24099126 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -176,14 +176,14 @@ export class ListField extends BasicField { this._proxies = data.fields; this._scriptIds = data.scripts; } - ToJson(): { type: Types, data: { fields: string[], scripts: string[] }, _id: string } { + ToJson() { return { type: Types.List, data: { fields: this._proxies, scripts: this._scriptIds, }, - _id: this.Id + id: this.Id }; } diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index 45b920e31..7eea360c0 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -15,9 +15,9 @@ export class NumberField extends BasicField { return new NumberField(this.Data); } - ToJson(): { _id: string, type: Types, data: number } { + ToJson() { return { - _id: this.Id, + id: this.Id, type: Types.Number, data: this.Data }; diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index 65e179894..718a1a4c0 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -22,11 +22,11 @@ export class PDFField extends BasicField { return `new PDFField("${this.Data}")`; } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.PDF, data: this.Data.href, - _id: this.Id + id: this.Id }; } diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 6f7b3074a..f53f48ca6 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -15,11 +15,11 @@ export class RichTextField extends BasicField { return new RichTextField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.RichText, data: this.Data, - _id: this.Id + id: this.Id }; } diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 34c8a7544..7f87be45d 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -73,7 +73,7 @@ export class ScriptField extends Field { }); } - ToJson(): { _id: string, type: Types, data: ScriptData } { + ToJson() { const { options, originalScript } = this.script; let capturedIds: { [id: string]: string } = {}; for (const capt in options.capturedVariables) { @@ -85,7 +85,7 @@ export class ScriptField extends Field { }; delete (opts as any).capturedVariables; return { - _id: this.Id, + id: this.Id, type: Types.Script, data: { script: originalScript, diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index 69d26f42f..ddedec9b1 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -15,11 +15,11 @@ export class TextField extends BasicField { return new TextField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Text, data: this.Data, - _id: this.Id + id: this.Id }; } } \ No newline at end of file diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts index ad0f6f350..347f1fa05 100644 --- a/src/fields/TupleField.ts +++ b/src/fields/TupleField.ts @@ -49,11 +49,11 @@ export class TupleField extends BasicField<[T, U]> { return new TupleField(this.Data); } - ToJson(): { type: Types, data: [T, U], _id: string } { + ToJson() { return { type: Types.Tuple, data: this.Data, - _id: this.Id + id: this.Id }; } } \ No newline at end of file diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts index d7cd7e968..838b811b1 100644 --- a/src/fields/VideoField.ts +++ b/src/fields/VideoField.ts @@ -19,11 +19,11 @@ export class VideoField extends BasicField { return new VideoField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Video, data: this.Data.href, - _id: this.Id + id: this.Id }; } diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 6023e9e6b..8b276a552 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -19,11 +19,11 @@ export class WebField extends BasicField { return new WebField(this.Data); } - ToJson(): { type: Types, data: string, _id: string } { + ToJson() { return { type: Types.Web, data: this.Data.href, - _id: this.Id + id: this.Id }; } diff --git a/src/server/Message.ts b/src/server/Message.ts index d22e5c17c..bbe4ffcad 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -1,146 +1,35 @@ import { Utils } from "../Utils"; export class Message { - private name: string; - private guid: string; - - get Name(): string { - return this.name; - } - - get Message(): string { - return this.guid; - } + private _name: string; + private _guid: string; constructor(name: string) { - this.name = name; - this.guid = Utils.GenerateDeterministicGuid(name); - } - - GetValue() { - return this.Name; - } -} - -class TestMessageArgs { - hello: string = ""; -} - -export class SetFieldArgs { - field: string; - value: any; - - constructor(f: string, v: any) { - this.field = f; - this.value = v; + this._name = name; + this._guid = Utils.GenerateDeterministicGuid(name); } -} -export class GetFieldArgs { - field: string; - - constructor(f: string) { - this.field = f; - } + get Name(): string { return this._name; } + get Message(): string { return this._guid; } } export enum Types { - Number, - List, - Key, - Image, - Web, - Document, - Text, - RichText, - DocumentReference, - Html, - Video, - Audio, - Ink, - PDF, - Tuple, - HistogramOp, - Boolean, - Script, -} - -export class DocumentTransfer implements Transferable { - readonly type = Types.Document; - _id: string; - - constructor( - readonly obj: { type: Types; data: [string, string][]; _id: string } - ) { - this._id = obj._id; - } -} - -export class ImageTransfer implements Transferable { - readonly type = Types.Image; - - constructor(readonly _id: string) { } -} - -export class KeyTransfer implements Transferable { - name: string; - readonly _id: string; - readonly type = Types.Key; - - constructor(i: string, n: string) { - this.name = n; - this._id = i; - } -} - -export class ListTransfer implements Transferable { - type = Types.List; - - constructor(readonly _id: string) { } -} - -export class NumberTransfer implements Transferable { - readonly type = Types.Number; - - constructor(readonly value: number, readonly _id: string) { } -} - -export class TextTransfer implements Transferable { - value: string; - readonly _id: string; - readonly type = Types.Text; - - constructor(t: string, i: string) { - this.value = t; - this._id = i; - } -} - -export class RichTextTransfer implements Transferable { - value: string; - readonly _id: string; - readonly type = Types.Text; - - constructor(t: string, i: string) { - this.value = t; - this._id = i; - } + Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, + Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, } export interface Transferable { - readonly _id: string; + readonly id: string; readonly type: Types; + readonly data?: any; } export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); - export const AddDocument = new Message("Add Document"); - export const SetField = new Message<{ _id: string; data: any; type: Types }>( - "Set Field" - ); - export const GetField = new Message("Get Field"); - export const GetFields = new Message("Get Fields"); + export const SetField = new Message("Set Field"); // send Transferable (no reply) + export const GetField = new Message("Get Field"); // send string 'id' get Transferable back + 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"); } diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 0973f82b1..818230c1a 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -1,83 +1,56 @@ -import { Field } from "./../fields/Field"; -import { TextField } from "./../fields/TextField"; -import { NumberField } from "./../fields/NumberField"; -import { RichTextField } from "./../fields/RichTextField"; -import { Key } from "./../fields/Key"; -import { ImageField } from "./../fields/ImageField"; -import { ListField } from "./../fields/ListField"; -import { Document } from "./../fields/Document"; -import { Server } from "./../client/Server"; -import { Types } from "./Message"; -import { Utils } from "../Utils"; -import { HtmlField } from "../fields/HtmlField"; -import { WebField } from "../fields/WebField"; +import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; import { AudioField } from "../fields/AudioField"; -import { VideoField } from "../fields/VideoField"; +import { BooleanField } from "../fields/BooleanField"; +import { HtmlField } from "../fields/HtmlField"; import { InkField } from "../fields/InkField"; import { PDFField } from "../fields/PDFField"; -import { TupleField } from "../fields/TupleField"; -import { BooleanField } from "../fields/BooleanField"; -import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; import { ScriptField } from "../fields/ScriptField"; +import { TupleField } from "../fields/TupleField"; +import { VideoField } from "../fields/VideoField"; +import { WebField } from "../fields/WebField"; +import { Utils } from "../Utils"; +import { Document } from "./../fields/Document"; +import { Field } from "./../fields/Field"; +import { ImageField } from "./../fields/ImageField"; +import { Key } from "./../fields/Key"; +import { ListField } from "./../fields/ListField"; +import { NumberField } from "./../fields/NumberField"; +import { RichTextField } from "./../fields/RichTextField"; +import { TextField } from "./../fields/TextField"; +import { Transferable, Types } from "./Message"; export class ServerUtils { public static prepend(extension: string): string { return window.location.origin + extension; } - public static FromJson(json: any): Field { - let obj = json; - let data: any = obj.data; - let id: string = obj._id; - let type: Types = obj.type; + public static FromJson(json: Transferable): Field { - if (!(data !== undefined && id && type !== undefined)) { + if (!(json.data !== undefined && json.id && json.type !== undefined)) { console.log( "how did you manage to get an object that doesn't have a data or an id?" ); return new TextField("Something to fill the space", Utils.GenerateGuid()); } - switch (type) { - case Types.Boolean: - return new BooleanField(data, id, false); - case Types.Number: - return new NumberField(data, id, false); - case Types.Text: - return new TextField(data, id, false); - case Types.Html: - return new HtmlField(data, id, false); - case Types.Web: - return new WebField(new URL(data), id, false); - case Types.RichText: - return new RichTextField(data, id, false); - case Types.Key: - return new Key(data, id, false); - case Types.Image: - return new ImageField(new URL(data), id, false); - case Types.HistogramOp: - return HistogramField.FromJson(id, data); - case Types.PDF: - return new PDFField(new URL(data), id, false); - case Types.List: - return ListField.FromJson(id, data); - case Types.Script: - return ScriptField.FromJson(id, data); - case Types.Audio: - return new AudioField(new URL(data), id, false); - case Types.Video: - return new VideoField(new URL(data), id, false); - case Types.Tuple: - return new TupleField(data, id, false); - case Types.Ink: - return InkField.FromJson(id, data); - case Types.Document: - let doc: Document = new Document(id, false); - let fields: [string, string][] = data as [string, string][]; - fields.forEach(element => { - doc._proxies.set(element[0], element[1]); - }); - return doc; + switch (json.type) { + case Types.Boolean: return new BooleanField(json.data, json.id, false); + case Types.Number: return new NumberField(json.data, json.id, false); + case Types.Text: return new TextField(json.data, json.id, false); + case Types.Html: return new HtmlField(json.data, json.id, false); + case Types.Web: return new WebField(new URL(json.data), json.id, false); + case Types.RichText: return new RichTextField(json.data, json.id, false); + case Types.Key: return new Key(json.data, json.id, false); + case Types.Image: return new ImageField(new URL(json.data), json.id, false); + case Types.HistogramOp: return HistogramField.FromJson(json.id, json.data); + case Types.PDF: return new PDFField(new URL(json.data), json.id, false); + case Types.List: return ListField.FromJson(json.id, json.data); + case Types.Script: return ScriptField.FromJson(json.id, json.data); + case Types.Audio: return new AudioField(new URL(json.data), json.id, false); + case Types.Video: return new VideoField(new URL(json.data), json.id, false); + case Types.Tuple: return new TupleField(json.data, json.id, false); + case Types.Ink: return InkField.FromJson(json.id, json.data); + case Types.Document: return Document.FromJson(json.data, json.id, false); default: throw Error( "Error, unrecognized field type received from server. If you just created a new field type, be sure to add it here" diff --git a/src/server/database.ts b/src/server/database.ts index e08385d98..c51d4a3f6 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,47 +1,55 @@ import * as mongodb from 'mongodb'; +import { Transferable } from './Message'; export class Database { public static DocumentsCollection = 'documents'; public static Instance = new Database(); private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; - private currentWrites: { [_id: string]: Promise } = {}; + private currentWrites: { [id: string]: Promise } = {}; private db?: mongodb.Db; constructor() { this.MongoClient.connect(this.url, (err, client) => this.db = client.db()); } - public update(id: string, value: any, callback: () => void, collectionName = Database.DocumentsCollection) { + public update(id: string, value: any, callback: () => void) { if (this.db) { - let collection = this.db.collection(collectionName); + let collection = this.db.collection('documents'); const prom = this.currentWrites[id]; + let newProm: Promise; const run = (): Promise => { - let newProm = new Promise(resolve => { - collection.updateOne({ _id: id }, { $set: value }, { upsert: true } - , (err, res) => { - if (err) { - console.log(err.message); - console.log(err.errmsg); - } - // if (res) { - // console.log(JSON.stringify(res.result)); - // } - if (this.currentWrites[id] === newProm) { - delete this.currentWrites[id]; - } - resolve(); - callback(); - }); + return new Promise(resolve => { + collection.updateOne({ _id: id }, { $set: value }, { + upsert: true + }, (err, res) => { + if (err) { + console.log(err.message); + console.log(err.errmsg); + } + // if (res) { + // console.log(JSON.stringify(res.result)); + // } + if (this.currentWrites[id] === newProm) { + delete this.currentWrites[id]; + } + resolve(); + callback(); + }); }); - return newProm; }; - this.currentWrites[id] = prom ? prom.then(run) : run(); + if (prom) { + newProm = prom.then(run); + this.currentWrites[id] = newProm; + } else { + newProm = run(); + this.currentWrites[id] = newProm; + } } } public delete(id: string, collectionName = Database.DocumentsCollection) { - this.db && this.db.collection(collectionName).remove({ _id: id }); + this.db && this.db.collection(collectionName).remove({ id: id }); } public deleteAll(collectionName = Database.DocumentsCollection): Promise { @@ -55,18 +63,18 @@ export class Database { ); } - public getDocument(id: string, fn: (res: any) => void, collectionName = Database.DocumentsCollection) { - this.db && this.db.collection(collectionName).findOne({ _id: id }, (err, result) => - fn(result ? result : undefined)); + public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { + this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => + fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)) } - public getDocuments(ids: string[], fn: (res: any) => void, collectionName = Database.DocumentsCollection) { - this.db && this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { + public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { + this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } - fn(docs); + fn(docs.map(doc => ({ id: doc._id, type: doc.type, data: doc.data }))); }); } diff --git a/src/server/index.ts b/src/server/index.ts index a6fe6fa2c..a86638186 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -246,17 +246,17 @@ function barReceived(guid: String) { clients[guid.toString()] = new Client(guid.toString()); } -function getField([id, callback]: [string, (result: any) => void]) { - Database.Instance.getDocument(id, (result: any) => +function getField([id, callback]: [string, (result?: Transferable) => void]) { + Database.Instance.getDocument(id, (result?: Transferable) => callback(result ? result : undefined)); } -function getFields([ids, callback]: [string[], (result: any) => void]) { +function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) { Database.Instance.getDocuments(ids, callback); } function setField(socket: Socket, newValue: Transferable) { - Database.Instance.update(newValue._id, newValue, () => + Database.Instance.update(newValue.id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); } -- cgit v1.2.3-70-g09d2 From 7e05ea0058766a3afa2ec82f6312f2df87178883 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 14 Apr 2019 12:23:10 -0400 Subject: starting to add LOD --- src/client/views/Main.tsx | 1 + .../views/collections/CollectionBaseView.tsx | 6 +- .../views/collections/CollectionDockingView.tsx | 1 + .../views/collections/CollectionSchemaView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 72 +++++++++++++--------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 13 ++-- src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/FieldView.tsx | 1 + src/fields/KeyStore.ts | 1 + 9 files changed, 57 insertions(+), 40 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index ed61aa5a7..babd3be2a 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -295,6 +295,7 @@ export class Main extends React.Component { { } return false; } + @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? @action.bound addDocument(doc: Document, allowDuplicates: boolean = false): boolean { let props = this.props; var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); + if (this.isAnnotationOverlay) { + doc.SetOnPrototype(KeyStore.Zoom, new NumberField(this.props.Document.GetNumber(KeyStore.Scale, 1))); + } if (curPage >= 0) { doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index eb1cd1c09..6d772b90e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -343,6 +343,7 @@ export class DockedFrameRenderer extends React.Component { - this.props.addDocument(this.bringToFront(newBox), false) + public addDocument = (newBox: Document, allowDuplicates: boolean) => { + if (this.isAnnotationOverlay) { + newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); + } + return this.props.addDocument(this.bringToFront(newBox), false); + } public selectDocuments = (docs: Document[]) => { SelectionManager.DeselectAll; @@ -131,25 +135,27 @@ export class CollectionFreeFormView extends CollectionSubView { let x = this.props.Document.GetNumber(KeyStore.PanX, 0); let y = this.props.Document.GetNumber(KeyStore.PanY, 0); let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); - let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0; - let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx; - let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0; - let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny; - let ranges = docs.filter(doc => doc).reduce((range, doc) => { - let x = doc.GetNumber(KeyStore.X, 0); - let xe = x + doc.GetNumber(KeyStore.Width, 0); - let y = doc.GetNumber(KeyStore.Y, 0); - let ye = y + doc.GetNumber(KeyStore.Height, 0); - return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], - [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; - }, [[minx, maxx], [miny, maxy]]); - let panelwidth = this._pwidth / this.scale / 2; - let panelheight = this._pheight / this.scale / 2; let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx; - if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx; - if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy; - if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy; + if (!this.isAnnotationOverlay) { + let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0; + let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx; + let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0; + let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny; + let ranges = docs.filter(doc => doc).reduce((range, doc) => { + let x = doc.GetNumber(KeyStore.X, 0); + let xe = x + doc.GetNumber(KeyStore.Width, 0); + let y = doc.GetNumber(KeyStore.Y, 0); + let ye = y + doc.GetNumber(KeyStore.Height, 0); + return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], + [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; + }, [[minx, maxx], [miny, maxy]]); + let panelwidth = this._pwidth / this.scale / 2; + let panelheight = this._pheight / this.scale / 2; + if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx; + if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx; + if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy; + if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy; + } this.SetPan(x - dx, y - dy); this._lastX = e.pageX; this._lastY = e.pageY; @@ -161,9 +167,9 @@ export class CollectionFreeFormView extends CollectionSubView { @action onPointerWheel = (e: React.WheelEvent): void => { - if (!this.props.active()) { - return; - } + // if (!this.props.active()) { + // return; + // } e.stopPropagation(); let coefficient = 1000; @@ -255,9 +261,10 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.focus(this.props.Document); } - getDocumentViewProps(document: Document): DocumentViewProps { + getDocumentViewProps(document: Document, opacity: number): DocumentViewProps { return { Document: document, + opacity: opacity, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, @@ -277,25 +284,30 @@ export class CollectionFreeFormView extends CollectionSubView { @computed get views() { 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) => { + let docviews = 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) { - prev.push(); + var zoom = doc.GetNumber(KeyStore.Zoom, 1); + var dv = DocumentManager.Instance.getDocumentView(doc); + let opacity = this.isAnnotationOverlay && (!dv || !SelectionManager.IsSelected(dv)) ? 1 - Math.abs(zoom - this.scale) : 1; + if ((page === curPage || page === -1)) { + prev.push(); } return prev; }, [] as JSX.Element[]); + untracked(() => this._selectOnLoaded = ""); + return docviews; } @computed get backgroundView() { return !this.backgroundLayout ? (null) : - (); } @computed get overlayView() { return !this.overlayLayout ? (null) : - (); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 77f41105f..0aa152209 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -6,7 +6,6 @@ import { Transform } from "../../util/Transform"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; import React = require("react"); -import { thisExpression } from "babel-types"; @observer @@ -16,18 +15,13 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)) - .scale(1 / this.contentScaling()) + .scale(1 / this.contentScaling()).scale(1 / this.zoom) @computed get docView() { @@ -74,6 +68,7 @@ export class CollectionFreeFormDocumentView extends React.Component; Document: Document; + opacity: number; addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean; removeDocument?: (doc: Document) => boolean; moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 0037d7b28..e0c5e19fb 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -79,6 +79,7 @@ export class FieldView extends React.Component { 1} PanelWidth={() => 100} diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index da2d7268f..19431bbe3 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -15,6 +15,7 @@ export namespace KeyStore { export const Width = new Key("Width"); export const Height = new Key("Height"); export const ZIndex = new Key("ZIndex"); + export const Zoom = new Key("Zoom"); export const Data = new Key("Data"); export const Annotations = new Key("Annotations"); export const ViewType = new Key("ViewType"); -- cgit v1.2.3-70-g09d2 From 845057ef78f272faf488b5bbc2fe79d64fb64120 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 14 Apr 2019 19:44:38 -0400 Subject: mostly northstar cleanup, plus cleaning up main.tsx --- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/northstar/manager/Gateway.ts | 16 +- .../model/binRanges/VisualBinRangeHelper.ts | 2 +- src/client/util/DragManager.ts | 9 +- src/client/util/SelectionManager.ts | 3 +- src/client/views/DocumentDecorations.tsx | 16 +- src/client/views/Main.scss | 18 -- src/client/views/Main.tsx | 279 ++++++--------------- src/client/views/MainOverlayTextBox.scss | 19 ++ src/client/views/MainOverlayTextBox.tsx | 110 ++++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- src/client/views/nodes/FormattedTextBox.tsx | 9 +- src/fields/KeyStore.ts | 2 +- .../authentication/models/current_user_utils.ts | 99 +++----- src/server/authentication/models/user_model.ts | 21 +- 15 files changed, 286 insertions(+), 322 deletions(-) create mode 100644 src/client/views/MainOverlayTextBox.scss create mode 100644 src/client/views/MainOverlayTextBox.tsx (limited to 'src/fields') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 2084fc346..3e94fed81 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -8,7 +8,7 @@ import { KeyStore } from "../../../fields/KeyStore"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange'; import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper"; -import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult, Result } from "../../northstar/model/idea/idea"; +import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea"; import { ModelHelpers } from "../../northstar/model/ModelHelpers"; import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; import { SizeConverter } from "../../northstar/utils/SizeConverter"; diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index 207a9ad19..d26f2724f 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -36,7 +36,7 @@ export class Gateway { public async ClearCatalog(): Promise { try { - const json = await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {}); + await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {}); } catch (error) { throw new Error("can not reach northstar's backend"); @@ -180,18 +180,18 @@ export class Gateway { public static ConstructUrl(appendix: string): string { - let base = Settings.Instance.ServerUrl; + let base = NorthstarSettings.Instance.ServerUrl; if (base.slice(-1) === "/") { base = base.slice(0, -1); } - let url = base + "/" + Settings.Instance.ServerApiPath + "/" + appendix; + let url = base + "/" + NorthstarSettings.Instance.ServerApiPath + "/" + appendix; return url; } } declare var ENV: any; -export class Settings { +export class NorthstarSettings { private _environment: any; @observable @@ -248,10 +248,10 @@ export class Settings { return window.location.origin + "/"; } - private static _instance: Settings; + private static _instance: NorthstarSettings; @action - public Update(environment: any): void { + public UpdateEnvironment(environment: any): void { /*let serverParam = new URL(document.URL).searchParams.get("serverUrl"); if (serverParam) { if (serverParam === "debug") { @@ -278,9 +278,9 @@ export class Settings { this.DegreeOfParallelism = environment.DEGREE_OF_PARALLISM; } - public static get Instance(): Settings { + public static get Instance(): NorthstarSettings { if (!this._instance) { - this._instance = new Settings(); + this._instance = new NorthstarSettings(); } return this._instance; } diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts index 9671e55f8..a92412686 100644 --- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts +++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts @@ -4,7 +4,7 @@ import { NominalVisualBinRange } from "./NominalVisualBinRange"; import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange"; import { AlphabeticVisualBinRange } from "./AlphabeticVisualBinRange"; import { DateTimeVisualBinRange } from "./DateTimeVisualBinRange"; -import { Settings } from "../../manager/Gateway"; +import { NorthstarSettings } from "../../manager/Gateway"; import { ModelHelpers } from "../ModelHelpers"; import { AttributeTransformationModel } from "../../core/attribute/AttributeTransformationModel"; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 2ee36d2ec..4bd654e15 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,13 +1,12 @@ import { action } from "mobx"; import { Document } from "../../fields/Document"; +import { FieldWaiting } from "../../fields/Field"; +import { KeyStore } from "../../fields/KeyStore"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { DocumentDecorations } from "../views/DocumentDecorations"; -import { Main } from "../views/Main"; -import { DocumentView } from "../views/nodes/DocumentView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; -import { KeyStore } from "../../fields/KeyStore"; -import { FieldWaiting } from "../../fields/Field"; +import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; export function SetupDrag(_reference: React.RefObject, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { @@ -177,7 +176,7 @@ export namespace DragManager { dragDiv.className = "dragManager-dragDiv"; DragManager.Root().appendChild(dragDiv); } - Main.Instance.SetTextDoc(); + MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 2fa45a086..c56f6a4ff 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -2,6 +2,7 @@ import { observable, action } from "mobx"; import { DocumentView } from "../views/nodes/DocumentView"; import { Document } from "../../fields/Document"; import { Main } from "../views/Main"; +import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; export namespace SelectionManager { class Manager { @@ -25,7 +26,7 @@ export namespace SelectionManager { DeselectAll(): void { manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)); manager.SelectedDocuments = []; - Main.Instance.SetTextDoc(); + MainOverlayTextBox.Instance.SetTextDoc(); } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2dc496bc1..b97a47a3c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,24 +1,20 @@ -import { action, computed, observable, trace, runInAction } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Key } from "../../fields/Key"; //import ContentEditable from 'react-contenteditable' import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; -import { Document } from "../../fields/Document"; import { TextField } from "../../fields/TextField"; -import { DragManager, DragLinksAsDocuments } from "../util/DragManager"; +import { emptyFunction } from "../../Utils"; +import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; -import { CollectionView } from "./collections/CollectionView"; +import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; +import { MainOverlayTextBox } from "./MainOverlayTextBox"; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); -import { FieldWaiting } from "../../fields/Field"; -import { emptyFunction } from "../../Utils"; -import { Main } from "./Main"; -import { undo } from "prosemirror-history"; -import { undoBatch } from "../util/UndoManager"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -304,7 +300,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> break; } - Main.Instance.SetTextDoc(); + MainOverlayTextBox.Instance.SetTextDoc(); SelectionManager.SelectedDocuments().forEach(element => { const rect = element.screenRect(); if (rect.width !== 0) { diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 13cadb10d..4373534b2 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -168,24 +168,6 @@ button:hover { left:0; overflow: scroll; } -.mainDiv-textInput { - background-color: rgba(248, 6, 6, 0.001); - width: 200px; - height: 200px; - position:absolute; - overflow: visible; - top: 0; - left: 0; - z-index: $mainTextInput-zindex; - .formattedTextBox-cont { - background-color: rgba(248, 6, 6, 0.001); - width: 100%; - height: 100%; - position:absolute; - top: 0; - left: 0; - } -} #mainContent-div { width:100%; height:100%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index f8c6ec0e2..51c076b14 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -15,20 +15,19 @@ import { ListField } from '../../fields/ListField'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; -import { Utils, returnTrue, emptyFunction, emptyDocFunction } from '../../Utils'; -import * as rp from 'request-promise'; import { RouteStore } from '../../server/RouteStore'; import { ServerUtils } from '../../server/ServerUtil'; +import { emptyDocFunction, emptyFunction, returnTrue, Utils } from '../../Utils'; import { Documents } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; -import { Gateway, Settings } from '../northstar/manager/Gateway'; -import { AggregateFunction, Catalog, Point } from '../northstar/model/idea/idea'; +import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway'; +import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; import { Server } from '../Server'; -import { SetupDrag, DragManager } from '../util/DragManager'; +import { SetupDrag } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; @@ -36,41 +35,28 @@ import { ContextMenu } from './ContextMenu'; import { DocumentDecorations } from './DocumentDecorations'; import { InkingControl } from './InkingControl'; import "./Main.scss"; +import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; -import { FormattedTextBox } from './nodes/FormattedTextBox'; -import { REPLCommand } from 'repl'; -import { Key } from '../../fields/Key'; import { PreviewCursor } from './PreviewCursor'; @observer export class Main extends React.Component { - // dummy initializations keep the compiler happy - @observable private mainfreeform?: Document; + public static Instance: Main; + @observable private _workspacesShown: boolean = false; @observable public pwidth: number = 0; @observable public pheight: number = 0; - private _northstarSchemas: Document[] = []; @computed private get mainContainer(): Document | undefined { - let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document); + let doc = CurrentUserUtils.UserDocument.GetT(KeyStore.ActiveWorkspace, Document); return doc === FieldWaiting ? undefined : doc; } - private set mainContainer(doc: Document | undefined) { - if (doc) { - this.userDocument.Set(KeyStore.ActiveWorkspace, doc); - } + doc && CurrentUserUtils.UserDocument.Set(KeyStore.ActiveWorkspace, doc); } - private get userDocument(): Document { - return CurrentUserUtils.UserDocument; - } - - public static Instance: Main; - constructor(props: Readonly<{}>) { super(props); - this._textProxyDiv = React.createRef(); Main.Instance = this; // causes errors to be generated when modifying an observable outside of an action configure({ enforceActions: "observed" }); @@ -102,6 +88,10 @@ export class Main extends React.Component { this.initializeNorthstar(); } + componentDidMount() { window.onpopstate = this.onHistory; } + + componentWillUnmount() { window.onpopstate = null; } + onHistory = () => { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); @@ -114,14 +104,6 @@ export class Main extends React.Component { } } - componentDidMount() { - window.onpopstate = this.onHistory; - } - - componentWillUnmount() { - window.onpopstate = null; - } - initEventListeners = () => { // window.addEventListener("pointermove", (e) => this.reportLocation(e)) window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler @@ -137,7 +119,7 @@ export class Main extends React.Component { initAuthenticationRouters = () => { // Load the user's active workspace, or create a new one if initial session after signup if (!CurrentUserUtils.MainDocId) { - this.userDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { + CurrentUserUtils.UserDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { if (doc) { CurrentUserUtils.MainDocId = doc.Id; this.openWorkspace(doc); @@ -158,7 +140,7 @@ export class Main extends React.Component { @action createNewWorkspace = (id?: string): void => { - this.userDocument.GetTAsync>(KeyStore.Workspaces, ListField).then(action((list: Opt>) => { + CurrentUserUtils.UserDocument.GetTAsync>(KeyStore.Workspaces, ListField).then(action((list: Opt>) => { if (list) { let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; @@ -179,7 +161,7 @@ export class Main extends React.Component { openWorkspace = (doc: Document, fromHistory = false): void => { this.mainContainer = doc; fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id); - this.userDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => { + CurrentUserUtils.UserDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => { // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(() => { if (col) { @@ -193,119 +175,33 @@ export class Main extends React.Component { }); } - @observable - workspacesShown: boolean = false; - - areWorkspacesShown = () => this.workspacesShown; - @action - toggleWorkspaces = () => { - this.workspacesShown = !this.workspacesShown; - } - - pwidthFunc = () => this.pwidth; - pheightFunc = () => this.pheight; - noScaling = () => 1; - - @observable _textDoc?: Document = undefined; - _textRect: any; - _textXf: Transform = Transform.Identity(); - _textScroll: number = 0; - _textFieldKey: Key = KeyStore.Data; - _textColor: string | null = null; - _textTargetDiv: HTMLDivElement | undefined; - _textProxyDiv: React.RefObject; - @action - SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: Transform) { - if (this._textTargetDiv) { - this._textTargetDiv.style.color = this._textColor; - } - - this._textDoc = undefined; - this._textDoc = textDoc; - this._textFieldKey = textFieldKey!; - this._textXf = tx ? tx : Transform.Identity(); - this._textTargetDiv = div; - if (div) { - this._textColor = div.style.color; - div.style.color = "transparent"; - this._textRect = div.getBoundingClientRect(); - this._textScroll = div.scrollTop; - } - } - - @action - textScroll = (e: React.UIEvent) => { - if (this._textProxyDiv.current && this._textTargetDiv) { - this._textTargetDiv.scrollTop = this._textScroll = this._textProxyDiv.current.children[0].scrollTop; - } - } - - textBoxDown = (e: React.PointerEvent) => { - if (e.button !== 0 || e.metaKey || e.altKey) { - document.addEventListener("pointermove", this.textBoxMove); - document.addEventListener('pointerup', this.textBoxUp); - } - } - textBoxMove = (e: PointerEvent) => { - if (e.movementX > 1 || e.movementY > 1) { - document.removeEventListener("pointermove", this.textBoxMove); - document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData([this._textDoc!]); - const [left, top] = this._textXf - .inverse() - .transformPoint(0, 0); - dragData.xOffset = e.clientX - left; - dragData.yOffset = e.clientY - top; - DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { - handlers: { - dragComplete: action(emptyFunction), - }, - hideSource: false - }); - } - } - textBoxUp = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.textBoxMove); - document.removeEventListener('pointerup', this.textBoxUp); - } - - @computed - get activeTextBox() { - if (this._textDoc) { - let x: number = this._textRect.x; - let y: number = this._textRect.y; - let w: number = this._textRect.width; - let h: number = this._textRect.height; - let t = this._textXf.transformPoint(0, 0); - let s = this._textXf.transformPoint(1, 0); - s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); - return
-
- this._textXf} focus={emptyDocFunction} /> -
- ; - } - else return (null); - } - @computed get mainContent() { - return !this.mainContainer ? (null) : - ; + trace(); + let pwidthFunc = () => this.pwidth; + let pheightFunc = () => this.pheight; + let noScaling = () => 1; + return { this.pwidth = r.entry.width; this.pheight = r.entry.height; })}> + {({ measureRef }) => +
+ {!this.mainContainer ? (null) : + } +
+ } +
; } /* 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. */ @@ -361,6 +257,7 @@ export class Main extends React.Component { get miscButtons() { let workspacesRef = React.createRef(); let logoutRef = React.createRef(); + let toggleWorkspaces = () => runInAction(() => { this._workspacesShown = !this._workspacesShown; }); let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ @@ -371,55 +268,50 @@ export class Main extends React.Component {
,
-
, + ,
]; } + @computed + get workspaceMenu() { + let areWorkspacesShown = () => this._workspacesShown; + let toggleWorkspaces = () => runInAction(() => { this._workspacesShown = !this._workspacesShown; }); + let workspaces = CurrentUserUtils.UserDocument.GetT>(KeyStore.Workspaces, ListField); + return (!workspaces || workspaces === FieldWaiting) ? (null) : + ; + } + render() { - let workspaceMenu: any = null; - let workspaces = this.userDocument.GetT>(KeyStore.Workspaces, ListField); - if (workspaces && workspaces !== FieldWaiting) { - workspaceMenu = ; - } return ( - <> -
- - runInAction(() => { - this.pwidth = r.entry.width; - this.pheight = r.entry.height; - })}> - {({ measureRef }) => -
- {this.mainContent} - -
- } -
- - {this.nodesMenu} - {this.miscButtons} - {workspaceMenu} - -
- {this.activeTextBox} - +
+ + {this.mainContent} + + + {this.nodesMenu} + {this.miscButtons} + {this.workspaceMenu} + + +
); } // --------------- Northstar hooks ------------- / + private _northstarSchemas: Document[] = []; - @action AddToNorthstarCatalog(ctlog: Catalog) { - CurrentUserUtils.NorthstarDBCatalog = CurrentUserUtils.NorthstarDBCatalog ? CurrentUserUtils.NorthstarDBCatalog : ctlog; + @action SetNorthstarCatalog(ctlog: Catalog) { + CurrentUserUtils.NorthstarDBCatalog = ctlog; if (ctlog && ctlog.schemas) { ctlog.schemas.map(schema => { - let promises: Promise[] = []; let schemaDocuments: Document[] = []; - CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { - let prom = Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { + let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); + Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { + promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { if (field instanceof Document) { schemaDocuments.push(field); } else { @@ -430,32 +322,17 @@ export class Main extends React.Component { new AttributeTransformationModel(atmod, AggregateFunction.Count)); schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); } - })); - promises.push(prom); - }); - Promise.all(promises).finally(() => { - let schemaDoc = Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }); - this._northstarSchemas.push(schemaDoc); - }); + }))); + return promises; + }, [] as Promise[])).finally(() => + this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); }); } } async initializeNorthstar(): Promise { - let envPath = "/assets/env.json"; - const response = await fetch(envPath, { - redirect: "follow", - method: "GET", - credentials: "include" - }); - const env = await response.json(); - Settings.Instance.Update(env); - let cat = Gateway.Instance.ClearCatalog(); - cat.then(async () => { - this.AddToNorthstarCatalog(await Gateway.Instance.GetCatalog()); - // if (!CurrentUserUtils.GetNorthstarSchema("Book1")) - // this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv", "Book1")); - }); - + const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); + NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); + Gateway.Instance.ClearCatalog().then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog())); } } diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss new file mode 100644 index 000000000..697d68c8c --- /dev/null +++ b/src/client/views/MainOverlayTextBox.scss @@ -0,0 +1,19 @@ +@import "globalCssVariables"; +.mainOverlayTextBox-textInput { + background-color: rgba(248, 6, 6, 0.001); + width: 200px; + height: 200px; + position:absolute; + overflow: visible; + top: 0; + left: 0; + z-index: $mainTextInput-zindex; + .formattedTextBox-cont { + background-color: rgba(248, 6, 6, 0.001); + width: 100%; + height: 100%; + position:absolute; + top: 0; + left: 0; + } +} \ No newline at end of file diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx new file mode 100644 index 000000000..df1addbc7 --- /dev/null +++ b/src/client/views/MainOverlayTextBox.tsx @@ -0,0 +1,110 @@ +import { action, observable, trace } from 'mobx'; +import { observer } from 'mobx-react'; +import "normalize.css"; +import * as React from 'react'; +import { Document } from '../../fields/Document'; +import { Key } from '../../fields/Key'; +import { KeyStore } from '../../fields/KeyStore'; +import { emptyDocFunction, emptyFunction, returnTrue } from '../../Utils'; +import '../northstar/model/ModelExtensions'; +import '../northstar/utils/Extensions'; +import { DragManager } from '../util/DragManager'; +import { Transform } from '../util/Transform'; +import "./MainOverlayTextBox.scss"; +import { FormattedTextBox } from './nodes/FormattedTextBox'; + +interface MainOverlayTextBoxProps { +} + +@observer +export class MainOverlayTextBox extends React.Component { + public static Instance: MainOverlayTextBox; + @observable public TextDoc?: Document = undefined; + public TextScroll: number = 0; + private _textRect: any; + private _textXf: Transform = Transform.Identity(); + private _textFieldKey: Key = KeyStore.Data; + private _textColor: string | null = null; + private _textTargetDiv: HTMLDivElement | undefined; + private _textProxyDiv: React.RefObject; + + constructor(props: MainOverlayTextBoxProps) { + super(props); + this._textProxyDiv = React.createRef(); + MainOverlayTextBox.Instance = this; + } + + @action + SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: Transform) { + if (this._textTargetDiv) { + this._textTargetDiv.style.color = this._textColor; + } + + this.TextDoc = undefined; + this.TextDoc = textDoc; + this._textFieldKey = textFieldKey!; + this._textXf = tx ? tx : Transform.Identity(); + this._textTargetDiv = div; + if (div) { + this._textColor = div.style.color; + div.style.color = "transparent"; + this._textRect = div.getBoundingClientRect(); + this.TextScroll = div.scrollTop; + } + } + + @action + textScroll = (e: React.UIEvent) => { + if (this._textProxyDiv.current && this._textTargetDiv) { + this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop; + } + } + + textBoxDown = (e: React.PointerEvent) => { + if (e.button !== 0 || e.metaKey || e.altKey) { + document.addEventListener("pointermove", this.textBoxMove); + document.addEventListener('pointerup', this.textBoxUp); + } + } + textBoxMove = (e: PointerEvent) => { + if (e.movementX > 1 || e.movementY > 1) { + document.removeEventListener("pointermove", this.textBoxMove); + document.removeEventListener('pointerup', this.textBoxUp); + let dragData = new DragManager.DocumentDragData([this.TextDoc!]); + const [left, top] = this._textXf + .inverse() + .transformPoint(0, 0); + dragData.xOffset = e.clientX - left; + dragData.yOffset = e.clientY - top; + DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + } + textBoxUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.textBoxMove); + document.removeEventListener('pointerup', this.textBoxUp); + } + + render() { + if (this.TextDoc) { + let x: number = this._textRect.x; + let y: number = this._textRect.y; + let w: number = this._textRect.width; + let h: number = this._textRect.height; + let t = this._textXf.transformPoint(0, 0); + let s = this._textXf.transformPoint(1, 0); + s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); + return
+
+ this._textXf} focus={emptyDocFunction} /> +
+ ; + } + else return (null); + } +} \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6c382a353..cb4e8fb2e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -24,6 +24,7 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); +import { MainOverlayTextBox } from "../../MainOverlayTextBox"; @observer export class CollectionFreeFormView extends CollectionSubView { @@ -205,7 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView { @action private SetPan(panX: number, panY: number) { - Main.Instance.SetTextDoc(); + MainOverlayTextBox.Instance.SetTextDoc(); var x1 = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY)); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 2e6272836..87c1bcb1e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -16,6 +16,7 @@ import "./FormattedTextBox.scss"; import React = require("react"); import { TextField } from "../../../fields/TextField"; import { KeyStore } from "../../../fields/KeyStore"; +import { MainOverlayTextBox } from "../MainOverlayTextBox"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -92,7 +93,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte }; if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id, + this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id, () => { if (this._editorView) { this._editorView.destroy(); @@ -103,7 +104,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte ); } else { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => this.props.isSelected() && Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform())); + () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform())); } this._reactionDisposer = reaction( @@ -184,10 +185,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte onFocused = (e: React.FocusEvent): void => { if (!this.props.isOverlay) { - Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()); + MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()); } else { if (this._ref.current) { - this._ref.current.scrollTop = Main.Instance._textScroll; + this._ref.current.scrollTop = MainOverlayTextBox.Instance.TextScroll; } } } diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 19431bbe3..16a909eb8 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -49,7 +49,7 @@ export namespace KeyStore { export const CopyDraggedItems = new Key("CopyDraggedItems"); export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, - Width, Height, ZIndex, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, + Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, Archives, Workspaces, Minimized, CopyDraggedItems diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 13eddafbf..34454eda0 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,15 +1,14 @@ -import { DashUserModel } from "./user_model"; +import { computed, observable, action } from "mobx"; import * as rp from 'request-promise'; -import { RouteStore } from "../../RouteStore"; -import { ServerUtils } from "../../ServerUtil"; +import { Documents } from "../../../client/documents/Documents"; +import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea"; +import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; import { Server } from "../../../client/Server"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { Documents } from "../../../client/documents/Documents"; -import { Schema, Attribute, AttributeGroup, Catalog } from "../../../client/northstar/model/idea/idea"; -import { observable, computed, action } from "mobx"; -import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; +import { RouteStore } from "../../RouteStore"; +import { ServerUtils } from "../../ServerUtil"; export class CurrentUserUtils { private static curr_email: string; @@ -17,65 +16,22 @@ export class CurrentUserUtils { private static user_document: Document; //TODO tfs: these should be temporary... private static mainDocId: string | undefined; - @observable private static catalog?: Catalog; - - public static get email(): string { - return this.curr_email; - } - - public static get id(): string { - return this.curr_id; - } - - public static get UserDocument(): Document { - return this.user_document; - } - public static get MainDocId(): string | undefined { - return this.mainDocId; - } - - public static set MainDocId(id: string | undefined) { - this.mainDocId = id; - } - - @computed public static get NorthstarDBCatalog(): Catalog | undefined { - return this.catalog; - } - public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { - this.catalog = ctlog; - } - public static GetNorthstarSchema(name: string): Schema | undefined { - return !this.catalog || !this.catalog.schemas ? undefined : - ArrayUtil.FirstOrDefault(this.catalog.schemas, (s: Schema) => s.displayName === name); - } - public static GetAllNorthstarColumnAttributes(schema: Schema) { - if (!schema || !schema.rootAttributeGroup) { - return []; - } - const recurs = (attrs: Attribute[], g: AttributeGroup) => { - if (g.attributes) { - attrs.push.apply(attrs, g.attributes); - if (g.attributeGroups) { - g.attributeGroups.forEach(ng => recurs(attrs, ng)); - } - } - }; - const allAttributes: Attribute[] = new Array(); - recurs(allAttributes, schema.rootAttributeGroup); - return allAttributes; - } + public static get email() { return this.curr_email; } + public static get id() { return this.curr_id; } + public static get UserDocument() { return this.user_document; } + public static get MainDocId() { return this.mainDocId; } + public static set MainDocId(id: string | undefined) { this.mainDocId = id; } private static createUserDocument(id: string): Document { let doc = new Document(id); - doc.Set(KeyStore.Workspaces, new ListField()); doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); return doc; } public static loadCurrentUser(): Promise { - let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then((response) => { + let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then(response => { if (response) { let obj = JSON.parse(response); CurrentUserUtils.curr_id = obj.id as string; @@ -86,17 +42,34 @@ export class CurrentUserUtils { }); let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { if (id) { - return Server.GetField(id).then(field => { - if (field instanceof Document) { - this.user_document = field; - } else { - this.user_document = this.createUserDocument(id); - } - }); + return Server.GetField(id).then(field => + this.user_document = field instanceof Document ? field : this.createUserDocument(id)); } else { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); return Promise.all([userPromise, userDocPromise]); } + + /* Northstar catalog ... really just for testing so this should eventually go away */ + @observable private static _northstarCatalog?: Catalog; + @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; } + public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; } + + public static GetNorthstarSchema(name: string): Schema | undefined { + return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined : + ArrayUtil.FirstOrDefault(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name); + } + public static GetAllNorthstarColumnAttributes(schema: Schema) { + const recurs = (attrs: Attribute[], g?: AttributeGroup) => { + if (g && g.attributes) { + attrs.push.apply(attrs, g.attributes); + if (g.attributeGroups) { + g.attributeGroups.forEach(ng => recurs(attrs, ng)); + } + } + return attrs; + }; + return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined); + } } \ No newline at end of file diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 1c6926517..d5c84c311 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -18,8 +18,8 @@ mongoose.connection.on('disconnected', function () { export type DashUserModel = mongoose.Document & { email: string, password: string, - passwordResetToken: string | undefined, - passwordResetExpires: Date | undefined, + passwordResetToken?: string, + passwordResetExpires?: Date, userDocumentId: string; @@ -67,11 +67,17 @@ const userSchema = new mongoose.Schema({ */ userSchema.pre("save", function save(next) { const user = this as DashUserModel; - if (!user.isModified("password")) { return next(); } + if (!user.isModified("password")) { + return next(); + } bcrypt.genSalt(10, (err, salt) => { - if (err) { return next(err); } + if (err) { + return next(err); + } bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => { - if (err) { return next(err); } + if (err) { + return next(err); + } user.password = hash; next(); }); @@ -79,9 +85,8 @@ userSchema.pre("save", function save(next) { }); const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) { - bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => { - cb(err, isMatch); - }); + bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => + cb(err, isMatch)); }; userSchema.methods.comparePassword = comparePassword; -- cgit v1.2.3-70-g09d2 From 95dff75290edc9b13e9741eefe2bc5851a60dde6 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Apr 2019 13:51:25 -0400 Subject: fixed workspace switching exception. started to refresh minimize functionality. --- src/client/util/DragManager.ts | 2 +- .../views/collections/CollectionDockingView.tsx | 11 +++++---- .../views/collections/CollectionTreeView.tsx | 9 +++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 10 +++++---- src/client/views/globalCssVariables.scss | 2 ++ src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +++++++++---- src/client/views/nodes/DocumentView.scss | 13 +++++------ src/client/views/nodes/DocumentView.tsx | 26 +++++++++++++++++----- src/fields/KeyStore.ts | 4 +++- 11 files changed, 76 insertions(+), 41 deletions(-) (limited to 'src/fields') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 64ea4342e..426c9fc3d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -250,7 +250,7 @@ export namespace DragManager { dragData.aliasOnDrop = e.ctrlKey || e.altKey; } if (e.shiftKey) { - abortDrag(); + AbortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 39e27b601..e4c647635 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -19,7 +19,7 @@ import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { TextField } from "../../../fields/TextField"; import { ListField } from "../../../fields/ListField"; -import { thisExpression } from "babel-types"; +import { Transform } from '../../util/Transform' @observer export class CollectionDockingView extends React.Component { @@ -336,9 +336,12 @@ export class DockedFrameRenderer extends React.Component { } ScreenToLocalTransform = () => { - 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()); + 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; + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling()); + } + return Transform.Identity(); } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 51a02fc25..e0387f4b4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,20 +1,17 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, trace } from "mobx"; +import { action, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { SetupDrag, DragManager } from "../../util/DragManager"; +import { DragManager, SetupDrag } from "../../util/DragManager"; import { EditableView } from "../EditableView"; -import "./CollectionTreeView.scss"; -import { CollectionView } from "./CollectionView"; -import * as globalCssVariables from "../../views/globalCssVariables.scss"; import { CollectionSubView } from "./CollectionSubView"; +import "./CollectionTreeView.scss"; import React = require("react"); -import { props } from 'bluebird'; export interface TreeViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 159db6279..af6819cd4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -71,20 +71,25 @@ export class CollectionFreeFormView extends CollectionSubView { @action drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { + console.log("DROP Aat " + de.x + " off " + de.data.xOffset); const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { - let dropX = de.data.droppedDocuments[0].GetNumber(KeyStore.X, 0); - let dropY = de.data.droppedDocuments[0].GetNumber(KeyStore.Y, 0); + let dragDoc = de.data.droppedDocuments[0]; + let dropX = dragDoc.GetNumber(KeyStore.X, 0); + let dropY = dragDoc.GetNumber(KeyStore.Y, 0); de.data.droppedDocuments.map(d => { + let minimized = d.GetBoolean(KeyStore.Minimized, false); d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX)); d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY)); - if (!d.GetNumber(KeyStore.Width, 0)) { - d.SetNumber(KeyStore.Width, 300); - } - if (!d.GetNumber(KeyStore.Height, 0)) { - let nw = d.GetNumber(KeyStore.NativeWidth, 0); - let nh = d.GetNumber(KeyStore.NativeHeight, 0); - d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + if (!minimized) { + if (!d.GetNumber(KeyStore.Width, 0)) { + d.SetNumber(KeyStore.Width, 300); + } + if (!d.GetNumber(KeyStore.Height, 0)) { + let nw = d.GetNumber(KeyStore.NativeWidth, 0); + let nh = d.GetNumber(KeyStore.NativeHeight, 0); + d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + } } this.bringToFront(d); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 65f461b27..8b94374fa 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -11,6 +11,7 @@ import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; +import { MINIMIZED_ICON_SIZE } from '../../../views/globalCssVariables.scss' import "./MarqueeView.scss"; import React = require("react"); @@ -207,11 +208,12 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { + let minimized = doc.GetBoolean(KeyStore.Minimized, false); var z = doc.GetNumber(KeyStore.Zoom, 1); - var x = doc.GetNumber(KeyStore.X, 0); - var y = doc.GetNumber(KeyStore.Y, 0); - var w = doc.Width() / z; - var h = doc.Height() / z; + var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0); + var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0); + var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z; + var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 5c8e9c8fc..f154f8158 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -23,7 +23,9 @@ $mainTextInput-zindex: 999; // then text input overlay so that it's context menu $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; +$MINIMIZED_ICON_SIZE:25; :export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; + MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index ed8573f41..cc77d987a 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -2,6 +2,7 @@ interface IGlobalScss { contextMenuZindex: string; // context menu shows up over everything COLLECTION_BORDER_WIDTH: string; + MINIMIZED_ICON_SIZE: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 97d53a47e..a3689414d 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,7 +17,7 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() - .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)) + .translate(-this.X, -this.Y) .scale(1 / this.contentScaling()).scale(1 / this.zoom) contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); - panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); + panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth(); + panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight(); @computed get docView() { @@ -64,6 +70,8 @@ export class CollectionFreeFormDocumentView extends React.Component; } + get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); } + render() { let zoomFade = 1; //var zoom = doc.GetNumber(KeyStore.Zoom, 1); diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 690ee50e8..85c305b5a 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -13,7 +13,6 @@ } .top { - background: #232323; height: 20px; cursor: pointer; } @@ -32,13 +31,13 @@ .documentView-node-topmost { background: white; } - .minimized-box { - height: 10px; - width: 10px; - border-radius: 2px; - background: $dark-color; - transform-origin: left top; + position: absolute; + left:0; + top:0; + width:$MINIMIZED_ICON_SIZE; + height:$MINIMIZED_ICON_SIZE; + transform-origin: left top; } .minimized-box:hover { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d74f9fc57..af52e44e1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,12 +1,13 @@ +import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faObjectGroup, faStickyNote, faFilePdf, faFilm, faImage } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { BooleanField } from "../../../fields/BooleanField"; import { Document } from "../../../fields/Document"; -import { Field, FieldWaiting, Opt } from "../../../fields/Field"; +import { Field, Opt } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { TextField } from "../../../fields/TextField"; import { ServerUtils } from "../../../server/ServerUtil"; import { emptyFunction, Utils } from "../../../Utils"; import { Documents } from "../../documents/Documents"; @@ -19,12 +20,19 @@ import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; +import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Document; @@ -216,6 +224,8 @@ export class DocumentView extends React.Component { @action public minimize = (): void => { this.props.Document.SetBoolean(KeyStore.Minimized, true); + this.props.Document.SetNumber(KeyStore.MinimizedX, 0); + this.props.Document.SetNumber(KeyStore.MinimizedY, 0); SelectionManager.DeselectAll(); } @@ -314,8 +324,14 @@ export class DocumentView extends React.Component { var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%"; if (this.isMinimized()) { - return
; + let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf : + this.layout.indexOf("ImageBox") !== -1 ? faImage : + this.layout.indexOf("Formatted") !== -1 ? faStickyNote : + this.layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return
+ +
} return (
Date: Fri, 19 Apr 2019 16:34:32 -0400 Subject: played with iconifying things in a different way. fixed some things with schemas. --- src/Utils.ts | 2 +- src/client/documents/Documents.ts | 16 ++++ src/client/northstar/dash-nodes/HistogramBox.scss | 6 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 42 ++++++---- src/client/views/Main.tsx | 8 +- .../views/collections/CollectionSchemaView.scss | 9 ++- .../views/collections/CollectionSchemaView.tsx | 5 +- .../CollectionFreeFormLinkView.tsx | 8 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 9 +-- src/client/views/globalCssVariables.scss | 2 + src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 26 +++---- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/DocumentView.scss | 16 +--- src/client/views/nodes/DocumentView.tsx | 71 ++++++++--------- src/client/views/nodes/FieldView.tsx | 5 ++ src/client/views/nodes/IconBox.scss | 12 +++ src/client/views/nodes/IconBox.tsx | 90 ++++++++++++++++++++++ src/fields/IconFIeld.ts | 25 ++++++ src/fields/KeyStore.ts | 10 +-- src/server/Message.ts | 2 +- src/server/ServerUtil.ts | 2 + 24 files changed, 264 insertions(+), 121 deletions(-) create mode 100644 src/client/views/nodes/IconBox.scss create mode 100644 src/client/views/nodes/IconBox.tsx create mode 100644 src/fields/IconFIeld.ts (limited to 'src/fields') diff --git a/src/Utils.ts b/src/Utils.ts index dec6245ef..98f75d3b9 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,7 +1,7 @@ import v4 = require('uuid/v4'); import v5 = require("uuid/v5"); import { Socket } from 'socket.io'; -import { Message, Types, Transferable } from './server/Message'; +import { Message } from './server/Message'; import { Document } from './fields/Document'; export class Utils { diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4febfa7eb..b0bb74d89 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,6 +32,9 @@ import { action } from "mobx"; import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; +import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; +import { IconBox } from "../views/nodes/IconBox"; +import { IconField } from "../../fields/IconFIeld"; export interface DocumentOptions { x?: number; @@ -63,6 +66,7 @@ export namespace Documents { let videoProto: Document; let audioProto: Document; let pdfProto: Document; + let iconProto: Document; const textProtoId = "textProto"; const histoProtoId = "histoProto"; const pdfProtoId = "pdfProto"; @@ -72,6 +76,7 @@ export namespace Documents { const kvpProtoId = "kvpProto"; const videoProtoId = "videoProto"; const audioProtoId = "audioProto"; + const iconProtoId = "iconProto"; export function initProtos(): Promise { return Server.GetFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => { @@ -84,6 +89,7 @@ export namespace Documents { videoProto = fields[videoProtoId] as Document || CreateVideoPrototype(); audioProto = fields[audioProtoId] as Document || CreateAudioPrototype(); pdfProto = fields[pdfProtoId] as Document || CreatePdfPrototype(); + iconProto = fields[iconProtoId] as Document || CreateIconPrototype(); }); } function assignOptions(doc: Document, options: DocumentOptions): Document { @@ -92,6 +98,8 @@ export namespace Documents { if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); } if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); } if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); } + if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); } + if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); } if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } @@ -139,6 +147,11 @@ export namespace Documents { histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString()); return histoProto; } + function CreateIconPrototype(): Document { + let iconProto = setupPrototypeOptions(iconProtoId, "ICON_PROTO", IconBox.LayoutString(), + { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data] }); + return iconProto; + } function CreateTextPrototype(): Document { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); @@ -203,6 +216,9 @@ export namespace Documents { export function TextDocument(options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(textProto, options, ["", TextField]).MakeDelegate(), options); } + export function IconDocument(icon: string, options: DocumentOptions = {}) { + return assignToDelegate(SetInstanceOptions(iconProto, { width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data], layout: IconBox.LayoutString(), ...options }, [icon, IconField]), options); + } export function PdfDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); } diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index e899cf15e..06d781263 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -1,12 +1,12 @@ .histogrambox-container { padding: 0vw; position: absolute; - top: 0; - left:0; + top: -50%; + left:-50%; text-align: center; width: 100%; height: 100%; - background: black; + background: black; } .histogrambox-xaxislabel { position:absolute; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 0e84ace50..e2ecc8c83 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -146,7 +146,7 @@ export class HistogramBox extends React.Component { return ( runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}> {({ measureRef }) => -
+
{labelY} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cfb9befd5..da2c7a3be 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,17 +5,18 @@ import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; +import { Document } from "../../fields/Document"; import { emptyFunction } from "../../Utils"; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; import { MainOverlayTextBox } from "./MainOverlayTextBox"; -import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); import { CompileScript } from "../util/Scripting"; +import { IconBox } from "./nodes/IconBox"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -191,6 +192,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointerup", this.onMinimizeUp); } } + + @observable _minimizedX = 0; + @observable _minimizedY = 0; @action onMinimizeMove = (e: PointerEvent): void => { e.stopPropagation(); @@ -201,12 +205,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let xf = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().inverse().transformPoint(0, 0); let dx = e.pageX - xf[0]; let dy = e.pageY - xf[1]; - if (Math.abs(dx) < 20 && Math.abs(dy) < 20) - dx = dy = 0; + this._minimizedX = e.clientX; + this._minimizedY = e.clientY; + if (Math.abs(dx) < 20 && Math.abs(dy) < 20) { + this._minimizedX = xf[0]; + this._minimizedY = xf[1]; + } SelectionManager.SelectedDocuments().map(dv => { - let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformDirection(dx, dy); - dv.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - dv.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + let minDoc = dv.props.Document.Get(KeyStore.MinimizedDoc); + if (minDoc instanceof Document) { + let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformPoint(this._minimizedX, this._minimizedY); + let minDocument = minDoc as Document; + minDocument.SetNumber(KeyStore.X, where[0] + dv.props.Document.GetNumber(KeyStore.X, 0)); + minDocument.SetNumber(KeyStore.Y, where[1] + dv.props.Document.GetNumber(KeyStore.Y, 0)); + } }); } } @@ -219,6 +231,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (Math.abs(dx) < 4 && Math.abs(dy) < 4 && !this._iconifying) { SelectionManager.SelectedDocuments().map(dv => dv.minimize()); SelectionManager.DeselectAll(); + } else { + this._minimizedX = this._minimizedY = 0; } document.removeEventListener("pointermove", this.onMinimizeMove); document.removeEventListener("pointerup", this.onMinimizeUp); @@ -404,24 +418,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (bounds.x === Number.MAX_VALUE || !seldoc) { return (null); } - let minvec = [seldoc.props.Document.GetNumber(KeyStore.MinimizedX, 0), seldoc.props.Document.GetNumber(KeyStore.MinimizedY, 0)]; - minvec = seldoc.props.ScreenToLocalTransform().scale(seldoc.props.ContentScaling()).inverse().transformDirection(minvec[0], minvec[1]); - let selpos = minvec[0] !== 0 || minvec[1] !== 0 ? - [minvec[0] - 12 + (!this._iconifying ? 8 : 0), minvec[1] - 12 + (!this._iconifying ? 28 : 0)] : + let selpos = this._minimizedX !== 0 || this._minimizedY !== 0 ? + [this._minimizedX - 12 + (!this._iconifying ? 8 : 0), this._minimizedY - 12 + (!this._iconifying ? 28 : 0)] : [0, this._iconifying ? -18 : 0]; let minimizeIcon = (
- {SelectionManager.SelectedDocuments().length == 1 ? SelectionManager.SelectedDocuments()[0].minimizedIcon : "..."} + {SelectionManager.SelectedDocuments().length == 1 ? IconBox.DocumentIcon(SelectionManager.SelectedDocuments()[0].props.Document.GetText(KeyStore.Layout, "...")) : "..."}
); if (this._iconifying) { - let xfpt = seldoc.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - return (
- {minimizeIcon} -
); + return (
{minimizeIcon}
); } - // console.log(this._documents.length) - // let test = this._documents[0].props.Document.Title; + if (this.Hidden) { return (null); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 503a11b35..09ef30f6b 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -85,11 +85,11 @@ export class Main extends React.Component { this.initEventListeners(); this.initAuthenticationRouters(); - // try { - // this.initializeNorthstar(); - // } catch (e) { + try { + this.initializeNorthstar(); + } catch (e) { - // } + } } componentDidMount() { window.onpopstate = this.onHistory; } diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 6eabbe17c..cfdb3ab22 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,6 +1,7 @@ @import "../globalCssVariables"; + .collectionSchemaView-container { border-width: $COLLECTION_BORDER_WIDTH; border-color : $intermediate-color; @@ -10,6 +11,10 @@ position: absolute; width: 100%; height: 100%; + + .collectionSchemaView-cellContents { + height: $MAX_ROW_HEIGHT; + } .collectionSchemaView-previewRegion { position: relative; @@ -104,7 +109,7 @@ } .rt-tr-group { direction: ltr; - max-height: 44px; + max-height: $MAX_ROW_HEIGHT; } .rt-td { border-width: 1px; @@ -136,7 +141,7 @@ } .ReactTable .rt-th, .ReactTable .rt-td { - max-height: 44; + max-height: $MAX_ROW_HEIGHT; padding: 3px 7px; font-size: 13px; text-align: center; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b61eb342d..90077b053 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' import "react-table/react-table.css"; import { Document } from "../../../fields/Document"; import { Field, Opt } from "../../../fields/Field"; @@ -99,11 +100,11 @@ export class CollectionSchemaView extends CollectionSubView { return false; }; return ( -
+
{ let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 8868f7df0..20c5a84bf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { - console.log("DROP Aat " + de.x + " off " + de.data.xOffset); const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; let dropX = dragDoc.GetNumber(KeyStore.X, 0); let dropY = dragDoc.GetNumber(KeyStore.Y, 0); de.data.droppedDocuments.map(d => { - let minimized = d.GetBoolean(KeyStore.Minimized, false); - d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedX, 0) : 0)) - dropX); - d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedY, 0) : 0)) - dropY); - if (!minimized) { + d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX); + d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY); + if (!d.GetBoolean(KeyStore.IsMinimized, false)) { if (!d.GetNumber(KeyStore.Width, 0)) { d.SetNumber(KeyStore.Width, 300); } @@ -264,7 +263,9 @@ export class CollectionFreeFormView extends CollectionSubView { let docviews = 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) { - prev.push(); + let minim = doc.GetT(KeyStore.IsMinimized, BooleanField); + if (minim === undefined || (minim && !minim.Data)) + prev.push(); } return prev; }, [] as JSX.Element[]); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8b94374fa..bf918beba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -208,12 +208,11 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { - let minimized = doc.GetBoolean(KeyStore.Minimized, false); var z = doc.GetNumber(KeyStore.Zoom, 1); - var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0); - var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0); - var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z; - var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z; + var x = doc.GetNumber(KeyStore.X, 0); + var y = doc.GetNumber(KeyStore.Y, 0); + var w = doc.Width() / z; + var h = doc.Height() / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index f154f8158..4f68b71b0 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -24,8 +24,10 @@ $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; $MINIMIZED_ICON_SIZE:25; +$MAX_ROW_HEIGHT: 44px; :export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; + MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index cc77d987a..9788d31f7 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -3,6 +3,7 @@ interface IGlobalScss { contextMenuZindex: string; // context menu shows up over everything COLLECTION_BORDER_WIDTH: string; MINIMIZED_ICON_SIZE: string; + MAX_ROW_HEIGHT: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a3689414d..1d42b3899 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -46,10 +46,10 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() @@ -57,8 +57,8 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth(); - panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight(); + panelWidth = () => this.props.PanelWidth(); + panelHeight = () => this.props.PanelHeight(); @computed get docView() { @@ -70,19 +70,17 @@ export class CollectionFreeFormDocumentView extends React.Component; } - get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); } - render() { let zoomFade = 1; //var zoom = doc.GetNumber(KeyStore.Zoom, 1); - let transform = this.getTransform().scale(this.contentScaling()).inverse(); - var [sptX, sptY] = transform.transformPoint(0, 0); - let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); - let w = bptX - sptX; - //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; - let fadeUp = .75 * 1800; - let fadeDown = .075 * 1800; - zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; + // let transform = this.getTransform().scale(this.contentScaling()).inverse(); + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); + // let w = bptX - sptX; + // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; + // let fadeUp = .75 * 1800; + // let fadeDown = .075 * 1800; + // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; return (
Error loading layout keys

; } return ; @@ -189,10 +179,10 @@ export class DocumentView extends React.Component { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - if (!SelectionManager.IsSelected(this) && e.button !== 2 && - Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { - SelectionManager.SelectDoc(this, e.ctrlKey); - } + if (!SelectionManager.IsSelected(this) && e.button !== 2) + if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { + SelectionManager.SelectDoc(this, e.ctrlKey); + } } stopPropagation = (e: React.SyntheticEvent) => { e.stopPropagation(); @@ -221,13 +211,33 @@ export class DocumentView extends React.Component { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } + @action createIcon = (layoutString: string): void => { + let iconDoc = Documents.IconDocument(layoutString); + iconDoc.SetBoolean(KeyStore.IsMinimized, false); + iconDoc.SetNumber(KeyStore.NativeWidth, 0); + iconDoc.SetNumber(KeyStore.NativeHeight, 0); + iconDoc.Set(KeyStore.Prototype, this.props.Document); + iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document); + this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc); + this.props.addDocument && this.props.addDocument(iconDoc, false); + } + @action - public minimize = (where: number[]): void => { - this.props.Document.SetBoolean(KeyStore.Minimized, true); - if (where[0] !== 0 || where[1] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - if (where[1] !== 0 || where[0] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + public minimize = (): void => { + this.props.Document.SetBoolean(KeyStore.IsMinimized, true); + this.props.Document.GetAsync(KeyStore.MinimizedDoc, mindoc => { + if (mindoc === undefined) { + this.props.Document.GetAsync(KeyStore.BackgroundLayout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + else this.props.Document.GetAsync(KeyStore.Layout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + }); + }); + } + else if (mindoc instanceof Document) { + this.props.addDocument && this.props.addDocument(mindoc, false); + } + }); } @undoBatch @@ -295,7 +305,6 @@ export class DocumentView extends React.Component { } e.preventDefault(); - !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: () => this.minimize([0, 0]) }); ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }); ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }); @@ -309,9 +318,6 @@ export class DocumentView extends React.Component { SelectionManager.SelectDoc(this, false); } - @action - expand = (e: React.MouseEvent) => { this.props.Document.SetBoolean(KeyStore.Minimized, false); SelectionManager.SelectDoc(this, e.ctrlKey); } - isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false); isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); @@ -319,27 +325,12 @@ export class DocumentView extends React.Component { @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get contents() { return (); } - @computed get minimizedIcon() { - let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf : - this.layout.indexOf("ImageBox") !== -1 ? faImage : - this.layout.indexOf("Formatted") !== -1 ? faStickyNote : - this.layout.indexOf("Video") !== -1 ? faFilm : - this.layout.indexOf("Collection") !== -1 ? faObjectGroup : - faCaretUp; - return - } render() { var scaling = this.props.ContentScaling(); var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%"; var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%"; - if (this.isMinimized()) { - return ( -
- {this.minimizedIcon} -
); - } return (
{ else if (field instanceof ImageField) { return ; } + else if (field instanceof IconField) { + return ; + } else if (field instanceof VideoField) { return ; } diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss new file mode 100644 index 000000000..ce0ee2e09 --- /dev/null +++ b/src/client/views/nodes/IconBox.scss @@ -0,0 +1,12 @@ + +@import "../globalCssVariables"; +.iconBox-container { + position: absolute; + left:0; + top:0; + svg { + width: 100% !important; + height: 100%; + background: white; + } +} \ No newline at end of file diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx new file mode 100644 index 000000000..5ada2186d --- /dev/null +++ b/src/client/views/nodes/IconBox.tsx @@ -0,0 +1,90 @@ +import React = require("react"); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Document } from '../../../fields/Document'; +import { IconField } from "../../../fields/IconFIeld"; +import { KeyStore } from "../../../fields/KeyStore"; +import { SelectionManager } from "../../util/SelectionManager"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./IconBox.scss"; + + +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + +@observer +export class IconBox extends React.Component { + public static LayoutString() { return FieldView.LayoutString(IconBox); } + + @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } + @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

Error loading layout data

" as string); } + @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } + + public static DocumentIcon(layout: string) { + let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf : + layout.indexOf("ImageBox") !== -1 ? faImage : + layout.indexOf("Formatted") !== -1 ? faStickyNote : + layout.indexOf("Video") !== -1 ? faFilm : + layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return + } + + animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) { + setTimeout(() => { + let now = Date.now(); + let progress = Math.min(1, (now - stime) / 200); + let pval = maximizing ? + [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] : + [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress]; + target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress); + target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress); + target.SetNumber(KeyStore.X, pval[0]); + target.SetNumber(KeyStore.Y, pval[1]); + if (now < stime + 200) { + this.animateTransition(icon, targ, width, height, stime, target, maximizing); + } + else { + if (!maximizing) { + target.SetBoolean(KeyStore.IsMinimized, true); + target.SetNumber(KeyStore.X, targ[0]); + target.SetNumber(KeyStore.Y, targ[1]); + target.SetNumber(KeyStore.Width, width); + target.SetNumber(KeyStore.Height, height); + } + this._completed = true; + } + }, + 2); + } + + _completed = true; + + @action + public toggleMinimize = (): void => { + SelectionManager.DeselectAll(); + if (this.maximized instanceof Document && this._completed) { + this._completed = false; + let minimized = this.maximized.GetBoolean(KeyStore.IsMinimized, false); + this.maximized.SetBoolean(KeyStore.IsMinimized, false); + this.animateTransition( + [this.props.Document.GetNumber(KeyStore.X, 0), this.props.Document.GetNumber(KeyStore.Y, 0)], + [this.maximized.GetNumber(KeyStore.X, 0), this.maximized.GetNumber(KeyStore.Y, 0)], + this.maximized.GetNumber(KeyStore.Width, 0), this.maximized.GetNumber(KeyStore.Width, 0), + Date.now(), this.maximized, minimized); + } + } + + render() { + return ( +
+ {this.minimizedIcon} +
); + } +} \ No newline at end of file diff --git a/src/fields/IconFIeld.ts b/src/fields/IconFIeld.ts new file mode 100644 index 000000000..a6694cc49 --- /dev/null +++ b/src/fields/IconFIeld.ts @@ -0,0 +1,25 @@ +import { BasicField } from "./BasicField"; +import { FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class IconField extends BasicField { + constructor(data: string = "", id?: FieldId, save: boolean = true) { + super(data, save, id); + } + + ToScriptString(): string { + return `new IconField("${this.Data}")`; + } + + Copy() { + return new IconField(this.Data); + } + + ToJson() { + return { + type: Types.Icon, + data: this.Data, + id: this.Id + }; + } +} \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index ff2f31003..a347f8bcf 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -4,8 +4,6 @@ export namespace KeyStore { export const Prototype = new Key("Prototype"); export const X = new Key("X"); export const Y = new Key("Y"); - export const MinimizedX = new Key("MinimizedX"); - export const MinimizedY = new Key("MinimizedY"); export const Page = new Key("Page"); export const Title = new Key("Title"); export const Author = new Key("Author"); @@ -47,14 +45,16 @@ export namespace KeyStore { export const OptionalRightCollection = new Key("OptionalRightCollection"); export const Archives = new Key("Archives"); export const Workspaces = new Key("Workspaces"); - export const Minimized = new Key("Minimized"); + export const IsMinimized = new Key("IsMinimized"); + export const MinimizedDoc = new Key("MinimizedDoc"); + export const MaximizedDoc = new Key("MaximizedDoc"); export const CopyDraggedItems = new Key("CopyDraggedItems"); - export const KeyList: Key[] = [Prototype, X, Y, MinimizedX, MinimizedY, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, + export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, - Archives, Workspaces, Minimized, CopyDraggedItems + Archives, Workspaces, IsMinimized, MinimizedDoc, MaximizedDoc, CopyDraggedItems ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { diff --git a/src/server/Message.ts b/src/server/Message.ts index bbe4ffcad..15916ef12 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -14,7 +14,7 @@ export class Message { } export enum Types { - Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, + Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference, Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, } diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 818230c1a..79ca5e55d 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -18,6 +18,7 @@ import { NumberField } from "./../fields/NumberField"; import { RichTextField } from "./../fields/RichTextField"; import { TextField } from "./../fields/TextField"; import { Transferable, Types } from "./Message"; +import { IconField } from "../fields/IconFIeld"; export class ServerUtils { public static prepend(extension: string): string { @@ -37,6 +38,7 @@ export class ServerUtils { case Types.Boolean: return new BooleanField(json.data, json.id, false); case Types.Number: return new NumberField(json.data, json.id, false); case Types.Text: return new TextField(json.data, json.id, false); + case Types.Icon: return new IconField(json.data, json.id, false); case Types.Html: return new HtmlField(json.data, json.id, false); case Types.Web: return new WebField(new URL(json.data), json.id, false); case Types.RichText: return new RichTextField(json.data, json.id, false); -- cgit v1.2.3-70-g09d2