From e262d9ac73af5b2cef384468c47d69917e205d44 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 7 Apr 2020 23:01:46 -0400 Subject: lots of code cleanup - removed all northstar db stuff. added scriptingBox. renamed things. made collectiontypes strings not numbers. --- src/client/apis/youtube/YoutubeBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/apis/youtube/YoutubeBox.tsx') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index c940bba43..4b4145fcc 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -171,9 +171,9 @@ export class YoutubeBox extends React.Component { * in the title of the videos. */ filterYoutubeTitleResult = (resultTitle: string) => { - let processedTitle: string = resultTitle.ReplaceAll("&", "&"); - processedTitle = processedTitle.ReplaceAll("'", "'"); - processedTitle = processedTitle.ReplaceAll(""", "\""); + let processedTitle: string = resultTitle.replace(/&/g, "&");//.ReplaceAll("&", "&"); + processedTitle = processedTitle.replace(/"'/g, "'"); + processedTitle = processedTitle.replace(/"/g, "\""); return processedTitle; } -- cgit v1.2.3-70-g09d2 From 952318fb56cce16c428a5b41afe27a0ee4d20589 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 11 Apr 2020 21:50:07 -0400 Subject: fixed double click on freeformviews. changed signature for DocumentHierarchyFromJson() to have an 'all' parameter --- src/client/apis/youtube/YoutubeBox.tsx | 4 +-- src/client/cognitive_services/CognitiveServices.ts | 2 +- src/client/documents/Documents.ts | 33 +++++++++++++--------- .../util/Import & Export/DirectoryImportBox.tsx | 2 +- src/client/util/Import & Export/ImageUtils.ts | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 ++++++---- src/client/views/nodes/ImageBox.tsx | 2 +- 7 files changed, 35 insertions(+), 25 deletions(-) (limited to 'src/client/apis/youtube/YoutubeBox.tsx') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index 4b4145fcc..4e990537f 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -156,14 +156,14 @@ export class YoutubeBox extends React.Component { @action processVideoDetails = (videoDetails: any[]) => { this.videoDetails = videoDetails; - this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp"); + this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp", undefined, false); } /** * The function that stores the search results in the props document. */ backUpSearchResults = (videos: any[]) => { - this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp"); + this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp", undefined, false); } /** diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 3f3726621..e464aff55 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -192,7 +192,7 @@ export namespace CognitiveServices { let results = await ExecuteQuery(Service.Handwriting, Manager, inkData); if (results) { results.recognitionUnits && (results = results.recognitionUnits); - target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis"); + target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis", undefined, false); const recognizedText = results.map((item: any) => item.recognizedText); const recognizedObjects = results.map((item: any) => item.recognizedObject); const individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b5c6dc06a..30f72a6b2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -116,7 +116,7 @@ export interface DocumentOptions { borderRounding?: string; boxShadow?: string; dontRegisterChildren?: boolean; - "onClick-rawScript"?:string; // onClick script in raw text form + "onClick-rawScript"?: string; // onClick script in raw text form _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views schemaColumns?: List; dockingConfig?: string; @@ -405,7 +405,7 @@ export namespace Docs { const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); - Docs.Get.DocumentHierarchyFromJson(device, undefined, deviceProto); + Docs.Get.DocumentHierarchyFromJson(device, undefined, deviceProto, false); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { console.log(errors); @@ -732,19 +732,21 @@ export namespace Docs { * @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 + * @param appendToTarget -??? + * @param all whether fields should be converted even if they contain no data */ - export function DocumentHierarchyFromJson(input: any, title?: string, appendToTarget?: Doc): Opt { + export function DocumentHierarchyFromJson(input: any, title: string, appendToTarget: Opt, all?:boolean): Opt { if (input === undefined || input === null || ![...primitives, "object"].includes(typeof input)) { return undefined; } input = JSON.parse(typeof input === "string" ? input : JSON.stringify(input)); - let converted: Doc; + let converted: Opt; if (typeof input === "object" && !(input instanceof Array)) { - converted = convertObject(input, title, appendToTarget); + converted = convertObject(input, title, appendToTarget, all); } else { (converted = new Doc).json = toField(input); } - title && (converted.title = title); + title && converted && (converted.title = title); return converted; } @@ -755,12 +757,15 @@ export namespace Docs { * @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, target?: Doc): Doc => { - const resolved = target ?? new Doc; - let result: Opt; - Object.keys(object).map(key => (result = toField(object[key], key)) && (resolved[key] = result)); - title && !resolved.title && (resolved.title = title); - return resolved; + const convertObject = (object: any, title?: string, target?: Doc, all?:boolean): Opt => { + const objkeys = Object.keys(object); + if (objkeys.length || all) { + const resolved = target ?? new Doc; + let result: Opt; + Object.keys(object).map(key => (result = toField(object[key], key)) && (resolved[key] = result)); + title && !resolved.title && (resolved.title = title); + return resolved; + } }; /** @@ -778,7 +783,7 @@ export namespace Docs { }; - const toField = (data: any, title?: string): Opt => { + const toField = (data: any, title?: string, all?:boolean): Opt => { if (data === null || data === undefined) { return undefined; } @@ -786,7 +791,7 @@ export namespace Docs { return data; } if (typeof data === "object") { - return data instanceof Array ? convertList(data) : convertObject(data, title); + return data instanceof Array ? convertList(data) : convertObject(data, title, undefined, all); } throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`); }; diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 3d8bcbab7..01a0eddf8 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -126,7 +126,7 @@ export default class DirectoryImportBox extends React.Component const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { - Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data); + Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data, "", undefined, false); docs.push(document); } })); diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index ab8c73d15..135454a33 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -20,7 +20,7 @@ export namespace ImageUtils { nativeHeight, exifData: { error, data } } = await Networking.PostToServer("/inspectImage", { source }); - document.exif = error || Docs.Get.DocumentHierarchyFromJson(data); + document.exif = error || Docs.Get.DocumentHierarchyFromJson(data, "", undefined, false); const proto = Doc.GetProto(document); proto["data-nativeWidth"] = nativeWidth; proto["data-nativeHeight"] = nativeHeight; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ed6286675..f27b37e2c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -493,17 +493,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u onPointerUp = (e: PointerEvent): void => { if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + this.removeMoveListeners(); + this.removeEndListeners(); + } + + onClick = (e: React.MouseEvent) => { if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) { if (Date.now() - this._lastTap < 300) { const docpt = this.getTransform().transformPoint(e.clientX, e.clientY); this.scaleAtPt(docpt, NumCast(this.layoutDoc.targetScale, NumCast(this.layoutDoc.scale))); + e.stopPropagation(); + e.preventDefault(); } this._lastTap = Date.now(); } - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - this.removeMoveListeners(); - this.removeEndListeners(); } @action @@ -1129,7 +1134,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document return
{ const converter = (results: any) => { const faceDocs = new List(); - results.reduce((face: CognitiveServices.Image.Face, faceDocs: List) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!), new List()); + results.reduce((face: CognitiveServices.Image.Face, faceDocs: List) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`, undefined, false)!), new List()); return faceDocs; }; this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter); -- cgit v1.2.3-70-g09d2 From 3f037a4426f17c0f542a06daceecead29e63803f Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 11 Apr 2020 20:16:44 -0700 Subject: document from json improvements and documentation --- src/client/apis/youtube/YoutubeBox.tsx | 4 +- src/client/cognitive_services/CognitiveServices.ts | 2 +- src/client/documents/Documents.ts | 92 ++++++++++++++++------ .../util/Import & Export/DirectoryImportBox.tsx | 2 +- src/client/util/Import & Export/ImageUtils.ts | 2 +- src/client/views/nodes/ImageBox.tsx | 4 +- 6 files changed, 72 insertions(+), 34 deletions(-) (limited to 'src/client/apis/youtube/YoutubeBox.tsx') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index 4e990537f..1575e53fc 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -156,14 +156,14 @@ export class YoutubeBox extends React.Component { @action processVideoDetails = (videoDetails: any[]) => { this.videoDetails = videoDetails; - this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp", undefined, false); + this.props.Document.cachedDetails = Docs.Get.FromJson({ data: videoDetails, title: "detailBackUp" }); } /** * The function that stores the search results in the props document. */ backUpSearchResults = (videos: any[]) => { - this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp", undefined, false); + this.props.Document.cachedSearchResults = Docs.Get.FromJson({ data: videos, title: "videosBackUp" }); } /** diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index e464aff55..5d83de233 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -192,7 +192,7 @@ export namespace CognitiveServices { let results = await ExecuteQuery(Service.Handwriting, Manager, inkData); if (results) { results.recognitionUnits && (results = results.recognitionUnits); - target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis", undefined, false); + target[keys[0]] = Docs.Get.FromJson({ data: results, title: "Ink Analysis" }); const recognizedText = results.map((item: any) => item.recognizedText); const recognizedObjects = results.map((item: any) => item.recognizedObject); const individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 30f72a6b2..ec864b268 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -405,7 +405,7 @@ export namespace Docs { const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); - Docs.Get.DocumentHierarchyFromJson(device, undefined, deviceProto, false); + Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { console.log(errors); @@ -712,6 +712,15 @@ export namespace Docs { const primitives = ["string", "number", "boolean"]; + export interface JsonConversionOpts { + data: any; + title?: string; + appendToExisting?: { targetDoc: Doc, fieldKey?: string }; + excludeEmptyObjects?: boolean; + } + + const defaultKey = "json"; + /** * 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. @@ -729,25 +738,49 @@ export namespace Docs { * 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, + * @param data 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 - * @param appendToTarget -??? - * @param all whether fields should be converted even if they contain no data + * @param title an optional title to give to the highest parent document in the hierarchy. + * If whether this function creates a new document or appendToExisting is specified and that document already has a title, + * because this title field can be left undefined for the opposite behavior, including a title will overwrite the existing title. + * @param appendToExisting **if specified**, there are two cases: the json to be converted can be represented as a document, in which ase + * the target document will receive all the conversion results as new fields on it, or, if the json can't be represented as a document, + * the function will assign the converstion results to either the specified key on the target document, or to the "json" key by default. + * If not specified, will create a new entirely generic. + * + * One might choose to specify this field if you want to write to a document returned from a Document.Create function call, + * say a TreeView document that will be rendered, not just an untyped, identityless doc that would otherwise be created + * from a default call to new Doc. + * + * @param excludeEmptyObjects whether non-primitive objects (TypeScript objects and arrays) should be converted even + * if they contain no data. By default, empty objects and arrays are ignored. */ - export function DocumentHierarchyFromJson(input: any, title: string, appendToTarget: Opt, all?:boolean): Opt { - if (input === undefined || input === null || ![...primitives, "object"].includes(typeof input)) { + export function FromJson({ data, title, appendToExisting, excludeEmptyObjects }: JsonConversionOpts): Opt { + if (excludeEmptyObjects === undefined) { + excludeEmptyObjects = true; + } + if (data === undefined || data === null || ![...primitives, "object"].includes(typeof data)) { + return undefined; + } + let resolved: any; + try { + resolved = JSON.parse(typeof data === "string" ? data : JSON.stringify(data)); + } catch (e) { return undefined; } - input = JSON.parse(typeof input === "string" ? input : JSON.stringify(input)); - let converted: Opt; - if (typeof input === "object" && !(input instanceof Array)) { - converted = convertObject(input, title, appendToTarget, all); + let output: Opt; + if (typeof resolved === "object" && !(resolved instanceof Array)) { + output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc); } else { - (converted = new Doc).json = toField(input); + const result = toField(resolved, excludeEmptyObjects); + if (appendToExisting) { + (output = appendToExisting.targetDoc)[appendToExisting.fieldKey || defaultKey] = result; + } else { + (output = new Doc).json = result; + } } - title && converted && (converted.title = title); - return converted; + title && output && (output.title = title); + return output; } /** @@ -757,13 +790,19 @@ export namespace Docs { * @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, target?: Doc, all?:boolean): Opt => { - const objkeys = Object.keys(object); - if (objkeys.length || all) { + const convertObject = (object: any, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt => { + const hasEntries = Object.keys(object).length; + if (hasEntries || !excludeEmptyObjects) { const resolved = target ?? new Doc; - let result: Opt; - Object.keys(object).map(key => (result = toField(object[key], key)) && (resolved[key] = result)); - title && !resolved.title && (resolved.title = title); + if (hasEntries) { + let result: Opt; + Object.keys(object).map(key => { + if (result = toField(object[key], excludeEmptyObjects, key)) { + (resolved[key] = result); + } + }); + } + title && (resolved.title = title); return resolved; } }; @@ -775,15 +814,16 @@ export namespace Docs { * @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 => { + const convertList = (list: Array, excludeEmptyObjects: boolean): Opt> => { const target = new List(); let result: Opt; - list.map(item => (result = toField(item)) && target.push(result)); - return target; + list.map(item => (result = toField(item, excludeEmptyObjects)) && target.push(result)); + if (target.length || !excludeEmptyObjects) { + return target; + } }; - - const toField = (data: any, title?: string, all?:boolean): Opt => { + const toField = (data: any, excludeEmptyObjects: boolean, title?: string): Opt => { if (data === null || data === undefined) { return undefined; } @@ -791,7 +831,7 @@ export namespace Docs { return data; } if (typeof data === "object") { - return data instanceof Array ? convertList(data) : convertObject(data, title, undefined, all); + return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data, excludeEmptyObjects, title, undefined); } throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`); }; diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 01a0eddf8..438904688 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -126,7 +126,7 @@ export default class DirectoryImportBox extends React.Component const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { - Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data, "", undefined, false); + Doc.GetProto(document).exif = error || Docs.Get.FromJson({ data }); docs.push(document); } })); diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 135454a33..9fae5ff93 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -20,7 +20,7 @@ export namespace ImageUtils { nativeHeight, exifData: { error, data } } = await Networking.PostToServer("/inspectImage", { source }); - document.exif = error || Docs.Get.DocumentHierarchyFromJson(data, "", undefined, false); + document.exif = error || Docs.Get.FromJson({ data }); const proto = Doc.GetProto(document); proto["data-nativeWidth"] = nativeWidth; proto["data-nativeHeight"] = nativeHeight; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c45f14975..de1640027 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -186,9 +186,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const converter = (results: any) => { - const faceDocs = new List(); - results.reduce((face: CognitiveServices.Image.Face, faceDocs: List) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`, undefined, false)!), new List()); - return faceDocs; + return results.map((face: CognitiveServices.Image.Face) => Docs.Get.FromJson({ data: face, title: `Face: ${face.faceId}` })!); }; this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter); } -- cgit v1.2.3-70-g09d2