sales-frontend-utils 0.0.56 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +54 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +52 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/download-utils.cjs +84 -0
- package/dist/utils/download-utils.cjs.map +1 -0
- package/dist/utils/download-utils.d.cts +8 -0
- package/dist/utils/download-utils.d.ts +8 -0
- package/dist/utils/download-utils.js +80 -0
- package/dist/utils/download-utils.js.map +1 -0
- package/package.json +11 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/utils/file-utils.ts
|
|
4
|
+
function base64ToBlob(base64String, contentType = "") {
|
|
5
|
+
const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;
|
|
6
|
+
const matches = base64String.match(regex);
|
|
7
|
+
if (matches === null) {
|
|
8
|
+
const debugInfo = {
|
|
9
|
+
base64String
|
|
10
|
+
};
|
|
11
|
+
throw new Error(`Invalid base64 string format. Debug info: ${JSON.stringify(debugInfo, null, 2)}`);
|
|
12
|
+
}
|
|
13
|
+
const contentTypeFinal = contentType || matches[1];
|
|
14
|
+
try {
|
|
15
|
+
const byteCharacters = atob(base64String.replace(regex, ""));
|
|
16
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
17
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
18
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
19
|
+
}
|
|
20
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
21
|
+
return new Blob([byteArray], { type: contentTypeFinal });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`Failed to decode base64 string. Original error: ${error instanceof Error ? error.message : "Unknown error"}. String length: ${base64String?.length}, Content type: ${contentTypeFinal}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/utils/download-utils.ts
|
|
30
|
+
var getBlobUrl = async (url) => {
|
|
31
|
+
let downloadUrl = "";
|
|
32
|
+
if (url.startsWith("http")) {
|
|
33
|
+
const response = await fetch(url);
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Failed to download ${url}`);
|
|
36
|
+
}
|
|
37
|
+
const blob = await response.blob();
|
|
38
|
+
downloadUrl = window.URL.createObjectURL(blob);
|
|
39
|
+
} else if (url.startsWith("blob")) {
|
|
40
|
+
downloadUrl = url;
|
|
41
|
+
} else if (url.startsWith("data")) {
|
|
42
|
+
downloadUrl = URL.createObjectURL(base64ToBlob(url));
|
|
43
|
+
} else {
|
|
44
|
+
throw new Error(`unknown type : ${url}`);
|
|
45
|
+
}
|
|
46
|
+
return downloadUrl;
|
|
47
|
+
};
|
|
48
|
+
var downloadFromNewWindow = async (url, fileName) => {
|
|
49
|
+
try {
|
|
50
|
+
const aTag = document.createElement("a");
|
|
51
|
+
const downloadUrl = await getBlobUrl(url);
|
|
52
|
+
aTag.href = downloadUrl;
|
|
53
|
+
aTag.download = fileName;
|
|
54
|
+
const newWin = window.open();
|
|
55
|
+
newWin?.document.body.appendChild(aTag);
|
|
56
|
+
aTag.click();
|
|
57
|
+
aTag.remove();
|
|
58
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
console.error(e);
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var downloadFromCurrentWindow = async (url, fileName) => {
|
|
65
|
+
try {
|
|
66
|
+
const a = document.createElement("a");
|
|
67
|
+
const downloadUrl = await getBlobUrl(url);
|
|
68
|
+
a.href = downloadUrl;
|
|
69
|
+
a.download = fileName;
|
|
70
|
+
document.body.appendChild(a);
|
|
71
|
+
a.click();
|
|
72
|
+
a.remove();
|
|
73
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.error(e);
|
|
76
|
+
throw e;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
exports.downloadFromCurrentWindow = downloadFromCurrentWindow;
|
|
81
|
+
exports.downloadFromNewWindow = downloadFromNewWindow;
|
|
82
|
+
exports.getBlobUrl = getBlobUrl;
|
|
83
|
+
//# sourceMappingURL=download-utils.cjs.map
|
|
84
|
+
//# sourceMappingURL=download-utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/file-utils.ts","../../src/utils/download-utils.ts"],"names":[],"mappings":"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","file":"download-utils.cjs","sourcesContent":["import { getCookie } from './cookie-utils';\n\nexport function base64ToBlob(base64String: string, contentType = '') {\n const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;\n const matches = base64String.match(regex);\n\n if (matches === null) {\n // ✅ 디버깅 정보 추가\n const debugInfo = {\n base64String\n };\n\n throw new Error(`Invalid base64 string format. Debug info: ${JSON.stringify(debugInfo, null, 2)}`);\n }\n\n const contentTypeFinal = contentType || matches[1];\n\n try {\n const byteCharacters = atob(base64String.replace(regex, ''));\n const byteNumbers = new Array(byteCharacters.length);\n\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n\n const byteArray = new Uint8Array(byteNumbers);\n\n return new Blob([byteArray], { type: contentTypeFinal });\n } catch (error) {\n // ✅ atob 실패 시 추가 정보\n throw new Error(\n `Failed to decode base64 string. Original error: ${error instanceof Error ? error.message : 'Unknown error'}. String length: ${base64String?.length}, Content type: ${contentTypeFinal}`\n );\n }\n}\n\nexport function base64ToFile(base64String: string, fileName: string, contentType = '') {\n try {\n const blob = base64ToBlob(base64String, contentType);\n\n if (!blob) {\n throw new Error(\n `Failed to create blob. FileName: ${fileName}, ContentType: ${contentType}, StringLength: ${base64String?.length}`\n );\n }\n\n return blobToFile(blob, fileName);\n } catch (error) {\n // ✅ 상위 함수에서도 컨텍스트 추가\n throw new Error(\n `base64ToFile failed for \"${fileName}\". ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\nexport function blobToFile(blob: Blob, fileName: string) {\n return new File([blob], fileName, {\n type: blob.type,\n lastModified: Date.now()\n });\n}\n\nexport async function fileToBase64(file: File | Blob): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onload = () => {\n if (typeof reader.result === 'string') {\n resolve(reader.result);\n } else {\n reject(new Error('Invalid file type'));\n }\n };\n\n reader.onerror = (error) => {\n reject(error);\n };\n\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * 파일확장자 리턴\n * @param data string File Blob\n */\nexport function getExt(data: string | File | Blob) {\n if (typeof data === 'string') {\n return data.split('.').pop();\n }\n\n if (data instanceof File) {\n return data.name.split('/').pop();\n }\n\n if (data instanceof Blob) {\n return data.type.split('/').pop();\n }\n}\n\nexport async function objectUrlToBlob(objectUrl: string) {\n try {\n const response = await fetch(objectUrl);\n const blob = await response.blob();\n\n return blob;\n } catch (error) {\n console.error('Error converting object URL to Blob:', error);\n throw error;\n }\n}\n\nexport async function objectUrlToBase64(objectUrl: string): Promise<string> {\n const blob = await objectUrlToBlob(objectUrl);\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n if (typeof reader.result === 'string') {\n resolve(reader.result);\n } else {\n reject(new Error('Invalid file type'));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n}\n\nexport function downloadBlob(blob: Blob, filename: string) {\n // 1. Create a temporary URL for the Blob object\n const url = URL.createObjectURL(blob);\n\n // 2. Create a hidden anchor element\n const link = document.createElement('a');\n link.style.display = 'none';\n link.href = url;\n\n // 3. Set the 'download' attribute with the desired file name\n // This attribute forces the browser to download the URL content instead of navigating to it\n link.download = `${filename}.${getExt(blob)}`;\n\n // 4. Append the link to the body (necessary for the click to work in some browsers)\n document.body.appendChild(link);\n\n // 5. Simulate a click on the link to trigger the download\n link.click();\n\n // 6. Clean up: Remove the link and revoke the object URL\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * image url을 File Object로 변경.\n * @param imageUrl fileObject로 변경할 image url\n * @note fetch를 이용하여 변환하기때문에, 앱내 커스텀스킴을 사용하는경우는 처리불가. imageUrlToFileWithCanvas사용\n * @return file object\n */\nexport async function imageUrlToFileFetch(imageUrl: string): Promise<File> {\n const headers = new Headers();\n headers.append('cache-control', 'no-cache');\n const resImage = await fetch(imageUrl, { headers });\n const blob = await resImage.blob();\n const { type } = blob;\n const name = type.split('/').join('.');\n const file = new File([blob], name, { type });\n\n return file;\n}\n\nexport async function imageUrlToFile(imageUrl: string): Promise<File> {\n const fileConvertTypeCookieKey = 'dsp-debug-mode-file-convert-type';\n const fileConvertType = getCookie(fileConvertTypeCookieKey);\n\n if (fileConvertType === 'fetch') {\n return await imageUrlToFileFetch(imageUrl);\n }\n\n if (fileConvertType === 'xhr') {\n return await imageUrlToFileWithXMLHttpRequest(imageUrl);\n }\n\n return await imageUrlToFileWithCanvas(imageUrl);\n}\n\n/**\n * imageUrlToFile버전을 사용할수 없는경우 대체하여 사용.\n * 메모리소모가 증가하고, 이미지손실가능성이 있음.\n * 이미지원본에 대한 보존이 필수인경우 비추\n * @param imageUrl\n * @returns\n */\nexport async function imageUrlToFileWithCanvas(imageUrl: string): Promise<File> {\n const newImage = new Image();\n newImage.src = imageUrl;\n newImage.crossOrigin = 'Anonymous';\n\n return new Promise((resolve, reject) => {\n newImage.onload = () => {\n const canvas = document.createElement('canvas');\n canvas.width = newImage.width;\n canvas.height = newImage.height;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(newImage, 0, 0);\n canvas.toBlob((blob) => {\n if (blob) {\n const ext = getExt(imageUrl);\n const file = new File([blob], `image.${ext}`, { type: blob.type });\n resolve(file);\n }\n });\n }\n };\n newImage.onerror = (e) => {\n reject(JSON.stringify(e));\n };\n });\n}\n\nexport async function imageUrlToFileWithXMLHttpRequest(imageUrl: string): Promise<File> {\n const xhr = new XMLHttpRequest();\n xhr.open('GET', imageUrl, true);\n xhr.responseType = 'blob';\n xhr.send();\n\n return new Promise((resolve, reject) => {\n xhr.onload = () => {\n if (xhr.status === 200) {\n const blob = xhr.response;\n const file = new File([blob], `image.${getExt(imageUrl)}`, { type: blob.type });\n resolve(file);\n } else {\n reject(new Error(`Failed to load image: ${xhr.status}`));\n }\n };\n xhr.onerror = (e) => {\n reject(JSON.stringify(e));\n };\n });\n}\n","import { base64ToBlob } from \"./file-utils\";\n\nexport const getBlobUrl = async (url: string) => {\n let downloadUrl = '';\n\n if (url.startsWith('http')) {\n //url type : http, https\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download ${url}`);\n }\n const blob = await response.blob();\n downloadUrl = window.URL.createObjectURL(blob);\n } else if (url.startsWith('blob')) {\n //url type : blob\n downloadUrl = url;\n } else if (url.startsWith('data')) {\n //url type : data\n downloadUrl = URL.createObjectURL(base64ToBlob(url));\n } else {\n //unknown type\n throw new Error(`unknown type : ${url}`);\n }\n\n return downloadUrl;\n};\nexport const downloadFromNewWindow = async (url: string, fileName: string) => {\n try {\n const aTag = document.createElement('a');\n const downloadUrl = await getBlobUrl(url);\n aTag.href = downloadUrl;\n aTag.download = fileName;\n const newWin = window.open();\n newWin?.document.body.appendChild(aTag);\n aTag.click();\n aTag.remove();\n window.URL.revokeObjectURL(downloadUrl);\n } catch (e) {\n console.error(e);\n throw e;\n }\n};\n\n/**\n * 파일 다운로드 헬퍼 함수\n */\nexport const downloadFromCurrentWindow = async (url: string, fileName: string) => {\n try {\n const a = document.createElement('a');\n const downloadUrl = await getBlobUrl(url);\n a.href = downloadUrl;\n a.download = fileName;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(downloadUrl);\n } catch (e) {\n console.error(e);\n throw e;\n }\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const getBlobUrl: (url: string) => Promise<string>;
|
|
2
|
+
declare const downloadFromNewWindow: (url: string, fileName: string) => Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* 파일 다운로드 헬퍼 함수
|
|
5
|
+
*/
|
|
6
|
+
declare const downloadFromCurrentWindow: (url: string, fileName: string) => Promise<void>;
|
|
7
|
+
|
|
8
|
+
export { downloadFromCurrentWindow, downloadFromNewWindow, getBlobUrl };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const getBlobUrl: (url: string) => Promise<string>;
|
|
2
|
+
declare const downloadFromNewWindow: (url: string, fileName: string) => Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* 파일 다운로드 헬퍼 함수
|
|
5
|
+
*/
|
|
6
|
+
declare const downloadFromCurrentWindow: (url: string, fileName: string) => Promise<void>;
|
|
7
|
+
|
|
8
|
+
export { downloadFromCurrentWindow, downloadFromNewWindow, getBlobUrl };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/utils/file-utils.ts
|
|
2
|
+
function base64ToBlob(base64String, contentType = "") {
|
|
3
|
+
const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;
|
|
4
|
+
const matches = base64String.match(regex);
|
|
5
|
+
if (matches === null) {
|
|
6
|
+
const debugInfo = {
|
|
7
|
+
base64String
|
|
8
|
+
};
|
|
9
|
+
throw new Error(`Invalid base64 string format. Debug info: ${JSON.stringify(debugInfo, null, 2)}`);
|
|
10
|
+
}
|
|
11
|
+
const contentTypeFinal = contentType || matches[1];
|
|
12
|
+
try {
|
|
13
|
+
const byteCharacters = atob(base64String.replace(regex, ""));
|
|
14
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
15
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
16
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
17
|
+
}
|
|
18
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
19
|
+
return new Blob([byteArray], { type: contentTypeFinal });
|
|
20
|
+
} catch (error) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Failed to decode base64 string. Original error: ${error instanceof Error ? error.message : "Unknown error"}. String length: ${base64String?.length}, Content type: ${contentTypeFinal}`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/utils/download-utils.ts
|
|
28
|
+
var getBlobUrl = async (url) => {
|
|
29
|
+
let downloadUrl = "";
|
|
30
|
+
if (url.startsWith("http")) {
|
|
31
|
+
const response = await fetch(url);
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Failed to download ${url}`);
|
|
34
|
+
}
|
|
35
|
+
const blob = await response.blob();
|
|
36
|
+
downloadUrl = window.URL.createObjectURL(blob);
|
|
37
|
+
} else if (url.startsWith("blob")) {
|
|
38
|
+
downloadUrl = url;
|
|
39
|
+
} else if (url.startsWith("data")) {
|
|
40
|
+
downloadUrl = URL.createObjectURL(base64ToBlob(url));
|
|
41
|
+
} else {
|
|
42
|
+
throw new Error(`unknown type : ${url}`);
|
|
43
|
+
}
|
|
44
|
+
return downloadUrl;
|
|
45
|
+
};
|
|
46
|
+
var downloadFromNewWindow = async (url, fileName) => {
|
|
47
|
+
try {
|
|
48
|
+
const aTag = document.createElement("a");
|
|
49
|
+
const downloadUrl = await getBlobUrl(url);
|
|
50
|
+
aTag.href = downloadUrl;
|
|
51
|
+
aTag.download = fileName;
|
|
52
|
+
const newWin = window.open();
|
|
53
|
+
newWin?.document.body.appendChild(aTag);
|
|
54
|
+
aTag.click();
|
|
55
|
+
aTag.remove();
|
|
56
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error(e);
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var downloadFromCurrentWindow = async (url, fileName) => {
|
|
63
|
+
try {
|
|
64
|
+
const a = document.createElement("a");
|
|
65
|
+
const downloadUrl = await getBlobUrl(url);
|
|
66
|
+
a.href = downloadUrl;
|
|
67
|
+
a.download = fileName;
|
|
68
|
+
document.body.appendChild(a);
|
|
69
|
+
a.click();
|
|
70
|
+
a.remove();
|
|
71
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.error(e);
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export { downloadFromCurrentWindow, downloadFromNewWindow, getBlobUrl };
|
|
79
|
+
//# sourceMappingURL=download-utils.js.map
|
|
80
|
+
//# sourceMappingURL=download-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/file-utils.ts","../../src/utils/download-utils.ts"],"names":[],"mappings":"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","file":"download-utils.js","sourcesContent":["import { getCookie } from './cookie-utils';\n\nexport function base64ToBlob(base64String: string, contentType = '') {\n const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;\n const matches = base64String.match(regex);\n\n if (matches === null) {\n // ✅ 디버깅 정보 추가\n const debugInfo = {\n base64String\n };\n\n throw new Error(`Invalid base64 string format. Debug info: ${JSON.stringify(debugInfo, null, 2)}`);\n }\n\n const contentTypeFinal = contentType || matches[1];\n\n try {\n const byteCharacters = atob(base64String.replace(regex, ''));\n const byteNumbers = new Array(byteCharacters.length);\n\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n\n const byteArray = new Uint8Array(byteNumbers);\n\n return new Blob([byteArray], { type: contentTypeFinal });\n } catch (error) {\n // ✅ atob 실패 시 추가 정보\n throw new Error(\n `Failed to decode base64 string. Original error: ${error instanceof Error ? error.message : 'Unknown error'}. String length: ${base64String?.length}, Content type: ${contentTypeFinal}`\n );\n }\n}\n\nexport function base64ToFile(base64String: string, fileName: string, contentType = '') {\n try {\n const blob = base64ToBlob(base64String, contentType);\n\n if (!blob) {\n throw new Error(\n `Failed to create blob. FileName: ${fileName}, ContentType: ${contentType}, StringLength: ${base64String?.length}`\n );\n }\n\n return blobToFile(blob, fileName);\n } catch (error) {\n // ✅ 상위 함수에서도 컨텍스트 추가\n throw new Error(\n `base64ToFile failed for \"${fileName}\". ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\nexport function blobToFile(blob: Blob, fileName: string) {\n return new File([blob], fileName, {\n type: blob.type,\n lastModified: Date.now()\n });\n}\n\nexport async function fileToBase64(file: File | Blob): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onload = () => {\n if (typeof reader.result === 'string') {\n resolve(reader.result);\n } else {\n reject(new Error('Invalid file type'));\n }\n };\n\n reader.onerror = (error) => {\n reject(error);\n };\n\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * 파일확장자 리턴\n * @param data string File Blob\n */\nexport function getExt(data: string | File | Blob) {\n if (typeof data === 'string') {\n return data.split('.').pop();\n }\n\n if (data instanceof File) {\n return data.name.split('/').pop();\n }\n\n if (data instanceof Blob) {\n return data.type.split('/').pop();\n }\n}\n\nexport async function objectUrlToBlob(objectUrl: string) {\n try {\n const response = await fetch(objectUrl);\n const blob = await response.blob();\n\n return blob;\n } catch (error) {\n console.error('Error converting object URL to Blob:', error);\n throw error;\n }\n}\n\nexport async function objectUrlToBase64(objectUrl: string): Promise<string> {\n const blob = await objectUrlToBlob(objectUrl);\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n if (typeof reader.result === 'string') {\n resolve(reader.result);\n } else {\n reject(new Error('Invalid file type'));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n}\n\nexport function downloadBlob(blob: Blob, filename: string) {\n // 1. Create a temporary URL for the Blob object\n const url = URL.createObjectURL(blob);\n\n // 2. Create a hidden anchor element\n const link = document.createElement('a');\n link.style.display = 'none';\n link.href = url;\n\n // 3. Set the 'download' attribute with the desired file name\n // This attribute forces the browser to download the URL content instead of navigating to it\n link.download = `${filename}.${getExt(blob)}`;\n\n // 4. Append the link to the body (necessary for the click to work in some browsers)\n document.body.appendChild(link);\n\n // 5. Simulate a click on the link to trigger the download\n link.click();\n\n // 6. Clean up: Remove the link and revoke the object URL\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * image url을 File Object로 변경.\n * @param imageUrl fileObject로 변경할 image url\n * @note fetch를 이용하여 변환하기때문에, 앱내 커스텀스킴을 사용하는경우는 처리불가. imageUrlToFileWithCanvas사용\n * @return file object\n */\nexport async function imageUrlToFileFetch(imageUrl: string): Promise<File> {\n const headers = new Headers();\n headers.append('cache-control', 'no-cache');\n const resImage = await fetch(imageUrl, { headers });\n const blob = await resImage.blob();\n const { type } = blob;\n const name = type.split('/').join('.');\n const file = new File([blob], name, { type });\n\n return file;\n}\n\nexport async function imageUrlToFile(imageUrl: string): Promise<File> {\n const fileConvertTypeCookieKey = 'dsp-debug-mode-file-convert-type';\n const fileConvertType = getCookie(fileConvertTypeCookieKey);\n\n if (fileConvertType === 'fetch') {\n return await imageUrlToFileFetch(imageUrl);\n }\n\n if (fileConvertType === 'xhr') {\n return await imageUrlToFileWithXMLHttpRequest(imageUrl);\n }\n\n return await imageUrlToFileWithCanvas(imageUrl);\n}\n\n/**\n * imageUrlToFile버전을 사용할수 없는경우 대체하여 사용.\n * 메모리소모가 증가하고, 이미지손실가능성이 있음.\n * 이미지원본에 대한 보존이 필수인경우 비추\n * @param imageUrl\n * @returns\n */\nexport async function imageUrlToFileWithCanvas(imageUrl: string): Promise<File> {\n const newImage = new Image();\n newImage.src = imageUrl;\n newImage.crossOrigin = 'Anonymous';\n\n return new Promise((resolve, reject) => {\n newImage.onload = () => {\n const canvas = document.createElement('canvas');\n canvas.width = newImage.width;\n canvas.height = newImage.height;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(newImage, 0, 0);\n canvas.toBlob((blob) => {\n if (blob) {\n const ext = getExt(imageUrl);\n const file = new File([blob], `image.${ext}`, { type: blob.type });\n resolve(file);\n }\n });\n }\n };\n newImage.onerror = (e) => {\n reject(JSON.stringify(e));\n };\n });\n}\n\nexport async function imageUrlToFileWithXMLHttpRequest(imageUrl: string): Promise<File> {\n const xhr = new XMLHttpRequest();\n xhr.open('GET', imageUrl, true);\n xhr.responseType = 'blob';\n xhr.send();\n\n return new Promise((resolve, reject) => {\n xhr.onload = () => {\n if (xhr.status === 200) {\n const blob = xhr.response;\n const file = new File([blob], `image.${getExt(imageUrl)}`, { type: blob.type });\n resolve(file);\n } else {\n reject(new Error(`Failed to load image: ${xhr.status}`));\n }\n };\n xhr.onerror = (e) => {\n reject(JSON.stringify(e));\n };\n });\n}\n","import { base64ToBlob } from \"./file-utils\";\n\nexport const getBlobUrl = async (url: string) => {\n let downloadUrl = '';\n\n if (url.startsWith('http')) {\n //url type : http, https\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download ${url}`);\n }\n const blob = await response.blob();\n downloadUrl = window.URL.createObjectURL(blob);\n } else if (url.startsWith('blob')) {\n //url type : blob\n downloadUrl = url;\n } else if (url.startsWith('data')) {\n //url type : data\n downloadUrl = URL.createObjectURL(base64ToBlob(url));\n } else {\n //unknown type\n throw new Error(`unknown type : ${url}`);\n }\n\n return downloadUrl;\n};\nexport const downloadFromNewWindow = async (url: string, fileName: string) => {\n try {\n const aTag = document.createElement('a');\n const downloadUrl = await getBlobUrl(url);\n aTag.href = downloadUrl;\n aTag.download = fileName;\n const newWin = window.open();\n newWin?.document.body.appendChild(aTag);\n aTag.click();\n aTag.remove();\n window.URL.revokeObjectURL(downloadUrl);\n } catch (e) {\n console.error(e);\n throw e;\n }\n};\n\n/**\n * 파일 다운로드 헬퍼 함수\n */\nexport const downloadFromCurrentWindow = async (url: string, fileName: string) => {\n try {\n const a = document.createElement('a');\n const downloadUrl = await getBlobUrl(url);\n a.href = downloadUrl;\n a.download = fileName;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(downloadUrl);\n } catch (e) {\n console.error(e);\n throw e;\n }\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sales-frontend-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.57",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -158,6 +158,16 @@
|
|
|
158
158
|
"types": "./dist/utils/gender.d.cts",
|
|
159
159
|
"default": "./dist/utils/gender.cjs"
|
|
160
160
|
}
|
|
161
|
+
},
|
|
162
|
+
"./download": {
|
|
163
|
+
"import": {
|
|
164
|
+
"types": "./dist/utils/download-utils.d.ts",
|
|
165
|
+
"default": "./dist/utils/download-utils.js"
|
|
166
|
+
},
|
|
167
|
+
"require": {
|
|
168
|
+
"types": "./dist/utils/download-utils.d.cts",
|
|
169
|
+
"default": "./dist/utils/download-utils.cjs"
|
|
170
|
+
}
|
|
161
171
|
}
|
|
162
172
|
},
|
|
163
173
|
"dependencies": {
|