From 516c0b35bbb7a184931ab0fe1d54086d8052bda4 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 17 Jul 2019 15:15:49 -0400 Subject: changed image proxying stuff --- src/client/documents/Documents.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/documents/Documents.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index af2b95659..3c248760b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -311,8 +311,9 @@ export namespace Docs { } export function ImageDocument(url: string, options: DocumentOptions = {}) { - let inst = InstanceFromProto(Prototypes.get(DocumentType.IMG), new ImageField(new URL(url)), { title: path.basename(url), ...options }); - requestImageSize(window.origin + RouteStore.corsProxy + "/" + url) + let imgField = new ImageField(new URL(url)); + let inst = InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: path.basename(url), ...options }); + requestImageSize(imgField.url.href) .then((size: any) => { let aspect = size.height / size.width; if (!inst.proto!.nativeWidth) { -- cgit v1.2.3-70-g09d2 From 6da55377db662a8fda3a241e7c9d115d33baff83 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 19 Jul 2019 18:33:17 -0400 Subject: json to documents conversion function --- src/client/documents/Documents.ts | 87 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'src/client/documents/Documents.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3c248760b..5a6eff04c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -439,6 +439,93 @@ export namespace Docs { export namespace Get { + /** + * This function takes any valid JSON(-like) data, i.e. parsed or unparsed, and at arbitrarily + * deep levels of nesting, converts the data and structure into nested documents with the appropriate fields. + * + * After building a hierarchy within / below a top-level document, it then returns that top-level parent. + * + * @param input for convenience and flexibility, either a valid JSON string to be parsed, + * or the result of any JSON.parse() call. + * @param title an optional title to give to the highest parent document in the hierarchy + */ + export function DocumentHierarchyFromJson(input: any, title?: string): Opt; + export function DocumentHierarchyFromJson(input: string, title?: string): Opt { + // preliminary check - making a document out of null or undefined is meaningless + if (input === null || input === undefined) { + return undefined; + } + let parsed: any = input; + // if we've received a string, treat it like valid JSON and try to parse it into an object. + if (typeof input === "string") { + try { + parsed = JSON.parse(input); + } catch (e) { + // if this fails, the string is invalid JSON, so we should assume that the input is the + // result of a JSON.parse() call that returned a regular string value to be stored. + parsed = input; + } + } else if (!["object", "boolean", "number"].includes(typeof input)) { + // since the caller might also pass in the results of a JSON.parse() call, input + // might be an object, an array (still typeof object), a boolean or a number. + // anything else (a function, etc. that is passed in naively as any) is meaningless for this operation + return undefined; + } + let converted: Doc; + if (typeof parsed === "object" && !(parsed instanceof Array)) { + // JavaScript object: this gets converted directly to a document, which is a also a list of key value pairs + converted = convertObject(parsed); + } else { + // Array, a boolean, a string or a number: this gets stored as a field in a wrapper document, since no key value structure exists + (converted = new Doc).json = valueOf(parsed); + } + // if we passed in a title, assign it + title && (converted.title = title); + return converted; + } + + const convertObject = (object: any): Doc => { + // create the document that will store this object's data + let target = new Doc(); + // for each value of the document, recursively convert it to a document or other field + // and store the field at the appropriate key in the document + Object.keys(object).map(key => { + let result = valueOf(object[key]); + // if the result is undefined, ignore it + result && (target[key] = result); + }); + return target; + }; + + const convertList = (list: Array): List => { + // create the list (Field implementation) that will store this Array's data + let thisLevel = new List(); + // for each element in the list, recursively convert it to a document or other field + // and push the field to the list + list.map(item => { + let result = valueOf(item); + // if the result is undefined, ignore it + result && thisLevel.push(result); + }); + return thisLevel; + }; + + const valueOf = (data: any): Opt => { + if (data === null || data === undefined) { + return undefined; + } + if (typeof data === "object") { + // recursively convert the object or array to the appropriate field value and return it + return data instanceof Array ? convertList(data) : convertObject(data); + } else if (["string", "number", "boolean"].includes(typeof data)) { + // no real conversion necessary - just return the data, already a valid field, to be stored + return data; + } else { + // any other type cannot be stored in JSON, but ya never know + throw new Error(`How did ${data} end up in JSON?`); + } + }; + export async function DocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { -- cgit v1.2.3-70-g09d2 From 2899cbc887398688b82dd284ee482cdb136c6452 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 22 Jul 2019 00:38:50 -0400 Subject: json conversion tweaks --- src/Utils.ts | 16 +++++- src/client/documents/Documents.ts | 102 ++++++++++++++++++-------------------- src/new_fields/InkField.ts | 4 +- 3 files changed, 64 insertions(+), 58 deletions(-) (limited to 'src/client/documents/Documents.ts') diff --git a/src/Utils.ts b/src/Utils.ts index ac6d127cc..8df67df5d 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -146,7 +146,7 @@ export type Without = Pick>; export type Predicate = (entry: [K, V]) => boolean; -export function deepCopy(source: Map, predicate?: Predicate) { +export function DeepCopy(source: Map, predicate?: Predicate) { let deepCopy = new Map(); let entries = source.entries(), next = entries.next(); while (!next.done) { @@ -157,4 +157,18 @@ export function deepCopy(source: Map, predicate?: Predicate) { next = entries.next(); } return deepCopy; +} + +export namespace JSONUtils { + + export function tryParse(source: string) { + let results: any; + try { + results = JSON.parse(source); + } catch (e) { + results = source; + } + return results; + } + } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5a6eff04c..de049be5a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -21,7 +21,7 @@ import { AggregateFunction } from "../northstar/model/idea/idea"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { IconBox } from "../views/nodes/IconBox"; import { Field, Doc, Opt } from "../../new_fields/Doc"; -import { OmitKeys } from "../../Utils"; +import { OmitKeys, JSONUtils } from "../../Utils"; import { ImageField, VideoField, AudioField, PdfField, WebField } from "../../new_fields/URLField"; import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; @@ -439,91 +439,83 @@ export namespace Docs { export namespace Get { + const primitives = ["string", "number", "boolean"]; + /** * This function takes any valid JSON(-like) data, i.e. parsed or unparsed, and at arbitrarily * deep levels of nesting, converts the data and structure into nested documents with the appropriate fields. * * After building a hierarchy within / below a top-level document, it then returns that top-level parent. * + * If we've received a string, treat it like valid JSON and try to parse it into an object. If this fails, the + * string is invalid JSON, so we should assume that the input is the result of a JSON.parse() + * call that returned a regular string value to be stored as a Field. + * + * If we've received something other than a string, since the caller might also pass in the results of a + * JSON.parse() call, valid input might be an object, an array (still typeof object), a boolean or a number. + * Anything else (like a function, etc. passed in naively as any) is meaningless for this operation. + * + * All TS/JS objects get converted directly to documents, directly preserving the key value structure. Everything else, + * lacking the key value structure, gets stored as a field in a wrapper document. + * * @param input for convenience and flexibility, either a valid JSON string to be parsed, * or the result of any JSON.parse() call. * @param title an optional title to give to the highest parent document in the hierarchy */ - export function DocumentHierarchyFromJson(input: any, title?: string): Opt; - export function DocumentHierarchyFromJson(input: string, title?: string): Opt { - // preliminary check - making a document out of null or undefined is meaningless - if (input === null || input === undefined) { - return undefined; - } - let parsed: any = input; - // if we've received a string, treat it like valid JSON and try to parse it into an object. - if (typeof input === "string") { - try { - parsed = JSON.parse(input); - } catch (e) { - // if this fails, the string is invalid JSON, so we should assume that the input is the - // result of a JSON.parse() call that returned a regular string value to be stored. - parsed = input; - } - } else if (!["object", "boolean", "number"].includes(typeof input)) { - // since the caller might also pass in the results of a JSON.parse() call, input - // might be an object, an array (still typeof object), a boolean or a number. - // anything else (a function, etc. that is passed in naively as any) is meaningless for this operation + export function DocumentHierarchyFromJson(input: any, title?: string): Opt { + if (input === null || ![...primitives, "object"].includes(typeof input)) { return undefined; } + let parsed: any = typeof input === "string" ? JSONUtils.tryParse(input) : input; let converted: Doc; if (typeof parsed === "object" && !(parsed instanceof Array)) { - // JavaScript object: this gets converted directly to a document, which is a also a list of key value pairs - converted = convertObject(parsed); + converted = convertObject(parsed, title); } else { - // Array, a boolean, a string or a number: this gets stored as a field in a wrapper document, since no key value structure exists - (converted = new Doc).json = valueOf(parsed); + (converted = new Doc).json = toField(parsed); } - // if we passed in a title, assign it title && (converted.title = title); return converted; } - const convertObject = (object: any): Doc => { - // create the document that will store this object's data - let target = new Doc(); - // for each value of the document, recursively convert it to a document or other field - // and store the field at the appropriate key in the document - Object.keys(object).map(key => { - let result = valueOf(object[key]); - // if the result is undefined, ignore it - result && (target[key] = result); - }); + /** + * For each value of the object, recursively convert it to its appropriate field value + * and store the field at the appropriate key in the document if it is not undefined + * @param object the object to convert + * @returns the object mapped from JSON to field values, where each mapping + * might involve arbitrary recursion (since toField might itself call convertObject) + */ + const convertObject = (object: any, title?: string): Doc => { + let target = new Doc(), result: Opt; + Object.keys(object).map(key => (result = toField(object[key], key)) && (target[key] = result)); + title && (target.title = title); return target; }; + /** + * For each element in the list, recursively convert it to a document or other field + * and push the field to the list if it is not undefined + * @param list the list to convert + * @returns the list mapped from JSON to field values, where each mapping + * might involve arbitrary recursion (since toField might itself call convertList) + */ const convertList = (list: Array): List => { - // create the list (Field implementation) that will store this Array's data - let thisLevel = new List(); - // for each element in the list, recursively convert it to a document or other field - // and push the field to the list - list.map(item => { - let result = valueOf(item); - // if the result is undefined, ignore it - result && thisLevel.push(result); - }); - return thisLevel; + let target = new List(), result: Opt; + list.map(item => (result = toField(item)) && target.push(result)); + return target; }; - const valueOf = (data: any): Opt => { + + const toField = (data: any, title?: string): Opt => { if (data === null || data === undefined) { return undefined; } - if (typeof data === "object") { - // recursively convert the object or array to the appropriate field value and return it - return data instanceof Array ? convertList(data) : convertObject(data); - } else if (["string", "number", "boolean"].includes(typeof data)) { - // no real conversion necessary - just return the data, already a valid field, to be stored + if (primitives.includes(typeof data)) { return data; - } else { - // any other type cannot be stored in JSON, but ya never know - throw new Error(`How did ${data} end up in JSON?`); } + if (typeof data === "object") { + return data instanceof Array ? convertList(data) : convertObject(data, title); + } + throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`); }; export async function DocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 4e3b7abe0..39c6c8ce3 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -2,7 +2,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; import { ObjectField } from "./ObjectField"; import { Copy, ToScriptString } from "./FieldSymbols"; -import { deepCopy } from "../Utils"; +import { DeepCopy } from "../Utils"; export enum InkTool { None, @@ -39,7 +39,7 @@ export class InkField extends ObjectField { } [Copy]() { - return new InkField(deepCopy(this.inkData)); + return new InkField(DeepCopy(this.inkData)); } [ToScriptString]() { -- cgit v1.2.3-70-g09d2 From 8db50c6ba0be83b85c896043da53e40c17523e90 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 13:45:32 -0400 Subject: more missing stuff .. bad merge? --- src/client/documents/Documents.ts | 3 ++- src/client/views/nodes/FormattedTextBox.tsx | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src/client/documents/Documents.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index de049be5a..7563fda20 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -55,7 +55,8 @@ export enum DocumentType { ICON = "icon", IMPORT = "import", LINK = "link", - LINKDOC = "linkdoc" + LINKDOC = "linkdoc", + TEMPLATE = "template" } export interface DocumentOptions { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 99801ecff..0a79677e2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -233,10 +233,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`; }, field2 => { - if (StrCast(this.props.Document.layout).indexOf("\"" + this.props.fieldKey + "\"") !== -1) { // bcz: UGH! why is this needed... something is happening out of order. test with making a collection, then adding a text note and converting that to a template field. - this._editorView && !this._applyingChange && - this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2))); - } + this._editorView && !this._applyingChange && + this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2))); } ); -- cgit v1.2.3-70-g09d2