From c7e82629337ab81f10d9008afa6fd886b3b582b4 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Thu, 23 Apr 2026 15:05:59 +0200 Subject: [PATCH 1/6] Fixed JavaScript modules with special characters not displayed correctly in the editor --- ui-ngx/src/app/core/utils.ts | 8 +++++++- ui-ngx/src/app/shared/components/file-input.component.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 348d4e7e9b..903e3d1e03 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -210,7 +210,13 @@ export function objToBase64(obj: any): string { } export function base64toString(b64Encoded: string): string { - return decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); + const binary = atob(b64Encoded); + const bytes = Uint8Array.from(binary, c => c.charCodeAt(0)); + try { + return new TextDecoder('utf-8', { fatal: true }).decode(bytes); + } catch { + return new TextDecoder('iso-8859-1').decode(bytes); + } } export function objToBase64URI(obj: any): string { diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index 69945170da..29cfaccfb5 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -235,7 +235,7 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, if (this.readAsBinary) { reader.readAsBinaryString(file.file); } else { - reader.readAsText(file.file); + reader.readAsText(file.file, 'ISO-8859-1'); } }); } From 22d8b9e9fc57dc9952ed44b3027e2ade7f9746e5 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 28 Apr 2026 09:05:34 +0200 Subject: [PATCH 2/6] Optimized code --- ui-ngx/src/app/core/utils.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 903e3d1e03..6c12e94560 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -209,13 +209,19 @@ export function objToBase64(obj: any): string { })); } +const textDecoderUtf8 = new TextDecoder('utf-8', { fatal: true }); +const textDecoderLatin1 = new TextDecoder('iso-8859-1'); + export function base64toString(b64Encoded: string): string { const binary = atob(b64Encoded); - const bytes = Uint8Array.from(binary, c => c.charCodeAt(0)); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } try { - return new TextDecoder('utf-8', { fatal: true }).decode(bytes); + return textDecoderUtf8.decode(bytes); } catch { - return new TextDecoder('iso-8859-1').decode(bytes); + return textDecoderLatin1.decode(bytes); } } From 970d8ed21d9c8c209587e7c942fbae41dac4c130 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Wed, 29 Apr 2026 14:17:01 +0200 Subject: [PATCH 3/6] Fixed approach --- .../shared/components/file-input.component.ts | 84 +++++++++++++------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index 29cfaccfb5..c7c977311e 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -205,37 +205,69 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, private readerAsFile(file: flowjs.FlowFile): Promise { return new Promise((resolve) => { - const reader = new FileReader(); - reader.onload = () => { - let fileName = null; - let fileContent = null; - let files = null; - let mediaType = null; - if (reader.readyState === reader.DONE) { - if (!this.workFromFileObj) { - fileContent = reader.result; - if (fileContent && fileContent.length > 0) { - if (this.contentConvertFunction) { - fileContent = this.contentConvertFunction(fileContent); + if (this.readAsBinary) { + const reader = new FileReader(); + reader.onload = () => { + let fileName = null; + let fileContent = null; + let files = null; + let mediaType = null; + if (reader.readyState === reader.DONE) { + if (!this.workFromFileObj) { + fileContent = reader.result; + if (fileContent && fileContent.length > 0) { + if (this.contentConvertFunction) { + fileContent = this.contentConvertFunction(fileContent as string); + } + fileName = fileContent ? file.name : null; + mediaType = file?.file?.type || null; } - fileName = fileContent ? file.name : null; - mediaType = file?.file?.type || null; + } else if (file.name || file.file) { + files = file.file; + fileName = file.name; + mediaType = file.file.type || null; } - } else if (file.name || file.file){ - files = file.file; - fileName = file.name; - mediaType = file.file.type || null; } - } - resolve({fileContent, fileName, files, mediaType}); - }; - reader.onerror = () => { - resolve({fileContent: null, fileName: null, files: null, mediaType: null}); - }; - if (this.readAsBinary) { + resolve({fileContent, fileName, files, mediaType}); + }; + reader.onerror = () => { + resolve({fileContent: null, fileName: null, files: null, mediaType: null}); + }; reader.readAsBinaryString(file.file); } else { - reader.readAsText(file.file, 'ISO-8859-1'); + if (this.workFromFileObj) { + resolve({ + fileContent: null, + fileName: file.name, + files: file.file, + mediaType: file.file?.type || null + }); + return; + } + file.file.arrayBuffer().then(buf => { + const bytes = new Uint8Array(buf); + let text: string; + try { + text = new TextDecoder('utf-8', {fatal: true}).decode(bytes); + } catch { + text = new TextDecoder('iso-8859-1').decode(bytes); + } + + let fileContent: any = text && text.length > 0 ? text : null; + let fileName: string = null; + const mediaType: string = file?.file?.type || null; + + if (fileContent) { + if (this.contentConvertFunction) { + fileContent = this.contentConvertFunction(fileContent); + } + fileName = fileContent ? file.name : null; + } + + resolve({fileContent, fileName, files: null, mediaType}); + }).catch(() => { + resolve({fileContent: null, fileName: null, files: null, mediaType: null}); + }); } }); } From 19fcdcb5d18420288a1403bb673723c73ed49ebf Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Wed, 29 Apr 2026 14:25:29 +0200 Subject: [PATCH 4/6] Fixed base64toObj --- ui-ngx/src/app/core/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 6c12e94560..a858865b0c 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -230,8 +230,7 @@ export function objToBase64URI(obj: any): string { } export function base64toObj(b64Encoded: string): any { - const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); - return JSON.parse(json); + return JSON.parse(base64toString(b64Encoded)); } export function stringToBase64(value: string): string { From ee81d4b967ccc81c4ed912de85ab741485851cfc Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Wed, 29 Apr 2026 14:28:07 +0200 Subject: [PATCH 5/6] Fixed --- .../shared/components/file-input.component.ts | 86 ++++++++----------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index c7c977311e..51b3fec787 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -205,45 +205,40 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, private readerAsFile(file: flowjs.FlowFile): Promise { return new Promise((resolve) => { - if (this.readAsBinary) { - const reader = new FileReader(); - reader.onload = () => { - let fileName = null; - let fileContent = null; - let files = null; - let mediaType = null; - if (reader.readyState === reader.DONE) { - if (!this.workFromFileObj) { - fileContent = reader.result; - if (fileContent && fileContent.length > 0) { - if (this.contentConvertFunction) { - fileContent = this.contentConvertFunction(fileContent as string); - } - fileName = fileContent ? file.name : null; - mediaType = file?.file?.type || null; - } - } else if (file.name || file.file) { - files = file.file; - fileName = file.name; - mediaType = file.file.type || null; + if (this.workFromFileObj) { + resolve({ + fileContent: null, + fileName: file.name, + files: file.file, + mediaType: file.file?.type || null + }); + return; + } + + const reader = new FileReader(); + reader.onload = () => { + let fileName = null; + let fileContent = null; + let mediaType = null; + if (reader.readyState === reader.DONE) { + fileContent = reader.result; + if (fileContent && fileContent.length > 0) { + if (this.contentConvertFunction) { + fileContent = this.contentConvertFunction(fileContent); } + fileName = fileContent ? file.name : null; + mediaType = file?.file?.type || null; } - resolve({fileContent, fileName, files, mediaType}); - }; - reader.onerror = () => { - resolve({fileContent: null, fileName: null, files: null, mediaType: null}); - }; + } + resolve({fileContent, fileName, files: null, mediaType}); + }; + reader.onerror = () => { + resolve({fileContent: null, fileName: null, files: null, mediaType: null}); + }; + + if (this.readAsBinary) { reader.readAsBinaryString(file.file); } else { - if (this.workFromFileObj) { - resolve({ - fileContent: null, - fileName: file.name, - files: file.file, - mediaType: file.file?.type || null - }); - return; - } file.file.arrayBuffer().then(buf => { const bytes = new Uint8Array(buf); let text: string; @@ -252,26 +247,13 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, } catch { text = new TextDecoder('iso-8859-1').decode(bytes); } - - let fileContent: any = text && text.length > 0 ? text : null; - let fileName: string = null; - const mediaType: string = file?.file?.type || null; - - if (fileContent) { - if (this.contentConvertFunction) { - fileContent = this.contentConvertFunction(fileContent); - } - fileName = fileContent ? file.name : null; - } - - resolve({fileContent, fileName, files: null, mediaType}); - }).catch(() => { - resolve({fileContent: null, fileName: null, files: null, mediaType: null}); - }); + Object.defineProperty(reader, 'readyState', {value: FileReader.DONE, configurable: true}); + Object.defineProperty(reader, 'result', {value: text, configurable: true}); + reader.onload(new ProgressEvent('load')); + }).catch(() => reader.onerror(new ProgressEvent('error'))); } }); } - private checkMaxSize(file: flowjs.FlowFile): boolean { return !this.maxSizeByte || file.size <= this.maxSizeByte; } From 459c8d44520d4d683049d862835997dcca87bf64 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Wed, 29 Apr 2026 14:32:15 +0200 Subject: [PATCH 6/6] Types fix --- ui-ngx/src/app/shared/components/file-input.component.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index 3a309a97ac..5b09c30c25 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -215,6 +215,7 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, }); return; } + const reader = new FileReader(); reader.onload = () => { let fileName = null; @@ -235,7 +236,6 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, reader.onerror = () => { resolve({fileContent: null, fileName: null, files: null, mediaType: null}); }; - if (this.readAsBinary) { reader.readAsBinaryString(file.file); } else { @@ -249,11 +249,12 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, } Object.defineProperty(reader, 'readyState', {value: FileReader.DONE, configurable: true}); Object.defineProperty(reader, 'result', {value: text, configurable: true}); - reader.onload(new ProgressEvent('load')); - }).catch(() => reader.onerror(new ProgressEvent('error'))); + reader.onload(new ProgressEvent('load') as ProgressEvent); + }).catch(() => reader.onerror(new ProgressEvent('error') as ProgressEvent)); } }); } + private checkMaxSize(file: flowjs.FlowFile): boolean { return !this.maxSizeByte || file.size <= this.maxSizeByte; }